Les Objets Request & Response

Les objets ServerRequest et Response fournissent une abstraction autour de la requête et des réponses HTTP. L’objet ServerRequest dans CakePHP vous permet de faire une introspection de la requête entrante, tandis que l’objet Response vous permet de créer sans effort des réponses HTTP à partir de vos controllers.

ServerRequest

class Cake\Http\ServerRequest

ServerRequest est l’objet requête utilisé par défaut dans CakePHP. Il centralise un certain nombre de fonctionnalités pour interroger et interagir avec les données demandées. Pour chaque requête, une ServerRequest est créée et passée en référence aux différentes couches de l’application que la requête de données utilise. Par défaut la requête est assignée à $this->request, et est disponible dans les Controllers, Cells, Vues et Helpers. Vous pouvez aussi y accéder dans les Components en utilisant la référence du controller. Certaines des tâches incluses que ServerRequest permet sont les suivantes :

  • Transformer les tableaux GET, POST, et FILES en structures de données avec lesquelles vous êtes familiers.
  • Fournir une introspection de l’environnement se rapportant à la demande. Des informations comme les envois d’en-têtes (headers), l’adresse IP du client et les informations des sous-domaines/domaines sur lesquels le serveur de l’application tourne.
  • Fournit un accès aux paramètres de la requête à la fois en tableaux indicés et en propriétés d’un objet.

Depuis la version 3.4.0, l’objet ServerRequest de CakePHP implémente l’interface PSR-7 ServerServerRequestInterface facilitant l’utilisation des librairies en-dehors de CakePHP.

Paramètres de la Requête

ServerRequest propose les paramètres de routing avec la méthode getParam():

$controllerName = $this->request->getParam('controller');

// Avant 3.4.0
$controllerName = $this->request->param('controller');

Tous les éléments de route Les Eléments de Route sont accessibles à travers cette interface.

En plus des éléments de routes Les Eléments de Route, vous avez souvent besoin d’accéder aux arguments passés Arguments Passés. Ceux-ci sont aussi tous les deux disponibles dans l’objet request:

// Arguments passés
$passedArgs = $this->request->getParam('pass');

Tous vous fournissent un accès aux arguments passés. Il y a de nombreux paramètres importants et utiles que CakePHP utilise en interne qu’on peut aussi trouver dans les paramètres de routing:

  • plugin Le plugin gérant la requête aura une valeur nulle quand il n’y a pas de plugins.
  • controller Le controller gérant la requête courante.
  • action L’action gérant la requête courante.
  • prefix Le préfixe pour l’action courante. Voir Prefix de Routage pour plus d’informations.

Accéder aux Paramètres Querystring

Cake\Http\ServerRequest::getQuery($name)

Les paramètres Querystring peuvent être lus en utilisant la méthode getQuery():

// l'URL est /posts/index?page=1&sort=title
$page = $this->request->getQuery('page');

// Avant 3.4.0
$page = $this->request->query('page');

Vous pouvez soit directement accéder à la propriété demandée, soit vous pouvez utiliser getQuery() pour lire l’URL requêtée sans erreur. Toute clé qui n’existe pas va retourner null:

$foo = $this->request->getQuery('valeur_qui_n_existe_pas');
// $foo === null

// Vous pouvez également définir des valeurs par défaut
$foo = $this->request->getQuery('n_existe_pas', 'valeur par défaut');

Si vous souhaitez accéder à tous les paramètres de requête, vous pouvez utiliser getQueryParams():

$query = $this->request->getQueryParams();

Nouveau dans la version 3.4.0: getQueryParams() et getQuery() ont été ajoutées dans la version 3.4.0

Données du Corps de la Requête

Cake\Http\ServerRequest::getData($name, $default = null)

Toutes les données POST sont accessibles en utilisant Cake\Http\ServerRequest::getData(). Toute donnée de formulaire qui contient un préfix data aura ce préfixe supprimé. Par exemple:

// Un input avec un attribut de nom égal à 'MyModel[title]' est accessible via
$title = $this->request->getData('MyModel.title');

Toute clé qui n’existe pas va retourner null:

$foo = $this->request->getData('Valeur.qui.n.existe.pas');
// $foo == null

Accéder aux Données PUT, PATCH ou DELETE

Cake\Http\ServerRequest::input($callback[, $options])

Quand vous construisez des services REST, vous acceptez souvent des données requêtées sur des requêtes PUT et DELETE. Toute donnée de corps de requête application/x-www-form-urlencoded va automatiquement être parsée et définie dans $this->data pour les requêtes PUT et DELETE. Si vous acceptez les données JSON ou XML, regardez la section ci-dessous pour voir comment vous pouvez accéder aux corps de ces requêtes.

Lorsque vous accédez aux données d’entrée, vous pouvez les décoder avec une fonction optionnelle. Cela peut être utile quand vous devez interagir avec du contenu de requête XML ou JSON. Les paramètres supplémentaires pour la fonction de décodage peuvent être passés comme arguments à input():

$jsonData = $this->request->input('json_decode');

Variables d’Environnement (à partir de $_SERVER et $_ENV)

Cake\Http\ServerRequest::env($key, $value = null)

ServerRequest::env() est un wrapper pour la fonction globale env() et agit comme un getter/setter pour les variables d’environnement sans avoir à modifier les variables globales $_SERVER et $_ENV:

// Obtenir l'host
$host = $this->request->env('HTTP_HOST');

// Définir une valeur, généralement utile pour les tests.
$this->request->env('REQUEST_METHOD', 'POST');

Pour accéder à toutes les variables d’environnement dans une requête, utilisez getServerParams():

$env = $this->request->getServerParams();

Nouveau dans la version 3.4.0: getServerParams() a été ajoutée dans la version 3.4.0

Données XML ou JSON

Les applications employant REST échangent souvent des données dans des organes post non encodées en URL. Vous pouvez lire les données entrantes dans n’importe quel format en utilisant Http\ServerRequest::input(). En fournissant une fonction de décodage, vous pouvez recevoir le contenu dans un format déserializé:

// Obtenir les données encodées JSON soumises par une action PUT/POST
$jsonData = $this->request->input('json_decode');

Quelques méthodes de desérialization requièrent des paramètres supplémentaires quand elles sont appelées, comme le paramètre de type tableau de json_decode. Si vous voulez convertir du XML en objet DOMDocument, Http\ServerRequest::input() supporte aussi le passage de paramètres supplémentaires:

// Obtenir les données encodées en XML soumises avec une action PUT/POST
$data = $this->request->input('Cake\Utility\Xml::build', ['return' => 'domdocument']);

Informations du Chemin

L’objet ServerRequest fournit aussi des informations utiles sur les chemins dans votre application. Les attributs base et webroot sont utiles pour générer des URLs et déterminer si votre application est ou n’est pas dans un sous-dossier. Les attributs que vous pouvez utiliser sont:

// Suppose que la requête URL courante est /subdir/articles/edit/1?page=1

// Contient /subdir/articles/edit/1?page=1
$here = $request->getRequestTarget();

// Contient /subdir
$base = $request->getAttribute('base');

// Contient /subdir/
$base = $request->getAttribute('webroot');

// Avant la version 3.4.0
$webroot = $request->webroot;
$base = $request->base;
$here = $request->here();

Vérifier les Conditions de la Requête

Cake\Http\ServerRequest::is($type, $args...)

L’objet ServerRequest fournit une façon d’inspecter différentes conditions de la requête utilisée. En utilisant la méthode is(), vous pouvez vérifier un certain nombre de conditions, ainsi qu’inspecter d’autres critères de la requête spécifique à l’application:

$isPost = $this->request->is('post');

Vous pouvez aussi étendre les détecteurs de la requête qui sont disponibles, en utilisant Cake\Http\ServerRequest::addDetector() pour créer de nouveaux types de détecteurs. Il y a quatre différents types de détecteurs que vous pouvez créer:

  • Comparaison avec valeur d’environnement - Compare l’égalité de la valeur extraite à partir de env() avec la valeur fournie.
  • Comparaison de valeur avec motif - Vous permet de comparer la valeur extraite de env() avec une expression régulière.
  • Comparaison basée sur les options - Utilise une liste d’options pour créer une expression régulière. Les appels suivants pour ajouter un détecteur d’option déjà défini, vont fusionner les options.
  • Les détecteurs de Callback - Vous permettent de fournir un type “callback” pour gérer la vérification. Le callback va recevoir l’objet ServerRequest comme seul paramètre.
Cake\Http\ServerRequest::addDetector($name, $options)

Quelques exemples seraient:

// Ajouter un détecteur d'environnement.
$this->request->addDetector(
    'post',
    ['env' => 'REQUEST_METHOD', 'value' => 'POST']
);

// Ajouter un détecteur de valeur avec motif.
$this->request->addDetector(
    'iphone',
    ['env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i']
);

// Ajouter un détecteur d'options
$this->request->addDetector('internalIp', [
    'env' => 'CLIENT_IP',
    'options' => ['192.168.0.101', '192.168.0.100']
]);

// Ajouter un détecteur de callback. Doit être un callable valide.
$this->request->addDetector(
    'awesome',
    function ($request) {
        return $request->getParam('awesome');
    }
);

// Ajouter un détecteur qui utilise des arguments supplémentaires. Depuis la version 3.3.0
$this->request->addDetector(
    'controller',
    function ($request, $name) {
        return $request->getParam('controller') === $name;
    }
);

ServerRequest inclut aussi des méthodes comme Cake\Http\ServerRequest::domain(), Cake\Http\ServerRequest::subdomains() et Cake\Http\ServerRequest::host() qui facilitent la vie des applications avec sous-domaines.

Il y a plusieurs détecteurs intégrés que vous pouvez utiliser :

  • is('get') Vérifie si la requête courante est un GET.
  • is('put') Vérifie si la requête courante est un PUT.
  • is('patch') Vérifie si la requête courante est un PATCH.
  • is('post') Vérifie si la requête courante est un POST.
  • is('delete') Vérifie si la requête courante est un DELETE.
  • is('head') Vérifie si la requête courante est un HEAD.
  • is('options') Vérifie si la requête courante est OPTIONS.
  • is('ajax') Vérifie si la requête courante vient d’un X-Requested-With = XMLHttpRequest.
  • is('ssl') Vérifie si la requête courante est via SSL.
  • is('flash') Vérifie si la requête courante a un User-Agent de Flash.
  • is('requested') Vérifie si la requête a un paramètre de requête “requested” avec la valeur 1.
  • is('json') Vérifie si la requête a l’extension “json” ajoutée et si elle accepte le mimetype “application/json”.
  • is('xml') Vérifie si la requête a l’extension “xml” ajoutée et si elle accepte le mimetype “application/xml” ou “text/xml”.

Nouveau dans la version 3.3.0: Les détecteurs peuvent prendre des paramètres supplémentaires depuis la version 3.3.0.

Données de Session

Pour accéder à la session pour une requête donnée, utilisez la méthode session():

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

Pour plus d’informations, consultez la documentation Sessions sur la façon d’utiliser l’objet Session.

Hôte et Nom de Domaine

Cake\Http\ServerRequest::domain($tldLength = 1)

Retourne le nom de domaine sur lequel votre application tourne:

// Affiche 'example.org'
echo $request->domain();
Cake\Http\ServerRequest::subdomains($tldLength = 1)

Retourne un tableau avec les sous-domaines sur lequel votre application tourne:

// Retourne ['my', 'dev'] pour 'my.dev.example.org'
$subdomains = $request->subdomains();
Cake\Http\ServerRequest::host()

Retourne l’hôte sur lequel votre application tourne:

// Affiche 'my.dev.example.org'
echo $request->host();

Lire la Méthode HTTP

Cake\Http\ServerRequest::getMethod()

Retourne la méthode HTTP où la requête a été faite:

// Affiche POST
echo $request->getMethod();

// Avant la version 3.4.0
echo $request->method();

Restreindre les Méthodes HTTP qu’une Action Accepte

Cake\Http\ServerRequest::allowMethod($methods)

Définit les méthodes HTTP autorisées. Si elles ne correspondent pas, elle va lancer une MethodNotAllowedException. La réponse 405 va inclure l’en-tête Allow nécessaire avec les méthodes passées:

public function delete()
{
    // Only accept POST and DELETE requests
    $this->request->allowMethod(['post', 'delete']);
    ...
}

Lire les En-têtes HTTP

Ces méthodes vous permettent d’accéder à n’importe quel en-tête HTTP_* qui ont été utilisés dans la requête. Par exemple:

// Récupère le header dans une chaîne
$userAgent = $this->request->getHeaderLine('User-Agent');

// Récupère un tableau de toutes les valeurs
$acceptHeader = $this->request->getHeader('Accept');

// Vérifie l'existence d'un header
$hasAcceptHeader = $this->request->hasHeader('Accept');

// Avant to 3.4.0
$userAgent = $this->request->header('User-Agent');

Du fait que certaines installations d’Apache ne rendent pas le header Authorization accessible, CakePHP le rend disponible via des méthodes spécifiques.

Cake\Http\ServerRequest::referer($local = false)

Retourne l’adresse référente de la requête.

Cake\Http\ServerRequest::clientIp()

Retourne l’adresse IP du visiteur.

Faire Confiance aux Headers de Proxy

Si votre application est derrière un load balancer ou exécutée sur un service cloud, vous voudrez souvent obtenir l’hôte de load balancer, le port et le schéma dans vos requêtes. Souvent les load balancers vont aussi envoyer des en-têtes HTTP-X-Forwarded-* avec les valeurs originales. Les en-têtes forwarded ne seront pas utilisés par CakePHP directement. Pour que l’objet request utilise les en-têtes, définissez la propriété trustProxy à true:

$this->request->trustProxy = true;

// Ces méthodes utiliseront maintenant les en-têtes du proxy.
$port = $this->request->port();
$host = $this->request->host();
$scheme = $this->request->scheme();
$clientIp = $this->request->clientIp();

Vérifier les En-têtes Acceptés

Cake\Http\ServerRequest::accepts($type = null)

Trouve les types de contenu que le client accepte ou vérifie s’il accepte un type particulier de contenu.

Récupère tous les types:

$accepts = $this->request->accepts();

Vérifie pour un unique type:

$acceptsJson = $this->request->accepts('application/json');
static Cake\Http\ServerRequest::acceptLanguage($language = null)

Obtenir toutes les langues acceptées par le client, ou alors vérifier si une langue spécifique est acceptée.

Obtenir la liste des langues acceptées:

$acceptsLanguages = $this->request->acceptLanguage();

Vérifier si une langue spécifique est acceptée:

$acceptsFrench = $this->request->acceptLanguage('fr-fr');

Cookies

Les cookies de la Request peuvent être lus à travers plusieurs méthodes:

// Récupère la valeur du cookie, ou null si le cookie n'existe pas
$rememberMe = $this->request->getCookie('remember_me');

// Lit la valeur ou retourne le défaut (qui est 0 ici)
$rememberMe = $this->request->getCookie('remember_me', 0);

// Récupère tous les cookies dans un tableau
$cookies = $this->request->getCookieParams();

// Récupère une instance de CookieCollection (à partir de 3.5.0)
$cookies = $this->request->getCookieCollection()

Référez-vous à la documentation de Cake\Http\Cookie\CookieCollection pour savoir comment travailler avec les collections de cookies.

Nouveau dans la version 3.5.0: ServerRequest::getCookieCollection() a été ajouté dans 3.5.0

Response

class Cake\Http\Response

Cake\Http\Response est la classe de réponse par défaut dans CakePHP. Elle encapsule un nombre de fonctionnalités et de caractéristiques pour la génération de réponses HTTP dans votre application. Elle aide aussi à tester des objets factices (mocks/stubs), vous permettant d’inspecter les en-têtes qui vont être envoyés. Cake\Http\ServerRequest, Cake\Http\Response consolide un certain nombre de méthodes qu’on pouvait trouver avant dans Controller, ServerRequestHandlerComponent et Dispatcher. Les anciennes méthodes sont dépréciées en faveur de l’utilisation de Cake\Http\Response.

Response fournit une interface pour envelopper les tâches de réponse communes liées, telles que:

  • Envoyer des en-têtes pour les redirections.
  • Envoyer des en-têtes de type de contenu.
  • Envoyer tout en-tête.
  • Envoyer le corps de la réponse.

Gérer les Types de Contenu

Cake\Http\Response::withType($contentType = null)

Vous pouvez contrôler le Content-Type des réponses de votre application en utilisant Cake\Http\Response::withType(). Si votre application a besoin de gérer les types de contenu qui ne sont pas construits dans Response, vous pouvez faire correspondre ces types avec withType() comme ceci:

// Ajouter un type vCard
$this->response->withType(['vcf' => 'text/v-card']);

// Configurer la réponse de Type de Contenu pour vcard.
$this->response->withType('vcf');

// Avant 3.4.0
$this->response->type('vcf');

Habituellement, vous voudrez faire correspondre des types de contenu supplémentaires dans le callback beforeFilter() de votre controller afin que vous puissiez tirer parti de la fonctionnalité de vue de commutation automatique de RequestHandlerComponent, si vous l’utilisez.

Envoyer des fichiers

Cake\Http\Response::withFile($path, $options = [])

Il y a des fois où vous voulez envoyer des fichiers en réponses de vos requêtes. Vous pouvez le faire en utilisant Cake\Http\Response::withFile():

public function sendFile($id)
{
    $file = $this->Attachments->getFile($id);
    $response = $this->response->withFile($file['path']);
    // Retourne la réponse pour éviter que le controller n'essaie de
    // rendre la vue
    return $response;
}

// Avant 3.4.0
$file = $this->Attachments->getFile($id);
$this->response->file($file['path']);
// Retourne la réponse pour éviter que le controller n'essaie de
// rendre la vue
return $this->response;

Comme montré dans l’exemple ci-dessus, vous devez passer le chemin du fichier à la méthode. CakePHP va envoyer le bon en-tête de type de contenu si c’est un type de fichier connu listé dans Cake\Http\Reponse::$_mimeTypes. Vous pouvez ajouter des nouveaux types avant d’appeler Cake\Http\Response::withFile() en utilisant la méthode Cake\Http\Response::withType().

Si vous voulez, vous pouvez aussi forcer un fichier à être téléchargé au lieu d’être affiché dans le navigateur en spécifiant les options:

$response = $this->response->withFile(
    $file['path'],
    ['download' => true, 'name' => 'foo']
);

// Avant 3.4.0
$this->response->file(
    $file['path'],
    ['download' => true, 'name' => 'foo']
);

les options possibles sont:

name
Le nom vous permet de spécifier un nom de fichier alternatif à envoyer à l’utilisateur.
download
Une valeur booléenne indiquant si les en-têtes doivent être définis pour forcer le téléchargement.

Envoyer une Chaîne de Caractères en Fichier

Vous pouvez répondre avec un fichier qui n’existe pas sur le disque, par exemple si vous voulez générer un pdf ou un ics à la volée à partir d’une chaine:

public function sendIcs()
{
    $icsString = $this->Calendars->generateIcs();
    $reponse = $this->response;
    $response->body($icsString);

    $this->response->withType('ics');

    // Force le téléchargement de fichier en option
    $response = $this->response->withDownload('filename_for_download.ics');

    // Retourne l'object pour éviter au controller d'essayer de rendre
    // une vue
    return $response;
}

Streaming Resources

Vous pouvez utiliser une fonction de rappel avec body() pour convertir des flux de ressources en réponses:

$file = fopen('/some/file.png', 'r');
$this->response->body(function () use ($file) {
    rewind($file);
    fpassthru($file);
    fclose($file);
});

Les fonctions de rappel peuvent également renvoyer le corps en tant que chaîne de caractères:

$path = '/some/file.png';
$this->response->body(function () use ($path) {
    return file_get_contents($path);
});

Définir les En-têtes

Cake\Http\Response::withHeader($header, $value)

Les définitions de headers se font avec la méthode Cake\Http\Response::withHeader(). Comme toutes les méthodes de l’interface PSR-7, cette méthode retourne une nouvelle instance avec le nouvel header:

// Ajoute / remplace un header
$response = $response->withHeader('X-Extra', 'My header');

// Définit plusieurs headers
$response = $response->withHeader('X-Extra', 'My header')
    ->withHeader('Location', 'http://example.com');

// Ajoute une valeur à un header existant
$response = $response->withAddedHeader('Set-Cookie', 'remember_me=1');

// Avant to 3.4.0 - Définit a header
$this->response->header('Location', 'http://example.com');

Les headers ne sont pas envoyés dès que vous les définissez. Ils sont stockés jusqu’à ce que la réponse soit émise par Cake\Http\Server.

Vous pouvez maintenant utiliser la méthode Cake\Http\Response::withLocation() pour définir ou obtenir directement le header « redirect location ».

Définir le Corps de la réponse

Cake\Http\Response::withStringBody($string)

Pour définir une chaîne comme corps de réponse, écrivez ceci:

// Définit une chaîne dans le corps
$response = $response->withStringBody('My Body');

// Si vous souhaitez une réponse JSON
$response = $response->withType('application/json')
    ->withStringBody(json_encode(['Foo' => 'bar']));

Nouveau dans la version 3.4.3: withStringBody() was added in 3.4.3

Cake\Http\Response::withBody($body)

Pour définir le corps de la réponse, utilisez la méthode withBody() qui est fournie par le Zend\Diactoros\MessageTrait:

$response = $response->withBody($stream);

// Avant 3.4.0, pour définir le corps de la réponse
$this->response->body('My Body');

Assurez-vous que $stream est un objet de type Psr\Http\Message\StreamInterface. Ci-dessous, la manière de créer un nouveau stream.

Vous pouvez également « streamer » les réponses depuis des fichiers en utilisant des streams Zend\Diactoros\Stream:

// Pour "streamer" depuis un fichier
use Zend\Diactoros\Stream;

$stream = new Stream('/path/to/file', 'rb');
$response = $response->withBody($stream);

Vous pouvez aussi streamer des réponses depuis un callback en utilisant un CallbackStream. C’est utile si vous avez des ressources comme des images, des fichiers CSV ou des fichiers PDF à streamer au client:

// Streamer depuis un callback
use Cake\Http\CallbackStream;

// Création d'une image
$img = imagecreate(100, 100);
// ...

$stream = new CallbackStream(function () use ($img) {
    imagepng($img);
});
$response = $response->withBody($stream);

// Avant 3.4.0, vous pouvez utiliser la méthode ci-dessous pour créer des
// réponses sous forme de stream
$file = fopen('/some/file.png', 'r');
$this->response->body(function () use ($file) {
    rewind($file);
    fpassthru($file);
    fclose($file);
});

Définir le Character Set

Cake\Http\Response::withCharset($charset)

Cette méthode permet de définir le charset qui sera utilisé dans la réponse:

$this->response = $this->response->withCharset('UTF-8');

// Avant to 3.4.0
$this->response->charset('UTF-8');

Interagir avec le Cache du Navigateur

Cake\Http\Response::withDisabledCache()

Parfois, vous avez besoin de forcer les navigateurs à ne pas mettre en cache les résultats de l’action d’un controller. Cake\Http\Response::withDisabledCache() est justement prévue pour cela:

public function index()
{
    // Désactive le cache
    $this->response = $this->response->withDisabledCache();
}

Avertissement

Désactiver le cache à partir de domaines SSL pendant que vous essayez d’envoyer des fichiers à Internet Explorer peut entraîner des erreurs.

Cake\Http\Response::withCache($since, $time = '+1 day')

Vous pouvez aussi dire aux clients que vous voulez qu’ils mettent en cache des réponses. En utilisant Cake\Http\Response::withCache():

public function index()
{
    $this->response = $this->response->withCache('-1 minute', '+5 days');
}

Ce qui est au-dessus indiquera aux clients de mettre en cache la réponse résultante pendant 5 jours, en espérant accélérer l’expérience de vos visiteurs. La méthode withCache() définit valeur Last-Modified en premier argument. L’entête Expires et max-age sont définis en se basant sur le second paramètre. Le Cache-Control est défini aussi à public.

Configuration affinée du Cache HTTP

L’une des meilleures méthodes et des plus simples pour rendre votre application plus rapide est d’utiliser le cache HTTP. Selon ce modèle de mise en cache, vous êtes seulement tenu d’aider les clients à décider s’ils doivent utiliser une copie de la réponse mise en cache en définissant quelques propriétés d’en-têtes comme la date de mise à jour et la balise entity de réponse.

Plutôt que d’avoir à coder la logique de mise en cache et de sa désactivation (rafraîchissement) une fois que les données ont changé, HTTP utilise deux modèles, l’expiration et la validation qui sont habituellement beaucoup plus simples à utiliser.

En dehors de l’utilisation de Cake\Http\Response::withCache(), vous pouvez également utiliser d’autres méthodes pour affiner les en-têtes de cache HTTP pour tirer profit du cache du navigateur ou du proxy inverse.

L’En-tête de Contrôle du Cache

Cake\Http\Response::withSharable($public = null, $time = null)

Utilisé sous le modèle d’expiration, cet en-tête contient de multiples indicateurs qui peuvent changer la façon dont les navigateurs ou les proxies utilisent le contenu mis en cache. Un en-tête Cache-Control peut ressembler à ceci:

Cache-Control: private, max-age=3600, must-revalidate

La classe Response vous aide à configurer cet en-tête avec quelques méthodes utiles qui vont produire un en-tête final Cache Control valide. La première est la méthode withSharable(), qui indique si une réponse peut être considérée comme partageable pour différents utilisateurs ou clients. Cette méthode contrôle en fait la partie public ou private de cet en-tête. Définir une réponse en private indique que tout ou partie de celle-ci est prévue pour un unique utilisateur. Pour tirer profit des mises en cache partagées, il est nécessaire de définir la directive de contrôle en public.

Le deuxième paramètre de cette méthode est utilisé pour spécifier un max-age pour le cache qui est le nombre de secondes après lesquelles la réponse n’est plus considérée comme récente:

public function view()
{
    ...
    // Définit le Cache-Control en public pour 3600 secondes
    $this->response = $this->response->withSharable(true, 3600);
}

public function mes_donnees()
{
    ...
    // Définit le Cache-Control en private pour 3600 secondes
    $this->response = $this->response->withSharable(false, 3600);
}

Response expose des méthodes séparées pour la définition de chaque component dans l’en-tête de Cache-Control.

L’En-tête d’Expiration

Cake\Http\Response::withExpires($time = null)

Vous pouvez définir l’en-tête Expires avec une date et un temps après lesquels la réponse n’est plus considérée comme récente. Cet en-tête peut être défini en utilisant la méthode withExpires():

public function view()
{
    $this->response = $this->response->withExpires('+5 days');
}

Cette méthode accepte aussi une instance DateTime ou toute chaîne de caractère qui peut être parsée par la classe DateTime.

L’En-tête Etag

Cake\Http\Response::withEtag($tag, $weak = false)

La validation du Cache dans HTTP est souvent utilisée quand le contenu change constamment et demande à l’application de générer seulement les contenus de la réponse si le cache n’est plus récent. Sous ce modèle, le client continue de stocker les pages dans le cache, mais au lieu de l’utiliser directement, il demande à l’application à chaque fois si les ressources ont changé ou non. C’est utilisé couramment avec des ressources statiques comme les images et autres choses.

La méthode withEtag() (appelée balise d’entité) est une chaîne de caractère qui identifie de façon unique les ressources requêtées comme le fait un checksum pour un fichier, afin de déterminer si elle correspond à une ressource du cache.

Pour réellement tirer profit de l’utilisation de cet en-tête, vous devez soit appeler manuellement la méthode checkNotModified() ou inclure le Request Handling (Gestion des requêtes) in your controller:

public function index()
{
    $articles = $this->Articles->find('all');
    $response = $this->response->withEtag($this->Articles->generateHash($articles));
    if ($response->checkNotModified($this->request)) {
        return $response;
    }
    $this->response = $response;
    // ...
}

Note

La plupart des utilisateurs proxy devront probablement penser à utiliser l’en-tête Last Modified plutôt que Etags pour des raisons de performance et de compatibilité.

L’En-tête Last-Modified

Cake\Http\Response::withModified($time = null)

De même, avec le modèle de validation du cache HTTP, vous pouvez définir l’en-tête Last-Modified pour indiquer la date et l’heure à laquelle la ressource a été modifiée pour la dernière fois. Définir cet en-tête aide CakePHP à indiquer à ces clients si la réponse a été modifiée ou n’est pas basée sur leur cache.

Pour réellement tirer profit de l’utilisation de cet en-tête, vous devez soit appeler manuellement la méthode checkNotModified() ou inclure le Request Handling (Gestion des requêtes) in your controller:

public function view()
{
    $article = $this->Articles->find()->first();
    $response = this->response->withModified($article->modified);
    if ($this->response->checkNotModified($this->request)) {
        return $response;
    }
    $this->response;
    // ...
}

L’En-tête Vary

Cake\Http\Response::withVary($header)

Dans certains cas, vous voudrez offrir différents contenus en utilisant la même URL. C’est souvent le cas quand vous avez une page multilingue ou que vous répondez avec différentes pages HTML selon le navigateur qui requête la ressource. Dans ces circonstances, vous pouvez utiliser l’en-tête Vary:

$this->response = $this->response->withVary('User-Agent');
$this->response = $this->response->withVary('Accept-Encoding', 'User-Agent');
$this->response = $this->response->withVary('Accept-Language');

Envoyer des Réponses Non-Modifiées

Cake\Http\Response::checkNotModified(ServerRequest $request)

Compare les en-têtes de cache pour l’objet requêté avec l’en-tête du cache de la réponse et determine s’il peut toujours être considéré comme récent. Si oui, il supprime le contenu de la réponse et envoie l’en-tête 304 Not Modified:

// Dans une action de controller.
if ($this->response->checkNotModified($this->request)) {
    return $this->response;
}

Définir des Cookies

Des cookies peuvent être ajoutés aux réponses en utilisant soit un tableau, soit un objet Cake\Http\Cookie\Cookie:

// Ajoute un cookie avec un tableau en utilisant l'API immutable (3.4.0+)
$this->response = $this->response->withCookie('remember_me', [
    'value' => 'yes',
    'path' => '/',
    'httpOnly' => true,
    'secure' => false,
    'expire' => strtotime('+1 year')
]);

// Avant 3.4.0
$this->response->cookie('remember', [
    'value' => 'yes',
    'path' => '/',
    'httpOnly' => true,
    'secure' => false,
    'expire' => strtotime('+1 year')
]);

Référez-vous à la section Créer des Cookies pour savoir comment utiliser l’objet Cookie. Vous pouvez utiliser withExpiredCookie() pour envoyer un cookie expiré dans la réponse. De cette manière, le navigateur supprimera son cookie local:

// À partir de 3.5.0
$this->response = $this->response->withExpiredCookie('remember_me');

Définir les En-têtes de Requête d’Origine Croisée (Cross Origin Request Headers = CORS)

Depuis 3.2, vous pouvez utiliser la méthode cors() pour définir le Contrôle d’Accès HTTP et ses en-têtes liés avec une interface simple:

$this->response->cors($this->request)
    ->allowOrigin(['*.cakephp.org'])
    ->allowMethods(['GET', 'POST'])
    ->allowHeaders(['X-CSRF-Token'])
    ->allowCredentials()
    ->exposeHeaders(['Link'])
    ->maxAge(300)
    ->build();

Les en-têtes liés au CORS vont seulement être appliqués à la réponse si les critères suivants sont vérifiés:

  1. La requête a un en-tête Origin.
  2. La valeur Origin de la requête correspond à une des valeurs autorisées de Origin.

Nouveau dans la version 3.2: CorsBuilder a été ajouté dans 3.2

Erreurs Communes avec les Responses Immutables

Depuis CakePHP 3.4.0, les objets responses offrent de nombreuses méthodes qui traitent les responses comme des objets immutables. Les objets immutables permettent de prévenir les effets de bord difficiles à repérer. Malgré leurs nombreux avantages, s’habituer aux objets immutables peut prendre un peu de temps. Toutes les méthodes qui commencent par with intéragiront avec la réponse à la manière immutable et retourneront toujours une nouvelle instance. L’erreur la plus fréquente quand les développeurs travaillent avec les objets immutables est d’oublier de persister l’instance modifiée:

$this->response->withHeader('X-CakePHP', 'yes!');

Dans le code ci-dessus, la réponse ne contiendra pas le header X-CakePHP car la valeur retournée par withHeader() n’a pas été persistée. Pour avoir un code fonctionnel, vous devrez écrire:

$this->response = $this->response->withHeader('X-CakePHP', 'yes!');

CookieCollections

class Cake\Http\Cookie\CookieCollection

Les objets CookieCollection sont accessibles depuis les objets Request et Response. Ils vous permettent d’intéragir avec des groupes de cookies en utilisant des patterns immutables, ce qui permet au caractère immutable des Request et des Response d’être préservé.

Créer des Cookies

class Cake\Http\Cookie\Cookie

Les objets Cookie peuvent être définis via le constructor ou en utilisant l’interface fluide qui suit les patterns immutables:

use Cake\Http\Cookie\Cookie;

// Tous les arguments dans le constructor
$cookie = new Cookie(
    'remember_me', // nom
    1, // valeur
    new DateTime('+1 year'), // durée d'expiration, si applicable
    '/', // chemin, si applicable
    'example.com', // domaine, si applicable
    false, // seulement en mode 'secure' ?
    true // seulement en http ?
);

// En utilisant les méthodes immutables
$cookie = (new Cookie('remember_me'))
    ->withValue('1')
    ->withExpiry(new DateTime('+1 year'))
    ->withPath('/')
    ->withDomain('example.com')
    ->withSecure(false)
    ->withHttpOnly(true);

Une fois que vous avez créer un cookie, vous pouvez l’ajouter à une nouvelle CookieCollection, ou à une existante:

use Cake\Http\Cookie\CookieCollection;

// Crée une nouvelle collection
$cookies = new CookieCollection([$cookie]);

// Ajoute à une collection existante
$cookies = $cookies->add($cookie);

// Supprime un cookie via son nom
$cookies = $cookies->remove('remember_me');

Note

Gardez bien à l’esprit que les collections sont immutables et qu’ajouter des cookies dans une collection ou retirer des cookies d’une collection va créer une nouvelle collection.

Vous devriez utiliser la méthode withCookie() pour ajouter des cookies aux objets Response:

$response = $this->response->withCookie($cookie);

Les cookies ajoutés aux Response peuvent être chiffrés en utilisant le Middleware de Gestion de Cookies Chiffrés

Lire des Cookies

Une fois que vous avez une instance de CookieCollection, vous pouvez accéder aux cookies qu’elle contient:

// Vérifie l'existence d'un cookie
$cookies->has('remember_me');

// Récupère le nombre de cookie dans une collection
count($cookies);

// Récupère l'instance d'un cookie
$cookie = $cookies->get('remember_me');

Une fois que vous avez un objet Cookie, vous pouvez intéragir avec son état et le modifier. Gardez à l’esprit que les cookies sont immutables, donc vous allez devoir mettre à jour la collection si vous modifiez un cookie:

// Récupère la valeur
$value = $cookie->getValue()

// Accède à une donnée dans une valeur JSON
$id = $cookie->read('User.id');

// Vérifie l'état
$cookie->isHttpOnly();
$cookie->isSecure();

Nouveau dans la version 3.5.0: CookieCollection et Cookie ont été ajoutés dans 3.5.0.