4

Doctrine 2 を使用して、次のいずれかを実行できますか?

  • 生成されたプロキシ クラスからプロパティを除外しますか?
  • 遅延読み込み/プロキシ生成を完全に無効にしますか?

エンティティのシリアル化に問題があります (Symfony と JMS シリアライザーを使用)。クエリで明示的に取得した関連エンティティのみをシリアル化したい。

fe JMS シリアライザーを使用する場合、Doctrine 2 の遅延読み込みを無効にしますか?で説明されている解決策 部分的にしか機能していません。仮想プロパティがある場合:

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;

/**
 * Profile
 *
 * @ORM\Table(name="profile")
 * @ORM\Entity
 */
class Profile
{
    // ...

    /**
     * @return string
     *
     * @Serializer\VirtualProperty()
     */
    public function getLabel()
    {
        return implode(' ', [$this->firstname, $this->lastname]) . " ({$this->email})";
    }
}

関連するクラスは、シリアル化プロセスでプロキシを介してロードされます。

4

2 に答える 2

3

これは、上記の問題を解決するためにこれまでに思いついた最良の解決策です。JMSSerializer コードの変更は必要ありません。完全なコードはこの Gist にあります: https://gist.github.com/Jaap-van-Hengstum/0d400ea4f986d8f8a044

秘訣は、空の「偽の」クラスを作成することです。

namespace MyApp\ApiBundle\Serializer;

class SerializerProxyType
{
  // this class is supposed to be empty
}

customDoctrineProxySubscriberで、イベント タイプをそのクラスに設定します。このように、JMSSerializer はそのタイプをアノテーション処理に使用するため、 のようなアノテーションに遭遇したときに Doctrine プロキシーをトリガーしません@VirtualProperty

class DoctrineProxySubscriber implements EventSubscriberInterface
{
    public function onPreSerialize(PreSerializeEvent $event)
    {
        $object = $event->getObject();
        $type = $event->getType();

        ...
        // This line is commented, so proxy loading on serializing is disabled
        // $object->__load();

        if ( ! $virtualType) {
            // This line is commented because a different type is used
            // $event->setType(get_parent_class($object));

            // This assumes that every Doctrine entity has a single 'Id' primary
            // key field.
            $event->setType('MyApp\ApiBundle\Serializer\SerializerProxyType',
                ["id" => $object->getId()]);
        }
    }

    public static function getSubscribedEvents()
    {
        return array(
            array('event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize'),
        );
    }
}

その後、JMSSerializer ハンドラーを使用して、空のクラスのカスタム ハンドラーを追加できます。このハンドラーは、シリアライズされた json/xml にエンティティの ID を含めるだけです。

class DoctrineProxyHandler implements SubscribingHandlerInterface
{
    /**
     * {@inheritdoc}
     */
    public static function getSubscribingMethods()
    {
        $methods = [];

        foreach (array('json', 'xml') as $format)
        {
            $methods[] = [
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                'format' => $format,
                'type' => 'MyApp\\ApiBundle\\Serializer\\SerializerProxyType',
                'method' => 'serializeTo' . ucfirst($format),
            ];
        }

        return $methods;
    }

    public function serializeToJson(VisitorInterface $visitor, $entity, array $type, Context $context)
    {
        $object = new \stdClass();
        $object->id = $type['params']['id'];

        return $object;
    }

    public function serializeToXml(XmlSerializationVisitor $visitor, $entity, array $type, Context $context)
    {
        $visitor->getCurrentNode()->appendChild(
            $node = $visitor->getDocument()->createElement('id', $type['params']['id'])
        );

        return $node;
    }
}

これらのクラスを使用するように Symfony を構成するには:

parameters:
    jms_serializer.doctrine_proxy_subscriber.class: MyApp\ApiBundle\Serializer\DoctrineProxySubscriber

services:
  doctrineproxy_handler:
    class: MyApp\ApiBundle\Serializer\DoctrineProxyHandler
    tags:
        - { name: jms_serializer.subscribing_handler }
于 2015-01-12T21:41:20.867 に答える
1

これは の長期的なバグだと思いますJMSSerializer。プロキシ/オブジェクトを生成するとき、Doctrineは実際にかなりまともな仕事をします。ある例では、プロキシからのオブジェクトのロードを無効にするために JMSSerializer ソースを編集しました。私はいつもそれが本当に面倒だと思っていました。

考えられる回避策 #1:NULLシリアル化の前に値を設定します。さらに使用するためにプロキシ参照を失います。はい、非常に醜いですが、仕事はします。

考えられる回避策 #2: 間違っているかもしれませんが、JMSSerializer の開発が行き詰まっているように感じます。プロジェクトを独自の GitHub にフォークし、フェッチを行う行を無効にして、代わりに独自のフォークを使用することができます。

于 2015-01-12T17:06:31.917 に答える