Saya sedang mengembangkan aplikasi game dan menggunakan Symfony 2.0. Saya memiliki banyak permintaan AJAX ke backend. Dan lebih banyak tanggapan yang mengubah entitas menjadi JSON. Sebagai contoh:
class DefaultController extends Controller
{
public function launchAction()
{
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->find($id);
// encode user to json format
$userDataAsJson = $this->encodeUserDataToJson($user);
return array(
'userDataAsJson' => $userDataAsJson
);
}
private function encodeUserDataToJson(User $user)
{
$userData = array(
'id' => $user->getId(),
'profile' => array(
'nickname' => $user->getProfile()->getNickname()
)
);
$jsonEncoder = new JsonEncoder();
return $jsonEncoder->encode($userData, $format = 'json');
}
}
Dan semua pengontrol saya melakukan hal yang sama: dapatkan entitas dan menyandikan beberapa bidangnya ke JSON. Saya tahu bahwa saya dapat menggunakan normalizer dan menyandikan semua entitas. Tetapi bagaimana jika suatu entitas telah mengayunkan tautan ke entitas lain? Atau grafik entitas sangat besar? Apakah Anda punya saran?
Saya memikirkan tentang beberapa skema encoding untuk entitas ... atau menggunakan NormalizableInterface
untuk menghindari bersepeda ..,
sumber
Dengan php5.4 sekarang Anda dapat melakukan:
use JsonSerializable; /** * @Entity(repositoryClass="App\Entity\User") * @Table(name="user") */ class MyUserEntity implements JsonSerializable { /** @Column(length=50) */ private $name; /** @Column(length=50) */ private $login; public function jsonSerialize() { return array( 'name' => $this->name, 'login'=> $this->login, ); } }
Dan kemudian panggil
sumber
OneToMany
relasi)Anda dapat secara otomatis menyandikan ke Json, entitas kompleks Anda dengan:
use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; use Symfony\Component\Serializer\Encoder\JsonEncoder; $serializer = new Serializer(array(new GetSetMethodNormalizer()), array('json' => new JsonEncoder())); $json = $serializer->serialize($entity, 'json');
sumber
Untuk melengkapi jawabannya: Symfony2 hadir dengan pembungkus di sekitar json_encode: Symfony / Component / HttpFoundation / JsonResponse
Penggunaan umum di Pengontrol Anda:
... use Symfony\Component\HttpFoundation\JsonResponse; ... public function acmeAction() { ... return new JsonResponse($array); }
Semoga ini membantu
J
sumber
Saya menemukan solusi untuk masalah serialisasi entitas adalah sebagai berikut:
#config/config.yml services: serializer.method: class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer serializer.encoder.json: class: Symfony\Component\Serializer\Encoder\JsonEncoder serializer: class: Symfony\Component\Serializer\Serializer arguments: - [@serializer.method] - {json: @serializer.encoder.json }
di pengontrol saya:
$serializer = $this->get('serializer'); $entity = $this->get('doctrine') ->getRepository('myBundle:Entity') ->findOneBy($params); $collection = $this->get('doctrine') ->getRepository('myBundle:Entity') ->findBy($params); $toEncode = array( 'response' => array( 'entity' => $serializer->normalize($entity), 'entities' => $serializer->normalize($collection) ), ); return new Response(json_encode($toEncode));
contoh lain:
$serializer = $this->get('serializer'); $collection = $this->get('doctrine') ->getRepository('myBundle:Entity') ->findBy($params); $json = $serializer->serialize($collection, 'json'); return new Response($json);
Anda bahkan dapat mengkonfigurasinya untuk deserialisasi array di http://api.symfony.com/2.0
sumber
Saya hanya harus memecahkan masalah yang sama: json-encoding suatu entitas ("Pengguna") yang memiliki Asosiasi Dua Arah Satu-Ke-Banyak ke Entitas lain ("Lokasi").
Saya mencoba beberapa hal dan saya pikir sekarang saya menemukan solusi terbaik yang dapat diterima. Idenya adalah menggunakan kode yang sama seperti yang ditulis oleh David, tetapi entah bagaimana menghalangi rekursi tak terbatas dengan memberi tahu Normalizer untuk berhenti di beberapa titik.
Saya tidak ingin menerapkan normalizer khusus, karena GetSetMethodNormalizer ini adalah pendekatan yang bagus menurut saya (berdasarkan refleksi, dll.). Jadi saya telah memutuskan untuk membuat subkelasnya, yang pada pandangan pertama tidak sepele, karena metode untuk mengatakan apakah menyertakan properti (isGetMethod) adalah pribadi.
Tapi, seseorang dapat menimpa metode normalisasi, jadi saya memotong pada titik ini, dengan hanya membatalkan pengaturan properti yang mereferensikan "Lokasi" - sehingga loop tak terbatas terputus.
Dalam kode terlihat seperti ini:
class GetSetMethodNormalizer extends \Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer { public function normalize($object, $format = null) { // if the object is a User, unset location for normalization, without touching the original object if($object instanceof \Leonex\MoveBundle\Entity\User) { $object = clone $object; $object->setLocations(new \Doctrine\Common\Collections\ArrayCollection()); } return parent::normalize($object, $format); } }
sumber
Saya memiliki masalah yang sama dan saya memilih untuk membuat encoder saya sendiri, yang akan mengatasinya sendiri dengan rekursi.
Saya membuat kelas yang mengimplementasikan
Symfony\Component\Serializer\Normalizer\NormalizerInterface
, dan layanan yang menampung setiapNormalizerInterface
.#This is the NormalizerService class NormalizerService { //normalizer are stored in private properties private $entityOneNormalizer; private $entityTwoNormalizer; public function getEntityOneNormalizer() { //Normalizer are created only if needed if ($this->entityOneNormalizer == null) $this->entityOneNormalizer = new EntityOneNormalizer($this); //every normalizer keep a reference to this service return $this->entityOneNormalizer; } //create a function for each normalizer //the serializer service will also serialize the entities //(i found it easier, but you don't really need it) public function serialize($objects, $format) { $serializer = new Serializer( array( $this->getEntityOneNormalizer(), $this->getEntityTwoNormalizer() ), array($format => $encoder) ); return $serializer->serialize($response, $format); }
Contoh dari Normalizer:
use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class PlaceNormalizer implements NormalizerInterface { private $normalizerService; public function __construct($normalizerService) { $this->service = normalizerService; } public function normalize($object, $format = null) { $entityTwo = $object->getEntityTwo(); $entityTwoNormalizer = $this->service->getEntityTwoNormalizer(); return array( 'param' => object->getParam(), //repeat for every parameter //!!!! this is where the entityOneNormalizer dealt with recursivity 'entityTwo' => $entityTwoNormalizer->normalize($entityTwo, $format.'_without_any_entity_one') //the 'format' parameter is adapted for ignoring entity one - this may be done with different ways (a specific method, etc.) ); } }
Di pengontrol:
$normalizerService = $this->get('normalizer.service'); //you will have to configure services.yml $json = $normalizerService->serialize($myobject, 'json'); return new Response($json);
Kode lengkapnya ada di sini: https://github.com/progracqteur/WikiPedale/tree/master/src/Progracqteur/WikipedaleBundle/Resources/Normalizer
sumber
di Symfony 2.3
/app/config/config.yml
framework: # сервис конвертирования объектов в массивы, json, xml и обратно serializer: enabled: true services: object_normalizer: class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer tags: # помечаем к чему относится этот сервис, это оч. важно, т.к. иначе работать не будет - { name: serializer.normalizer }
dan contoh untuk pengontrol Anda:
/** * Поиск сущности по ИД объекта и ИД языка * @Route("/search/", name="orgunitSearch") */ public function orgunitSearchAction() { $array = $this->get('request')->query->all(); $entity = $this->getDoctrine() ->getRepository('IntranetOrgunitBundle:Orgunit') ->findOneBy($array); $serializer = $this->get('serializer'); //$json = $serializer->serialize($entity, 'json'); $array = $serializer->normalize($entity); return new JsonResponse( $array ); }
tetapi masalah dengan tipe bidang \ DateTime akan tetap ada.
sumber
Ini lebih merupakan pembaruan (untuk Symfony v: 2.7+ dan JmsSerializer v: 0.13. * @ Dev) , jadi untuk menghindari Jms mencoba memuat dan membuat serial seluruh grafik objek (atau dalam kasus hubungan siklik ..)
Model:
use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Annotation\Exclude; use JMS\Serializer\Annotation\MaxDepth; /* <=== Required */ /** * User * * @ORM\Table(name="user_table") ///////////////// OTHER Doctrine proprieties ////////////// */ public class User { /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\ManyToOne(targetEntity="FooBundle\Entity\Game") * @ORM\JoinColumn(nullable=false) * @MaxDepth(1) */ protected $game; /* Other proprieties ....and Getters ans setters ...................... ...................... */
Inside an Action:
use JMS\Serializer\SerializationContext; /* Necessary include to enbale max depth */ $users = $this ->getDoctrine() ->getManager() ->getRepository("FooBundle:User") ->findAll(); $serializer = $this->container->get('jms_serializer'); $jsonContent = $serializer ->serialize( $users, 'json', SerializationContext::create() ->enableMaxDepthChecks() ); return new Response($jsonContent);
sumber
Jika Anda menggunakan Symfony 2.7 atau yang lebih baru , dan tidak ingin menyertakan bundel tambahan untuk serialisasi, mungkin Anda dapat mengikuti cara ini untuk menyegel entitas doktrin ke json -
Dalam pengontrol (umum, induk) saya, saya memiliki fungsi yang mempersiapkan pembuat serial
use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; // ----------------------------- /** * @return Serializer */ protected function _getSerializer() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $normalizer = new ObjectNormalizer($classMetadataFactory); return new Serializer([$normalizer], [new JsonEncoder()]); }
Kemudian gunakan untuk membuat Entitas menjadi JSON
$this->_getSerializer()->normalize($anEntity, 'json'); $this->_getSerializer()->normalize($arrayOfEntities, 'json');
Selesai!
Tetapi Anda mungkin perlu beberapa penyesuaian. Sebagai contoh -
sumber
Saat Anda perlu membuat banyak endpoint REST API di Symfony, cara terbaik adalah menggunakan tumpukan bundel berikut:
Saat Anda mengonfigurasi semuanya dengan benar, kode entitas Anda akan terlihat seperti:
use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as JMS; /** * @ORM\Table(name="company") */ class Company { /** * @var string * * @ORM\Column(name="name", type="string", length=255) * * @JMS\Expose() * @JMS\SerializedName("name") * @JMS\Groups({"company_overview"}) */ private $name; /** * @var Campaign[] * * @ORM\OneToMany(targetEntity="Campaign", mappedBy="company") * * @JMS\Expose() * @JMS\SerializedName("campaigns") * @JMS\Groups({"campaign_overview"}) */ private $campaigns; }
Kemudian, kode di pengontrol:
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use FOS\RestBundle\Controller\Annotations\View; class CompanyController extends Controller { /** * Retrieve all companies * * @View(serializerGroups={"company_overview"}) * @ApiDoc() * * @return Company[] */ public function cgetAction() { return $this->getDoctrine()->getRepository(Company::class)->findAll(); } }
Manfaat dari pengaturan tersebut adalah:
sumber
Sekarang Anda juga dapat menggunakan Doctrine ORM Transformations untuk mengonversi entitas menjadi array bersarang skalar dan sebaliknya
sumber