使用 JMSSerializerBundle 序列化指定字段

问题描述 投票:0回答:2

我正在构建一个 REST API,我想让我的用户可以选择通过 URL 参数返回哪些字段,例如

/users?fields=username,email,address.city,address.country

有什么方法可以使用 JMSSerializerBundle 来完成此类功能吗?

//编辑

请注意嵌入的集合

php symfony jmsserializerbundle jms-serializer
2个回答
2
投票

我不认为这是

JMSSerializer
的工作,至少不完全是。相反,我会做的是:

// Do not serialize into JSON or XML, but to PHP array
$userSerialized = $jmsSerializer->toArray($user);

// Turn "username,email" into ['username' => 0, 'email' => 1, ... ]
$fields = array_flip(explode($request->query->get('fields')));

$userSerializedFiltered = array_intersect_key($userSerialized, $fields);

// Finally, put it into desired format, JSON for example:
$json = json_encode($userSerializedFiltered);

另一个想法:

您可以利用 Doctrine Partial 对象

$user = $em->createQuery("select partial u.{" . $fields . "} from MyApp\Domain\User u")->getResult();
$serialized = $jmsSerializer->serialize($user, 'json');

希望这有帮助...


1
投票

编辑:这个答案仅涵盖最初的问题,没有要求更深层次的序列化。无论如何我都会保留它,因为它也可能帮助其他人解决最初的问题。

我们以非常通用的方式做了完全相同的事情。

如果“fields”已作为参数附加,我们扩展了 ViewHandler 以从当前 Request 中读取数据,并向 SerializationContext 添加了 ExclusionStrategy

值得注意的是,这种方法适用于 FOS Rest Bundle 1.7.7(到目前为止我们还没有迁移到最新的 JMS 版本)、Symfony > 2.8 和 JMSSerializerBundle 1.1.0 - 但应该不会太难也可以将此方法迁移到任何其他组合。

class ViewHandler extends \FOS\RestBundle\View\ViewHandler
{
/**
 * Extends ViewHandler, adds the exclusion strategies FieldListExclusionStrategy to the SerializationContext.
 *
 * Reads Request Parameter "fields" (comma separated list) and parses it into an array. Does some clean-up on parameter
 */
protected function getSerializationContext(View $view)
{
    $context = $view->getSerializationContext();
    $request = $this->container->get('request_stack')->getCurrentRequest();

    if ($request->isMethod('GET') && $request->query->has('fields')) {
        $fieldList = explode(',', $request->query->get('fields'));

        array_walk($fieldList, array(&$this, 'cleanString'));   //clean special characters except - and _
        $fieldList = array_filter($fieldList);                  // remove empty elements

        $context->addExclusionStrategy(new FieldListExclusionStrategy($fieldList));
    }

    $view->setSerializationContext($context);

    return parent::getSerializationContext($view);
}


/**
 * Helper to remove special characters from String, Compatible with array_walk
 *
 * @param string $string -
 * @param mixed  $key    -needed to be compatible with array_walk without raising a notice. (hands in 2 parameters)
 *
 * @return mixed
 */
private function cleanString(&$string, $key)
{
    $string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
    $string = preg_replace('/[^A-Za-z0-9\-\_]/', '', $string); // Removes special chars.

    return preg_replace('/-+/', '-', $string); // Replaces multiple hyphens with single one.
}
} 

这是 FieldListExclusionStrategy 类:

class FieldListExclusionStrategy implements ExclusionStrategyInterface
{
/**
 * @var array
 */
private $fields = array();
/**
 * @var int
 */
private $maxDepth;

/**
 * FieldListExclusionStrategy constructor.
 *
 * @param array $fields
 */
public function __construct(array $fields)
{
    $this->maxDepth = 1;
    $this->fields = $fields;
}

/**
 * Whether the class should be skipped.
 *
 * @param ClassMetadata $metadata
 * @param Context       $context
 * @return boolean
 */
public function shouldSkipClass(ClassMetadata $metadata, Context $context)
{
    return false;
}

/**
 * Whether the property should be skipped.
 *
 * @param PropertyMetadata $property
 * @param Context          $context
 *
 * @return boolean
 */
public function shouldSkipProperty(PropertyMetadata $property, Context $context)
{
    if (0 === count($this->fields)) {
        return false;
    }

    if ($context->getDepth() > $this->maxDepth) {
        return false;
    }

    $name = $property->serializedName ?: $property->name;

    return !in_array($name, $this->fields, true);
}
}
© www.soinside.com 2019 - 2024. All rights reserved.