diff --git a/core/modules/content_moderation/content_moderation.module b/core/modules/content_moderation/content_moderation.module index 5a7af0e..fa70153 100644 --- a/core/modules/content_moderation/content_moderation.module +++ b/core/modules/content_moderation/content_moderation.module @@ -278,6 +278,10 @@ function content_moderation_workflow_insert(WorkflowInterface $entity) { \Drupal::service('entity_type.bundle.info')->clearCachedBundles(); // Clear field cache so extra field is added or removed. \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); + // Update views data to add the new filters. + if (\Drupal::moduleHandler()->moduleExists('views')) { + \Drupal::service('views.views_data')->clear(); + } } /** @@ -289,6 +293,10 @@ function content_moderation_workflow_update(WorkflowInterface $entity) { \Drupal::service('entity_type.bundle.info')->clearCachedBundles(); // Clear field cache so extra field is added or removed. \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); + // Update views data to add the new filters. + if (\Drupal::moduleHandler()->moduleExists('views')) { + \Drupal::service('views.views_data')->clear(); + } } /** diff --git a/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php b/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php index 20cfa57..b82b3b3 100644 --- a/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php +++ b/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php @@ -27,11 +27,19 @@ class ModerationStateFilter extends InOperator { protected $entityTypeManager; /** + * The workflow this filter is attached to. + * + * @var \Drupal\workflows\WorkflowInterface + */ + protected $workflow; + + /** * Creates an instance of ModerationStateFilter. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->entityTypeManager = $entity_type_manager; + $this->workflow = Workflow::load($this->configuration['workflow']); } /** @@ -50,14 +58,14 @@ public static function create(ContainerInterface $container, array $configuratio * {@inheritdoc} */ public function getCacheTags() { - return Cache::mergeTags(parent::getCacheTags(), $this->entityTypeManager->getDefinition('workflow')->getListCacheTags()); + return Cache::mergeTags(parent::getCacheTags(), $this->workflow->getCacheTags()); } /** * {@inheritdoc} */ public function getCacheContexts() { - return Cache::mergeContexts(parent::getCacheContexts(), $this->entityTypeManager->getDefinition('workflow')->getListCacheContexts()); + return Cache::mergeContexts(parent::getCacheContexts(), $this->workflow->getCacheContexts()); } /** @@ -67,11 +75,9 @@ public function getValueOptions() { if (isset($this->valueOptions)) { return $this->valueOptions; } - $workflow = Workflow::load($this->configuration['workflow']); - $states = $workflow->getTypePlugin()->getStates(); $this->valueOptions = array_map(function (StateInterface $state) { return $state->label(); - }, $states); + }, $this->workflow ->getTypePlugin()->getStates()); return $this->valueOptions; } @@ -101,7 +107,7 @@ public function ensureMyTable() { ], [ 'field' => 'workflow', - 'value' => $this->configuration['workflow'], + 'value' => $this->workflow->id(), ], ], ]; @@ -122,12 +128,9 @@ public function ensureMyTable() { * {@inheritdoc} */ public function calculateDependencies() { - // Do not depend on the workflows which provide states that are utilised - // in the filter. States cannot be depended on directly and can also be - // common across multiple workflows. States and workflows with existing - // content cannot be deleted, so the impact of not depending on them here is - // mitigated. - return parent::calculateDependencies(); + $dependencies = parent::calculateDependencies(); + $dependencies[$this->workflow->getConfigDependencyKey()][] = $this->workflow->getConfigDependencyName(); + return $dependencies; } } diff --git a/core/modules/content_moderation/src/ViewsData.php b/core/modules/content_moderation/src/ViewsData.php index e050935..086045d 100644 --- a/core/modules/content_moderation/src/ViewsData.php +++ b/core/modules/content_moderation/src/ViewsData.php @@ -67,27 +67,49 @@ public function getViewsData() { foreach ($entity_types_with_moderation as $entity_type_id => $entity_type) { $table = $entity_type->getDataTable() ?: $entity_type->getBaseTable(); + $data[$table]['moderation_state'] = [ + 'title' => t('Moderation state'), + 'relationship' => [ + 'id' => 'standard', + 'label' => $this->t('@label moderation state', ['@label' => $entity_type->getLabel()]), + 'base' => $content_moderation_state_entity_base_table, + 'base field' => 'content_entity_id', + 'relationship field' => $entity_type->getKey('id'), + 'extra' => [ + [ + 'field' => 'content_entity_type_id', + 'value' => $entity_type_id, + ], + ], + ], + 'field' => ['default_formatter' => 'content_moderation_state'], + ]; + + $revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable(); + $data[$revision_table]['moderation_state'] = [ + 'title' => t('Moderation state'), + 'relationship' => [ + 'id' => 'standard', + 'label' => $this->t('@label moderation state', ['@label' => $entity_type->getLabel()]), + 'base' => $content_moderation_state_entity_revision_base_table, + 'base field' => 'content_entity_revision_id', + 'relationship field' => $entity_type->getKey('revision'), + 'extra' => [ + [ + 'field' => 'content_entity_type_id', + 'value' => $entity_type_id, + ], + ], + ], + 'field' => ['default_formatter' => 'content_moderation_state'], + ]; + foreach ($workflows as $workflow) { if (!in_array($entity_type_id, $workflow->getTypePlugin()->getEntityTypes())) { continue; } - $data[$table]['moderation_state__' . $workflow->id()] = [ 'title' => t('Moderation state (@workflow)', ['@workflow' => $workflow->label()]), - 'relationship' => [ - 'id' => 'standard', - 'label' => $this->t('@label moderation state', ['@label' => $entity_type->getLabel()]), - 'base' => $content_moderation_state_entity_base_table, - 'base field' => 'content_entity_id', - 'relationship field' => $entity_type->getKey('id'), - 'extra' => [ - [ - 'field' => 'content_entity_type_id', - 'value' => $entity_type_id, - ], - ], - ], - 'field' => ['default_formatter' => 'content_moderation_state'], 'filter' => [ 'id' => 'moderation_state_filter', 'allow empty' => TRUE, @@ -95,24 +117,8 @@ public function getViewsData() { 'field' => 'moderation_state', ], ]; - - $revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable(); $data[$revision_table]['moderation_state__' . $workflow->id()] = [ 'title' => t('Moderation state (@workflow)', ['@workflow' => $workflow->label()]), - 'relationship' => [ - 'id' => 'standard', - 'label' => $this->t('@label moderation state', ['@label' => $entity_type->getLabel()]), - 'base' => $content_moderation_state_entity_revision_base_table, - 'base field' => 'content_entity_revision_id', - 'relationship field' => $entity_type->getKey('revision'), - 'extra' => [ - [ - 'field' => 'content_entity_type_id', - 'value' => $entity_type_id, - ], - ], - ], - 'field' => ['default_formatter' => 'content_moderation_state'], 'filter' => [ 'id' => 'moderation_state_filter', 'allow empty' => TRUE, @@ -121,7 +127,6 @@ public function getViewsData() { ], ]; } - } return $data; diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter.yml b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter.yml index 5a25c11..5da3f08 100644 --- a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter.yml +++ b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter.yml @@ -2,6 +2,8 @@ uuid: 3c177a50-5e2c-457c-ad87-3587641d38ec langcode: en status: true dependencies: + config: + - workflows.workflow.editorial module: - content_moderation - node @@ -132,10 +134,10 @@ display: entity_field: nid plugin_id: field filters: - moderation_state: - id: moderation_state + moderation_state__editorial: + id: moderation_state__editorial table: node_field_data - field: moderation_state + field: moderation_state__editorial relationship: none group_type: group admin_label: '' @@ -144,11 +146,11 @@ display: group: 1 exposed: true expose: - operator_id: moderation_state_op + operator_id: moderation_state__editorial_op label: 'Default Revision State' description: '' use_operator: false - operator: moderation_state_op + operator: moderation_state__editorial_op identifier: default_revision_state required: false remember: false @@ -172,10 +174,10 @@ display: group_items: { } entity_type: node plugin_id: moderation_state_filter - moderation_state_1: - id: moderation_state_1 + moderation_state__editorial_1: + id: moderation_state__editorial_1 table: node_field_data - field: moderation_state + field: moderation_state__editorial relationship: none group_type: group admin_label: '' @@ -226,7 +228,7 @@ display: - 'user.node_grants:view' - user.permissions tags: - - 'config:workflow_list' + - 'config:workflows.workflow.editorial' page_1: display_plugin: page id: page_1 @@ -244,5 +246,4 @@ display: - 'user.node_grants:view' - user.permissions tags: - - 'config:workflow_list' - + - 'config:workflows.workflow.editorial' diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_entity_test.yml b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_entity_test.yml index c902ee2..18041de 100644 --- a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_entity_test.yml +++ b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_entity_test.yml @@ -2,6 +2,8 @@ uuid: f4dd0f80-d28c-4212-ae44-8ab081d1b2d8 langcode: en status: true dependencies: + config: + - workflows.workflow.editorial module: - content_moderation - entity_test @@ -113,10 +115,10 @@ display: hide_alter_empty: true plugin_id: standard filters: - moderation_state: - id: moderation_state + moderation_state__editorial: + id: moderation_state__editorial table: entity_test_no_bundle - field: moderation_state + field: moderation_state__editorial relationship: none group_type: group admin_label: '' @@ -165,5 +167,5 @@ display: contexts: - 'languages:language_interface' - url - tags: { } - + tags: + - 'config:workflows.workflow.editorial' diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_revision_table.yml b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_revision_table.yml index 9005e99..b92c1a6 100644 --- a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_revision_table.yml +++ b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_state_filter_revision_table.yml @@ -145,10 +145,10 @@ display: entity_field: nid plugin_id: field filters: - moderation_state: - id: moderation_state + moderation_state__editorial: + id: moderation_state__editorial table: node_field_revision - field: moderation_state + field: moderation_state__editorial relationship: none group_type: group admin_label: '' diff --git a/core/modules/content_moderation/tests/src/Functional/ViewsModerationStateFilterTest.php b/core/modules/content_moderation/tests/src/Functional/ViewsModerationStateFilterTest.php index 70a4897..8b06edd 100644 --- a/core/modules/content_moderation/tests/src/Functional/ViewsModerationStateFilterTest.php +++ b/core/modules/content_moderation/tests/src/Functional/ViewsModerationStateFilterTest.php @@ -17,14 +17,11 @@ class ViewsModerationStateFilterTest extends BrowserTestBase { * {@inheritdoc} */ public static $modules = [ - 'content_moderation_test_views', 'node', 'content_moderation', 'workflows', - 'workflow_type_test', - 'entity_test', + 'views', 'language', - 'content_translation', ]; /** @@ -34,18 +31,14 @@ protected function setUp() { parent::setUp(); NodeType::create([ - 'type' => 'example_a', - ])->save(); - NodeType::create([ - 'type' => 'example_b', + 'type' => 'example', ])->save(); - $new_workflow = Workflow::create([ - 'type' => 'content_moderation', - 'id' => 'new_workflow', - ]); - $new_workflow->getTypePlugin()->addState('bar', 'Bar'); - $new_workflow->save(); + $workflow = Workflow::load('editorial'); + $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example'); + $workflow->save(); + + $this->container->get('module_installer')->install(['content_moderation_test_views']); $this->drupalLogin($this->drupalCreateUser(['administer workflows'])); } @@ -54,14 +47,6 @@ protected function setUp() { * Tests the content moderation state filter caching is correct. */ public function testFilterRenderCache() { - // Initially there should be no filters. - $this->assertFilterStates(['All']); - - // Adding the "example_a" bundle to editorial will display all editorial - // states. - $this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [ - 'bundles[example_a]' => TRUE, - ], 'Save'); $this->assertFilterStates(['All', 'draft', 'published', 'archived']); // Adding a new state to the editorial workflow will display that state in @@ -71,12 +56,6 @@ public function testFilterRenderCache() { 'id' => 'foo', ], 'Save'); $this->assertFilterStates(['All', 'draft', 'published', 'archived', 'foo']); - - // Adding a second workflow to nodes will also show new states. - $this->drupalPostForm('admin/config/workflow/workflows/manage/new_workflow/type/node', [ - 'bundles[example_b]' => TRUE, - ], 'Save'); - $this->assertFilterStates(['All', 'draft', 'published', 'archived', 'foo', 'bar']); } /** diff --git a/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php b/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php index b5db1ba..b01ea73 100644 --- a/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php +++ b/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php @@ -170,60 +170,26 @@ public function testNonTranslateableEntityType() { * Tests the list of states in the filter plugin. */ public function testStateFilterStatesList() { - // By default a view of nodes will not have states to filter. - $this->assertPluginStates([]); - - // Adding a content type to the editorial workflow will enable all of the - // editorial states. - $workflow = Workflow::load('editorial'); - $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example'); - $workflow->save(); $this->assertPluginStates([ 'draft' => 'Draft', 'published' => 'Published', 'archived' => 'Archived', ]); - - // Adding a workflow which is not content moderation will not add any - // additional states to the views filter. - $workflow = Workflow::create(['id' => 'test', 'type' => 'workflow_type_complex_test']); - $workflow->getTypePlugin()->addState('draft', 'Draft'); - $workflow->save(); - $this->assertPluginStates([ - 'draft' => 'Draft', - 'published' => 'Published', - 'archived' => 'Archived', - ]); - - // Adding a new content moderation workflow will add additional states to - // filter. - $workflow = Workflow::create(['id' => 'moderation_test', 'type' => 'content_moderation']); - $workflow->getTypePlugin()->addState('foo', 'Foo State'); - $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example'); + // Deleting a state from a workflow will remove the state from the filter. + $workflow = Workflow::load('editorial'); + $workflow->getTypePlugin()->deleteState('archived'); $workflow->save(); $this->assertPluginStates([ 'draft' => 'Draft', 'published' => 'Published', - 'archived' => 'Archived', - 'foo' => 'Foo State', - ]); - - // Deleting a workflow will remove the states from the filter. - $workflow = Workflow::load('moderation_test'); - $workflow->delete(); - $this->assertPluginStates([ - 'draft' => 'Draft', - 'published' => 'Published', - 'archived' => 'Archived', ]); - - // Deleting a state from a workflow will remove the state from the filter. - $workflow = Workflow::load('editorial'); - $workflow->getTypePlugin()->deleteState('archived'); + // Adding a state will make it appear in the filter. + $workflow->getTypePlugin()->addState('foo', 'Foo'); $workflow->save(); $this->assertPluginStates([ 'draft' => 'Draft', 'published' => 'Published', + 'foo' => 'Foo', ]); } @@ -234,7 +200,9 @@ public function testStateFilterStatesList() { * The states which should appear in the filter. */ protected function assertPluginStates($states) { - $plugin = Views::pluginManager('filter')->createInstance('moderation_state_filter', []); + $plugin = Views::pluginManager('filter')->createInstance('moderation_state_filter', [ + 'workflow' => 'editorial', + ]); $view = Views::getView('test_content_moderation_state_filter'); $plugin->init($view, $view->getDisplay()); $this->assertEquals($states, $plugin->getValueOptions()); @@ -255,18 +223,6 @@ protected function assertNodesWithFilters(array $nodes, array $filters, $view_id $view->setExposedInput($filters); $view->execute(); - // Verify the join configuration. - $query = $view->getQuery(); - $join = $query->getTableInfo('content_moderation_state')['join']; - $configuration = $join->configuration; - $this->assertEquals('content_moderation_state_field_revision', $configuration['table']); - $this->assertEquals('content_entity_revision_id', $configuration['field']); - $this->assertEquals('vid', $configuration['left_field']); - $this->assertEquals('content_entity_type_id', $configuration['extra'][0]['field']); - $this->assertEquals('node', $configuration['extra'][0]['value']); - $this->assertEquals('langcode', $configuration['extra'][1]['field']); - $this->assertEquals('langcode', $configuration['extra'][1]['left_field']); - $expected_result = []; foreach ($nodes as $node) { $expected_result[] = ['nid' => $node->id()];