5 * Contains \Drupal\Tests\Core\Entity\EntityTypeManagerTest.
8 namespace Drupal\Tests\Core\Entity;
10 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
11 use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
12 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
13 use Drupal\Core\Cache\CacheBackendInterface;
14 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
15 use Drupal\Core\Entity\EntityHandlerBase;
16 use Drupal\Core\Entity\EntityInterface;
17 use Drupal\Core\Entity\EntityManagerInterface;
18 use Drupal\Core\Entity\EntityTypeInterface;
19 use Drupal\Core\Entity\EntityTypeManager;
20 use Drupal\Core\Entity\EntityTypeManagerInterface;
21 use Drupal\Core\Entity\Exception\InvalidLinkTemplateException;
22 use Drupal\Core\Extension\ModuleHandlerInterface;
23 use Drupal\Core\StringTranslation\TranslationInterface;
24 use Drupal\Tests\UnitTestCase;
25 use Prophecy\Argument;
26 use Symfony\Component\DependencyInjection\ContainerInterface;
29 * @coversDefaultClass \Drupal\Core\Entity\EntityTypeManager
32 class EntityTypeManagerTest extends UnitTestCase {
35 * The entity type manager under test.
37 * @var \Drupal\Core\Entity\EntityTypeManager
39 protected $entityTypeManager;
42 * The translation manager.
44 * @var \Drupal\Core\StringTranslation\TranslationInterface|\Prophecy\Prophecy\ProphecyInterface
46 protected $translationManager;
49 * The plugin discovery.
51 * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface|\Prophecy\Prophecy\ProphecyInterface
58 * @var \Drupal\Core\Extension\ModuleHandlerInterface|\Prophecy\Prophecy\ProphecyInterface
60 protected $moduleHandler;
65 * @var \Drupal\Core\Cache\CacheBackendInterface|\Prophecy\Prophecy\ProphecyInterface
67 protected $cacheBackend;
72 protected function setUp() {
75 $this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
76 $this->moduleHandler->getImplementations('entity_type_build')->willReturn([]);
77 $this->moduleHandler->alter('entity_type', Argument::type('array'))->willReturn(NULL);
79 $this->cacheBackend = $this->prophesize(CacheBackendInterface::class);
80 $this->translationManager = $this->prophesize(TranslationInterface::class);
82 $this->entityTypeManager = new TestEntityTypeManager(new \ArrayObject(), $this->moduleHandler->reveal(), $this->cacheBackend->reveal(), $this->translationManager->reveal(), $this->getClassResolverStub());
83 $this->discovery = $this->prophesize(DiscoveryInterface::class);
84 $this->entityTypeManager->setDiscovery($this->discovery->reveal());
88 * Sets up the entity type manager to be tested.
90 * @param \Drupal\Core\Entity\EntityTypeInterface[]|\Prophecy\Prophecy\ProphecyInterface[] $definitions
91 * (optional) An array of entity type definitions.
93 protected function setUpEntityTypeDefinitions($definitions = []) {
94 $class = $this->getMockClass(EntityInterface::class);
95 foreach ($definitions as $key => $entity_type) {
96 // \Drupal\Core\Entity\EntityTypeInterface::getLinkTemplates() is called
97 // by \Drupal\Core\Entity\EntityManager::processDefinition() so it must
99 $entity_type->getLinkTemplates()->willReturn([]);
101 // Give the entity type a legitimate class to return.
102 $entity_type->getClass()->willReturn($class);
103 $entity_type->setClass($class)->willReturn($entity_type->reveal());
105 $definitions[$key] = $entity_type->reveal();
108 $this->discovery->getDefinition(Argument::cetera())
109 ->will(function ($args) use ($definitions) {
110 $entity_type_id = $args[0];
111 $exception_on_invalid = $args[1];
112 if (isset($definitions[$entity_type_id])) {
113 return $definitions[$entity_type_id];
115 elseif (!$exception_on_invalid) {
118 else throw new PluginNotFoundException($entity_type_id);
120 $this->discovery->getDefinitions()->willReturn($definitions);
125 * Tests the hasHandler() method.
127 * @covers ::hasHandler
129 * @dataProvider providerTestHasHandler
131 public function testHasHandler($entity_type_id, $expected) {
132 $apple = $this->prophesize(EntityTypeInterface::class);
133 $apple->hasHandlerClass('storage')->willReturn(TRUE);
135 $banana = $this->prophesize(EntityTypeInterface::class);
136 $banana->hasHandlerClass('storage')->willReturn(FALSE);
138 $this->setUpEntityTypeDefinitions([
143 $entity_type = $this->entityTypeManager->hasHandler($entity_type_id, 'storage');
144 $this->assertSame($expected, $entity_type);
148 * Provides test data for testHasHandler().
153 public function providerTestHasHandler() {
162 * Tests the getStorage() method.
164 * @covers ::getStorage
166 public function testGetStorage() {
167 $class = $this->getTestHandlerClass();
168 $entity = $this->prophesize(EntityTypeInterface::class);
169 $entity->getHandlerClass('storage')->willReturn($class);
170 $this->setUpEntityTypeDefinitions(['test_entity_type' => $entity]);
172 $this->assertInstanceOf($class, $this->entityTypeManager->getStorage('test_entity_type'));
176 * Tests the getListBuilder() method.
178 * @covers ::getListBuilder
180 public function testGetListBuilder() {
181 $class = $this->getTestHandlerClass();
182 $entity = $this->prophesize(EntityTypeInterface::class);
183 $entity->getHandlerClass('list_builder')->willReturn($class);
184 $this->setUpEntityTypeDefinitions(['test_entity_type' => $entity]);
186 $this->assertInstanceOf($class, $this->entityTypeManager->getListBuilder('test_entity_type'));
190 * Tests the getViewBuilder() method.
192 * @covers ::getViewBuilder
194 public function testGetViewBuilder() {
195 $class = $this->getTestHandlerClass();
196 $entity = $this->prophesize(EntityTypeInterface::class);
197 $entity->getHandlerClass('view_builder')->willReturn($class);
198 $this->setUpEntityTypeDefinitions(['test_entity_type' => $entity]);
200 $this->assertInstanceOf($class, $this->entityTypeManager->getViewBuilder('test_entity_type'));
204 * Tests the getAccessControlHandler() method.
206 * @covers ::getAccessControlHandler
208 public function testGetAccessControlHandler() {
209 $class = $this->getTestHandlerClass();
210 $entity = $this->prophesize(EntityTypeInterface::class);
211 $entity->getHandlerClass('access')->willReturn($class);
212 $this->setUpEntityTypeDefinitions(['test_entity_type' => $entity]);
214 $this->assertInstanceOf($class, $this->entityTypeManager->getAccessControlHandler('test_entity_type'));
218 * Tests the getFormObject() method.
220 * @covers ::getFormObject
222 public function testGetFormObject() {
223 $entity_manager = $this->prophesize(EntityManagerInterface::class);
224 $container = $this->prophesize(ContainerInterface::class);
225 $container->get('entity.manager')->willReturn($entity_manager->reveal());
226 \Drupal::setContainer($container->reveal());
228 $apple = $this->prophesize(EntityTypeInterface::class);
229 $apple->getFormClass('default')->willReturn(TestEntityForm::class);
231 $banana = $this->prophesize(EntityTypeInterface::class);
232 $banana->getFormClass('default')->willReturn(TestEntityFormInjected::class);
234 $this->setUpEntityTypeDefinitions([
239 $apple_form = $this->entityTypeManager->getFormObject('apple', 'default');
240 $this->assertInstanceOf(TestEntityForm::class, $apple_form);
241 $this->assertAttributeInstanceOf(ModuleHandlerInterface::class, 'moduleHandler', $apple_form);
242 $this->assertAttributeInstanceOf(TranslationInterface::class, 'stringTranslation', $apple_form);
244 $banana_form = $this->entityTypeManager->getFormObject('banana', 'default');
245 $this->assertInstanceOf(TestEntityFormInjected::class, $banana_form);
246 $this->assertAttributeEquals('yellow', 'color', $banana_form);
251 * Tests the getFormObject() method with an invalid operation.
253 * @covers ::getFormObject
255 public function testGetFormObjectInvalidOperation() {
256 $entity = $this->prophesize(EntityTypeInterface::class);
257 $entity->getFormClass('edit')->willReturn('');
258 $this->setUpEntityTypeDefinitions(['test_entity_type' => $entity]);
260 $this->setExpectedException(InvalidPluginDefinitionException::class);
261 $this->entityTypeManager->getFormObject('test_entity_type', 'edit');
265 * Tests the getHandler() method.
267 * @covers ::getHandler
269 public function testGetHandler() {
270 $class = $this->getTestHandlerClass();
271 $apple = $this->prophesize(EntityTypeInterface::class);
272 $apple->getHandlerClass('storage')->willReturn($class);
274 $this->setUpEntityTypeDefinitions([
278 $apple_controller = $this->entityTypeManager->getHandler('apple', 'storage');
279 $this->assertInstanceOf($class, $apple_controller);
280 $this->assertAttributeInstanceOf(ModuleHandlerInterface::class, 'moduleHandler', $apple_controller);
281 $this->assertAttributeInstanceOf(TranslationInterface::class, 'stringTranslation', $apple_controller);
285 * Tests the getHandler() method when no controller is defined.
287 * @covers ::getHandler
289 public function testGetHandlerMissingHandler() {
290 $entity = $this->prophesize(EntityTypeInterface::class);
291 $entity->getHandlerClass('storage')->willReturn('');
292 $this->setUpEntityTypeDefinitions(['test_entity_type' => $entity]);
293 $this->setExpectedException(InvalidPluginDefinitionException::class);
294 $this->entityTypeManager->getHandler('test_entity_type', 'storage');
298 * @covers ::getRouteProviders
300 public function testGetRouteProviders() {
301 $apple = $this->prophesize(EntityTypeInterface::class);
302 $apple->getRouteProviderClasses()->willReturn(['default' => TestRouteProvider::class]);
304 $this->setUpEntityTypeDefinitions([
308 $apple_route_provider = $this->entityTypeManager->getRouteProviders('apple');
309 $this->assertInstanceOf(TestRouteProvider::class, $apple_route_provider['default']);
310 $this->assertAttributeInstanceOf(ModuleHandlerInterface::class, 'moduleHandler', $apple_route_provider['default']);
311 $this->assertAttributeInstanceOf(TranslationInterface::class, 'stringTranslation', $apple_route_provider['default']);
315 * Tests the processDefinition() method.
317 * @covers ::processDefinition
319 public function testProcessDefinition() {
320 $apple = $this->prophesize(EntityTypeInterface::class);
321 $this->setUpEntityTypeDefinitions(['apple' => $apple]);
323 $apple->getLinkTemplates()->willReturn(['canonical' => 'path/to/apple']);
325 $definition = $apple->reveal();
326 $this->setExpectedException(InvalidLinkTemplateException::class, "Link template 'canonical' for entity type 'apple' must start with a leading slash, the current link template is 'path/to/apple'");
327 $this->entityTypeManager->processDefinition($definition, 'apple');
331 * Tests the getDefinition() method.
333 * @covers ::getDefinition
335 * @dataProvider providerTestGetDefinition
337 public function testGetDefinition($entity_type_id, $expected) {
338 $entity = $this->prophesize(EntityTypeInterface::class);
340 $this->setUpEntityTypeDefinitions([
345 $entity_type = $this->entityTypeManager->getDefinition($entity_type_id, FALSE);
347 $this->assertInstanceOf(EntityTypeInterface::class, $entity_type);
350 $this->assertNull($entity_type);
355 * Provides test data for testGetDefinition().
360 public function providerTestGetDefinition() {
369 * Tests the getDefinition() method with an invalid definition.
371 * @covers ::getDefinition
373 public function testGetDefinitionInvalidException() {
374 $this->setUpEntityTypeDefinitions();
376 $this->setExpectedException(PluginNotFoundException::class, 'The "pear" entity type does not exist.');
377 $this->entityTypeManager->getDefinition('pear', TRUE);
381 * Gets a mock controller class name.
384 * A mock controller class name.
386 protected function getTestHandlerClass() {
387 return get_class($this->getMockForAbstractClass(EntityHandlerBase::class));
392 class TestEntityTypeManager extends EntityTypeManager {
395 * Sets the discovery for the manager.
397 * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
398 * The discovery object.
400 public function setDiscovery(DiscoveryInterface $discovery) {
401 $this->discovery = $discovery;
407 * Provides a test entity form.
409 class TestEntityForm extends EntityHandlerBase {
412 * The entity manager.
414 * @var \Drupal\Core\Entity\EntityManagerInterface
416 protected $entityManager;
419 * The entity type manager.
421 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
423 protected $entityTypeManager;
428 public function getBaseFormId() {
429 return 'the_base_form_id';
435 public function getFormId() {
436 return 'the_form_id';
442 public function setEntity(EntityInterface $entity) {
449 public function setOperation($operation) {
456 public function setEntityManager(EntityManagerInterface $entity_manager) {
457 $this->entityManager = $entity_manager;
464 public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_manager) {
465 $this->entityTypeManager = $entity_type_manager;
472 * Provides a test entity form that uses injection.
474 class TestEntityFormInjected extends TestEntityForm implements ContainerInjectionInterface {
477 * The color of the entity type.
484 * Constructs a new TestEntityFormInjected.
486 * @param string $color
487 * The color of the entity type.
489 public function __construct($color) {
490 $this->color = $color;
496 public static function create(ContainerInterface $container) {
497 return new static('yellow');
503 * Provides a test entity route provider.
505 class TestRouteProvider extends EntityHandlerBase {