Skip to content

Add some missing docs. #8061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 12, 2025
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
175 changes: 169 additions & 6 deletions en/controllers/request-response.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1076,9 +1076,10 @@ will make the browser remove its local cookie::
Setting Cross Origin Request Headers (CORS)
-------------------------------------------

The ``cors()`` method is used to define `HTTP Access Control
The ``cors()`` method returns a ``CorsBuilder`` instance which provides a fluent
interface for defining `HTTP Access Control
<https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS>`__
related headers with a fluent interface::
related headers::

$this->response = $this->response->cors($this->request)
->allowOrigin(['*.cakephp.org'])
Expand All @@ -1095,11 +1096,173 @@ criteria are met:
#. The request has an ``Origin`` header.
#. The request's ``Origin`` value matches one of the allowed Origin values.

.. tip::
CorsBuilder Methods
~~~~~~~~~~~~~~~~~~~

CakePHP has no built-in CORS middleware because dealing with CORS requests
is very application specific. We recommend you build your own ``CORSMiddleware``
if you need one and adjust the response object as desired.
.. php:class:: CorsBuilder

The ``CorsBuilder`` provides the following methods for configuring CORS:

.. php:method:: allowOrigin(array|string $domains)

Set the list of allowed domains. You can use wildcards ``*.example.com`` to
accept subdomains, or ``*`` to allow all domains::

// Allow a specific domain
->allowOrigin('https://example.com')

// Allow multiple domains
->allowOrigin(['https://example.com', 'https://app.example.com'])

// Allow all subdomains
->allowOrigin(['*.example.com'])

// Allow all origins (use with caution!)
->allowOrigin('*')

.. php:method:: allowMethods(array $methods)

Set the list of allowed HTTP methods::

->allowMethods(['GET', 'POST', 'PUT', 'DELETE'])

.. php:method:: allowHeaders(array $headers)

Define which headers can be sent in CORS requests::

->allowHeaders(['X-CSRF-Token', 'Content-Type', 'Authorization'])

.. php:method:: allowCredentials()

Enable cookies to be sent in CORS requests. This sets the
``Access-Control-Allow-Credentials`` header to ``true``::

->allowCredentials()

.. php:method:: exposeHeaders(array $headers)

Define which headers the client library/browser can expose to scripting::

->exposeHeaders(['X-Total-Count', 'Link'])

.. php:method:: maxAge(string|int $age)

Define how long preflight OPTIONS requests are valid for (in seconds)::

->maxAge(3600) // Cache preflight for 1 hour

.. php:method:: build()

Apply the configured headers to the response and return it. This must be
called to actually apply the CORS headers::

$response = $corsBuilder->build();

Practical CORS Examples
~~~~~~~~~~~~~~~~~~~~~~~

Here are some common CORS configurations:

**API accepting requests from a SPA frontend**::

// In your controller
public function beforeFilter(EventInterface $event)
{
parent::beforeFilter($event);

if ($this->request->is('options')) {
// Handle preflight requests
$this->response = $this->response->cors($this->request)
->allowOrigin(['https://app.example.com'])
->allowMethods(['GET', 'POST', 'PUT', 'DELETE'])
->allowHeaders(['Content-Type', 'Authorization'])
->allowCredentials()
->maxAge(86400)
->build();

return $this->response;
}
}

public function index()
{
// Apply CORS to regular requests
$this->response = $this->response->cors($this->request)
->allowOrigin(['https://app.example.com'])
->allowCredentials()
->build();

// Your regular controller logic...
}

**Public API with relaxed CORS**::

$this->response = $this->response->cors($this->request)
->allowOrigin('*')
->allowMethods(['GET'])
->exposeHeaders(['X-Total-Count', 'X-Page'])
->maxAge(3600)
->build();

Creating CORS Middleware
~~~~~~~~~~~~~~~~~~~~~~~~

For consistent CORS handling across your application, create a middleware::

// src/Middleware/CorsMiddleware.php
namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class CorsMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Handle preflight requests
if ($request->getMethod() === 'OPTIONS') {
$response = new \Cake\Http\Response();
$response = $response->cors($request)
->allowOrigin(['*.myapp.com'])
->allowMethods(['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'])
->allowHeaders(['Content-Type', 'Authorization'])
->allowCredentials()
->maxAge(3600)
->build();

return $response;
}

$response = $handler->handle($request);

// Add CORS headers to regular requests
return $response->cors($request)
->allowOrigin(['*.myapp.com'])
->allowCredentials()
->build();
}
}

Then add it to your application middleware stack in ``src/Application.php``::

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
// Add CORS middleware early in the stack
->add(new \App\Middleware\CorsMiddleware())
// ... other middleware
->add(new ErrorHandlerMiddleware(Configure::read('Error')))
->add(new AssetMiddleware([
'cacheTime' => Configure::read('Asset.cacheTime'),
]))
->add(new RoutingMiddleware($this));

return $middlewareQueue;
}

Running logic after the Response has been sent
----------------------------------------------
Expand Down
5 changes: 4 additions & 1 deletion en/orm/database-basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,10 @@ uuid
generate a ``CHAR(36)`` field.
binaryuuid
Maps to the UUID type if the database provides one, otherwise this will
generate a ``BINARY(16)`` column
generate a ``BINARY(16)`` column. Binary UUIDs provide more efficient storage
compared to string UUIDs by storing the UUID as 16 bytes of binary data rather
than a 36-character string. This type automatically handles conversion between
string UUID format (with dashes) and binary format.
nativeuuid
Maps to the UUID type in MySQL with MariaDb. In all other databases,
``nativeuuid`` is an alias for ``uuid``.
Expand Down
Loading