Skip to content

Commit

Permalink
Merge pull request #135 from StrykeSlammerII/5.1
Browse files Browse the repository at this point in the history
Ch 8 proofreading
  • Loading branch information
lcharette authored Mar 30, 2024
2 parents 7456940 + 9a3355e commit 9c8109e
Show file tree
Hide file tree
Showing 11 changed files with 53 additions and 53 deletions.
2 changes: 1 addition & 1 deletion pages/07.dependency-injection/02.the-di-container/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ You'll notice that the callable used to create a `Logger` object takes two param

### Binding Interfaces

Earlier we discussed the benefits of using interfaces, as the constructor can accept any class that implement the correct interface:
Earlier we discussed the benefits of using interfaces, as the constructor can accept any class that implements the correct interface:

```php
public function __construct(NestInterface $nest) // Accept both `Nest` and `ImprovedNest`
Expand Down
4 changes: 2 additions & 2 deletions pages/08.routes-and-controllers/01.introduction/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ if (isset($_POST)) {

This is what is commonly referred to as ***spaghetti code***. All of the logic and presentation for a feature is mixed up into a single file. There is little or no object-oriented design, and probably a lot of repetitive code from one feature to the next. It's also really difficult to write clean HTML when we're building it with `echo` statements and interpolating all sorts of PHP statements with the HTML content.

MVC organizes our application into three main domains - the **model**, which represents our [database](/database) entities and other types of encapsulated logic, the **view**, which generates the final output (often HTML) that the user receives, and the **controller**, which controls the flow of interaction between the model and the view (and may contain some logic of its own as well).
MVC organizes our application into three main domains - the **model**, which represents our [database](/database) entities and other types of encapsulated logic; the **view**, which generates the final output (often HTML) that the user receives; and the **controller**, which controls the flow of interaction between the model and the view (and may contain some logic of its own as well).

UserFrosting uses a templating engine called [Twig](/templating-with-twig) to handle the rendering of HTML output in the view. UserFrosting's model consists of a set of [Eloquent](https://laravel.com/docs/8.x/eloquent) models for handling interactions with the database, as well as a number of other accessory classes that perform most of heavy lifting for your application. We'll talk about both of these in later chapters.
UserFrosting uses a templating engine called [Twig](/templating-with-twig) to handle the rendering of HTML output in the view. UserFrosting's model consists of a set of [Eloquent](https://laravel.com/docs/10.x/eloquent) models for handling interactions with the database, as well as a number of other accessory classes that perform most of the heavy lifting for your application. We'll talk about both of these in later chapters.

In this chapter, we discuss UserFrosting's **controller**, which is based around the [Slim 4](https://www.slimframework.com/docs/v4/) microframework. Whenever you are looking to add a new page or feature to your application, you probably want to start with the controller.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The default status code used by the `Response` object. You should use this code

You should use this whenever you permanently rename a route - especially for pages! You want the old route to automatically resolve to your new URL, otherwise this could hurt your search engine rankings.

Recommended practice is to create a new route definition class in your Sprinkle and keep your redirect routes together. The [redirect helper](https://www.slimframework.com/docs/v4/objects/routing.html#redirect-helper) can help to perform the actual link between the old and the new route :
Recommended practice is to create a new route definition class in your Sprinkle and keep your redirect routes together. Slim's [redirect helper](https://www.slimframework.com/docs/v4/objects/routing.html#redirect-helper) assists in performing the actual link between the old and the new route :

```php
<?php
Expand Down Expand Up @@ -51,15 +51,15 @@ Note that most major browsers perform the redirect automatically when they recei

### 400 (Bad Request)

Respond with this code when the client has submitted an "invalid" request. In most cases where the user's request has failed validation, `400` is the appropriate code to return.
Respond with this code when the client has submitted an "invalid" request. In most cases where the user's request has failed [validation](/routes-and-controllers/client-input/validation), `400` is the appropriate code to return.

[notice=note]Don't return a 400 code if the error isn't the client's fault, or if the request was valid but refused for some other reason (like failing authorization, or a CSRF token check).[/notice]

### 401 (Unauthorized)

