1<?php 2 3namespace Drupal\Tests\serialization\Unit\Normalizer; 4 5use Drupal\Core\Entity\EntityFieldManagerInterface; 6use Drupal\Core\Entity\EntityTypeManagerInterface; 7use Drupal\Core\Entity\EntityTypeRepositoryInterface; 8use Drupal\Core\Entity\FieldableEntityInterface; 9use Drupal\Core\Field\FieldItemListInterface; 10use Drupal\serialization\Normalizer\EntityNormalizer; 11use Drupal\Tests\UnitTestCase; 12use Symfony\Component\Serializer\Exception\UnexpectedValueException; 13 14/** 15 * @coversDefaultClass \Drupal\serialization\Normalizer\EntityNormalizer 16 * @group serialization 17 */ 18class EntityNormalizerTest extends UnitTestCase { 19 20 /** 21 * The mock entity field manager. 22 * 23 * @var \Drupal\Core\Entity\EntityFieldManagerInterface|\PHPUnit\Framework\MockObject\MockObject 24 */ 25 protected $entityFieldManager; 26 27 /** 28 * The mock entity type manager. 29 * 30 * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject 31 */ 32 protected $entityTypeManager; 33 34 /** 35 * The mock entity type repository. 36 * 37 * @var \Drupal\Core\Entity\EntityTypeRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject 38 */ 39 protected $entityTypeRepository; 40 41 /** 42 * The mock serializer. 43 * 44 * @var \Symfony\Component\Serializer\SerializerInterface|\PHPUnit\Framework\MockObject\MockObject 45 */ 46 protected $serializer; 47 48 /** 49 * The entity normalizer. 50 * 51 * @var \Drupal\serialization\Normalizer\EntityNormalizer 52 */ 53 protected $entityNormalizer; 54 55 /** 56 * {@inheritdoc} 57 */ 58 protected function setUp(): void { 59 $this->entityFieldManager = $this->createMock(EntityFieldManagerInterface::class); 60 $this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class); 61 $this->entityTypeRepository = $this->createMock(EntityTypeRepositoryInterface::class); 62 63 $this->entityNormalizer = new EntityNormalizer( 64 $this->entityTypeManager, 65 $this->entityTypeRepository, 66 $this->entityFieldManager 67 ); 68 } 69 70 /** 71 * Tests the normalize() method. 72 * 73 * @covers ::normalize 74 */ 75 public function testNormalize() { 76 $list_item_1 = $this->createMock('Drupal\Core\TypedData\TypedDataInterface'); 77 $list_item_2 = $this->createMock('Drupal\Core\TypedData\TypedDataInterface'); 78 79 $definitions = [ 80 'field_1' => $list_item_1, 81 'field_2' => $list_item_2, 82 ]; 83 84 $content_entity = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase') 85 ->disableOriginalConstructor() 86 ->onlyMethods(['getFields']) 87 ->getMockForAbstractClass(); 88 $content_entity->expects($this->once()) 89 ->method('getFields') 90 ->will($this->returnValue($definitions)); 91 92 $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer') 93 ->disableOriginalConstructor() 94 ->onlyMethods(['normalize']) 95 ->getMock(); 96 $serializer->expects($this->exactly(2)) 97 ->method('normalize') 98 ->withConsecutive( 99 [$list_item_1, 'test_format'], 100 [$list_item_2, 'test_format'], 101 ); 102 103 $this->entityNormalizer->setSerializer($serializer); 104 105 $this->entityNormalizer->normalize($content_entity, 'test_format'); 106 } 107 108 /** 109 * Tests the denormalize() method with no entity type provided in context. 110 * 111 * @covers ::denormalize 112 */ 113 public function testDenormalizeWithNoEntityType() { 114 $this->expectException(UnexpectedValueException::class); 115 $this->entityNormalizer->denormalize([], 'Drupal\Core\Entity\ContentEntityBase'); 116 } 117 118 /** 119 * Tests the denormalize method with a bundle property. 120 * 121 * @covers ::denormalize 122 */ 123 public function testDenormalizeWithValidBundle() { 124 $test_data = [ 125 'key_1' => 'value_1', 126 'key_2' => 'value_2', 127 'test_type' => [ 128 ['name' => 'test_bundle'], 129 ], 130 ]; 131 132 $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface'); 133 134 $entity_type->expects($this->once()) 135 ->method('id') 136 ->willReturn('test'); 137 $entity_type->expects($this->once()) 138 ->method('hasKey') 139 ->with('bundle') 140 ->will($this->returnValue(TRUE)); 141 $entity_type->expects($this->once()) 142 ->method('getKey') 143 ->with('bundle') 144 ->will($this->returnValue('test_type')); 145 $entity_type->expects($this->once()) 146 ->method('entityClassImplements') 147 ->with(FieldableEntityInterface::class) 148 ->willReturn(TRUE); 149 150 $entity_type->expects($this->once()) 151 ->method('getBundleEntityType') 152 ->will($this->returnValue('test_bundle')); 153 154 $entity_type_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface'); 155 $entity_type_storage_definition->expects($this->once()) 156 ->method('getMainPropertyName') 157 ->will($this->returnValue('name')); 158 159 $entity_type_definition = $this->createMock('Drupal\Core\Field\FieldDefinitionInterface'); 160 $entity_type_definition->expects($this->once()) 161 ->method('getFieldStorageDefinition') 162 ->will($this->returnValue($entity_type_storage_definition)); 163 164 $base_definitions = [ 165 'test_type' => $entity_type_definition, 166 ]; 167 168 $this->entityTypeManager->expects($this->once()) 169 ->method('getDefinition') 170 ->with('test') 171 ->will($this->returnValue($entity_type)); 172 $this->entityFieldManager->expects($this->once()) 173 ->method('getBaseFieldDefinitions') 174 ->with('test') 175 ->will($this->returnValue($base_definitions)); 176 177 $entity_query_mock = $this->createMock('Drupal\Core\Entity\Query\QueryInterface'); 178 $entity_query_mock->expects($this->once()) 179 ->method('execute') 180 ->will($this->returnValue(['test_bundle' => 'test_bundle'])); 181 182 $entity_type_storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface'); 183 $entity_type_storage->expects($this->once()) 184 ->method('getQuery') 185 ->will($this->returnValue($entity_query_mock)); 186 187 $key_1 = $this->createMock(FieldItemListInterface::class); 188 $key_2 = $this->createMock(FieldItemListInterface::class); 189 190 $entity = $this->createMock(FieldableEntityInterface::class); 191 $entity->expects($this->exactly(2)) 192 ->method('get') 193 ->willReturnMap([ 194 ['key_1', $key_1], 195 ['key_2', $key_2], 196 ]); 197 198 $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface'); 199 // Create should only be called with the bundle property at first. 200 $expected_test_data = [ 201 'test_type' => 'test_bundle', 202 ]; 203 204 $storage->expects($this->once()) 205 ->method('create') 206 ->with($expected_test_data) 207 ->will($this->returnValue($entity)); 208 209 $this->entityTypeManager->expects($this->exactly(2)) 210 ->method('getStorage') 211 ->willReturnMap([ 212 ['test_bundle', $entity_type_storage], 213 ['test', $storage], 214 ]); 215 216 // Setup expectations for the serializer. This will be called for each field 217 // item. 218 $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer') 219 ->disableOriginalConstructor() 220 ->onlyMethods(['denormalize']) 221 ->getMock(); 222 $serializer->expects($this->exactly(2)) 223 ->method('denormalize') 224 ->withConsecutive( 225 ['value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']], 226 ['value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']], 227 ); 228 229 $this->entityNormalizer->setSerializer($serializer); 230 231 $this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test'])); 232 } 233 234 /** 235 * Tests the denormalize method with a bundle property. 236 * 237 * @covers ::denormalize 238 */ 239 public function testDenormalizeWithInvalidBundle() { 240 $test_data = [ 241 'key_1' => 'value_1', 242 'key_2' => 'value_2', 243 'test_type' => [ 244 ['name' => 'test_bundle'], 245 ], 246 ]; 247 248 $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface'); 249 250 $entity_type->expects($this->once()) 251 ->method('id') 252 ->willReturn('test'); 253 $entity_type->expects($this->once()) 254 ->method('hasKey') 255 ->with('bundle') 256 ->will($this->returnValue(TRUE)); 257 $entity_type->expects($this->once()) 258 ->method('getKey') 259 ->with('bundle') 260 ->will($this->returnValue('test_type')); 261 $entity_type->expects($this->once()) 262 ->method('entityClassImplements') 263 ->with(FieldableEntityInterface::class) 264 ->willReturn(TRUE); 265 266 $entity_type->expects($this->once()) 267 ->method('getBundleEntityType') 268 ->will($this->returnValue('test_bundle')); 269 270 $entity_type_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface'); 271 $entity_type_storage_definition->expects($this->once()) 272 ->method('getMainPropertyName') 273 ->will($this->returnValue('name')); 274 275 $entity_type_definition = $this->createMock('Drupal\Core\Field\FieldDefinitionInterface'); 276 $entity_type_definition->expects($this->once()) 277 ->method('getFieldStorageDefinition') 278 ->will($this->returnValue($entity_type_storage_definition)); 279 280 $base_definitions = [ 281 'test_type' => $entity_type_definition, 282 ]; 283 284 $this->entityTypeManager->expects($this->once()) 285 ->method('getDefinition') 286 ->with('test') 287 ->will($this->returnValue($entity_type)); 288 $this->entityFieldManager->expects($this->once()) 289 ->method('getBaseFieldDefinitions') 290 ->with('test') 291 ->will($this->returnValue($base_definitions)); 292 293 $entity_query_mock = $this->createMock('Drupal\Core\Entity\Query\QueryInterface'); 294 $entity_query_mock->expects($this->once()) 295 ->method('execute') 296 ->will($this->returnValue(['test_bundle_other' => 'test_bundle_other'])); 297 298 $entity_type_storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface'); 299 $entity_type_storage->expects($this->once()) 300 ->method('getQuery') 301 ->will($this->returnValue($entity_query_mock)); 302 303 $this->entityTypeManager->expects($this->once()) 304 ->method('getStorage') 305 ->with('test_bundle') 306 ->will($this->returnValue($entity_type_storage)); 307 308 $this->expectException(UnexpectedValueException::class); 309 $this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test']); 310 } 311 312 /** 313 * Tests the denormalize method with no bundle defined. 314 * 315 * @covers ::denormalize 316 */ 317 public function testDenormalizeWithNoBundle() { 318 $test_data = [ 319 'key_1' => 'value_1', 320 'key_2' => 'value_2', 321 ]; 322 323 $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface'); 324 $entity_type->expects($this->once()) 325 ->method('entityClassImplements') 326 ->with(FieldableEntityInterface::class) 327 ->willReturn(TRUE); 328 $entity_type->expects($this->once()) 329 ->method('hasKey') 330 ->with('bundle') 331 ->will($this->returnValue(FALSE)); 332 $entity_type->expects($this->never()) 333 ->method('getKey'); 334 335 $this->entityTypeManager->expects($this->once()) 336 ->method('getDefinition') 337 ->with('test') 338 ->will($this->returnValue($entity_type)); 339 340 $key_1 = $this->createMock(FieldItemListInterface::class); 341 $key_2 = $this->createMock(FieldItemListInterface::class); 342 343 $entity = $this->createMock(FieldableEntityInterface::class); 344 $entity->expects($this->exactly(2)) 345 ->method('get') 346 ->willReturnMap([ 347 ['key_1', $key_1], 348 ['key_2', $key_2], 349 ]); 350 351 $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface'); 352 $storage->expects($this->once()) 353 ->method('create') 354 ->with([]) 355 ->will($this->returnValue($entity)); 356 357 $this->entityTypeManager->expects($this->once()) 358 ->method('getStorage') 359 ->with('test') 360 ->will($this->returnValue($storage)); 361 362 $this->entityFieldManager->expects($this->never()) 363 ->method('getBaseFieldDefinitions'); 364 365 // Setup expectations for the serializer. This will be called for each field 366 // item. 367 $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer') 368 ->disableOriginalConstructor() 369 ->onlyMethods(['denormalize']) 370 ->getMock(); 371 $serializer->expects($this->exactly(2)) 372 ->method('denormalize') 373 ->withConsecutive( 374 ['value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']], 375 ['value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']], 376 ); 377 378 $this->entityNormalizer->setSerializer($serializer); 379 380 $this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test'])); 381 } 382 383 /** 384 * Tests the denormalize method with no bundle defined. 385 * 386 * @covers ::denormalize 387 */ 388 public function testDenormalizeWithNoFieldableEntityType() { 389 $test_data = [ 390 'key_1' => 'value_1', 391 'key_2' => 'value_2', 392 ]; 393 394 $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface'); 395 $entity_type->expects($this->once()) 396 ->method('entityClassImplements') 397 ->with(FieldableEntityInterface::class) 398 ->willReturn(FALSE); 399 400 $entity_type->expects($this->never()) 401 ->method('getKey'); 402 403 $this->entityTypeManager->expects($this->once()) 404 ->method('getDefinition') 405 ->with('test') 406 ->will($this->returnValue($entity_type)); 407 408 $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface'); 409 $storage->expects($this->once()) 410 ->method('create') 411 ->with($test_data) 412 ->will($this->returnValue($this->createMock('Drupal\Core\Entity\EntityInterface'))); 413 414 $this->entityTypeManager->expects($this->once()) 415 ->method('getStorage') 416 ->with('test') 417 ->will($this->returnValue($storage)); 418 419 $this->entityFieldManager->expects($this->never()) 420 ->method('getBaseFieldDefinitions'); 421 422 $this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test'])); 423 } 424 425} 426