瀏覽代碼

Added Doctrine Object Constructor.

Guilherme Blanco 12 年之前
父節點
當前提交
6342ff64e7

+ 9 - 1
DependencyInjection/Configuration.php

@@ -46,6 +46,7 @@ class Configuration implements ConfigurationInterface
                 ->children()
         ;
 
+        $this->addConstructorSection($root);
         $this->addSerializersSection($root);
         $this->addMetadataSection($root);
         $this->addVisitorsSection($root);
@@ -53,6 +54,12 @@ class Configuration implements ConfigurationInterface
         return $tb;
     }
 
+    private function addConstructorSection(NodeBuilder $builder)
+    {
+        $builder
+            ->scalarNode('constructor')->defaultNull()->end();
+    }
+
     private function addSerializersSection(NodeBuilder $builder)
     {
         $builder
@@ -76,7 +83,8 @@ class Configuration implements ConfigurationInterface
 
         foreach ($this->factories as $factory) {
             $factory->addConfiguration(
-                $handlerNode->arrayNode($factory->getConfigKey())->canBeUnset());
+                $handlerNode->arrayNode($factory->getConfigKey())->canBeUnset()
+            );
         }
     }
 

+ 5 - 0
DependencyInjection/JMSSerializerExtension.php

@@ -41,6 +41,11 @@ class JMSSerializerExtension extends ConfigurableExtension
                         __DIR__.'/../Resources/config/')));
         $loader->load('services.xml');
 
+        // constructor
+        if ($config['constructor']) {
+            $container->setAlias('jms_serializer.object_constructor', $config['constructor']);
+        }
+
         // add factories as resource
         foreach ($this->factories as $factory) {
             $container->addObjectResource($factory);

+ 5 - 0
Resources/config/services.xml

@@ -20,6 +20,7 @@
         <parameter key="jms_serializer.serialized_name_annotation_strategy.class">JMS\SerializerBundle\Serializer\Naming\SerializedNameAnnotationStrategy</parameter>
         <parameter key="jms_serializer.cache_naming_strategy.class">JMS\SerializerBundle\Serializer\Naming\CacheNamingStrategy</parameter>
 
+        <parameter key="jms_serializer.doctrine_object_constructor.class">JMS\SerializerBundle\Serializer\Construction\DoctrineObjectConstructor</parameter>
         <parameter key="jms_serializer.unserialize_object_constructor.class">JMS\SerializerBundle\Serializer\Construction\UnserializeObjectConstructor</parameter>
 
         <parameter key="jms_serializer.version_exclusion_strategy.class">JMS\SerializerBundle\Serializer\Exclusion\VersionExclusionStrategy</parameter>
@@ -104,6 +105,10 @@
         <service id="jms_serializer.naming_strategy" alias="jms_serializer.serialized_name_annotation_strategy" public="false" />
 
         <!-- Object Constructors -->
+        <service id="jms_serializer.doctrine_object_constructor" class="%jms_serializer.doctrine_object_constructor.class%" public="false">
+            <argument type="service" id="doctrine"/>
+            <argument type="service" id="jms_serializer.unserialize_object_constructor"/>
+        </service>
         <service id="jms_serializer.unserialize_object_constructor" class="%jms_serializer.unserialize_object_constructor.class%" public="false" />
         <service id="jms_serializer.object_constructor" alias="jms_serializer.unserialize_object_constructor" public="false" />
 

+ 91 - 0
Serializer/Construction/DoctrineObjectConstructor.php

@@ -0,0 +1,91 @@
+<?php
+
+/*
+ * Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace JMS\SerializerBundle\Serializer\Construction;
+
+use Symfony\Bridge\Doctrine\ManagerRegistry;
+use JMS\SerializerBundle\Serializer\VisitorInterface;
+use JMS\SerializerBundle\Metadata\ClassMetadata;
+
+class DoctrineObjectConstructor implements ObjectConstructorInterface
+{
+    /**
+     * @var \Symfony\Bridge\Doctrine\ManagerRegistry
+     */
+    private $managerRegistry;
+
+    /**
+     * @var \JMS\SerializerBundle\Serializer\Construction\ObjectConstructorInterface
+     */
+    private $fallbackConstructor;
+
+    /**
+     * Constructor.
+     *
+     * @param \Symfony\Bridge\Doctrine\ManagerRegistry                                 $managerRegistry
+     * @param \JMS\SerializerBundle\Serializer\Construction\ObjectConstructorInterface $fallbackConstructor
+     */
+    public function __construct(ManagerRegistry $managerRegistry, ObjectConstructorInterface $fallbackConstructor)
+    {
+        $this->managerRegistry     = $managerRegistry;
+        $this->fallbackConstructor = $fallbackConstructor;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, $type)
+    {
+        // Locate possible ObjectManager
+        $objectManager = $this->managerRegistry->getManagerForClass($metadata->name);
+
+        if (!$objectManager) {
+            // No ObjectManager found, proceed with normal deserialization
+            return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type);
+        }
+
+        // Locate possible ClassMetadata
+        $classMetadataFactory = $objectManager->getMetadataFactory();
+
+        if ($classMetadataFactory->isTransient($metadata->name)) {
+            // No ClassMetadata found, proceed with normal deserialization
+            return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type);
+        }
+
+        // Managed entity, check for proxy load
+        if (!is_array($data)) {
+            // Single identifier, load proxy
+            return $objectManager->getReference($metadata->name, $data);
+        }
+
+        // Entity update, load it from database
+        $classMetadata         = $objectManager->getClassMetadata($metadata->name);
+        $identifierList        = $classMetadata->getIdentifierFieldNames();
+        $missingIdentifierList = array_filter(
+            $identifierList,
+            function ($identifier) use ($data)
+            {
+                return !isset($data[$identifier]);
+            }
+        );
+
+        return (!$missingIdentifierList)
+            ? $objectManager->find($metadata->name, $data)
+            : $this->fallbackConstructor->construct($visitor, $metadata, $data, $type);
+    }
+}

+ 1 - 0
composer.json

@@ -19,6 +19,7 @@
         "symfony/framework-bundle": "<2.1-dev"
     },
     "require-dev": {
+        "symfony/doctrine-bridge": ">=2.1,<2.2-dev",
         "symfony/framework-bundle": ">=2.1,<2.2-dev",
         "symfony/yaml": ">=2.1,<2.3-dev",
         "symfony/form": ">=2.1,<2.3-dev",