Dmy*_*sun 87 ajax doctrine symfony doctrine-orm
我正在开发游戏应用程序并使用Symfony 2.0.我对后端有很多AJAX请求.更多的响应是将实体转换为JSON.例如:
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');
}
}
Run Code Online (Sandbox Code Playgroud)
我的所有控制器都做同样的事情:获取一个实体并将其一些字段编码为JSON.我知道我可以使用规范化器并对所有权限进行编码.但是,如果一个实体已经循环链接到其他实体呢?或实体图非常大?你有什么建议吗?
我想一下实体的一些编码模式......或者NormalizableInterface用来避免循环..,
小智 147
有了php5.4,你现在可以做到:
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,
);
}
}
Run Code Online (Sandbox Code Playgroud)
然后打电话
json_encode(MyUserEntity);
Run Code Online (Sandbox Code Playgroud)
Sof*_*fia 81
另一种选择是使用JMSSerializerBundle.然后在你的控制器中
$serializer = $this->container->get('serializer');
$reports = $serializer->serialize($doctrineobject, 'json');
return new Response($reports); // should be $reports as $doctrineobject is not serialized
Run Code Online (Sandbox Code Playgroud)
您可以通过在实体类中使用注释来配置序列化的完成方式.请参阅上面链接中的文档.例如,以下是排除链接实体的方法:
/**
* Iddp\RorBundle\Entity\Report
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Iddp\RorBundle\Entity\ReportRepository")
* @ExclusionPolicy("None")
*/
....
/**
* @ORM\ManyToOne(targetEntity="Client", inversedBy="reports")
* @ORM\JoinColumn(name="client_id", referencedColumnName="id")
* @Exclude
*/
protected $client;
Run Code Online (Sandbox Code Playgroud)
web*_*a2l 39
您可以使用以下命令自动编码为复杂实体Json:
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');
Run Code Online (Sandbox Code Playgroud)
jer*_*ome 11
要完成答案:Symfony2附带了一个json_encode包装器: Symfony/Component/HttpFoundation/JsonResponse
控制器中的典型用法:
...
use Symfony\Component\HttpFoundation\JsonResponse;
...
public function acmeAction() {
...
return new JsonResponse($array);
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助
Ĵ
rkm*_*max 10
我发现序列化实体问题的解决方案如下:
#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 }
Run Code Online (Sandbox Code Playgroud)
在我的控制器中:
$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));
Run Code Online (Sandbox Code Playgroud)
其他例子:
$serializer = $this->get('serializer');
$collection = $this->get('doctrine')
->getRepository('myBundle:Entity')
->findBy($params);
$json = $serializer->serialize($collection, 'json');
return new Response($json);
Run Code Online (Sandbox Code Playgroud)
您甚至可以将其配置为在http://api.symfony.com/2.0中反序列化数组
我只需要解决同样的问题:json编码一个实体("用户"),它具有与另一个实体("位置")的一对多双向关联.
我尝试了几件事,我想现在我找到了最好的解决方案.我的想法是使用David编写的相同代码,但是通过告诉Normalizer在某个时刻停止来以某种方式拦截无限递归.
我不想实现自定义规范化器,因为在我看来这个GetSetMethodNormalizer是一个很好的方法(基于反射等).所以我决定将它子类化,这在初看起来并非无足轻重,因为说明是否包含属性(isGetMethod)的方法是私有的.
但是,可以覆盖normalize方法,所以我在这一点上拦截,只需取消设置引用"Location"的属性 - 因此无限循环被中断.
在代码中它看起来像这样:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我有同样的问题,我选择创建自己的编码器,它将自己应对递归.
我创建了实现的类Symfony\Component\Serializer\Normalizer\NormalizerInterface,以及保存每个类的服务NormalizerInterface.
#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);
}
Run Code Online (Sandbox Code Playgroud)
规范化器的一个示例:
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.)
);
}
}
Run Code Online (Sandbox Code Playgroud)
在控制器中:
$normalizerService = $this->get('normalizer.service'); //you will have to configure services.yml
$json = $normalizerService->serialize($myobject, 'json');
return new Response($json);
Run Code Online (Sandbox Code Playgroud)
完整的代码在这里:https://github.com/progracqteur/WikiPedale/tree/master/src/Progracqteur/WikipedaleBundle/Resources/Normalizer
/app/config/config.yml
framework:
# ?????? ??????????????? ???????? ? ???????, json, xml ? ???????
serializer:
enabled: true
services:
object_normalizer:
class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
tags:
# ???????? ? ???? ????????? ???? ??????, ??? ??. ?????, ?.?. ????? ???????? ?? ?????
- { name: serializer.normalizer }
Run Code Online (Sandbox Code Playgroud)
以及控制器的示例:
/**
* ????? ???????? ?? ?? ??????? ? ?? ?????
* @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 );
}
Run Code Online (Sandbox Code Playgroud)
但字段类型\ DateTime的问题将保留.
这更像是一个更新(对于Symfony v:2.7+和JmsSerializer v:0.13.*@ dev),所以为了避免Jms尝试加载和序列化整个对象图(或者在循环关系的情况下......)
模型:
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
......................
......................
*/
Run Code Online (Sandbox Code Playgroud)
内部动作:
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);
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Symfony 2.7 或更高版本,并且不想包含任何额外的用于序列化的包,也许您可以按照这种方式将学说实体序列化为 json -
在我的(公共的,父级)控制器中,我有一个准备序列化程序的函数
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()]);
}
Run Code Online (Sandbox Code Playgroud)然后使用它来将实体序列化为 JSON
$this->_getSerializer()->normalize($anEntity, 'json');
$this->_getSerializer()->normalize($arrayOfEntities, 'json');
Run Code Online (Sandbox Code Playgroud)完毕!
但是您可能需要一些微调。例如 -
| 归档时间: |
|
| 查看次数: |
110286 次 |
| 最近记录: |