1<?php 2 3namespace Drupal\Tests\Core\Config\Entity; 4 5use Drupal\Component\Uuid\UuidInterface; 6use Drupal\Core\Cache\Cache; 7use Drupal\Core\Cache\CacheTagsInvalidatorInterface; 8use Drupal\Core\Cache\MemoryCache\MemoryCache; 9use Drupal\Core\Config\Config; 10use Drupal\Core\Config\ConfigDuplicateUUIDException; 11use Drupal\Core\Config\ConfigFactoryInterface; 12use Drupal\Core\Config\ConfigManagerInterface; 13use Drupal\Core\Config\Entity\ConfigEntityBase; 14use Drupal\Core\Config\Entity\ConfigEntityInterface; 15use Drupal\Core\Config\Entity\ConfigEntityStorage; 16use Drupal\Core\Config\Entity\ConfigEntityType; 17use Drupal\Core\Config\ImmutableConfig; 18use Drupal\Core\Config\TypedConfigManagerInterface; 19use Drupal\Core\Entity\EntityInterface; 20use Drupal\Core\Entity\EntityMalformedException; 21use Drupal\Core\Entity\EntityStorageException; 22use Drupal\Core\Entity\EntityTypeManagerInterface; 23use Drupal\Core\Entity\Query\QueryFactoryInterface; 24use Drupal\Core\Entity\Query\QueryInterface; 25use Drupal\Core\Extension\ModuleHandlerInterface; 26use Drupal\Core\Language\Language; 27use Drupal\Core\Language\LanguageManagerInterface; 28use Drupal\Tests\UnitTestCase; 29use Prophecy\Argument; 30use Symfony\Component\DependencyInjection\ContainerBuilder; 31 32/** 33 * @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityStorage 34 * @group Config 35 */ 36class ConfigEntityStorageTest extends UnitTestCase { 37 38 /** 39 * The type ID of the entity under test. 40 * 41 * @var string 42 */ 43 protected $entityTypeId; 44 45 /** 46 * The module handler. 47 * 48 * @var \Drupal\Core\Extension\ModuleHandlerInterface|\Prophecy\Prophecy\ProphecyInterface 49 */ 50 protected $moduleHandler; 51 52 /** 53 * The UUID service. 54 * 55 * @var \Drupal\Component\Uuid\UuidInterface|\Prophecy\Prophecy\ProphecyInterface 56 */ 57 protected $uuidService; 58 59 /** 60 * The language manager. 61 * 62 * @var \Drupal\Core\Language\LanguageManagerInterface|\Prophecy\Prophecy\ProphecyInterface 63 */ 64 protected $languageManager; 65 66 /** 67 * The config storage. 68 * 69 * @var \Drupal\Core\Config\Entity\ConfigEntityStorage 70 */ 71 protected $entityStorage; 72 73 /** 74 * The config factory service. 75 * 76 * @var \Drupal\Core\Config\ConfigFactoryInterface|\Prophecy\Prophecy\ProphecyInterface 77 */ 78 protected $configFactory; 79 80 /** 81 * The entity query. 82 * 83 * @var \Drupal\Core\Entity\Query\QueryInterface|\Prophecy\Prophecy\ProphecyInterface 84 */ 85 protected $entityQuery; 86 87 /** 88 * The mocked cache backend. 89 * 90 * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\Prophecy\Prophecy\ProphecyInterface 91 */ 92 protected $cacheTagsInvalidator; 93 94 /** 95 * The configuration manager. 96 * 97 * @var \Drupal\Core\Config\ConfigManagerInterface|\Prophecy\Prophecy\ProphecyInterface 98 */ 99 protected $configManager; 100 101 /** 102 * {@inheritdoc} 103 * 104 * @covers ::__construct 105 */ 106 protected function setUp(): void { 107 parent::setUp(); 108 109 $this->entityTypeId = 'test_entity_type'; 110 111 $entity_type = new ConfigEntityType([ 112 'id' => $this->entityTypeId, 113 'class' => get_class($this->getMockEntity()), 114 'provider' => 'the_provider', 115 'config_prefix' => 'the_config_prefix', 116 'entity_keys' => [ 117 'id' => 'id', 118 'uuid' => 'uuid', 119 'langcode' => 'langcode', 120 ], 121 'config_export' => [ 122 'id', 123 ], 124 'list_cache_tags' => [$this->entityTypeId . '_list'], 125 ]); 126 127 $this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class); 128 129 $this->uuidService = $this->prophesize(UuidInterface::class); 130 131 $this->languageManager = $this->prophesize(LanguageManagerInterface::class); 132 $this->languageManager->getCurrentLanguage()->willReturn(new Language(['id' => 'hu'])); 133 134 $this->configFactory = $this->prophesize(ConfigFactoryInterface::class); 135 136 $this->entityQuery = $this->prophesize(QueryInterface::class); 137 $entity_query_factory = $this->prophesize(QueryFactoryInterface::class); 138 $entity_query_factory->get($entity_type, 'AND')->willReturn($this->entityQuery->reveal()); 139 140 $this->entityStorage = new ConfigEntityStorage($entity_type, $this->configFactory->reveal(), $this->uuidService->reveal(), $this->languageManager->reveal(), new MemoryCache()); 141 $this->entityStorage->setModuleHandler($this->moduleHandler->reveal()); 142 143 $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class); 144 $entity_type_manager->getDefinition('test_entity_type')->willReturn($entity_type); 145 146 $this->cacheTagsInvalidator = $this->prophesize(CacheTagsInvalidatorInterface::class); 147 148 $typed_config_manager = $this->prophesize(TypedConfigManagerInterface::class); 149 $typed_config_manager 150 ->getDefinition(Argument::containingString('the_provider.the_config_prefix.')) 151 ->willReturn(['mapping' => ['id' => '', 'uuid' => '', 'dependencies' => '']]); 152 153 $this->configManager = $this->prophesize(ConfigManagerInterface::class); 154 155 $container = new ContainerBuilder(); 156 $container->set('entity_type.manager', $entity_type_manager->reveal()); 157 $container->set('entity.query.config', $entity_query_factory->reveal()); 158 $container->set('config.typed', $typed_config_manager->reveal()); 159 $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator->reveal()); 160 $container->set('config.manager', $this->configManager->reveal()); 161 $container->set('language_manager', $this->languageManager->reveal()); 162 \Drupal::setContainer($container); 163 164 } 165 166 /** 167 * @covers ::create 168 * @covers ::doCreate 169 */ 170 public function testCreateWithPredefinedUuid() { 171 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera())->shouldNotBeCalled(); 172 173 $entity = $this->getMockEntity(); 174 $entity->set('id', 'foo'); 175 $entity->set('langcode', 'hu'); 176 $entity->set('uuid', 'baz'); 177 $entity->setOriginalId('foo'); 178 $entity->enforceIsNew(); 179 180 $this->moduleHandler->invokeAll('test_entity_type_create', [$entity]) 181 ->shouldBeCalled(); 182 $this->moduleHandler->invokeAll('entity_create', [$entity, 'test_entity_type']) 183 ->shouldBeCalled(); 184 185 $this->uuidService->generate()->shouldNotBeCalled(); 186 187 $entity = $this->entityStorage->create(['id' => 'foo', 'uuid' => 'baz']); 188 $this->assertInstanceOf(EntityInterface::class, $entity); 189 $this->assertSame('foo', $entity->id()); 190 $this->assertSame('baz', $entity->uuid()); 191 } 192 193 /** 194 * @covers ::create 195 * @covers ::doCreate 196 * 197 * @return \Drupal\Core\Entity\EntityInterface 198 */ 199 public function testCreate() { 200 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera())->shouldNotBeCalled(); 201 202 $entity = $this->getMockEntity(); 203 $entity->set('id', 'foo'); 204 $entity->set('langcode', 'hu'); 205 $entity->set('uuid', 'bar'); 206 $entity->setOriginalId('foo'); 207 $entity->enforceIsNew(); 208 209 $this->moduleHandler->invokeAll('test_entity_type_create', [$entity]) 210 ->shouldBeCalled(); 211 $this->moduleHandler->invokeAll('entity_create', [$entity, 'test_entity_type']) 212 ->shouldBeCalled(); 213 214 $this->uuidService->generate()->willReturn('bar'); 215 216 $entity = $this->entityStorage->create(['id' => 'foo']); 217 $this->assertInstanceOf(EntityInterface::class, $entity); 218 $this->assertSame('foo', $entity->id()); 219 $this->assertSame('bar', $entity->uuid()); 220 return $entity; 221 } 222 223 /** 224 * @covers ::create 225 * @covers ::doCreate 226 */ 227 public function testCreateWithCurrentLanguage() { 228 $this->languageManager->getLanguage('hu')->willReturn(new Language(['id' => 'hu'])); 229 230 $entity = $this->entityStorage->create(['id' => 'foo']); 231 $this->assertSame('hu', $entity->language()->getId()); 232 } 233 234 /** 235 * @covers ::create 236 * @covers ::doCreate 237 */ 238 public function testCreateWithExplicitLanguage() { 239 $this->languageManager->getLanguage('en')->willReturn(new Language(['id' => 'en'])); 240 241 $entity = $this->entityStorage->create(['id' => 'foo', 'langcode' => 'en']); 242 $this->assertSame('en', $entity->language()->getId()); 243 } 244 245 /** 246 * @covers ::save 247 * @covers ::doSave 248 * 249 * @param \Drupal\Core\Entity\EntityInterface $entity 250 * 251 * @return \Drupal\Core\Entity\EntityInterface 252 * 253 * @depends testCreate 254 */ 255 public function testSaveInsert(EntityInterface $entity) { 256 $immutable_config_object = $this->prophesize(ImmutableConfig::class); 257 $immutable_config_object->isNew()->willReturn(TRUE); 258 259 $config_object = $this->prophesize(Config::class); 260 $config_object 261 ->setData([ 262 'id' => 'foo', 263 'uuid' => 'bar', 264 'dependencies' => [], 265 'langcode' => 'hu', 266 'status' => TRUE, 267 ]) 268 ->shouldBeCalled(); 269 $config_object->save(FALSE)->shouldBeCalled(); 270 $config_object->get()->willReturn([]); 271 272 $this->cacheTagsInvalidator->invalidateTags([$this->entityTypeId . '_list']) 273 ->shouldBeCalled(); 274 275 $this->configFactory->get('the_provider.the_config_prefix.foo') 276 ->willReturn($immutable_config_object->reveal()); 277 $this->configFactory->getEditable('the_provider.the_config_prefix.foo') 278 ->willReturn($config_object->reveal()); 279 280 $this->moduleHandler->invokeAll('test_entity_type_presave', [$entity]) 281 ->shouldBeCalled(); 282 $this->moduleHandler->invokeAll('entity_presave', [$entity, 'test_entity_type']) 283 ->shouldBeCalled(); 284 $this->moduleHandler->invokeAll('test_entity_type_insert', [$entity]) 285 ->shouldBeCalled(); 286 $this->moduleHandler->invokeAll('entity_insert', [$entity, 'test_entity_type']) 287 ->shouldBeCalled(); 288 289 $this->entityQuery->condition('uuid', 'bar')->willReturn($this->entityQuery); 290 $this->entityQuery->execute()->willReturn([]); 291 292 $return = $this->entityStorage->save($entity); 293 $this->assertSame(SAVED_NEW, $return); 294 return $entity; 295 } 296 297 /** 298 * @covers ::save 299 * @covers ::doSave 300 * 301 * @param \Drupal\Core\Entity\EntityInterface $entity 302 * 303 * @return \Drupal\Core\Entity\EntityInterface 304 * 305 * @depends testSaveInsert 306 */ 307 public function testSaveUpdate(EntityInterface $entity) { 308 $immutable_config_object = $this->prophesize(ImmutableConfig::class); 309 $immutable_config_object->isNew()->willReturn(FALSE); 310 311 $config_object = $this->prophesize(Config::class); 312 $config_object 313 ->setData([ 314 'id' => 'foo', 315 'uuid' => 'bar', 316 'dependencies' => [], 317 'langcode' => 'hu', 318 'status' => TRUE, 319 ]) 320 ->shouldBeCalled(); 321 $config_object->save(FALSE)->shouldBeCalled(); 322 $config_object->get()->willReturn([]); 323 324 $this->cacheTagsInvalidator->invalidateTags([$this->entityTypeId . '_list']) 325 ->shouldBeCalled(); 326 327 $this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo']) 328 ->willReturn([]) 329 ->shouldBeCalledTimes(2); 330 $this->configFactory 331 ->get('the_provider.the_config_prefix.foo') 332 ->willReturn($immutable_config_object->reveal()) 333 ->shouldBeCalledTimes(1); 334 $this->configFactory 335 ->getEditable('the_provider.the_config_prefix.foo') 336 ->willReturn($config_object->reveal()) 337 ->shouldBeCalledTimes(1); 338 339 $this->moduleHandler->invokeAll('test_entity_type_presave', [$entity]) 340 ->shouldBeCalled(); 341 $this->moduleHandler->invokeAll('entity_presave', [$entity, 'test_entity_type']) 342 ->shouldBeCalled(); 343 $this->moduleHandler->invokeAll('test_entity_type_update', [$entity]) 344 ->shouldBeCalled(); 345 $this->moduleHandler->invokeAll('entity_update', [$entity, 'test_entity_type']) 346 ->shouldBeCalled(); 347 348 $this->entityQuery->condition('uuid', 'bar')->willReturn($this->entityQuery); 349 $this->entityQuery->execute()->willReturn([$entity->id()]); 350 351 $return = $this->entityStorage->save($entity); 352 $this->assertSame(SAVED_UPDATED, $return); 353 return $entity; 354 } 355 356 /** 357 * @covers ::save 358 * @covers ::doSave 359 * 360 * @depends testSaveInsert 361 */ 362 public function testSaveRename(ConfigEntityInterface $entity) { 363 $immutable_config_object = $this->prophesize(ImmutableConfig::class); 364 $immutable_config_object->isNew()->willReturn(FALSE); 365 366 $config_object = $this->prophesize(Config::class); 367 $config_object 368 ->setData([ 369 'id' => 'bar', 370 'uuid' => 'bar', 371 'dependencies' => [], 372 'langcode' => 'hu', 373 'status' => TRUE, 374 ]) 375 ->shouldBeCalled(); 376 $config_object->save(FALSE) 377 ->shouldBeCalled(); 378 $config_object->get()->willReturn([]); 379 380 $this->cacheTagsInvalidator->invalidateTags([$this->entityTypeId . '_list']) 381 ->shouldBeCalled(); 382 383 $this->configFactory->get('the_provider.the_config_prefix.foo') 384 ->willReturn($immutable_config_object->reveal()); 385 $this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo']) 386 ->willReturn([]); 387 $this->configFactory->rename('the_provider.the_config_prefix.foo', 'the_provider.the_config_prefix.bar') 388 ->shouldBeCalled(); 389 $this->configFactory->getEditable('the_provider.the_config_prefix.bar') 390 ->willReturn($config_object->reveal()); 391 392 // Performing a rename does not change the original ID until saving. 393 $this->assertSame('foo', $entity->getOriginalId()); 394 $entity->set('id', 'bar'); 395 $this->assertSame('foo', $entity->getOriginalId()); 396 397 $this->entityQuery->condition('uuid', 'bar')->willReturn($this->entityQuery); 398 $this->entityQuery->execute()->willReturn([$entity->id()]); 399 400 $return = $this->entityStorage->save($entity); 401 $this->assertSame(SAVED_UPDATED, $return); 402 $this->assertSame('bar', $entity->getOriginalId()); 403 } 404 405 /** 406 * @covers ::save 407 */ 408 public function testSaveInvalid() { 409 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera()) 410 ->shouldNotBeCalled(); 411 412 $entity = $this->getMockEntity(); 413 $this->expectException(EntityMalformedException::class); 414 $this->expectExceptionMessage('The entity does not have an ID.'); 415 $this->entityStorage->save($entity); 416 } 417 418 /** 419 * @covers ::save 420 * @covers ::doSave 421 */ 422 public function testSaveDuplicate() { 423 $config_object = $this->prophesize(ImmutableConfig::class); 424 $config_object->isNew()->willReturn(FALSE); 425 426 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera()) 427 ->shouldNotBeCalled(); 428 429 $this->configFactory->get('the_provider.the_config_prefix.foo') 430 ->willReturn($config_object->reveal()); 431 432 $entity = $this->getMockEntity(['id' => 'foo']); 433 $entity->enforceIsNew(); 434 435 $this->expectException(EntityStorageException::class); 436 $this->entityStorage->save($entity); 437 } 438 439 /** 440 * @covers ::save 441 * @covers ::doSave 442 */ 443 public function testSaveMismatch() { 444 $config_object = $this->prophesize(ImmutableConfig::class); 445 $config_object->isNew()->willReturn(TRUE); 446 447 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera()) 448 ->shouldNotBeCalled(); 449 450 $this->configFactory->get('the_provider.the_config_prefix.foo') 451 ->willReturn($config_object->reveal()); 452 453 $this->entityQuery->condition('uuid', NULL)->willReturn($this->entityQuery); 454 $this->entityQuery->execute()->willReturn(['baz']); 455 456 $entity = $this->getMockEntity(['id' => 'foo']); 457 $this->expectException(ConfigDuplicateUUIDException::class); 458 $this->expectExceptionMessage('when this UUID is already used for'); 459 $this->entityStorage->save($entity); 460 } 461 462 /** 463 * @covers ::save 464 * @covers ::doSave 465 */ 466 public function testSaveNoMismatch() { 467 $immutable_config_object = $this->prophesize(ImmutableConfig::class); 468 $immutable_config_object->isNew()->willReturn(TRUE); 469 470 $config_object = $this->prophesize(Config::class); 471 $config_object->get()->willReturn([]); 472 $config_object 473 ->setData([ 474 'id' => 'foo', 475 'uuid' => NULL, 476 'dependencies' => [], 477 'langcode' => 'en', 478 'status' => TRUE, 479 ]) 480 ->shouldBeCalled(); 481 $config_object->save(FALSE)->shouldBeCalled(); 482 483 $this->cacheTagsInvalidator->invalidateTags([$this->entityTypeId . '_list']) 484 ->shouldBeCalled(); 485 486 $this->configFactory->get('the_provider.the_config_prefix.baz') 487 ->willReturn($immutable_config_object->reveal()) 488 ->shouldBeCalled(); 489 $this->configFactory->rename('the_provider.the_config_prefix.baz', 'the_provider.the_config_prefix.foo') 490 ->shouldBeCalled(); 491 $this->configFactory->getEditable('the_provider.the_config_prefix.foo') 492 ->willReturn($config_object->reveal()) 493 ->shouldBeCalled(); 494 495 $this->entityQuery->condition('uuid', NULL)->willReturn($this->entityQuery); 496 $this->entityQuery->execute()->willReturn(['baz']); 497 498 $entity = $this->getMockEntity(['id' => 'foo']); 499 $entity->setOriginalId('baz'); 500 $entity->enforceIsNew(); 501 $this->entityStorage->save($entity); 502 } 503 504 /** 505 * @covers ::save 506 * @covers ::doSave 507 */ 508 public function testSaveChangedUuid() { 509 $config_object = $this->prophesize(ImmutableConfig::class); 510 $config_object->get()->willReturn(['id' => 'foo']); 511 $config_object->get('id')->willReturn('foo'); 512 $config_object->isNew()->willReturn(FALSE); 513 $config_object->getName()->willReturn('foo'); 514 $config_object->getCacheContexts()->willReturn([]); 515 $config_object->getCacheTags()->willReturn(['config:foo']); 516 $config_object->getCacheMaxAge()->willReturn(Cache::PERMANENT); 517 518 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera()) 519 ->shouldNotBeCalled(); 520 521 $this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo']) 522 ->willReturn([$config_object->reveal()]); 523 $this->configFactory->get('the_provider.the_config_prefix.foo') 524 ->willReturn($config_object->reveal()); 525 $this->configFactory->rename(Argument::cetera())->shouldNotBeCalled(); 526 527 $this->moduleHandler->getImplementations('entity_load')->willReturn([]); 528 $this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]); 529 530 $this->entityQuery->condition('uuid', 'baz')->willReturn($this->entityQuery); 531 $this->entityQuery->execute()->willReturn(['foo']); 532 533 $entity = $this->getMockEntity(['id' => 'foo']); 534 535 $entity->set('uuid', 'baz'); 536 $this->expectException(ConfigDuplicateUUIDException::class); 537 $this->expectExceptionMessage('when this entity already exists with UUID'); 538 $this->entityStorage->save($entity); 539 } 540 541 /** 542 * @covers ::load 543 * @covers ::postLoad 544 * @covers ::mapFromStorageRecords 545 * @covers ::doLoadMultiple 546 */ 547 public function testLoad() { 548 $config_object = $this->prophesize(ImmutableConfig::class); 549 $config_object->get()->willReturn(['id' => 'foo']); 550 $config_object->get('id')->willReturn('foo'); 551 $config_object->getCacheContexts()->willReturn([]); 552 $config_object->getCacheTags()->willReturn(['config:foo']); 553 $config_object->getCacheMaxAge()->willReturn(Cache::PERMANENT); 554 $config_object->getName()->willReturn('foo'); 555 556 $this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo']) 557 ->willReturn([$config_object->reveal()]); 558 559 $this->moduleHandler->getImplementations('entity_load')->willReturn([]); 560 $this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]); 561 562 $entity = $this->entityStorage->load('foo'); 563 $this->assertInstanceOf(EntityInterface::class, $entity); 564 $this->assertSame('foo', $entity->id()); 565 566 $this->expectException(\AssertionError::class); 567 $this->expectExceptionMessage(sprintf('Cannot load the "%s" entity with NULL ID.', $this->entityTypeId)); 568 $this->entityStorage->load(NULL); 569 } 570 571 /** 572 * @covers ::loadMultiple 573 * @covers ::postLoad 574 * @covers ::mapFromStorageRecords 575 * @covers ::doLoadMultiple 576 */ 577 public function testLoadMultipleAll() { 578 $foo_config_object = $this->prophesize(ImmutableConfig::class); 579 $foo_config_object->get()->willReturn(['id' => 'foo']); 580 $foo_config_object->get('id')->willReturn('foo'); 581 $foo_config_object->getCacheContexts()->willReturn([]); 582 $foo_config_object->getCacheTags()->willReturn(['config:foo']); 583 $foo_config_object->getCacheMaxAge()->willReturn(Cache::PERMANENT); 584 $foo_config_object->getName()->willReturn('foo'); 585 586 $bar_config_object = $this->prophesize(ImmutableConfig::class); 587 $bar_config_object->get()->willReturn(['id' => 'bar']); 588 $bar_config_object->get('id')->willReturn('bar'); 589 $bar_config_object->getCacheContexts()->willReturn([]); 590 $bar_config_object->getCacheTags()->willReturn(['config:bar']); 591 $bar_config_object->getCacheMaxAge()->willReturn(Cache::PERMANENT); 592 $bar_config_object->getName()->willReturn('foo'); 593 594 $this->configFactory->listAll('the_provider.the_config_prefix.') 595 ->willReturn(['the_provider.the_config_prefix.foo', 'the_provider.the_config_prefix.bar']); 596 $this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo', 'the_provider.the_config_prefix.bar']) 597 ->willReturn([$foo_config_object->reveal(), $bar_config_object->reveal()]); 598 599 $this->moduleHandler->getImplementations('entity_load')->willReturn([]); 600 $this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]); 601 602 $entities = $this->entityStorage->loadMultiple(); 603 $expected['foo'] = 'foo'; 604 $expected['bar'] = 'bar'; 605 $this->assertContainsOnlyInstancesOf(EntityInterface::class, $entities); 606 foreach ($entities as $id => $entity) { 607 $this->assertSame($id, $entity->id()); 608 $this->assertSame($expected[$id], $entity->id()); 609 } 610 } 611 612 /** 613 * @covers ::loadMultiple 614 * @covers ::postLoad 615 * @covers ::mapFromStorageRecords 616 * @covers ::doLoadMultiple 617 */ 618 public function testLoadMultipleIds() { 619 $config_object = $this->prophesize(ImmutableConfig::class); 620 $config_object->get()->willReturn(['id' => 'foo']); 621 $config_object->get('id')->willReturn('foo'); 622 $config_object->getCacheContexts()->willReturn([]); 623 $config_object->getCacheTags()->willReturn(['config:foo']); 624 $config_object->getCacheMaxAge()->willReturn(Cache::PERMANENT); 625 $config_object->getName()->willReturn('foo'); 626 627 $this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo']) 628 ->willReturn([$config_object->reveal()]); 629 630 $this->moduleHandler->getImplementations('entity_load')->willReturn([]); 631 $this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]); 632 633 $entities = $this->entityStorage->loadMultiple(['foo']); 634 $this->assertContainsOnlyInstancesOf(EntityInterface::class, $entities); 635 foreach ($entities as $id => $entity) { 636 $this->assertSame($id, $entity->id()); 637 } 638 } 639 640 /** 641 * @covers ::loadRevision 642 */ 643 public function testLoadRevision() { 644 $this->assertSame(NULL, $this->entityStorage->loadRevision(1)); 645 } 646 647 /** 648 * @covers ::deleteRevision 649 */ 650 public function testDeleteRevision() { 651 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera()) 652 ->shouldNotBeCalled(); 653 654 $this->assertSame(NULL, $this->entityStorage->deleteRevision(1)); 655 } 656 657 /** 658 * @covers ::delete 659 * @covers ::doDelete 660 */ 661 public function testDelete() { 662 // Dependencies are tested in 663 // \Drupal\Tests\config\Kernel\ConfigDependencyTest. 664 $this->configManager 665 ->getConfigEntitiesToChangeOnDependencyRemoval('config', ['the_provider.the_config_prefix.foo'], FALSE) 666 ->willReturn(['update' => [], 'delete' => [], 'unchanged' => []]); 667 $this->configManager 668 ->getConfigEntitiesToChangeOnDependencyRemoval('config', ['the_provider.the_config_prefix.bar'], FALSE) 669 ->willReturn(['update' => [], 'delete' => [], 'unchanged' => []]); 670 671 $entities = []; 672 foreach (['foo', 'bar'] as $id) { 673 $entity = $this->getMockEntity(['id' => $id]); 674 $entities[] = $entity; 675 676 $config_object = $this->prophesize(Config::class); 677 $config_object->delete()->shouldBeCalled(); 678 679 $this->configFactory->getEditable("the_provider.the_config_prefix.$id") 680 ->willReturn($config_object->reveal()); 681 682 $this->moduleHandler->invokeAll('test_entity_type_predelete', [$entity]) 683 ->shouldBeCalled(); 684 $this->moduleHandler->invokeAll('entity_predelete', [$entity, 'test_entity_type']) 685 ->shouldBeCalled(); 686 687 $this->moduleHandler->invokeAll('test_entity_type_delete', [$entity]) 688 ->shouldBeCalled(); 689 $this->moduleHandler->invokeAll('entity_delete', [$entity, 'test_entity_type']) 690 ->shouldBeCalled(); 691 } 692 693 $this->cacheTagsInvalidator->invalidateTags([$this->entityTypeId . '_list']) 694 ->shouldBeCalled(); 695 696 $this->entityStorage->delete($entities); 697 } 698 699 /** 700 * @covers ::delete 701 * @covers ::doDelete 702 */ 703 public function testDeleteNothing() { 704 $this->moduleHandler->getImplementations(Argument::cetera())->shouldNotBeCalled(); 705 $this->moduleHandler->invokeAll(Argument::cetera())->shouldNotBeCalled(); 706 707 $this->configFactory->get(Argument::cetera())->shouldNotBeCalled(); 708 $this->configFactory->getEditable(Argument::cetera())->shouldNotBeCalled(); 709 710 $this->cacheTagsInvalidator->invalidateTags(Argument::cetera())->shouldNotBeCalled(); 711 712 $this->entityStorage->delete([]); 713 } 714 715 /** 716 * Creates an entity with specific methods mocked. 717 * 718 * @param array $values 719 * (optional) Values to pass to the constructor. 720 * @param array $methods 721 * (optional) The methods to mock. 722 * 723 * @return \Drupal\Core\Entity\EntityInterface|\PHPUnit\Framework\MockObject\MockObject 724 */ 725 public function getMockEntity(array $values = [], $methods = []) { 726 return $this->getMockForAbstractClass(ConfigEntityBase::class, [$values, 'test_entity_type'], '', TRUE, TRUE, TRUE, $methods); 727 } 728 729} 730 731namespace Drupal\Core\Config\Entity; 732 733if (!defined('SAVED_NEW')) { 734 define('SAVED_NEW', 1); 735} 736if (!defined('SAVED_UPDATED')) { 737 define('SAVED_UPDATED', 2); 738} 739