diff --git a/.drone.yml b/.drone.yml index 85b59905..821c8a86 100644 --- a/.drone.yml +++ b/.drone.yml @@ -11,6 +11,15 @@ services: image: percona/percona-server:5.6 environment: - MYSQL_ALLOW_EMPTY_PASSWORD=yes + selenium: + image: selenium/standalone-chrome:3.141.5 + shm_size: 2g + environment: + - DISPLAY=:99 + - SCREEN_WIDTH=1280 + - SCREEN_HEIGHT=800 + - NODE_MAX_INSTANCES=5 + - NODE_MAX_SESSION=5 pipeline: composer-install: diff --git a/composer.json b/composer.json index 2eaf4bcf..9e0982bb 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "prefer-stable": true, "require": { "drupal/core": "^8.8", - "openeuropa/entity_meta_relation": "dev-OPENEUROPA-3271", + "openeuropa/entity_meta_relation": "dev-8.x-1.x", "drupal/search_api": "~1.17", "php": ">=7.2" }, diff --git a/config/install/emr.entity_meta_type.oe_list_page.yml b/config/install/emr.entity_meta_type.oe_list_page.yml new file mode 100755 index 00000000..6bb5d2cb --- /dev/null +++ b/config/install/emr.entity_meta_type.oe_list_page.yml @@ -0,0 +1,5 @@ +langcode: en +status: true +dependencies: { } +id: oe_list_page +label: 'List Page' diff --git a/config/install/field.field.entity_meta.oe_list_page.oe_list_page_config.yml b/config/install/field.field.entity_meta.oe_list_page.oe_list_page_config.yml new file mode 100644 index 00000000..44975372 --- /dev/null +++ b/config/install/field.field.entity_meta.oe_list_page.oe_list_page_config.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - emr.entity_meta_type.oe_list_page + - field.storage.entity_meta.oe_list_page_config +id: entity_meta.oe_list_page.oe_list_page_config +field_name: oe_list_page_config +entity_type: entity_meta +bundle: oe_list_page +label: 'List Pages configuration' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string_long diff --git a/config/install/field.field.entity_meta.oe_list_page.oe_list_page_source.yml b/config/install/field.field.entity_meta.oe_list_page.oe_list_page_source.yml new file mode 100644 index 00000000..14c9ef90 --- /dev/null +++ b/config/install/field.field.entity_meta.oe_list_page.oe_list_page_source.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - emr.entity_meta_type.oe_list_page + - field.storage.entity_meta.oe_list_page_source +id: entity_meta.oe_list_page.oe_list_page_source +field_name: oe_list_page_source +entity_type: entity_meta +bundle: oe_list_page +label: 'List Pages source' +description: '' +required: true +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/config/install/field.storage.entity_meta.oe_list_page_config.yml b/config/install/field.storage.entity_meta.oe_list_page_config.yml new file mode 100644 index 00000000..0e9ba1de --- /dev/null +++ b/config/install/field.storage.entity_meta.oe_list_page_config.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + module: + - emr +id: entity_meta.oe_list_page_config +field_name: oe_list_page_config +entity_type: entity_meta +type: string_long +settings: + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/install/field.storage.entity_meta.oe_list_page_source.yml b/config/install/field.storage.entity_meta.oe_list_page_source.yml new file mode 100644 index 00000000..d4e1aae6 --- /dev/null +++ b/config/install/field.storage.entity_meta.oe_list_page_source.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + module: + - emr +id: entity_meta.oe_list_page_source +field_name: oe_list_page_source +entity_type: entity_meta +type: string +settings: + max_length: 255 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/docker-compose.yml b/docker-compose.yml index 7a02cb4f..1e164598 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,6 +21,27 @@ services: # ports: # - 3306:3306 + # If you would like to see what is going on you can run the following on your host: + # docker run --rm -p 4444:4444 -p 5900:5900 --network="host" selenium/standalone-chrome-debug:latest + # Newer version of this image might run into this issue: + # @link https://github.com/elgalu/docker-selenium/issues/20 + selenium: + image: selenium/standalone-chrome-debug:3.141.59-oxygen + expose: + - '4444' + environment: + - DISPLAY=:99 + - SE_OPTS=-debug + - SCREEN_WIDTH=1280 + - SCREEN_HEIGHT=800 + - VNC_NO_PASSWORD=1 + ports: + - '4444:4444' + - "5900:5900" + volumes: + - /dev/shm:/dev/shm + shm_size: 2g + #### Mac users: uncomment the "volumes" key to enable the NFS file sharing. You can find more information about Docker for Mac here: https://github.com/openeuropa/openeuropa/blob/master/docs/starting/tooling.md#using-docker-on-macos #volumes: diff --git a/oe_list_pages.info.yml b/oe_list_pages.info.yml index 7a57d1dd..5dc62131 100644 --- a/oe_list_pages.info.yml +++ b/oe_list_pages.info.yml @@ -6,5 +6,13 @@ type: module core: 8.x dependencies: - - emr_node:emr_node + - emr:emr_node - search_api:search_api + +config_devel: + install: + - emr.entity_meta_type.oe_list_page + - field.field.entity_meta.oe_list_page.list_page_plugin + - field.field.entity_meta.oe_list_page.list_page_plugin_config + - field.storage.entity_meta.list_page_plugin + - field.storage.entity_meta.list_page_plugin_config diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7002013e..db99eb82 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,6 +6,7 @@ + diff --git a/runner.yml.dist b/runner.yml.dist index 0f099b9b..544bf5a5 100644 --- a/runner.yml.dist +++ b/runner.yml.dist @@ -30,6 +30,12 @@ drupal: - "vendor" - "${drupal.root}" + +selenium: + host: "http://selenium" + port: "4444" + browser: "chrome" + commands: drupal:site-setup: - { task: "symlink", from: "../../..", to: "${drupal.root}/modules/custom/oe_list_pages" } diff --git a/src/ListPageEvents.php b/src/ListPageEvents.php new file mode 100644 index 00000000..a52599af --- /dev/null +++ b/src/ListPageEvents.php @@ -0,0 +1,26 @@ +entityTypes = $entity_types; + $this->bundles = $bundles; + } + + /** + * Returns the allowed entity types. + * + * @return string[] + * The list of entity types. + */ + public function getEntityTypes(): array { + return $this->entityTypes; + } + + /** + * Set the allowed entity types. + * + * @param array $entity_types + * The list of entity types. + */ + public function setEntityTypes(array $entity_types): void { + $this->entityTypes = $entity_types; + } + + /** + * Returns the allowed bundles. + * + * @return string[] + * The list of allowed bundles. + */ + public function getBundles(): array { + return $this->bundles; + } + + /** + * Set the allowed bundles. + * + * @param string $entity_type + * The entity type. + * @param array $bundles + * The bundles. + */ + public function setBundles(string $entity_type, array $bundles): void { + $this->entityTypes = [$entity_type]; + $this->bundles = $bundles; + } + +} diff --git a/src/ListPageWrapper.php b/src/ListPageWrapper.php new file mode 100644 index 00000000..9ed95fc8 --- /dev/null +++ b/src/ListPageWrapper.php @@ -0,0 +1,91 @@ +entityMeta->set('oe_list_page_source', $entity_type . ':' . $bundle); + } + + /** + * Returns the entity meta list page source. + * + * This is a pair of entity_type:bundle that will be used for querying on this + * list page. + * + * @return string|null + * The entity_type:bundle pair source. + */ + public function getSource(): ?string { + return $this->entityMeta->get('oe_list_page_source')->value; + } + + /** + * Returns the entity type used as the source. + * + * @return string|null + * The entity type. + */ + public function getSourceEntityType(): ?string { + $source = $this->getSource(); + if (!$source) { + return NULL; + } + + list($entity_type, $bundle) = explode(':', $source); + return $entity_type; + } + + /** + * Returns the bundle used in the source. + * + * @return string|null + * The bundle. + */ + public function getSourceEntityBundle(): ?string { + $source = $this->getSource(); + if (!$source) { + return NULL; + } + + list($entity_type, $bundle) = explode(':', $source); + return $bundle; + } + + /** + * Returns the entity meta configuration. + * + * @return array + * The list page configuration. + */ + public function getConfiguration(): array { + return $this->entityMeta->get('oe_list_page_config')->isEmpty() ? [] : unserialize($this->entityMeta->get('oe_list_page_config')->value); + } + + /** + * Sets the entity meta configuration. + * + * @param array $configuration + * The list page configuration. + */ + public function setConfiguration(array $configuration): void { + $this->entityMeta->set('oe_list_page_config', serialize($configuration)); + } + +} diff --git a/src/Plugin/EntityMetaRelation/ListPage.php b/src/Plugin/EntityMetaRelation/ListPage.php new file mode 100755 index 00000000..b04c22c5 --- /dev/null +++ b/src/Plugin/EntityMetaRelation/ListPage.php @@ -0,0 +1,214 @@ +entityTypeBundleInfo = $entity_type_bundle_info; + $this->eventDispatcher = $dispatcher; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('entity_field.manager'), + $container->get('entity_type.manager'), + $container->get('entity_type.bundle.info'), + $container->get('event_dispatcher') + ); + } + + /** + * Ajax request handler. + * + * @param array $form + * The form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return array + * The form element. + */ + public function updateEntityBundles(array &$form, FormStateInterface $form_state): array { + $key = $this->getFormKey(); + return $form[$key]['bundle_wrapper']; + } + + /** + * {@inheritdoc} + */ + public function build(array $form, FormStateInterface $form_state, ContentEntityInterface $entity): array { + $key = $this->getFormKey(); + $this->buildFormContainer($form, $form_state, $key); + $entity_meta_bundle = $this->getPluginDefinition()['entity_meta_bundle']; + + // Get the related List Page entity meta. + /** @var \Drupal\emr\Field\EntityMetaItemListInterface $entity_meta_list */ + $entity_meta_list = $entity->get('emr_entity_metas'); + /** @var \Drupal\emr\Entity\EntityMetaInterface $navigation_block_entity_meta */ + $entity_meta = $entity_meta_list->getEntityMeta($entity_meta_bundle); + /** @var \Drupal\oe_list_pages\ListPageWrapper $entity_meta_wrapper */ + $entity_meta_wrapper = $entity_meta->getWrapper(); + + $entity_type_options = []; + $entity_types = $this->entityTypeManager->getDefinitions(); + foreach ($entity_types as $entity_type_key => $entity_type) { + if (!$entity_type instanceof ContentEntityTypeInterface) { + continue; + } + $entity_type_options[$entity_type_key] = $entity_type->getLabel(); + } + + $event = new ListPageSourceAlterEvent(array_keys($entity_type_options)); + $this->eventDispatcher->dispatch(ListPageEvents::ALTER_ENTITY_TYPES, $event); + $entity_type_options = array_intersect_key($entity_type_options, array_combine($event->getEntityTypes(), $event->getEntityTypes())); + + $entity_type_id = $entity_meta_wrapper->getSourceEntityType(); + + $form[$key]['entity_type'] = [ + '#type' => 'select', + '#title' => $this->t('Source entity type'), + '#description' => $this->t('Select the entity type that will be used as the source for this list page.'), + '#options' => $entity_type_options, + // If there is no selection, the default entity type will be Node, due to + // self::fillDefaultEntityMetaValues(). + '#default_value' => $form_state->getValue('entity_type') ?? $entity_type_id, + '#required' => TRUE, + '#ajax' => [ + 'callback' => [$this, 'updateEntityBundles'], + 'disable-refocus' => FALSE, + 'event' => 'change', + 'wrapper' => 'list-page-entity-bundles', + ], + ]; + + $bundle_options = []; + if ($selected_entity_type = $form[$key]['entity_type']['#default_value']) { + $bundles = $this->entityTypeBundleInfo->getBundleInfo($selected_entity_type); + foreach ($bundles as $bundle_key => $bundle) { + $bundle_options[$bundle_key] = $bundle['label']; + } + + $event->setBundles($selected_entity_type, array_keys($bundle_options)); + $this->eventDispatcher->dispatch(ListPageEvents::ALTER_BUNDLES, $event); + $bundle_options = array_intersect_key($bundle_options, array_combine($event->getBundles(), $event->getBundles())); + } + + $entity_bundle_id = $entity_meta_wrapper->getSourceEntityBundle(); + + $form[$key]['bundle_wrapper'] = [ + '#type' => 'container', + '#attributes' => [ + 'id' => 'list-page-entity-bundles', + ], + ]; + + if (!empty($form_state->getValue('entity_type')) || $entity_bundle_id) { + $form[$key]['bundle_wrapper']['bundle'] = [ + '#type' => 'select', + '#title' => $this->t('Source bundle'), + '#default_value' => $form_state->getValue('bundle') ?? $entity_bundle_id, + '#options' => $bundle_options, + '#required' => TRUE, + ]; + } + + // Set the entity meta so we use it in the submit handler. + $form_state->set($entity_meta_bundle . '_entity_meta', $entity_meta); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submit(array $form, FormStateInterface $form_state): void { + // Do not save new entity meta if we don't have required values. + if (!$form_state->getValue('entity_type') || !$form_state->getValue('bundle')) { + return; + } + /** @var \Drupal\Core\Entity\ContentEntityInterface $host_entity */ + $host_entity = $form_state->getFormObject()->getEntity(); + + $entity_meta_bundle = $this->getPluginDefinition()['entity_meta_bundle']; + + /** @var \Drupal\emr\Entity\EntityMetaInterface $entity_meta */ + $entity_meta = $form_state->get($entity_meta_bundle . '_entity_meta'); + /** @var \Drupal\oe_list_pages\ListPageWrapper $entity_meta_wrapper */ + $entity_meta_wrapper = $entity_meta->getWrapper(); + + $entity_meta_wrapper->setSource($form_state->getValue('entity_type'), $form_state->getValue('bundle')); + $host_entity->get('emr_entity_metas')->attach($entity_meta); + } + + /** + * {@inheritdoc} + */ + public function fillDefaultEntityMetaValues(EntityMetaInterface $entity_meta): void { + // Set the default value to be the first node bundle. + // We want to do this because we don't want any entity meta being created + // without a value (via the API). + $bundles = $this->entityTypeBundleInfo->getBundleInfo('node'); + /** @var \Drupal\oe_list_pages\ListPageWrapper $wrapper */ + $wrapper = $entity_meta->getWrapper(); + $wrapper->setSource('node', key($bundles)); + } + +} diff --git a/tests/FunctionalJavascript/ListPagesPluginTest.php b/tests/FunctionalJavascript/ListPagesPluginTest.php new file mode 100755 index 00000000..c07ac39f --- /dev/null +++ b/tests/FunctionalJavascript/ListPagesPluginTest.php @@ -0,0 +1,242 @@ +drupalCreateContentType([ + 'type' => 'node_type_one', + 'name' => 'Node Type 1', + ]); + + $this->drupalCreateContentType([ + 'type' => 'node_type_two', + 'name' => 'Node Type 2', + ]); + + $this->drupalCreateContentType([ + 'type' => 'node_type_three', + 'name' => 'Node Type 3', + ]); + + Vocabulary::create([ + 'vid' => 'vocab_one', + 'name' => 'Vocabulary 1', + ])->save(); + + Vocabulary::create([ + 'vid' => 'vocab_two', + 'name' => 'Vocabulary 2', + ])->save(); + + Vocabulary::create([ + 'vid' => 'vocab_three', + 'name' => 'Vocabulary 3', + ])->save(); + + /** @var \Drupal\emr\EntityMetaRelationInstaller $installer */ + $installer = \Drupal::service('emr.installer'); + $installer->installEntityMetaTypeOnContentEntityType('oe_list_page', 'node', [ + 'node_type_one', + ]); + } + + /** + * Test List Page entity meta plugin and available entity types/bundles. + */ + public function testListPagePluginForm(): void { + $this->drupalLogin($this->rootUser); + $this->drupalGet('node/add/node_type_one'); + + // Open the list page details element. + $this->clickLink('List Page'); + + $actual_entity_types = $this->getSelectOptions('Source entity type'); + + $expected_entity_types = [ + 'entity_meta_relation' => 'Entity Meta Relation', + 'entity_meta' => 'Entity meta', + 'node' => 'Content', + 'path_alias' => 'URL alias', + 'search_api_task' => 'Search task', + 'user' => 'User', + 'taxonomy_term' => 'Taxonomy term', + ]; + $this->assertEquals($expected_entity_types, $actual_entity_types); + // By default, Node is selected if there are no stored values. + $this->assertOptionSelected('Source entity type', 'Content'); + + $actual_bundles = $this->getSelectOptions('Source bundle'); + $expected_bundles = [ + 'node_type_one' => 'Node Type 1', + 'node_type_two' => 'Node Type 2', + 'node_type_three' => 'Node Type 3', + ]; + $this->assertEquals($expected_bundles, $actual_bundles); + + // Switch to the taxonomy term and assert that we have different bundles. + $this->getSession()->getPage()->selectFieldOption('Source entity type', 'taxonomy_term'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $actual_bundles = $this->getSelectOptions('Source bundle'); + $expected_bundles = [ + 'vocab_one' => 'Vocabulary 1', + 'vocab_two' => 'Vocabulary 2', + 'vocab_three' => 'Vocabulary 3', + ]; + $this->assertEquals($expected_bundles, $actual_bundles); + + // Switch to a bundle-less entity type and assert we have only one bundle + // selection available. + $this->getSession()->getPage()->selectFieldOption('Source entity type', 'user'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $actual_bundles = $this->getSelectOptions('Source bundle'); + $expected_bundles = [ + 'user' => 'User', + ]; + $this->assertEquals($expected_bundles, $actual_bundles); + + // Set state values to trigger the test event subscriber and make some + // limitations. + $allowed = [ + 'node' => [ + 'node_type_two', + 'node_type_three', + ], + 'taxonomy_term' => [ + 'vocab_one', + 'vocab_three', + ], + ]; + \Drupal::state()->set('oe_list_pages_test.allowed_entity_types_bundles', $allowed); + + $this->drupalGet('node/add/node_type_one'); + $this->clickLink('List Page'); + $actual_entity_types = $this->getSelectOptions('Source entity type'); + $this->assertEquals([ + 'node' => 'Content', + 'taxonomy_term' => 'Taxonomy term', + ], $actual_entity_types); + $this->assertOptionSelected('Source entity type', 'Content'); + $actual_bundles = $this->getSelectOptions('Source bundle'); + $expected_bundles = [ + 'node_type_two' => 'Node Type 2', + 'node_type_three' => 'Node Type 3', + ]; + $this->assertEquals($expected_bundles, $actual_bundles); + $this->getSession()->getPage()->selectFieldOption('Source entity type', 'taxonomy_term'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $actual_bundles = $this->getSelectOptions('Source bundle'); + $expected_bundles = [ + 'vocab_one' => 'Vocabulary 1', + 'vocab_three' => 'Vocabulary 3', + ]; + $this->assertEquals($expected_bundles, $actual_bundles); + + // Select a bundle and save the node. + $this->getSession()->getPage()->fillField('Title', 'Node title'); + $this->getSession()->getPage()->selectFieldOption('Source bundle', 'vocab_three'); + $this->getSession()->getPage()->pressButton('Save'); + + // Assert the entity meta was correctly saved. + $node = Node::load(1); + $this->assertEquals(1, $node->getRevisionId()); + $this->assertEquals('Node title', $node->label()); + /** @var \Drupal\emr\Field\ComputedEntityMetasItemList $entity_meta_list */ + $entity_meta_list = $node->get('emr_entity_metas'); + $entity_meta = $entity_meta_list->getEntityMeta('oe_list_page'); + $this->assertFalse($entity_meta->isNew()); + + /** @var \Drupal\oe_list_pages\ListPageWrapper $entity_meta_wrapper */ + $entity_meta_wrapper = $entity_meta->getWrapper(); + $this->assertEquals('taxonomy_term:vocab_three', $entity_meta_wrapper->getSource()); + $this->assertEquals('taxonomy_term', $entity_meta_wrapper->getSourceEntityType()); + $this->assertEquals('vocab_three', $entity_meta_wrapper->getSourceEntityBundle()); + + // Edit the node and assert that we show correct values in the form. + $this->drupalGet($node->toUrl('edit-form')); + $this->clickLink('List Page'); + $this->assertOptionSelected('Source entity type', 'Taxonomy term'); + $this->assertOptionSelected('Source bundle', 'Vocabulary 3'); + + // Change the source to a Node type. + $this->getSession()->getPage()->fillField('Title', 'Node title 2'); + $this->getSession()->getPage()->selectFieldOption('Source entity type', 'node'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $this->getSession()->getPage()->selectFieldOption('Source bundle', 'node_type_two'); + $this->getSession()->getPage()->pressButton('Save'); + + \Drupal::entityTypeManager()->getStorage('node')->resetCache(); + $node = Node::load(1); + $this->assertEquals(2, $node->getRevisionId()); + /** @var \Drupal\emr\Field\ComputedEntityMetasItemList $entity_meta_list */ + $entity_meta_list = $node->get('emr_entity_metas'); + $entity_meta = $entity_meta_list->getEntityMeta('oe_list_page'); + $entity_meta_wrapper = $entity_meta->getWrapper(); + $this->assertEquals('node:node_type_two', $entity_meta_wrapper->getSource()); + $this->assertEquals('node', $entity_meta_wrapper->getSourceEntityType()); + $this->assertEquals('node_type_two', $entity_meta_wrapper->getSourceEntityBundle()); + + // Assert the previous entity meta revision kept the old value. + $first_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision(1); + $this->assertEquals(1, $first_revision->getRevisionId()); + /** @var \Drupal\emr\Field\ComputedEntityMetasItemList $entity_meta_list */ + $entity_meta_list = $first_revision->get('emr_entity_metas'); + $entity_meta = $entity_meta_list->getEntityMeta('oe_list_page'); + $this->assertFalse($entity_meta->isNew()); + + /** @var \Drupal\oe_list_pages\ListPageWrapper $entity_meta_wrapper */ + $entity_meta_wrapper = $entity_meta->getWrapper(); + $this->assertEquals('taxonomy_term:vocab_three', $entity_meta_wrapper->getSource()); + $this->assertEquals('taxonomy_term', $entity_meta_wrapper->getSourceEntityType()); + $this->assertEquals('vocab_three', $entity_meta_wrapper->getSourceEntityBundle()); + } + + /** + * Get available options of select box. + * + * @param string $field + * The label, id or name of select box. + * + * @return array + * Select box options. + */ + protected function getSelectOptions(string $field): array { + $page = $this->getSession()->getPage(); + $options = $page->findField($field)->findAll('css', 'option'); + $actual_options = []; + foreach ($options as $option) { + $actual_options[$option->getValue()] = $option->getText(); + } + return $actual_options; + } + +} diff --git a/tests/Kernel/ListPagesTest.php b/tests/Kernel/ListPagesTest.php new file mode 100644 index 00000000..9aa8b566 --- /dev/null +++ b/tests/Kernel/ListPagesTest.php @@ -0,0 +1,106 @@ +installConfig(['oe_list_pages', 'emr', 'emr_node']); + $this->installSchema('node', ['node_access']); + $this->installEntitySchema('node'); + $this->installEntitySchema('entity_meta'); + $this->installEntitySchema('entity_meta_relation'); + + $values = ['type' => 'list_page', 'name' => 'List page']; + $this->nodeType = NodeType::create($values); + $this->nodeType->save(); + + /** @var \Drupal\emr\EntityMetaRelationInstaller $installer */ + $installer = \Drupal::service('emr.installer'); + $installer->installEntityMetaTypeOnContentEntityType('oe_list_page', 'node', [ + 'list_page', + ]); + + $this->nodeStorage = $this->entityTypeManager->getStorage('node'); + $this->entityMetaStorage = $this->entityTypeManager->getStorage('entity_meta'); + } + + /** + * Tests that node works correctly with entity meta. + */ + public function testListPagesEntityMeta(): void { + $node_storage = $this->entityTypeManager->getStorage('node'); + $node = $node_storage->create([ + 'type' => $this->nodeType->id(), + 'title' => 'List Page', + ]); + $node->save(); + + /** @var \Drupal\emr\Entity\EntityMetaInterface $entity_meta */ + $entity_meta = $node->get('emr_entity_metas')->getEntityMeta('oe_list_page'); + $this->assertFalse($entity_meta->isNew()); + /** @var \Drupal\oe_list_pages\ListPageWrapper $wrapper */ + $wrapper = $entity_meta->getWrapper(); + $this->assertEquals('node:list_page', $wrapper->getSource()); + $this->assertEquals([], $wrapper->getConfiguration()); + $wrapper->setSource('node', 'list_page'); + $wrapper->setConfiguration(['exposed' => ['list']]); + $node->get('emr_entity_metas')->attach($entity_meta); + $node->save(); + + $updated_node = $node_storage->load($node->id()); + /** @var \Drupal\emr\Entity\EntityMetaInterface $entity_meta */ + $entity_meta = $updated_node->get('emr_entity_metas') + ->getEntityMeta('oe_list_page'); + + /** @var \Drupal\oe_list_pages\ListPageWrapper $wrapper */ + $wrapper = $entity_meta->getWrapper(); + $this->assertEquals($wrapper->getConfiguration(), ['exposed' => ['list']]); + } + +} diff --git a/tests/modules/oe_list_pages_test/oe_list_pages_test.info.yml b/tests/modules/oe_list_pages_test/oe_list_pages_test.info.yml new file mode 100755 index 00000000..d76a1428 --- /dev/null +++ b/tests/modules/oe_list_pages_test/oe_list_pages_test.info.yml @@ -0,0 +1,9 @@ +name: OpenEuropa List Pages +type: module +description: The test module for OE List Pages. + +package: Testing +core: 8.x + +dependencies: + - oe_list_pages diff --git a/tests/modules/oe_list_pages_test/oe_list_pages_test.services.yml b/tests/modules/oe_list_pages_test/oe_list_pages_test.services.yml new file mode 100755 index 00000000..f6862f0f --- /dev/null +++ b/tests/modules/oe_list_pages_test/oe_list_pages_test.services.yml @@ -0,0 +1,6 @@ +services: + oe_list_pages_test.event_subscriber: + class: Drupal\oe_list_pages_test\EventSubscriber\ListPagesTestSubscriber + arguments: ['@state'] + tags: + - { name: event_subscriber } diff --git a/tests/modules/oe_list_pages_test/src/EventSubscriber/ListPagesTestSubscriber.php b/tests/modules/oe_list_pages_test/src/EventSubscriber/ListPagesTestSubscriber.php new file mode 100755 index 00000000..f6392fd0 --- /dev/null +++ b/tests/modules/oe_list_pages_test/src/EventSubscriber/ListPagesTestSubscriber.php @@ -0,0 +1,82 @@ +state = $state; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + return [ + ListPageEvents::ALTER_ENTITY_TYPES => ['onEntityTypesAlter'], + ListPageEvents::ALTER_BUNDLES => ['onBundlesAlter'], + ]; + } + + /** + * Event handler for limiting the allowed entity types. + * + * @param \Drupal\oe_list_pages\ListPageSourceAlterEvent $event + * The event object. + */ + public function onEntityTypesAlter(ListPageSourceAlterEvent $event): void { + $entity_types = $event->getEntityTypes(); + $allowed = $this->state->get('oe_list_pages_test.allowed_entity_types_bundles'); + if ($allowed === NULL) { + return; + } + + $allowed_entity_types = array_keys($allowed); + $event->setEntityTypes(array_intersect($entity_types, $allowed_entity_types)); + } + + /** + * Event handler for limiting the allowed bundles. + * + * @param \Drupal\oe_list_pages\ListPageSourceAlterEvent $event + * The event object. + */ + public function onBundlesAlter(ListPageSourceAlterEvent $event): void { + $entity_types = $event->getEntityTypes(); + $entity_type = reset($entity_types); + $bundles = $event->getBundles(); + + $allowed = $this->state->get('oe_list_pages_test.allowed_entity_types_bundles'); + if ($allowed === NULL) { + return; + } + + $allowed_bundles = $allowed[$entity_type] ?? []; + + $event->setBundles($entity_type, array_intersect($bundles, $allowed_bundles)); + } + +}