1<?php 2 3declare(strict_types=1); 4 5namespace JMS\Serializer\Tests\Serializer; 6 7use JMS\Serializer\Metadata\ClassMetadata; 8use JMS\Serializer\Metadata\PropertyMetadata; 9use JMS\Serializer\SerializationContext; 10use JMS\Serializer\SerializerBuilder; 11use JMS\Serializer\Tests\Fixtures\Author; 12use JMS\Serializer\Tests\Fixtures\BlogPost; 13use JMS\Serializer\Tests\Fixtures\InlineChild; 14use JMS\Serializer\Tests\Fixtures\Node; 15use JMS\Serializer\Tests\Fixtures\Publisher; 16use JMS\Serializer\Tests\Fixtures\VersionedObject; 17use PHPUnit\Framework\TestCase; 18 19class ContextTest extends TestCase 20{ 21 public function testSerializationContextPathAndDepth() 22 { 23 $object = new Node([ 24 new Node(), 25 new Node([new Node()]), 26 ]); 27 $objects = [$object, $object->children[0], $object->children[1], $object->children[1]->children[0]]; 28 29 $self = $this; 30 31 $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); 32 $exclusionStrategy->expects($this->any()) 33 ->method('shouldSkipClass') 34 ->with($this->anything(), $this->callback(static function (SerializationContext $context) use ($self, $objects) { 35 $expectedDepth = $expectedPath = null; 36 37 if ($context->getObject() === $objects[0]) { 38 $expectedDepth = 1; 39 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node'; 40 } elseif ($context->getObject() === $objects[1]) { 41 $expectedDepth = 2; 42 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; 43 } elseif ($context->getObject() === $objects[2]) { 44 $expectedDepth = 2; 45 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; 46 } elseif ($context->getObject() === $objects[3]) { 47 $expectedDepth = 3; 48 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; 49 } 50 51 $self->assertEquals($expectedDepth, $context->getDepth(), 'shouldSkipClass depth'); 52 $self->assertEquals($expectedPath, $context->getPath(), 'shouldSkipClass path'); 53 54 return true; 55 })) 56 ->will($this->returnValue(false)); 57 58 $exclusionStrategy->expects($this->any()) 59 ->method('shouldSkipProperty') 60 ->with($this->anything(), $this->callback(static function (SerializationContext $context) use ($self, $objects) { 61 $expectedDepth = $expectedPath = null; 62 63 if ($context->getObject() === $objects[0]) { 64 $expectedDepth = 1; 65 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node'; 66 } elseif ($context->getObject() === $objects[1]) { 67 $expectedDepth = 2; 68 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; 69 } elseif ($context->getObject() === $objects[2]) { 70 $expectedDepth = 2; 71 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; 72 } elseif ($context->getObject() === $objects[3]) { 73 $expectedDepth = 3; 74 $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; 75 } 76 77 $self->assertEquals($expectedDepth, $context->getDepth(), 'shouldSkipProperty depth'); 78 $self->assertEquals($expectedPath, $context->getPath(), 'shouldSkipProperty path'); 79 80 return true; 81 })) 82 ->will($this->returnValue(false)); 83 84 $serializer = SerializerBuilder::create()->build(); 85 86 $serializer->serialize($object, 'json', SerializationContext::create()->addExclusionStrategy($exclusionStrategy)); 87 } 88 89 public function testSerializationMetadataStack() 90 { 91 $object = new Node([ 92 $child = new InlineChild(), 93 ]); 94 $self = $this; 95 96 $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); 97 $exclusionStrategy->expects($this->any()) 98 ->method('shouldSkipClass') 99 ->will($this->returnCallback(static function (ClassMetadata $classMetadata, SerializationContext $context) use ($self, $object, $child) { 100 $stack = $context->getMetadataStack(); 101 102 if ($object === $context->getObject()) { 103 $self->assertEquals(0, $stack->count()); 104 } 105 106 if ($child === $context->getObject()) { 107 $self->assertEquals(2, $stack->count()); 108 $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[1]->name); 109 $self->assertEquals('children', $stack[0]->name); 110 } 111 112 return false; 113 })); 114 115 $exclusionStrategy->expects($this->any()) 116 ->method('shouldSkipProperty') 117 ->will($this->returnCallback(static function (PropertyMetadata $propertyMetadata, SerializationContext $context) use ($self) { 118 $stack = $context->getMetadataStack(); 119 120 if ('JMS\Serializer\Tests\Fixtures\Node' === $propertyMetadata->class && 'children' === $propertyMetadata->name) { 121 $self->assertEquals(1, $stack->count()); 122 $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[0]->name); 123 } 124 125 if ('JMS\Serializer\Tests\Fixtures\InlineChild' === $propertyMetadata->class) { 126 $self->assertEquals(3, $stack->count()); 127 $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[2]->name); 128 $self->assertEquals('children', $stack[1]->name); 129 $self->assertEquals('JMS\Serializer\Tests\Fixtures\InlineChild', $stack[0]->name); 130 } 131 132 return false; 133 })); 134 135 $serializer = SerializerBuilder::create()->build(); 136 $serializer->serialize($object, 'json', SerializationContext::create()->addExclusionStrategy($exclusionStrategy)); 137 } 138 139 public function getScalars() 140 { 141 return [ 142 ['string'], 143 [5], 144 [5.5], 145 [[]], 146 ]; 147 } 148 149 /** 150 * @dataProvider getScalars 151 */ 152 public function testCanVisitScalars($scalar) 153 { 154 $context = SerializationContext::create(); 155 156 $context->startVisiting($scalar); 157 self::assertFalse($context->isVisiting($scalar)); 158 $context->stopVisiting($scalar); 159 } 160 161 public function testInitialTypeCompatibility() 162 { 163 $context = SerializationContext::create(); 164 $context->setInitialType('foo'); 165 self::assertEquals('foo', $context->getInitialType()); 166 self::assertEquals('foo', $context->getAttribute('initial_type')); 167 168 $context = SerializationContext::create(); 169 $context->setAttribute('initial_type', 'foo'); 170 self::assertEquals('foo', $context->getInitialType()); 171 } 172 173 public function testMultipleCallsOnGroupsDoNotCreateMultipleExclusionStrategies() 174 { 175 $serializer = SerializerBuilder::create()->build(); 176 177 $context = SerializationContext::create(); 178 $context->setGroups(['foo', 'Default']); 179 $context->setGroups('post'); 180 181 $object = new BlogPost('serializer', new Author('me'), new \DateTime(), new Publisher('php')); 182 $serialized = $serializer->serialize($object, 'json', $context); 183 184 $data = json_decode($serialized, true); 185 186 self::assertArrayHasKey('id', $data); 187 self::assertArrayNotHasKey('created_at', $data); 188 } 189 190 public function testMultipleCallsOnVersionDoNotCreateMultipleExclusionStrategies() 191 { 192 $serializer = SerializerBuilder::create()->build(); 193 194 $context = SerializationContext::create(); 195 $context->setVersion('1.0.1'); 196 $context->setVersion('1.0.0'); 197 198 $object = new VersionedObject('a', 'b'); 199 $serialized = $serializer->serialize($object, 'json', $context); 200 201 $data = json_decode($serialized, true); 202 203 self::assertEquals('a', $data['name']); 204 } 205 206 public function testSerializeNullOption() 207 { 208 $context = SerializationContext::create(); 209 self::assertFalse($context->shouldSerializeNull()); 210 211 $context->setSerializeNull(false); 212 self::assertFalse($context->shouldSerializeNull()); 213 214 $context->setSerializeNull(true); 215 self::assertTrue($context->shouldSerializeNull()); 216 } 217} 218