Technically, this code is meant to be used with [HTTP Basic](https://en.wikipedia.org/wiki/Basic_access_authentication) and [HTTP Digest Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication), which UserFrosting doesn't use.
Technically, this code is meant to be used with [HTTP Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) and [HTTP Digest Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication), which UserFrosting doesn't use.

However in lieu of a better alternative, UserFrosting has co-opted this code for its own authentication checks. If an AJAX request fails because the user is **not logged in**, UserFrosting's **AuthGuard** middleware will return a 401 status code.
In lieu of a better alternative, UserFrosting has co-opted this code for its own authentication checks. If an AJAX request fails because the user is **not logged in**, UserFrosting's **AuthGuard** middleware will return a 401 status code.

For non-AJAX requests (i.e., when visiting a page), if a request fails because the user is not logged in, a 302 status code will be returned instead, and the user will be redirected to the login page.

Expand All @@ -81,7 +81,7 @@ if (!$authorizer->checkAccess($currentUser, 'uri_users')) {

The default exception handler that handles `ForbiddenException`s will automatically generate an error message/page response with a 403 response code.

In some cases, you may not want to disclose to unauthorized users that the resource even _exists_. In this case, you can [override](/advanced/error-handling) the `ForbiddenExceptionHandler` with your own handler and have it return a 404 error instead.
In some cases, you may not want to disclose to unauthorized users that the resource even _exists_. In this case, you can [override](/advanced/error-handling#creating-a-custom-exception-handler) the `ForbiddenExceptionHandler` with your own handler and have it return a 404 error instead.

### 404 (Not Found)

Expand Down Expand Up @@ -111,7 +111,7 @@ This code is automatically returned by the router when a route exists for a give

### 429 (Too Many Requests)

This code is returned by the [throttler](/routes-and-controllers/client-input/throttle), when a request's rate limit has been exceeded.
This code is returned by the [throttler](/routes-and-controllers/client-input/throttle) when a request's rate limit has been exceeded.

### 500 (Internal Server Error)

Expand All @@ -123,4 +123,4 @@ By default when an exception is thrown and no registered exception handler is fo

### 503 (Service Unavailable)

You should return this code, for example, if you absolutely need to have your application down for a period of time (for example, for maintenance).
You should return this code when you absolutely need to have your application down for a period of time (for example, for maintenance).
8 changes: 3 additions & 5 deletions pages/08.routes-and-controllers/02.REST/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ When HTTP was first designed, it was meant to reflect the transactional nature o

A url is simply a way of identifying a resource. The HTTP method then tells the server what the client wants to _do_ with that resource. You can think of this as the grammar of a natural language, with the method acting as the verb and the url as the object of a sentence. Together, a specific url and method are commonly referred to as an **endpoint**.

In the years since, there has been a tendency to build more abstractions on top of this very basic language. However, we have been seeing lately an effort to get back to the roots of HTTP as it was intended to be used - this is what people are commonly referring to when they talk about [REST](https://en.wikipedia.org/wiki/Representational_state_transfer).
In the years since, there has been a tendency to build more abstractions on top of this very basic language. However, we have been seeing lately an effort to get back to the roots of HTTP as it was intended to be used - this is what people are commonly referring to when they talk about [REST](https://en.wikipedia.org/wiki/REST).

## REST and PHP

Expand All @@ -36,14 +36,12 @@ www/

Then you would be able to access the page at `http://example.com/myNewbieProject/owls/barn_owl.php`. Most web servers are configured to automatically map the portion of the url after the scheme (`http://example.com/`) to an actual file in the document root directory, where each slash represents a subdirectory and the last portion corresponds to the name of a PHP script.

This system is easy for newbies to understand, but it has a lot of limitations. First, it requires you to have a separate file for each web page that you want to generate. In a real application, you may want to have hundreds of thousands of very similar web pages, and it doesn't make sense to require a separate file for each page. Also, it couples the structure of your **code** to the structure of your **urls**. To generate semantically useful urls, we'd have to have a messy and complicated maze of directories on our server.
This system is easy to understand, but it has a lot of limitations. First, it requires you to have a separate PHP file for each web page that you want to generate. In a real application, you may want to have hundreds of thousands of very similar web pages, and it doesn't make sense to require a separate file for each page. Also, it couples the structure of your **code** to the structure of your **urls**. To generate semantically useful urls, we'd have to have a messy and complicated maze of directories on our server.

Within each file, you'd also need control structures (if/else) to have it do different things depending on which HTTP method was used. All of this makes it very cumbersome to implement a RESTful design for your endpoints.

### The Better Way

UserFrosting, and most other modern frameworks and content management systems, use a [front controller](/routes-and-controllers/front-controller) to solve this problem. With a front controller, the web server is configured to pass all requests to a single script - `index.php`. From there, the request endpoint is interpreted, and a matching **route** is invoked. These routes do not need to be defined in PHP files that match the name of the url. Thus, we've **decoupled** the endpoints from the directory structure of our application.

Having done this, we are now free to choose any url and method for any request - whether it's a page, form submission, API request, or whatever. This allows us to design our endpoints according to the principles of REST. The next section explains how we should think when we're choosing the urls and methods that our application exposes to the client.

In the [next section](/routes-and-controllers/front-controller), we'll talk about how and where routes are defined in UserFrosting, so you can start implementing your endpoints.
Having done this, we are now free to choose any url and method for any request - whether it's a page, form submission, API request, or whatever. This allows us to more easily design our endpoints according to the principles of REST. The next section explains how we should think when we're choosing the urls and methods that our application exposes to the client.
10 changes: 5 additions & 5 deletions pages/08.routes-and-controllers/03.front-controller/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ taxonomy:

The front controller is a collective term for the **routes** that your web application defines for its various **endpoints**. This is how UserFrosting links urls and methods to your application's code.

Sprinkles define their routes in classes and register them in their Recipe. Inside, there are two ways to define a route - as a closure, or as a reference to a [controller class](/routes-and-controllers/controller-classes) method. We will use a simple closure example here to understand the concepts, but for your application **you should create controller classes**.
Sprinkles define their routes in classes and register them in their Recipe. There are two ways to define a route - as a closure, or as a reference to a [controller class](/routes-and-controllers/controller-classes) method. We will use a simple closure example here to illustrate the concept, but for your application **you should create controller classes**.

The following is an example of a `GET` route:

Expand All @@ -28,12 +28,12 @@ $app->get('/api/users/u/{username}', function (string $username, Request $reques
});
```

This is a very simplified example, but it illustrates the main features of a route definition. First, there is the call to `$app->get()`. The `get` refers to the HTTP method for which this route is defined. You may also define `post()`, `put()`, `delete()`, `options()`, and `patch()`, routes.
This is a very simplified example, but it illustrates the main features of a route definition. First, there is the call to `$app->get()`. The `get` refers to the HTTP method for which this route is defined. You may also define `post()`, `put()`, `delete()`, `options()`, and `patch()` routes.

The first parameter is the url for the route. Routes can contain placeholders, such as `{username}` to match arbitrary values in a portion of the url. These placeholders can even be matched according to regular expressions. See the [Slim documentation ](https://www.slimframework.com/docs/v4/objects/routing.html#route-placeholders) for a complete guide to url placeholders.
The first parameter is the url for the route. Routes can contain placeholders such as `{username}` to match arbitrary values in a portion of the url. These placeholders can even be matched according to regular expressions: see the [Slim documentation ](https://www.slimframework.com/docs/v4/objects/routing.html#route-placeholders) for a complete guide to url placeholders.

After the url comes the **closure**, where we place our actual route logic. In this example, the closure uses three parameters - the **placeholder** variable, the **request** object (which contains all the information from the client request) and the **response** object (which is used to build the response that the server sends back to the client). These parameters can vary from routes to routes. Behind the scenes, PHP-DI will intelligently inject the proper services and variables into the closure, more on that in a bit.
After the url comes the **closure**, where we place our actual route logic. In this example, the closure uses three parameters - a **placeholder** variable, the **request** object (which contains all the information from the client request) and the **response** object (which is used to build the response that the server sends back to the client). These parameters can vary from route to route. Behind the scenes, PHP-DI will intelligently inject the proper services and variables into the closure--more on that in a bit.

In the example above, we use the `username` placeholder to look up information for that user from the database. We then use the value of the `format` query parameter from the request, to decide what to put in the response. You'll notice that the closure writes to the body of the `$response` object before returning. Slim will return the response to the client, perhaps modifying it further through the use of [middleware](https://www.slimframework.com/docs/v4/concepts/middleware.html) first.
In the example above, we use the `username` placeholder to look up information for that user from the database. We then use the value of the `format` query parameter from the request to decide what to put in the response. You'll notice that the closure writes to the body of the `$response` object before returning. Slim will return the response to the client, perhaps first modifying it further through the use of [middleware](/advanced/middlewares).

For a more detailed guide to routes, we highly recommend that you read the [Slim documentation](https://www.slimframework.com/docs/v4/objects/routing.html).
Loading

0 comments on commit 9c8109e

Please sign in to comment.