Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,7 @@

# The depth of the table of contents in toc.ncx.
epub_tocdepth = 2

rst_epilog = """
.. |minphpversion| replace:: 7.1.0
"""
2 changes: 1 addition & 1 deletion en/appendices/4-0-migration-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
###################

CakePHP 4.0 contains breaking changes, and is not backwards compatible with 3.x
releases. Before attempting to upgrade to 4.0, first upgrade to 3.6 and resolve
releases. Before attempting to upgrade to 4.0, first upgrade to 3.7 and resolve
all deprecation warnings.

To upgrade to 4.0.x run the following composer command:
Expand Down
2 changes: 1 addition & 1 deletion en/console-and-shells.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ comes with an executable in the **bin** directory:

Running the Console with no arguments produces this help message::

Welcome to CakePHP v3.6.0 Console
Welcome to CakePHP v4.0.0 Console
---------------------------------------------------------------
App : App
Path: /Users/markstory/Sites/cakephp-app/src/
Expand Down
8 changes: 4 additions & 4 deletions en/contributing/code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,12 @@ branch, as you cannot edit it once the pull request is created.
choose **master** as your merge target.
* If your change is a **new feature** or an addition to the framework, then you
should choose the branch with the next version number. For example if the
current stable release is ``3.6.0``, the branch accepting new features will
be ``3.next``.
current stable release is ``4.0.0``, the branch accepting new features will
be ``4.next``.
* If your change is a breaks existing functionality, or API's then you'll have
to choose then next major release. For example, if the current release is
``3.6.0`` then the next time existing behavior can be broken will be in
``4.x`` so you should target that branch.
``4.0.0`` then the next time existing behavior can be broken will be in
``5.x`` so you should target that branch.

.. note::

Expand Down
157 changes: 38 additions & 119 deletions en/controllers/middleware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,16 @@ process, you can use the ``MiddlewareQueue`` object to attach middleware::
namespace App;

use Cake\Http\BaseApplication;
use Cake\Http\MiddlewareQueue;
use Cake\Error\Middleware\ErrorHandlerMiddleware;

class Application extends BaseApplication
{
public function middleware($middlewareQueue)
public function middleware(MiddlewareQueue $middlwareQueue): MiddlewareQueue
{
// Bind the error handler into the middleware queue.
$middlewareQueue->add(new ErrorHandlerMiddleware());
return $middlewareQueue;
$middlwareQueue->add(new ErrorHandlerMiddleware());
return $middlwareQueue;
}
}

Expand All @@ -86,27 +87,27 @@ a variety of operations::
$layer = new \App\Middleware\CustomMiddleware;

// Added middleware will be last in line.
$middlewareQueue->add($layer);
$middlwareQueue->add($layer);

// Prepended middleware will be first in line.
$middlewareQueue->prepend($layer);
$middlwareQueue->prepend($layer);

// Insert in a specific slot. If the slot is out of
// bounds, it will be added to the end.
$middlewareQueue->insertAt(2, $layer);
$middlwareQueue->insertAt(2, $layer);

