Comment puis-je envoyer une réponse JSON dans le contrôleur symfony2

90

J'utilise jQuerypour modifier mon formulaire intégré Symfony.

J'affiche le formulaire dans une jQueryboîte de dialogue, puis je le soumets.

Les données entrent correctement dans la base de données.

Mais je ne sais pas si je dois envoyer un certain JSONretour à jQuery. En fait, je suis un peu confus avec les JSONchoses.

Supposons que j'ai ajouté une ligne dans ma table avec `` jQuery et que lorsque je soumets le formulaire, une fois les données soumises, je souhaite renvoyer ces données de ligne afin que je puisse ajouter dynamiquement la ligne de table pour afficher les données ajoutées.

Je ne sais pas comment récupérer ces données.

Ceci est mon code actuel:

$editForm = $this->createForm(new StepsType(), $entity);

$request = $this->getRequest();

$editForm->bindRequest($request);

if ($editForm->isValid()) {
    $em->persist($entity);
    $em->flush();

    return $this->render('::success.html.twig');               
}

Ceci est juste le modèle avec le message de réussite.

Mirage
la source

Réponses:

187

Symfony 2.1

$response = new Response(json_encode(array('name' => $name)));
$response->headers->set('Content-Type', 'application/json');

return $response;

Symfony 2.2 et supérieur

Vous avez une classe JsonResponse spéciale , qui sérialise le tableau en JSON:

return new JsonResponse(array('name' => $name));

Mais si votre problème est de savoir comment sérialiser l'entité, vous devriez jeter un œil à JMSSerializerBundle

En supposant que vous l'avez installé, vous devrez simplement faire

$serializedEntity = $this->container->get('serializer')->serialize($entity, 'json');

return new Response($serializedEntity);

Vous devriez également rechercher des problèmes similaires sur StackOverflow:

Vitalii Zurian
la source
1
Alors, comment sérialiser l'entité ET l'envoyer en tant que réponse JSON? Je cherche ça depuis une semaine .. stackoverflow.com/questions/14798532/…
George Katsanos
Vous pouvez également utiliser symfony JsonResponse (Symfony \ Component \ HttpFoundation \ JsonResponse)
Kiddo
5
Il est préférable de définir l'en-tête de type de contenu return new Response ($ serializedEntity, 200, array ('Content-Type' => 'application / json'));
Sergii Smirnov
La suggestion de Sergii est la meilleure (du moins pour moi), si je ne règle pas le Content-Type, sur le client je recevrai un content-type text / html. Si j'utilise JsonResponse, pour une raison étrange, j'obtiens une seule chaîne avec le contenu à l'intérieur
LuisF
56

Symfony 2.1 a une classe JsonResponse .

return new JsonResponse(array('name' => $name));

Le tableau transmis sera encodé en JSON, le code d'état par défaut sera 200 et le type de contenu sera défini sur application / json.

Il existe également une setCallbackfonction pratique pour JSONP.

jmaloney
la source
16

Depuis Symfony 3.1, vous pouvez utiliser JSON Helper http://symfony.com/doc/current/book/controller.html#json-helper

public function indexAction()
{
// returns '{"username":"jane.doe"}' and sets the proper Content-Type header
return $this->json(array('username' => 'jane.doe'));

// the shortcut defines three optional arguments
// return $this->json($data, $status = 200, $headers = array(), $context = array());
}
Bettinz
la source
10

Pour compléter la réponse @thecatontheflat, je recommanderais également d'envelopper votre action dans un try … catchbloc. Cela empêchera votre point de terminaison JSON de se rompre sur les exceptions. Voici le squelette que j'utilise:

public function someAction()
{
    try {

        // Your logic here...

        return new JsonResponse([
            'success' => true,
            'data'    => [] // Your data here
        ]);

    } catch (\Exception $exception) {

        return new JsonResponse([
            'success' => false,
            'code'    => $exception->getCode(),
            'message' => $exception->getMessage(),
        ]);

    }
}

De cette façon, votre point de terminaison se comportera de manière cohérente même en cas d'erreurs et vous pourrez les traiter directement du côté client.

Slava Fomin II
la source
8

Si vos données sont déjà sérialisées:

a) envoyer une réponse JSON

public function someAction()
{
    $response = new Response();
    $response->setContent(file_get_contents('path/to/file'));
    $response->headers->set('Content-Type', 'application/json');
    return $response;
}

b) envoyer une réponse JSONP (avec rappel)

public function someAction()
{
    $response = new Response();
    $response->setContent('/**/FUNCTION_CALLBACK_NAME(' . file_get_contents('path/to/file') . ');');
    $response->headers->set('Content-Type', 'text/javascript');
    return $response;
}

Si vos données doivent être sérialisées:

c) envoyer une réponse JSON

public function someAction()
{
    $response = new JsonResponse();
    $response->setData([some array]);
    return $response;
}

d) envoyer une réponse JSONP (avec rappel)

public function someAction()
{
    $response = new JsonResponse();
    $response->setData([some array]);
    $response->setCallback('FUNCTION_CALLBACK_NAME');
    return $response;
}

e) utiliser des groupes dans Symfony 3.xx

Créez des groupes dans vos entités

<?php

namespace Mindlahus;

use Symfony\Component\Serializer\Annotation\Groups;

/**
 * Some Super Class Name
 *
 * @ORM    able("table_name")
 * @ORM\Entity(repositoryClass="SomeSuperClassNameRepository")
 * @UniqueEntity(
 *  fields={"foo", "boo"},
 *  ignoreNull=false
 * )
 */
class SomeSuperClassName
{
    /**
     * @Groups({"group1", "group2"})
     */
    public $foo;
    /**
     * @Groups({"group1"})
     */
    public $date;

    /**
     * @Groups({"group3"})
     */
    public function getBar() // is* methods are also supported
    {
        return $this->bar;
    }

    // ...
}

Normaliser votre objet Doctrine dans la logique de votre application

<?php

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
// For annotations
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;

...

$repository = $this->getDoctrine()->getRepository('Mindlahus:SomeSuperClassName');
$SomeSuperObject = $repository->findOneById($id);

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$encoder = new JsonEncoder();
$normalizer = new ObjectNormalizer($classMetadataFactory);
$callback = function ($dateTime) {
    return $dateTime instanceof \DateTime
        ? $dateTime->format('m-d-Y')
        : '';
};
$normalizer->setCallbacks(array('date' => $callback));
$serializer = new Serializer(array($normalizer), array($encoder));
$data = $serializer->normalize($SomeSuperObject, null, array('groups' => array('group1')));

$response = new Response();
$response->setContent($serializer->serialize($data, 'json'));
$response->headers->set('Content-Type', 'application/json');
return $response;
Avram Cosmin
la source