Browse Source

adds disjunct exclusion strategy (closes #44)

Johannes M. Schmitt 12 years ago
parent
commit
f361cfa287

+ 1 - 0
CHANGELOG.md

@@ -7,6 +7,7 @@ For instructions on how to upgrade from one version to another, please see the d
 - adds, and exposes SerializationContext/DeserializationContext
 - adds built-in support for deserialization of polymorphic objects when they have a common base class
 - adds serializer.pre_deserialize event
+- adds a disjunct exclusion strategy
 
 0.11 (2013-01-29)
 -----------------

+ 65 - 0
src/JMS/Serializer/Exclusion/DisjunctExclusionStrategy.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace JMS\Serializer\Exclusion;
+
+use JMS\Serializer\Context;
+use JMS\Serializer\Metadata\ClassMetadata;
+use JMS\Serializer\Metadata\PropertyMetadata;
+
+/**
+ * Disjunct Exclusion Strategy.
+ *
+ * This strategy is short-circuiting and will skip a class, or property as soon as one of the delegates skips it.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class DisjunctExclusionStrategy implements ExclusionStrategyInterface
+{
+    private $delegates;
+
+    /**
+     * @param ExclusionStrategyInterface[] $delegates
+     */
+    public function __construct(array $delegates)
+    {
+        $this->delegates = $delegates;
+    }
+
+    /**
+     * Whether the class should be skipped.
+     *
+     * @param ClassMetadata $metadata
+     * @param Context $navigatorContext
+     *
+     * @return boolean
+     */
+    public function shouldSkipClass(ClassMetadata $metadata, Context $context)
+    {
+        foreach ($this->delegates as $delegate) {
+            if ($delegate->shouldSkipClass($metadata, $context)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Whether the property should be skipped.
+     *
+     * @param PropertyMetadata $property
+     * @param Context $navigatorContext
+     *
+     * @return boolean
+     */
+    public function shouldSkipProperty(PropertyMetadata $property, Context $context)
+    {
+        foreach ($this->delegates as $delegate) {
+            if ($delegate->shouldSkipProperty($property, $context)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}

+ 2 - 2
src/JMS/Serializer/Exclusion/ExclusionStrategyInterface.php

@@ -37,7 +37,7 @@ interface ExclusionStrategyInterface
      *
      * @return boolean
      */
-    public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext);
+    public function shouldSkipClass(ClassMetadata $metadata, Context $context);
 
     /**
      * Whether the property should be skipped.
@@ -47,5 +47,5 @@ interface ExclusionStrategyInterface
      *
      * @return boolean
      */
-    public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext);
+    public function shouldSkipProperty(PropertyMetadata $property, Context $context);
 }

+ 147 - 0
tests/JMS/Serializer/Tests/Exclusion/DisjunctExclusionStrategyTest.php

@@ -0,0 +1,147 @@
+<?php
+
+namespace JMS\Serializer\Tests\Exclusion;
+
+use JMS\Serializer\Exclusion\DisjunctExclusionStrategy;
+use JMS\Serializer\Metadata\ClassMetadata;
+use JMS\Serializer\Metadata\PropertyMetadata;
+use JMS\Serializer\Metadata\StaticPropertyMetadata;
+use JMS\Serializer\SerializationContext;
+
+class DisjunctExclusionStrategyTest extends \PHPUnit_Framework_TestCase
+{
+    public function testShouldSkipClassShortCircuiting()
+    {
+        $metadata = new ClassMetadata('stdClass');
+        $context = SerializationContext::create();
+
+        $strat = new DisjunctExclusionStrategy(array(
+            $first = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+            $last = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+        ));
+
+        $first->expects($this->once())
+            ->method('shouldSkipClass')
+            ->with($metadata, $context)
+            ->will($this->returnValue(true));
+
+        $last->expects($this->never())
+            ->method('shouldSkipClass');
+
+        $this->assertTrue($strat->shouldSkipClass($metadata, $context));
+    }
+
+    public function testShouldSkipClassDisjunctBehavior()
+    {
+        $metadata = new ClassMetadata('stdClass');
+        $context = SerializationContext::create();
+
+        $strat = new DisjunctExclusionStrategy(array(
+            $first = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+            $last = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+        ));
+
+        $first->expects($this->once())
+            ->method('shouldSkipClass')
+            ->with($metadata, $context)
+            ->will($this->returnValue(false));
+
+        $last->expects($this->once())
+            ->method('shouldSkipClass')
+            ->with($metadata, $context)
+            ->will($this->returnValue(true));
+
+        $this->assertTrue($strat->shouldSkipClass($metadata, $context));
+    }
+
+    public function testShouldSkipClassReturnsFalseIfNoPredicateMatched()
+    {
+        $metadata = new ClassMetadata('stdClass');
+        $context = SerializationContext::create();
+
+        $strat = new DisjunctExclusionStrategy(array(
+            $first = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+            $last = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+        ));
+
+        $first->expects($this->once())
+            ->method('shouldSkipClass')
+            ->with($metadata, $context)
+            ->will($this->returnValue(false));
+
+        $last->expects($this->once())
+            ->method('shouldSkipClass')
+            ->with($metadata, $context)
+            ->will($this->returnValue(false));
+
+        $this->assertFalse($strat->shouldSkipClass($metadata, $context));
+    }
+
+    public function testShouldSkipPropertyShortCircuiting()
+    {
+        $metadata = new StaticPropertyMetadata('stdClass', 'foo', 'bar');
+        $context = SerializationContext::create();
+
+        $strat = new DisjunctExclusionStrategy(array(
+            $first = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+            $last = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+        ));
+
+        $first->expects($this->once())
+            ->method('shouldSkipProperty')
+            ->with($metadata, $context)
+            ->will($this->returnValue(true));
+
+        $last->expects($this->never())
+            ->method('shouldSkipProperty');
+
+        $this->assertTrue($strat->shouldSkipProperty($metadata, $context));
+    }
+
+    public function testShouldSkipPropertyDisjunct()
+    {
+        $metadata = new StaticPropertyMetadata('stdClass', 'foo', 'bar');
+        $context = SerializationContext::create();
+
+        $strat = new DisjunctExclusionStrategy(array(
+            $first = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+            $last = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+        ));
+
+        $first->expects($this->once())
+            ->method('shouldSkipProperty')
+            ->with($metadata, $context)
+            ->will($this->returnValue(false));
+
+        $last->expects($this->once())
+            ->method('shouldSkipProperty')
+            ->with($metadata, $context)
+            ->will($this->returnValue(true));
+
+        $this->assertTrue($strat->shouldSkipProperty($metadata, $context));
+    }
+
+
+    public function testShouldSkipPropertyReturnsFalseIfNoPredicateMatches()
+    {
+        $metadata = new StaticPropertyMetadata('stdClass', 'foo', 'bar');
+        $context = SerializationContext::create();
+
+        $strat = new DisjunctExclusionStrategy(array(
+            $first = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+            $last = $this->getMock('JMS\Serializer\Exclusion\ExclusionStrategyInterface'),
+        ));
+
+        $first->expects($this->once())
+            ->method('shouldSkipProperty')
+            ->with($metadata, $context)
+            ->will($this->returnValue(false));
+
+        $last->expects($this->once())
+            ->method('shouldSkipProperty')
+            ->with($metadata, $context)
+            ->will($this->returnValue(false));
+
+        $this->assertFalse($strat->shouldSkipProperty($metadata, $context));
+    }
+}