EntityResolverManagerTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <?php
  2. /**
  3. * @file
  4. * Contains \Drupal\Tests\Core\Entity\EntityResolverManagerTest.
  5. */
  6. namespace Drupal\Tests\Core\Entity;
  7. use Drupal\Core\Entity\EntityBase;
  8. use Drupal\Core\Entity\EntityInterface;
  9. use Drupal\Core\Entity\EntityResolverManager;
  10. use Drupal\Core\Form\FormBase;
  11. use Drupal\Core\Form\FormInterface;
  12. use Drupal\Core\Form\FormStateInterface;
  13. use Drupal\Tests\UnitTestCase;
  14. use Symfony\Component\Routing\Route;
  15. /**
  16. * @coversDefaultClass \Drupal\Core\Entity\EntityResolverManager
  17. * @group Entity
  18. */
  19. class EntityResolverManagerTest extends UnitTestCase {
  20. /**
  21. * The tested entity resolver manager.
  22. *
  23. * @var \Drupal\Core\Entity\EntityResolverManager
  24. */
  25. protected $entityResolverManager;
  26. /**
  27. * The mocked entity manager.
  28. *
  29. * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
  30. */
  31. protected $entityTypeManager;
  32. /**
  33. * The mocked class resolver.
  34. *
  35. * @var \Drupal\Core\DependencyInjection\ClassResolverInterface|\PHPUnit\Framework\MockObject\MockObject
  36. */
  37. protected $classResolver;
  38. /**
  39. * The mocked dependency injection container.
  40. *
  41. * @var \Symfony\Component\DependencyInjection\ContainerInterface|\PHPUnit\Framework\MockObject\MockObject
  42. */
  43. protected $container;
  44. /**
  45. * {@inheritdoc}
  46. *
  47. * @covers ::__construct
  48. */
  49. protected function setUp() {
  50. $this->entityTypeManager = $this->createMock('Drupal\Core\Entity\EntityTypeManagerInterface');
  51. $this->container = $this->createMock('Symfony\Component\DependencyInjection\ContainerInterface');
  52. $this->classResolver = $this->getClassResolverStub();
  53. $this->entityResolverManager = new EntityResolverManager($this->entityTypeManager, $this->classResolver);
  54. }
  55. /**
  56. * Tests setRouteOptions() with no parameter.
  57. *
  58. * We don't have any entity type involved, so we don't need any upcasting.
  59. *
  60. * @covers ::setRouteOptions
  61. * @covers ::getControllerClass
  62. *
  63. * @dataProvider providerTestSetRouteOptionsWithStandardRoute
  64. */
  65. public function testSetRouteOptionsWithStandardRoute($controller) {
  66. $route = new Route('/example', [
  67. '_controller' => $controller,
  68. ]);
  69. $defaults = $route->getDefaults();
  70. $this->entityResolverManager->setRouteOptions($route);
  71. $this->assertEquals($defaults, $route->getDefaults());
  72. $this->assertEmpty($route->getOption('parameters'));
  73. }
  74. /**
  75. * Data provider for testSetRouteOptionsWithStandardRoute.
  76. */
  77. public function providerTestSetRouteOptionsWithStandardRoute() {
  78. return [
  79. ['Drupal\Tests\Core\Entity\BasicControllerClass::exampleControllerMethod'],
  80. ['Drupal\Tests\Core\Entity\test_function_controller'],
  81. ];
  82. }
  83. /**
  84. * Tests setRouteOptions() with a controller with a non entity argument.
  85. *
  86. * @covers ::setRouteOptions
  87. * @covers ::getControllerClass
  88. *
  89. * @dataProvider providerTestSetRouteOptionsWithStandardRouteWithArgument
  90. */
  91. public function testSetRouteOptionsWithStandardRouteWithArgument($controller) {
  92. $route = new Route('/example/{argument}', [
  93. '_controller' => $controller,
  94. 'argument' => 'test',
  95. ]);
  96. $defaults = $route->getDefaults();
  97. $this->entityResolverManager->setRouteOptions($route);
  98. $this->assertEquals($defaults, $route->getDefaults());
  99. $this->assertEmpty($route->getOption('parameters'));
  100. }
  101. /**
  102. * Data provider for testSetRouteOptionsWithStandardRouteWithArgument.
  103. */
  104. public function providerTestSetRouteOptionsWithStandardRouteWithArgument() {
  105. return [
  106. ['Drupal\Tests\Core\Entity\BasicControllerClass::exampleControllerMethodWithArgument'],
  107. ['Drupal\Tests\Core\Entity\test_function_controller_with_argument'],
  108. ];
  109. }
  110. /**
  111. * Tests setRouteOptions() with a _content default.
  112. *
  113. * @covers ::setRouteOptions
  114. * @covers ::getControllerClass
  115. *
  116. * @dataProvider providerTestSetRouteOptionsWithContentController
  117. */
  118. public function testSetRouteOptionsWithContentController($controller) {
  119. $route = new Route('/example/{argument}', [
  120. '_controller' => $controller,
  121. 'argument' => 'test',
  122. ]);
  123. $defaults = $route->getDefaults();
  124. $this->entityResolverManager->setRouteOptions($route);
  125. $this->assertEquals($defaults, $route->getDefaults());
  126. $this->assertEmpty($route->getOption('parameters'));
  127. }
  128. /**
  129. * Data provider for testSetRouteOptionsWithContentController.
  130. */
  131. public function providerTestSetRouteOptionsWithContentController() {
  132. return [
  133. ['Drupal\Tests\Core\Entity\BasicControllerClass::exampleControllerMethodWithArgument'],
  134. ['Drupal\Tests\Core\Entity\test_function_controller_with_argument'],
  135. ];
  136. }
  137. /**
  138. * Tests setRouteOptions() with an entity type parameter.
  139. *
  140. * @covers ::setRouteOptions
  141. * @covers ::getControllerClass
  142. * @covers ::getEntityTypes
  143. * @covers ::setParametersFromReflection
  144. *
  145. * @dataProvider providerTestSetRouteOptionsWithEntityTypeNoUpcasting
  146. */
  147. public function testSetRouteOptionsWithEntityTypeNoUpcasting($controller) {
  148. $this->setupEntityTypes();
  149. $route = new Route('/example/{entity_test}', [
  150. '_controller' => $controller,
  151. ]);
  152. $defaults = $route->getDefaults();
  153. $this->entityResolverManager->setRouteOptions($route);
  154. $this->assertEquals($defaults, $route->getDefaults());
  155. $this->assertEmpty($route->getOption('parameters'));
  156. }
  157. /**
  158. * Data provider for testSetRouteOptionsWithEntityTypeNoUpcasting.
  159. */
  160. public function providerTestSetRouteOptionsWithEntityTypeNoUpcasting() {
  161. return [
  162. ['Drupal\Tests\Core\Entity\BasicControllerClass::exampleControllerWithEntityNoUpcasting'],
  163. ['Drupal\Tests\Core\Entity\test_function_controller_no_upcasting'],
  164. ];
  165. }
  166. /**
  167. * Tests setRouteOptions() with an entity type parameter, upcasting.
  168. *
  169. * @covers ::setRouteOptions
  170. * @covers ::getControllerClass
  171. * @covers ::getEntityTypes
  172. * @covers ::setParametersFromReflection
  173. *
  174. * @dataProvider providerTestSetRouteOptionsWithEntityTypeUpcasting
  175. */
  176. public function testSetRouteOptionsWithEntityTypeUpcasting($controller) {
  177. $this->setupEntityTypes();
  178. $route = new Route('/example/{entity_test}', [
  179. '_controller' => $controller,
  180. ]);
  181. $defaults = $route->getDefaults();
  182. $this->entityResolverManager->setRouteOptions($route);
  183. $this->assertEquals($defaults, $route->getDefaults());
  184. $parameters = $route->getOption('parameters');
  185. $this->assertEquals(['entity_test' => ['type' => 'entity:entity_test']], $parameters);
  186. }
  187. /**
  188. * Data provider for testSetRouteOptionsWithEntityTypeUpcasting.
  189. */
  190. public function providerTestSetRouteOptionsWithEntityTypeUpcasting() {
  191. return [
  192. ['Drupal\Tests\Core\Entity\BasicControllerClass::exampleControllerWithEntityUpcasting'],
  193. ['Drupal\Tests\Core\Entity\test_function_controller_entity_upcasting'],
  194. ];
  195. }
  196. /**
  197. * Tests setRouteOptions() with an entity type parameter form.
  198. *
  199. * @covers ::setRouteOptions
  200. * @covers ::getControllerClass
  201. * @covers ::getEntityTypes
  202. * @covers ::setParametersFromReflection
  203. */
  204. public function testSetRouteOptionsWithEntityFormUpcasting() {
  205. $this->setupEntityTypes();
  206. $route = new Route('/example/{entity_test}', [
  207. '_form' => 'Drupal\Tests\Core\Entity\BasicForm',
  208. ]);
  209. $defaults = $route->getDefaults();
  210. $this->entityResolverManager->setRouteOptions($route);
  211. $this->assertEquals($defaults, $route->getDefaults());
  212. $parameters = $route->getOption('parameters');
  213. $this->assertEquals(['entity_test' => ['type' => 'entity:entity_test']], $parameters);
  214. }
  215. /**
  216. * Tests setRouteOptions() with entity form upcasting, no create method.
  217. *
  218. * @covers ::setRouteOptions
  219. * @covers ::getControllerClass
  220. * @covers ::getEntityTypes
  221. * @covers ::setParametersFromReflection
  222. */
  223. public function testSetRouteOptionsWithEntityUpcastingNoCreate() {
  224. $this->setupEntityTypes();
  225. $route = new Route('/example/{entity_test}', [
  226. '_form' => 'Drupal\Tests\Core\Entity\BasicFormNoContainerInjectionInterface',
  227. ]);
  228. $defaults = $route->getDefaults();
  229. $this->entityResolverManager->setRouteOptions($route);
  230. $this->assertEquals($defaults, $route->getDefaults());
  231. $parameters = $route->getOption('parameters');
  232. $this->assertEquals(['entity_test' => ['type' => 'entity:entity_test']], $parameters);
  233. }
  234. /**
  235. * Tests setRouteOptions() with an form parameter without interface.
  236. *
  237. * @covers ::setRouteOptions
  238. * @covers ::getControllerClass
  239. * @covers ::getEntityTypes
  240. * @covers ::setParametersFromReflection
  241. */
  242. public function testSetRouteOptionsWithEntityFormNoUpcasting() {
  243. $this->setupEntityTypes();
  244. $route = new Route('/example/{entity_test}', [
  245. '_form' => 'Drupal\Tests\Core\Entity\BasicFormNoUpcasting',
  246. ]);
  247. $defaults = $route->getDefaults();
  248. $this->entityResolverManager->setRouteOptions($route);
  249. $this->assertEquals($defaults, $route->getDefaults());
  250. $this->assertEmpty($route->getOption('parameters'));
  251. }
  252. /**
  253. * Tests setRouteOptions() with an _entity_view route.
  254. *
  255. * @covers ::setRouteOptions
  256. * @covers ::getControllerClass
  257. * @covers ::getEntityTypes
  258. * @covers ::setParametersFromReflection
  259. * @covers ::setParametersFromEntityInformation
  260. */
  261. public function testSetRouteOptionsWithEntityViewRouteAndManualParameters() {
  262. $this->setupEntityTypes();
  263. $route = new Route('/example/{foo}',
  264. [
  265. '_entity_view' => 'entity_test.view',
  266. ],
  267. [],
  268. [
  269. 'parameters' => [
  270. 'foo' => [
  271. 'type' => 'entity:entity_test',
  272. ],
  273. ],
  274. ]
  275. );
  276. $defaults = $route->getDefaults();
  277. $this->entityResolverManager->setRouteOptions($route);
  278. $this->assertEquals($defaults, $route->getDefaults());
  279. $parameters = $route->getOption('parameters');
  280. $this->assertEquals(['foo' => ['type' => 'entity:entity_test']], $parameters);
  281. }
  282. /**
  283. * Tests setRouteOptions() with an _entity_view route.
  284. *
  285. * @covers ::setRouteOptions
  286. * @covers ::getControllerClass
  287. * @covers ::getEntityTypes
  288. * @covers ::setParametersFromReflection
  289. * @covers ::setParametersFromEntityInformation
  290. */
  291. public function testSetRouteOptionsWithEntityViewRoute() {
  292. $this->setupEntityTypes();
  293. $route = new Route('/example/{entity_test}', [
  294. '_entity_view' => 'entity_test.view',
  295. ]);
  296. $defaults = $route->getDefaults();
  297. $this->entityResolverManager->setRouteOptions($route);
  298. $this->assertEquals($defaults, $route->getDefaults());
  299. $parameters = $route->getOption('parameters');
  300. $this->assertEquals(['entity_test' => ['type' => 'entity:entity_test']], $parameters);
  301. }
  302. /**
  303. * Tests setRouteOptions() with an _entity_list route.
  304. *
  305. * @covers ::setRouteOptions
  306. * @covers ::getControllerClass
  307. * @covers ::getEntityTypes
  308. * @covers ::setParametersFromReflection
  309. * @covers ::setParametersFromEntityInformation
  310. */
  311. public function testSetRouteOptionsWithEntityListRoute() {
  312. $this->setupEntityTypes();
  313. $route = new Route('/example/{entity_test}', [
  314. '_entity_list' => 'entity_test',
  315. ]);
  316. $defaults = $route->getDefaults();
  317. $this->entityResolverManager->setRouteOptions($route);
  318. $this->assertEquals($defaults, $route->getDefaults());
  319. $parameters = $route->getOption('parameters');
  320. $this->assertNull($parameters);
  321. }
  322. /**
  323. * Tests setRouteOptions() with an _entity_form route.
  324. *
  325. * @covers ::setRouteOptions
  326. * @covers ::getControllerClass
  327. * @covers ::getEntityTypes
  328. * @covers ::setParametersFromReflection
  329. * @covers ::setParametersFromEntityInformation
  330. */
  331. public function testSetRouteOptionsWithEntityFormRoute() {
  332. $this->setupEntityTypes();
  333. $route = new Route('/example/{entity_test}', [
  334. '_entity_form' => 'entity_test.edit',
  335. ]);
  336. $defaults = $route->getDefaults();
  337. $this->entityResolverManager->setRouteOptions($route);
  338. $this->assertEquals($defaults, $route->getDefaults());
  339. $parameters = $route->getOption('parameters');
  340. $this->assertEquals(['entity_test' => ['type' => 'entity:entity_test']], $parameters);
  341. }
  342. /**
  343. * Tests an _entity_form route where a non-entity parameter is first.
  344. *
  345. * The {argument} preceding {entity_test} in route path, is upcasting with a
  346. * custom param converter.
  347. *
  348. * @covers ::setRouteOptions
  349. * @covers ::getControllerClass
  350. * @covers ::getEntityTypes
  351. * @covers ::setParametersFromReflection
  352. * @covers ::setParametersFromEntityInformation
  353. */
  354. public function testSetRouteOptionsWithEntityFormRouteAndArgument() {
  355. $this->setupEntityTypes();
  356. $route = new Route('/example/{argument}/{entity_test}', [
  357. '_entity_form' => 'entity_test.edit',
  358. ]);
  359. // Add {argument} parameter configuration. In this case {argument} is
  360. // upcasted by a custom param converter 'argument_type'.
  361. $route->setOption('parameters', ['argument' => ['type' => 'argument_type']]);
  362. $defaults = $route->getDefaults();
  363. $this->entityResolverManager->setRouteOptions($route);
  364. $this->assertEquals($defaults, $route->getDefaults());
  365. $parameters = $route->getOption('parameters');
  366. $expect = [
  367. 'argument' => ['type' => 'argument_type'],
  368. 'entity_test' => ['type' => 'entity:entity_test'],
  369. ];
  370. $this->assertEquals($expect, $parameters);
  371. }
  372. /**
  373. * Tests setRouteOptions() with an _entity_form route for an add form.
  374. *
  375. * @covers ::setRouteOptions
  376. * @covers ::getControllerClass
  377. * @covers ::getEntityTypes
  378. * @covers ::setParametersFromReflection
  379. * @covers ::setParametersFromEntityInformation
  380. */
  381. public function testSetRouteOptionsWithEntityAddFormRoute() {
  382. $this->setupEntityTypes();
  383. $route = new Route('/example/add', [
  384. '_entity_form' => 'entity_test.add',
  385. ]);
  386. $defaults = $route->getDefaults();
  387. $this->entityResolverManager->setRouteOptions($route);
  388. $this->assertEquals($defaults, $route->getDefaults());
  389. $this->assertFalse($route->hasOption('parameters'));
  390. }
  391. /**
  392. * Creates the entity manager mock returning entity type objects.
  393. */
  394. protected function setupEntityTypes() {
  395. $definition = $this->createMock('Drupal\Core\Entity\EntityTypeInterface');
  396. $definition->expects($this->any())
  397. ->method('getClass')
  398. ->will($this->returnValue('Drupal\Tests\Core\Entity\SimpleTestEntity'));
  399. $definition->expects($this->any())
  400. ->method('isRevisionable')
  401. ->willReturn(FALSE);
  402. $revisionable_definition = $this->createMock('Drupal\Core\Entity\EntityTypeInterface');
  403. $revisionable_definition->expects($this->any())
  404. ->method('getClass')
  405. ->will($this->returnValue('Drupal\Tests\Core\Entity\SimpleTestEntity'));
  406. $revisionable_definition->expects($this->any())
  407. ->method('isRevisionable')
  408. ->willReturn(TRUE);
  409. $this->entityTypeManager->expects($this->any())
  410. ->method('getDefinitions')
  411. ->will($this->returnValue([
  412. 'entity_test' => $definition,
  413. 'entity_test_rev' => $revisionable_definition,
  414. ]));
  415. $this->entityTypeManager->expects($this->any())
  416. ->method('getDefinition')
  417. ->will($this->returnCallback(function ($entity_type) use ($definition, $revisionable_definition) {
  418. if ($entity_type == 'entity_test') {
  419. return $definition;
  420. }
  421. elseif ($entity_type === 'entity_test_rev') {
  422. return $revisionable_definition;
  423. }
  424. else {
  425. return NULL;
  426. }
  427. }));
  428. }
  429. }
  430. /**
  431. * A class containing all kind of different controller methods.
  432. */
  433. class BasicControllerClass {
  434. public function exampleControllerMethod() {
  435. }
  436. public function exampleControllerMethodWithArgument($argument) {
  437. }
  438. public function exampleControllerWithEntityNoUpcasting($entity_test) {
  439. }
  440. public function exampleControllerWithEntityUpcasting(EntityInterface $entity_test) {
  441. }
  442. }
  443. /**
  444. * A concrete entity.
  445. */
  446. class SimpleTestEntity extends EntityBase {
  447. }
  448. /**
  449. * A basic form with a passed entity with an interface.
  450. *
  451. * @internal
  452. */
  453. class BasicForm extends FormBase {
  454. /**
  455. * {@inheritdoc}
  456. */
  457. public function getFormId() {
  458. }
  459. /**
  460. * {@inheritdoc}
  461. */
  462. public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity_test = NULL) {
  463. }
  464. /**
  465. * {@inheritdoc}
  466. */
  467. public function submitForm(array &$form, FormStateInterface $form_state) {
  468. }
  469. }
  470. /**
  471. * A basic form with a passed entity without an interface.
  472. */
  473. class BasicFormNoUpcasting extends FormBase {
  474. /**
  475. * {@inheritdoc}
  476. */
  477. public function getFormId() {
  478. }
  479. /**
  480. * {@inheritdoc}
  481. */
  482. public function buildForm(array $form, FormStateInterface $form_state, $entity_test = NULL) {
  483. }
  484. /**
  485. * {@inheritdoc}
  486. */
  487. public function submitForm(array &$form, FormStateInterface $form_state) {
  488. }
  489. }
  490. class BasicFormNoContainerInjectionInterface implements FormInterface {
  491. /**
  492. * {@inheritdoc}
  493. */
  494. public function getFormId() {
  495. }
  496. /**
  497. * {@inheritdoc}
  498. */
  499. public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity_test = NULL) {
  500. }
  501. /**
  502. * {@inheritdoc}
  503. */
  504. public function validateForm(array &$form, FormStateInterface $form_state) {
  505. }
  506. /**
  507. * {@inheritdoc}
  508. */
  509. public function submitForm(array &$form, FormStateInterface $form_state) {
  510. }
  511. }
  512. function test_function_controller() {
  513. }
  514. function test_function_controller_with_argument($argument) {
  515. }
  516. function test_function_controller_no_upcasting($entity_test) {
  517. }
  518. function test_function_controller_entity_upcasting(EntityInterface $entity_test) {
  519. }