As you are probably aware the heart of web application development is http messages.
There are always two parts, the Request and the Response.
From the Fig Psr https://www.php-fig.org/psr/psr-7/
Request
Response
Messages have a lot more data that is sent along with each depending on whether is a request or response. This could be headers, cookies, response codes etc. For most web applications the request is what starts your application processing. When thinking of applications in terms of the Psr's it goes something like this:
Incoming Http Request
Psr11 Container initialization / bootstrapping
Psr7 RequestInterface instance initialization
Psr15 RequestHandler processing
Psr7 ResponseInterface initialization
Response returned
script exit
First take a look at the RequestFactory since this class is responsible for creating our ServerRequest instance and seeding it with a Uri instance.
RequestFactory.php
So, how does using Laminas Diactoros (which is a RequestInterface/ResponseInterface implementation) library help us when handling request and responses? First let's look at the ServerRequest objects state just after initialization.
Given a url with the form of:
This is a section of what is returned if you var_dump($request) given that $request is a ServerRequest instance that has been created via the ServerRequestFactory::fromGlobals() method, which it should be in most circumstances. Note that the usage of ServerRequestFactory is within RequestFactory.
What this allows is for you to interact with the request. An example that comes to mind would be we need the user passed in the query string.
For the above url the $params would then contain:
Now, here is where it gets really awesome. Say, that based on what happens when tyrsson views his profile, say we are going to need some of the data later in processing. Well, we can add that data to the $request object as an attribute. So for example if we look at the revised code (that I will commit to the repo shortly) from the Kernel::__construct method we can see how this can be accomplished.
Now, with this in place at any future point in processing we can retrieve the requested users data from the request object. I make that data available to the template layer in the following code snippet. It's important to note that the user data will be available via the request object anywhere in the future of the application lifecycle, but it will only be available to the template layer within the scope of the /profile page.
So that's all great and good and all, but how does it figure out which page to load? Well, we get that information from the ServerRequest object as well since we are not using a Router in this application.
So with the current setup we need to load a page based on the path. Well lucky for us ServerRequest has us covered. Basically the following method just gets a Uri object from the ServerRequest object and we then call getPath. The problem is that it will be /profile. So we do a little string handling and remove the / and were set. The only requirement is that our template file has to match what we are requesting exactly. Since we have a MenuHelper that takes care of building the main navigation based on the available template files we always have the correct path in the link.
So, as simple as it is in this stage of development, that is pretty much it for how the Request is being used to drive the application. Thanks for reading and as always, if you see something that can be improved or something I missed please post it up in the replies along with any questions.
There are always two parts, the Request and the Response.
From the Fig Psr https://www.php-fig.org/psr/psr-7/
Request
Code:
POST /path HTTP/1.1
Host: example.com
foo=bar&baz=bat
Response
Code:
HTTP/1.1 200 OK
Content-Type: text/plain
This is the response body
Messages have a lot more data that is sent along with each depending on whether is a request or response. This could be headers, cookies, response codes etc. For most web applications the request is what starts your application processing. When thinking of applications in terms of the Psr's it goes something like this:
Incoming Http Request
Psr11 Container initialization / bootstrapping
Psr7 RequestInterface instance initialization
Psr15 RequestHandler processing
Psr7 ResponseInterface initialization
Response returned
script exit
First take a look at the RequestFactory since this class is responsible for creating our ServerRequest instance and seeding it with a Uri instance.
RequestFactory.php
So, how does using Laminas Diactoros (which is a RequestInterface/ResponseInterface implementation) library help us when handling request and responses? First let's look at the ServerRequest objects state just after initialization.
Given a url with the form of:
This is a section of what is returned if you var_dump($request) given that $request is a ServerRequest instance that has been created via the ServerRequestFactory::fromGlobals() method, which it should be in most circumstances. Note that the usage of ServerRequestFactory is within RequestFactory.
PHP:
private array 'attributes' =>
array (size=1)
'uri' =>
object(Laminas\Diactoros\Uri)[15]
protected 'allowedSchemes' =>
array (size=2)
...
private string 'scheme' => string 'http' (length=4)
private string 'userInfo' => string '' (length=0)
private string 'host' => string 'twitch.local' (length=12)
private ?int 'port' => null
private string 'path' => string '/profile' (length=8)
private string 'query' => string 'user=tyrsson&action=update' (length=26)
private string 'fragment' => string '' (length=0)
private ?string 'uriString' => null
What this allows is for you to interact with the request. An example that comes to mind would be we need the user passed in the query string.
PHP:
$params = $request->getQueryParams();
For the above url the $params would then contain:
PHP:
'user' => string 'tyrsson' (length=7)
'action' => string 'update' (length=6)
Security Note:
This code does not provide examples of input filtering etc. It should only be used as examples to learn the general concepts. We will cover security later.
Now, here is where it gets really awesome. Say, that based on what happens when tyrsson views his profile, say we are going to need some of the data later in processing. Well, we can add that data to the $request object as an attribute. So for example if we look at the revised code (that I will commit to the repo shortly) from the Kernel::__construct method we can see how this can be accomplished.
PHP:
private const USER_PARAM_KEY = 'user';
public const REQUESTED_USER = 'requestedUser';
private array $queryParams;
public function __construct(
private ServerRequest $request,
private View $view,
private array $config
) {
$this->queryParams = $this->request->getQueryParams();
if (
isset($this->queryParams[self::USER_PARAM_KEY])
&& isset($this->config['user-data'][$this->queryParams[self::USER_PARAM_KEY]])
) {
$this->request = $this->request->withAttribute(
'requestedUser',
$this->config['user-data'][$this->queryParams[self::USER_PARAM_KEY]]
);
}
}
Now, with this in place at any future point in processing we can retrieve the requested users data from the request object. I make that data available to the template layer in the following code snippet. It's important to note that the user data will be available via the request object anywhere in the future of the application lifecycle, but it will only be available to the template layer within the scope of the /profile page.
PHP:
protected function getModel(string $page = null): ModelInterface
{
$model = new ViewModel();
if ($page !== null && $page !== '') {
$model->setTemplate($page);
} else {
$model->setTemplate('home');
}
$model->setVariables($this->config['app_settings']['page_data'][$model->getTemplate()] ?? []);
if ($model->getTemplate() === 'profile') {
$model->setVariable(
self::USER_PARAM_KEY,
$this->request->getAttribute(self::REQUESTED_USER)
);
}
return $model;
}
So that's all great and good and all, but how does it figure out which page to load? Well, we get that information from the ServerRequest object as well since we are not using a Router in this application.
So with the current setup we need to load a page based on the path. Well lucky for us ServerRequest has us covered. Basically the following method just gets a Uri object from the ServerRequest object and we then call getPath. The problem is that it will be /profile. So we do a little string handling and remove the / and were set. The only requirement is that our template file has to match what we are requesting exactly. Since we have a MenuHelper that takes care of building the main navigation based on the available template files we always have the correct path in the link.
PHP:
protected function getRequestedPage(): string
{
$uri = $this->request->getUri();
$page = $uri->getPath();
return substr($page, 1, (strlen($page) - 1));
}
So, as simple as it is in this stage of development, that is pretty much it for how the Request is being used to drive the application. Thanks for reading and as always, if you see something that can be improved or something I missed please post it up in the replies along with any questions.
Last edited: