Bonjour,
J'aimerai que quelqu'un mexplqiue comment côté serveur (cakephp) rendre correctement une réponse ajax

Ce que je fais

J'ai essayé 2 choses :
1 - Dans mon AppController

public function initialize()
    {
        parent::initialize();
        $this->Auth->deny();
        $this->loadComponent('RequestHandler');
        if ($this->request->is('ajax'))  {
            $this->RequestHandler->renderAs($this, 'json');
        }
    }

Dans l'action du controller

$this->set(compact('data'));
$this->set('_serialize', ['data']);

2 - Dans mon AppController

public function initialize()
    {
        parent::initialize();
        $this->Auth->deny();
        $this->loadComponent('RequestHandler');
        if ($this->request->is('ajax'))  {
            $this->viewBuilder()->layout('ajax');
        }
    }

Le code de l'action du controller de change pas.
Et dans le template XXX.ctp associé à mon action XXX du controlleur contient :

<?= json_encode(compact('data')); ?>

Les 2 codes précédents marchent seulement voilà :
1 - dans le premier cas, j'ai l'impression que la classe AjaxView et le layout ajax ne servent à rien et il n'y a pas de template associé à l'action comme dans le code 2 (ce qui ne me dérange pas vu qu'il y a 1 ligne "bidon" à chauqe fois dedans)
2 - dans le deuxième cas, ce qui me dérange c'est justement l'avantage du premier cas : je suis obliger de créer pour chaque action retournant de l'ajax un template contenant 1 ligne "bidon".

Ce que je veux

Alors après tout ça vous me diriez : mais quel est ton problème !???
Eh bien c'est j'ai 2 solutions pour rendre une vue format json pour de l'ajax et que je pense qu'aucune des 2 n'est la bonne ...

J'aimerai que quelqu'un me dise simplement quel est la bonne manière dans Cakephp 3pour rendre du json pour une réponse ajax : code de l'action et/ou initialisation de son AppController.

Y a til une configuration ou quelque chose autre que le loadComponent('RequestHandler'); à faire ?

Enfin, j'aimerai quel est la bonne manière pour rendre une erreur/exception (400, 500) pour que mon appel ajax le détecte.

2 réponses


Ferias Quarante
Auteur
Réponse acceptée

Bon avec quelques recherches et tests, j'arrive à la solution suviante :

// config/routes.php , ajouter
Router::extensions(['json']);

// dans mon AppController , methode initialize() , ajouter
$this->loadComponent('RequestHandler');

// dans l'action du controller
$this->set(compact('data'));
$this->set('_serialize', ['data']);

// dans le code JS : ajouter **.json** dans l'url appelée

Je sais pas si c'est le mieux, quelqu'un qui passe par là plus tard pourrait il me dire si j'ai tout bon, où s'il y a une autre/meilleure manière ? Je trouve cette solution pas très bien vu qu'il faut ajouter .json sur les urls ...

Par contre toujours pas de solution pour retourner une réponse ajax avec un code erreur 200/400/500, quelqu'un sait il comment faire ?

PS : j'en avais pas parler, mais mes actions supportent l'appel classique et ajax, j'ai donc juste mis un if ($this->request->is('ajax')) pour faire un traitement de la réponse différente, est ce correct ?

PhiSyX
Réponse acceptée

Yop.

Crée des exceptions pour les erreurs (ou utilise ceux de cakephp). Cakephp "transformera" automatiquement l'exception sous format JSON avec le bon code d'erreur http ^^

# Dans un controlleur
if ($this->request->is('json')) {
    // Configure::write('debug', false);
    throw new \Cake\Network\Exception\NotFoundException('Erreur ;)');
}


A savoir qu'ici on voit qu'il y a un tableau "trace" parce que je suis en mode debug mais en mode non debug le tableau "trace" n'y sera pas. ^^

Et oui, ton code est bon.
Dans les dernières version de "cakephp/app" (voir github), il n'y a plus besoin de préciser $this->set('_serialize', ['data']).

Grace au code suivant:

# AppController.php
/**
 * Before render callback.
 *
 * @param \Cake\Event\Event $event The beforeRender event.
 */
public function beforeRender(\Cake\Event\Event $event)
{
    if (!array_key_exists('_serialize', $this->viewVars) &&
        in_array($this->response->type(), ['application/json', 'application/xml'])
    ) {
        $this->set('_serialize', true);
    }
}

Toutes les données qui seront transmis à une vue seront automatiquement sérializées. (donc après un $this->set('key', 'value'))