我有以下实体:
class A
{
/**
* @JMS\Groups({"writable", "other"})
*/
private $varA;
/**
* @JMS\Groups({"writable"})
*/
private $varB;
/**
* @JMS\Groups({"other"})
*/
private $varC;
}
我想让序列化器为BOTH组中存在的属性生成输出,所以在简单的单词中我需要一组分组属性。
$context = SerializationContext::create()->setGroups(['writable' ,'other']);
$serializer->serialize(new A(), 'json', $context);
上面的代码应该只输出变量$varA
,因为它定义了两个组。
如何实现呢?我想到的唯一一件事就是扩展来自JMSSerializer的GroupExclusionStategy,但也许还有更好的方法吗?
答案 0 :(得分:1)
我已经深入了解jms的代码,我发现setGroups使用的是GroupsExclusionStrategy,但也有不同的策略和ExclusionStrategyInterface。所以我已将此界面实现到我自己的
中<?php
namespace AppBundle\Jms\Serializer;
use JMS\Serializer\Context;
use JMS\Serializer\Exclusion\ExclusionStrategyInterface;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
/**
* Class IntersectGroupsExclusionStrategy
* @package AppBundle\Jms
*/
class IntersectGroupsExclusionStrategy implements ExclusionStrategyInterface
{
/**
* @var array
*/
private $groups;
/**
* IntersectGroupsExclusionStrategy constructor.
* @param array $groups
*/
public function __construct(array $groups)
{
$this->setGroups($groups);
}
/**
* {@inheritDoc}
*/
public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext)
{
if (is_array($this->groups) && is_array($property->groups)) {
return !(!empty($this->groups) && array_intersect($this->groups, $property->groups) === $this->groups);
}
return false;
}
/**
* Whether the class should be skipped.
*
* @param ClassMetadata $metadata
*
* @return boolean
*/
public function shouldSkipClass(ClassMetadata $metadata, Context $context)
{
return false;
}
/**
* @param array $groups
* @return $this
*/
public function setGroups(array $groups)
{
$this->groups = $groups;
return $this;
}
}
序列化而不是使用setGroups
我已经使用
$intersectExclusionStrategy = new IntersectGroupsExclusionStrategy($groups);
$serializationContext = SerializationContext::create();
$serializationContext->addExclusionStrategy($intersectExclusionStrategy);
$groups
保留值['writable' ,'other']
的位置。
效果很好。
如果有人需要,我也为它创建了测试。
<?php
use AppBundle\Jms\Serializer\IntersectGroupsExclusionStrategy;
class IntersectGroupsExclusionStrategyTest extends PHPUnit_Framework_TestCase
{
public function testShouldSkipPropertyGroups()
{
$intersectExclusionStrategy = new IntersectGroupsExclusionStrategy(['group_a', 'group_b']);
$propertyMetaData = $this->getMock('JMS\Serializer\Metadata\PropertyMetadata', [], [], '', false);
$context = $this->getMock('JMS\Serializer\Context', [], [], '', false);
$propertyMetaData->groups = ['group_a', 'group_b', 'group_c'];
$this->assertNotTrue($intersectExclusionStrategy->shouldSkipProperty($propertyMetaData, $context));
$propertyMetaData->groups = ['group_a', 'group_b'];
$this->assertNotTrue($intersectExclusionStrategy->shouldSkipProperty($propertyMetaData, $context));
}
public function testShouldNotSkipPropertyGroups()
{
$intersectExclusionStrategy = new IntersectGroupsExclusionStrategy(['group_a', 'group_b']);
$propertyMetaData = $this->getMock('JMS\Serializer\Metadata\PropertyMetadata', [], [], '', false);
$context = $this->getMock('JMS\Serializer\Context', [], [], '', false);
$propertyMetaData->groups = ['group_a', 'group_c'];
$this->assertTrue($intersectExclusionStrategy->shouldSkipProperty($propertyMetaData, $context));
$propertyMetaData->groups = ['group_d', 'group_e'];
$this->assertTrue($intersectExclusionStrategy->shouldSkipProperty($propertyMetaData, $context));
$intersectExclusionStrategy = new IntersectGroupsExclusionStrategy([]);
$this->assertTrue($intersectExclusionStrategy->shouldSkipProperty($propertyMetaData, $context));
}
public function testShouldSkipClassReturnsFalse()
{
$intersectExclusionStrategy = new IntersectGroupsExclusionStrategy(['group_a', 'group_b']);
$classMetaData = $this->getMock('JMS\Serializer\Metadata\ClassMetadata', [], [], '', false);
$context = $this->getMock('JMS\Serializer\Context', [], [], '', false);
$this->assertFalse($intersectExclusionStrategy->shouldSkipClass($classMetaData, $context));
}
}
答案 1 :(得分:1)
也许一个简单的解决方案可能是向$varA
属性添加另一个组名(“独占”):
/**
* @JMS\Groups({"writable", "other", "exclusive"})
*/
private $varA;
接下来是:
$context = SerializationContext::create()->setGroups('exclusive');
但可能这只是一个用例示例。另一方面,应该创建一个CustomGroupsExclusionStrategy()
。
默认情况下GroupsExclusionStrategy()
会检查是否有任何属性组包含在请求的组中:
private function shouldSkipUsingGroups(PropertyMetadata $property, $groups)
{
foreach ($property->groups as $group) {
if (in_array($group, $groups)) {
return false;
}
}
return true;
}
所以,要做到这一点,你需要改变这个:
private function shouldSkipUsingGroups(PropertyMetadata $property, $groups)
{
foreach ($groups as $group) {
if (!in_array($group, $property->groups)) {
return true;
}
}
return false;
}
因此,所有请求的组必须包含在属性组中。
解决方案:
https://gist.github.com/yceruto/90b1ac46c8e33d51ec21079725949f77
我在这里使用标志“严格”策略留下了一个实现:
$context = SerializationContext::create();
$context->addExclusionStrategy(
new CustomGroupsExclusionStrategy(['writable', 'other'], true)
);
$json = $this->get('serializer')->serialize(new A(), 'json', $context);
输出:
{"varA":"foo"}