// Insert before another middleware.
// If the named class cannot be found,
// an exception will be raised.
$middlewareQueue->insertBefore(
$middlwareQueue->insertBefore(
'Cake\Error\Middleware\ErrorHandlerMiddleware',
$layer
);

// Insert after another middleware.
// If the named class cannot be found, the
// middleware will added to the end.
$middlewareQueue->insertAfter(
$middlwareQueue->insertAfter(
'Cake\Error\Middleware\ErrorHandlerMiddleware',
$layer
);
Expand All @@ -118,110 +119,25 @@ middleware to specific sets of routes using
Adding Middleware from Plugins
------------------------------

After the middleware queue has been prepared by the application, the
``Server.buildMiddleware`` event is triggered. This event can be useful to add
middleware from plugins. Plugins can register listeners in their bootstrap
scripts, that add middleware::

// In ContactManager plugin bootstrap.php
use Cake\Event\EventManager;

EventManager::instance()->on(
'Server.buildMiddleware',
function ($event, $middlewareQueue) {
$middlewareQueue->add(new ContactPluginMiddleware());
});

PSR-7 Requests and Responses
============================

Middleware and the new HTTP stack are built on top of the `PSR-7 Request
& Response Interfaces <http://www.php-fig.org/psr/psr-7/>`__. While all
middleware will be exposed to these interfaces, your controllers, components,
and views will *not*.

Interacting with Requests
-------------------------

The ``RequestInterface`` provides methods for interacting with the headers,
method, URI, and body of a request. To interact with the headers, you can::

// Read a header as text
$value = $request->getHeaderLine('Content-Type');

// Read header as an array
$value = $request->getHeader('Content-Type');

// Read all the headers as an associative array.
$headers = $request->getHeaders();

Requests also give access to the cookies and uploaded files they contain::

// Get an array of cookie values.
$cookies = $request->getCookieParams();

// Get a list of UploadedFile objects
$files = $request->getUploadedFiles();

// Read the file data.
$files[0]->getStream();
$files[0]->getSize();
$files[0]->getClientFileName();

// Move the file.
$files[0]->moveTo($targetPath);
Plugins can use their ``middleware`` hook method to apply any middleware they
have to the application's middleware queue::

Requests contain a URI object, which contains methods for interacting with the
requested URI::
// in plugins/ContactManager/src/Plugin.php
namespace ContactManager;

// Get the URI
$uri = $request->getUri();

// Read data out of the URI.
$path = $uri->getPath();
$query = $uri->getQuery();
$host = $uri->getHost();

Lastly, you can interact with a request's 'attributes'. CakePHP uses these
attributes to carry framework specific request parameters. There are a few
important attributes in any request handled by CakePHP:

* ``base`` contains the base directory for your application if there is one.
* ``webroot`` contains the webroot directory for your application.
* ``params`` contains the results of route matching once routing rules have been
processed.
* ``session`` contains an instance of CakePHP's ``Session`` object. See
:ref:`accessing-session-object` for more information on how to use the session
object.

Interacting with Responses
--------------------------

The methods available to create a server response are the same as those
available when interacting with :ref:`httpclient-response-objects`. While the
interface is the same the usage scenarios are different.

When modifying the response, it is important to remember that responses are
**immutable**. You must always remember to store the results of any setter
method. For example::

// This does *not* modify $response. The new object was not
// assigned to a variable.
$response->withHeader('Content-Type', 'application/json');

// This works!
$newResponse = $response->withHeader('Content-Type', 'application/json');

Most often you'll be setting headers and response bodies on requests::
use Cake\Core\BasePlugin;
use Cake\Http\MiddlewareQueue;
use ContactManager\Middleware\ContactManagerContextMiddleware;

// Assign headers and a status code
$response = $response->withHeader('Content-Type', 'application/json')
->withHeader('Pragma', 'no-cache')
->withStatus(422);
class Plugin extends BasePlugin
{
public function middleware(MiddlewareQueue $middlwareQueue): MiddlewareQueue
{
$middlwareQueue->add(new ContactManagerContextMiddleware());

// Write to the body
$body = $response->getBody();
$body->write(json_encode(['errno' => $errorCode]));
return $middlwareQueue;
}
}

Creating Middleware
===================
Expand Down Expand Up @@ -252,7 +168,10 @@ creating their own response. We can see both options in our simple middleware::

class TrackingCookieMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface
{
// Calling $handler->handle() delegates control to the *next* middleware
// In your application's queue.
Expand Down Expand Up @@ -282,14 +201,14 @@ application::

class Application
{
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
public function middleware(MiddlewareQueue $middlwareQueue): MiddlewareQueue
{
// Add your simple middleware onto the queue
$middlewareQueue->add(new TrackingCookieMiddleware());
$middlwareQueue->add(new TrackingCookieMiddleware());

// Add some more middleware onto the queue

return $middlewareQueue;
return $middlwareQueue;
}
}

Expand All @@ -306,10 +225,10 @@ enable cached routes, provide the desired :ref:`cache configuration
<cache-configuration>` as a parameter::

// In Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
public function middleware(MiddlewareQueue $middlwareQueue): MiddlewareQueue
{
// ...
$middlewareQueue->add(new RoutingMiddleware($this, 'routing'));
$middlwareQueue->add(new RoutingMiddleware($this, 'routing'));
}

The above would use the ``routing`` cache engine to store the generated route
Expand Down Expand Up @@ -344,7 +263,7 @@ your application's middleware stack::
->noOpen()
->noSniff();

$middlewareQueue->add($securityHeaders);
$middlwareQueue->add($securityHeaders);

.. _encrypted-cookie-middleware:

Expand All @@ -364,7 +283,7 @@ Cookie data is encrypted with via OpenSSL using AES::
Configure::read('Security.cookieKey')
);

$middlewareQueue->add($cookies);
$middlwareQueue->add($cookies);

.. note::
It is recommended that the encryption key you use for cookie data, is used
Expand Down Expand Up @@ -392,14 +311,14 @@ stack you protect all the actions in application::
// in src/Application.php
use Cake\Http\Middleware\CsrfProtectionMiddleware;

public function middleware($middlewareQueue) {
public function middleware($middlwareQueue) {
$options = [
// ...
];
$csrf = new CsrfProtectionMiddleware($options);

$middlewareQueue->add($csrf);
return $middlewareQueue;
$middlwareQueue->add($csrf);
return $middlwareQueue;
}

By applying the ``CsrfProtectionMiddleware`` to routing scopes, you can include
Expand Down
42 changes: 39 additions & 3 deletions en/controllers/request-response.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ reference. Some of the duties ``ServerRequest`` performs include:
* Providing access to request parameters both as array indexes and object
properties.

As of 3.4.0, CakePHP's request object implements the `PSR-7
CakePHP's request object implements the `PSR-7
ServerRequestInterface <http://www.php-fig.org/psr/psr-7/>`_ making it easier to
use libraries from outside of CakePHP.

Expand Down Expand Up @@ -279,9 +279,12 @@ There are several built-in detectors that you can use:
Session Data
------------

To access the session for a given request use the ``session()`` method::
To access the session for a given request use the ``getSession()`` method or use the ``session`` attribute::

$userName = $this->request->session()->read('Auth.User.name');
$session = $this->request->getSession();
$session = $this->request->getAttribute('session');

$userName = $session->read('Auth.User.name');

For more information, see the :doc:`/development/sessions` documentation for how
to use the session object.
Expand Down Expand Up @@ -442,6 +445,39 @@ Request cookies can be read through a number of methods::
See the :php:class:`Cake\\Http\\Cookie\\CookieCollection` documentation for how
to work with cookie collection.


Uploaded Files
--------------

Requests expose the uploaded file data in ``getData()`` as
arrays, and as ``UploadedFileInterface`` objects by ``getUploadedFiles()``::

// Get a list of UploadedFile objects
$files = $request->getUploadedFiles();

// Read the file data.
$files[0]->getStream();
$files[0]->getSize();
$files[0]->getClientFileName();

// Move the file.
$files[0]->moveTo($targetPath);

Manipulating URIs
-----------------

Requests contain a URI object, which contains methods for interacting with the
requested URI::

// Get the URI
$uri = $request->getUri();

// Read data out of the URI.
$path = $uri->getPath();
$query = $uri->getQuery();
$host = $uri->getHost();


.. index:: $this->response

Response
Expand Down
6 changes: 0 additions & 6 deletions en/core-libraries/httpclient.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,6 @@ You can include files in request bodies by including a filehandle in the array::

The filehandle will be read until its end; it will not be rewound before being read.

.. warning::

For compatibility reasons, earlier versions of CakePHP will treat strings
beginning with ``@`` as local or remote file paths. This functionality was
deprecated in CakePHP 3.0.5 and was removed in a 3.7.

Building Multipart Request Bodies by Hand
-----------------------------------------

Expand Down
Loading