Kaynağa Gözat

merged branch vicb/validator/race_2.0 (PR #3587)

Commits
-------

93cc9ef [Validator] Remove a race condition in the ClassMetaDataFactory (fix #3217)

Discussion
----------

[Validator] Remove a race condition (fix #3217)

#3581 for 2.0
Fabien Potencier 13 yıl önce
ebeveyn
işleme
92c5785fe4

+ 1 - 1
src/Symfony/Component/Validator/Mapping/Cache/CacheInterface.php

@@ -32,7 +32,7 @@ interface CacheInterface
      *
      * @param string $class Class Name
      *
-     * @return ClassMetadata
+     * @return ClassMetadata|false A ClassMetadata instance or false on miss
      */
     function read($class);
 

+ 25 - 25
src/Symfony/Component/Validator/Mapping/ClassMetadataFactory.php

@@ -45,32 +45,32 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
     {
         $class = ltrim($class, '\\');
 
-        if (!isset($this->loadedClasses[$class])) {
-            if ($this->cache !== null && $this->cache->has($class)) {
-                $this->loadedClasses[$class] = $this->cache->read($class);
-            } else {
-                $metadata = new ClassMetadata($class);
-
-                // Include constraints from the parent class
-                if ($parent = $metadata->getReflectionClass()->getParentClass()) {
-                    $metadata->mergeConstraints($this->getClassMetadata($parent->getName()));
-                }
-
-                // Include constraints from all implemented interfaces
-                foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
-                    $metadata->mergeConstraints($this->getClassMetadata($interface->getName()));
-                }
-
-                $this->loader->loadClassMetadata($metadata);
-
-                $this->loadedClasses[$class] = $metadata;
-
-                if ($this->cache !== null) {
-                    $this->cache->write($metadata);
-                }
-            }
+        if (isset($this->loadedClasses[$class])) {
+            return $this->loadedClasses[$class];
         }
 
-        return $this->loadedClasses[$class];
+        if (null !== $this->cache && false !== ($this->loadedClasses[$class] = $this->cache->read($class))) {
+            return $this->loadedClasses[$class];
+        }
+
+        $metadata = new ClassMetadata($class);
+
+        // Include constraints from the parent class
+        if ($parent = $metadata->getReflectionClass()->getParentClass()) {
+            $metadata->mergeConstraints($this->getClassMetadata($parent->getName()));
+        }
+
+        // Include constraints from all implemented interfaces
+        foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
+            $metadata->mergeConstraints($this->getClassMetadata($interface->getName()));
+        }
+
+        $this->loader->loadClassMetadata($metadata);
+
+        if ($this->cache !== null) {
+            $this->cache->write($metadata);
+        }
+
+        return $this->loadedClasses[$class] = $metadata;
     }
 }

+ 5 - 5
tests/Symfony/Tests/Component/Validator/Mapping/ClassMetadataFactoryTest.php

@@ -74,8 +74,10 @@ class ClassMetadataFactoryTest extends \PHPUnit_Framework_TestCase
             new ConstraintA(array('groups' => array('Default', 'EntityParent'))),
         );
 
+        $cache->expects($this->never())
+              ->method('has');
         $cache->expects($this->once())
-              ->method('has')
+              ->method('read')
               ->with($this->equalTo(self::PARENTCLASS))
               ->will($this->returnValue(false));
         $cache->expects($this->once())
@@ -103,10 +105,8 @@ class ClassMetadataFactoryTest extends \PHPUnit_Framework_TestCase
         $loader->expects($this->never())
                ->method('loadClassMetadata');
 
-        $cache->expects($this->once())
-              ->method('has')
-              ->with($this->equalTo(self::PARENTCLASS))
-              ->will($this->returnValue(true));
+        $cache->expects($this->never())
+              ->method('has');
         $cache->expects($this->once())
               ->method('read')
               ->will($this->returnValue($metadata));