Issue #2862041 by Sam152, amateescu, timmillwood, jibran, hamrant, dawehner, plach, Manuel Garcia, Jo Fitzgerald, mgalalm, xjm, larowlan, webchick, Wim Leers, gambry, kkus, tim.plunkett, tedbow, CatherineOmega: Provide useful Views filters for Content Moderation State fields
parent
45662bb9e2
commit
418e4991b5
|
@ -0,0 +1,18 @@
|
||||||
|
views.filter.latest_revision:
|
||||||
|
type: views_filter
|
||||||
|
label: 'Latest revision'
|
||||||
|
mapping:
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
|
label: 'Value'
|
||||||
|
|
||||||
|
views.filter.moderation_state_filter:
|
||||||
|
type: views.filter.in_operator
|
||||||
|
label: 'Moderation state filter'
|
||||||
|
mapping:
|
||||||
|
limit_workflows:
|
||||||
|
type: sequence
|
||||||
|
label: 'Workflow'
|
||||||
|
sequence:
|
||||||
|
type: string
|
||||||
|
label: 'Workflow'
|
|
@ -0,0 +1,291 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\content_moderation\Plugin\views\filter;
|
||||||
|
|
||||||
|
use Drupal\Core\Cache\Cache;
|
||||||
|
use Drupal\Core\Database\Query\Condition;
|
||||||
|
use Drupal\Core\Entity\EntityStorageInterface;
|
||||||
|
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||||
|
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||||
|
use Drupal\views\Plugin\DependentWithRemovalPluginInterface;
|
||||||
|
use Drupal\views\Plugin\views\filter\InOperator;
|
||||||
|
use Drupal\views\Views;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a filter for the moderation state of an entity.
|
||||||
|
*
|
||||||
|
* @ingroup views_filter_handlers
|
||||||
|
*
|
||||||
|
* @ViewsFilter("moderation_state_filter")
|
||||||
|
*/
|
||||||
|
class ModerationStateFilter extends InOperator implements DependentWithRemovalPluginInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected $valueFormType = 'select';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity type manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||||
|
*/
|
||||||
|
protected $entityTypeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bundle information service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||||
|
*/
|
||||||
|
protected $bundleInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The storage handler of the workflow entity type.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||||
|
*/
|
||||||
|
protected $workflowStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of ModerationStateFilter.
|
||||||
|
*/
|
||||||
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_info, EntityStorageInterface $workflow_storage) {
|
||||||
|
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||||
|
$this->entityTypeManager = $entity_type_manager;
|
||||||
|
$this->bundleInfo = $bundle_info;
|
||||||
|
$this->workflowStorage = $workflow_storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||||
|
return new static(
|
||||||
|
$configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
$container->get('entity_type.manager'),
|
||||||
|
$container->get('entity_type.bundle.info'),
|
||||||
|
$container->get('entity_type.manager')->getStorage('workflow')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getCacheTags() {
|
||||||
|
return Cache::mergeTags(parent::getCacheTags(), $this->entityTypeManager->getDefinition('workflow')->getListCacheTags());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getCacheContexts() {
|
||||||
|
return Cache::mergeContexts(parent::getCacheContexts(), $this->entityTypeManager->getDefinition('workflow')->getListCacheContexts());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getValueOptions() {
|
||||||
|
if (isset($this->valueOptions)) {
|
||||||
|
return $this->valueOptions;
|
||||||
|
}
|
||||||
|
$this->valueOptions = [];
|
||||||
|
|
||||||
|
// Find all workflows which are moderating entity types of the same type the
|
||||||
|
// view is displaying.
|
||||||
|
foreach ($this->workflowStorage->loadByProperties(['type' => 'content_moderation']) as $workflow) {
|
||||||
|
/** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModerationInterface $workflow_type */
|
||||||
|
$workflow_type = $workflow->getTypePlugin();
|
||||||
|
if (in_array($this->getEntityType(), $workflow_type->getEntityTypes(), TRUE)) {
|
||||||
|
foreach ($workflow_type->getStates() as $state_id => $state) {
|
||||||
|
$this->valueOptions[$workflow->label()][implode('-', [$workflow->id(), $state_id])] = $state->label();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->valueOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function ensureMyTable() {
|
||||||
|
if (!isset($this->tableAlias)) {
|
||||||
|
$table_alias = $this->query->ensureTable($this->table, $this->relationship);
|
||||||
|
|
||||||
|
// Filter the moderation states of the content via the
|
||||||
|
// ContentModerationState field revision table, joining either the entity
|
||||||
|
// field data or revision table. This allows filtering states against
|
||||||
|
// either the default or latest revision, depending on the relationship of
|
||||||
|
// the filter.
|
||||||
|
$left_entity_type = $this->entityTypeManager->getDefinition($this->getEntityType());
|
||||||
|
$entity_type = $this->entityTypeManager->getDefinition('content_moderation_state');
|
||||||
|
$configuration = [
|
||||||
|
'table' => $entity_type->getRevisionDataTable(),
|
||||||
|
'field' => 'content_entity_revision_id',
|
||||||
|
'left_table' => $table_alias,
|
||||||
|
'left_field' => $left_entity_type->getKey('revision'),
|
||||||
|
'extra' => [
|
||||||
|
[
|
||||||
|
'field' => 'content_entity_type_id',
|
||||||
|
'value' => $left_entity_type->id(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
if ($left_entity_type->isTranslatable()) {
|
||||||
|
$configuration['extra'][] = [
|
||||||
|
'field' => $entity_type->getKey('langcode'),
|
||||||
|
'left_field' => $left_entity_type->getKey('langcode'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$join = Views::pluginManager('join')->createInstance('standard', $configuration);
|
||||||
|
$this->tableAlias = $this->query->addRelationship('content_moderation_state', $join, 'content_moderation_state_field_revision');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->tableAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function opSimple() {
|
||||||
|
if (empty($this->value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->ensureMyTable();
|
||||||
|
|
||||||
|
$entity_type = $this->entityTypeManager->getDefinition($this->getEntityType());
|
||||||
|
if ($entity_type->hasKey('bundle')) {
|
||||||
|
// Get a list of bundles that are being moderated by the workflows
|
||||||
|
// configured in this filter.
|
||||||
|
$workflow_ids = $this->getWorkflowIds();
|
||||||
|
$moderated_bundles = [];
|
||||||
|
foreach ($this->bundleInfo->getBundleInfo($this->getEntityType()) as $bundle_id => $bundle) {
|
||||||
|
if (isset($bundle['workflow']) && in_array($bundle['workflow'], $workflow_ids, TRUE)) {
|
||||||
|
$moderated_bundles[] = $bundle_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a list of moderated bundles, restrict the query to show only
|
||||||
|
// entities in those bundles.
|
||||||
|
if ($moderated_bundles) {
|
||||||
|
$entity_base_table_alias = $this->table;
|
||||||
|
|
||||||
|
// The bundle field of an entity type is not revisionable so we need to
|
||||||
|
// join the data table.
|
||||||
|
$entity_base_table = $entity_type->isTranslatable() ? $entity_type->getDataTable() : $entity_type->getBaseTable();
|
||||||
|
$entity_revision_base_table = $entity_type->isTranslatable() ? $entity_type->getRevisionDataTable() : $entity_type->getRevisionTable();
|
||||||
|
if ($this->table === $entity_revision_base_table) {
|
||||||
|
$configuration = [
|
||||||
|
'table' => $entity_base_table,
|
||||||
|
'field' => $entity_type->getKey('id'),
|
||||||
|
'left_table' => $entity_revision_base_table,
|
||||||
|
'left_field' => $entity_type->getKey('id'),
|
||||||
|
'type' => 'INNER',
|
||||||
|
];
|
||||||
|
if ($entity_type->isTranslatable()) {
|
||||||
|
$configuration['extra'][] = [
|
||||||
|
'field' => $entity_type->getKey('langcode'),
|
||||||
|
'left_field' => $entity_type->getKey('langcode'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$join = Views::pluginManager('join')->createInstance('standard', $configuration);
|
||||||
|
$entity_base_table_alias = $this->query->addRelationship($entity_base_table, $join, $entity_revision_base_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->query->addWhere($this->options['group'], "$entity_base_table_alias.{$entity_type->getKey('bundle')}", $moderated_bundles, 'IN');
|
||||||
|
}
|
||||||
|
// Otherwise, force the query to return an empty result.
|
||||||
|
else {
|
||||||
|
$this->query->addWhereExpression($this->options['group'], '1 = 0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->operator === 'in') {
|
||||||
|
$operator = "=";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$operator = "<>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// The values are strings composed from the workflow ID and the state ID, so
|
||||||
|
// we need to create a complex WHERE condition.
|
||||||
|
$field = new Condition('OR');
|
||||||
|
foreach ((array) $this->value as $value) {
|
||||||
|
list($workflow_id, $state_id) = explode('-', $value, 2);
|
||||||
|
|
||||||
|
$and = new Condition('AND');
|
||||||
|
$and
|
||||||
|
->condition("$this->tableAlias.workflow", $workflow_id, '=')
|
||||||
|
->condition("$this->tableAlias.$this->realField", $state_id, $operator);
|
||||||
|
|
||||||
|
$field->condition($and);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->query->addWhere($this->options['group'], $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function calculateDependencies() {
|
||||||
|
$dependencies = parent::calculateDependencies();
|
||||||
|
|
||||||
|
if ($workflow_ids = $this->getWorkflowIds()) {
|
||||||
|
/** @var \Drupal\workflows\WorkflowInterface $workflow */
|
||||||
|
foreach ($this->workflowStorage->loadMultiple($workflow_ids) as $workflow) {
|
||||||
|
$dependencies[$workflow->getConfigDependencyKey()][] = $workflow->getConfigDependencyName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onDependencyRemoval(array $dependencies) {
|
||||||
|
// See if this handler is responsible for any of the dependencies being
|
||||||
|
// removed. If this is the case, indicate that this handler needs to be
|
||||||
|
// removed from the View.
|
||||||
|
$remove = FALSE;
|
||||||
|
// Get all the current dependencies for this handler.
|
||||||
|
$current_dependencies = $this->calculateDependencies();
|
||||||
|
foreach ($current_dependencies as $group => $dependency_list) {
|
||||||
|
// Check if any of the handler dependencies match the dependencies being
|
||||||
|
// removed.
|
||||||
|
foreach ($dependency_list as $config_key) {
|
||||||
|
if (isset($dependencies[$group]) && array_key_exists($config_key, $dependencies[$group])) {
|
||||||
|
// This handlers dependency matches a dependency being removed,
|
||||||
|
// indicate that this handler needs to be removed.
|
||||||
|
$remove = TRUE;
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $remove;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of Workflow IDs configured for this filter.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* And array of workflow IDs.
|
||||||
|
*/
|
||||||
|
protected function getWorkflowIds() {
|
||||||
|
$workflow_ids = [];
|
||||||
|
foreach ((array) $this->value as $value) {
|
||||||
|
list($workflow_id) = explode('-', $value, 2);
|
||||||
|
$workflow_ids[] = $workflow_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_unique($workflow_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -83,6 +83,7 @@ class ViewsData {
|
||||||
'default_formatter' => 'content_moderation_state',
|
'default_formatter' => 'content_moderation_state',
|
||||||
'field_name' => 'moderation_state',
|
'field_name' => 'moderation_state',
|
||||||
],
|
],
|
||||||
|
'filter' => ['id' => 'moderation_state_filter', 'allow empty' => TRUE],
|
||||||
];
|
];
|
||||||
|
|
||||||
$revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable();
|
$revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable();
|
||||||
|
@ -106,6 +107,7 @@ class ViewsData {
|
||||||
'default_formatter' => 'content_moderation_state',
|
'default_formatter' => 'content_moderation_state',
|
||||||
'field_name' => 'moderation_state',
|
'field_name' => 'moderation_state',
|
||||||
],
|
],
|
||||||
|
'filter' => ['id' => 'moderation_state_filter', 'allow empty' => TRUE],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
langcode: en
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- content_moderation
|
||||||
|
- node
|
||||||
|
- user
|
||||||
|
id: test_content_moderation_state_filter_base_table
|
||||||
|
label: test_content_moderation_state_filter_base_table
|
||||||
|
module: views
|
||||||
|
description: ''
|
||||||
|
tag: ''
|
||||||
|
base_table: node_field_data
|
||||||
|
base_field: nid
|
||||||
|
core: 8.x
|
||||||
|
display:
|
||||||
|
default:
|
||||||
|
display_plugin: default
|
||||||
|
id: default
|
||||||
|
display_title: Master
|
||||||
|
position: 0
|
||||||
|
display_options:
|
||||||
|
access:
|
||||||
|
type: perm
|
||||||
|
options:
|
||||||
|
perm: 'access content'
|
||||||
|
cache:
|
||||||
|
type: tag
|
||||||
|
options: { }
|
||||||
|
query:
|
||||||
|
type: views_query
|
||||||
|
options:
|
||||||
|
disable_sql_rewrite: false
|
||||||
|
distinct: false
|
||||||
|
replica: false
|
||||||
|
query_comment: ''
|
||||||
|
query_tags: { }
|
||||||
|
exposed_form:
|
||||||
|
type: basic
|
||||||
|
options:
|
||||||
|
submit_button: Apply
|
||||||
|
reset_button: false
|
||||||
|
reset_button_label: Reset
|
||||||
|
exposed_sorts_label: 'Sort by'
|
||||||
|
expose_sort_order: true
|
||||||
|
sort_asc_label: Asc
|
||||||
|
sort_desc_label: Desc
|
||||||
|
pager:
|
||||||
|
type: none
|
||||||
|
options:
|
||||||
|
offset: 0
|
||||||
|
style:
|
||||||
|
type: default
|
||||||
|
options:
|
||||||
|
grouping: { }
|
||||||
|
row_class: ''
|
||||||
|
default_row_class: true
|
||||||
|
uses_fields: false
|
||||||
|
row:
|
||||||
|
type: fields
|
||||||
|
options:
|
||||||
|
inline: { }
|
||||||
|
separator: ''
|
||||||
|
hide_empty: false
|
||||||
|
default_field_elements: true
|
||||||
|
fields:
|
||||||
|
nid:
|
||||||
|
id: nid
|
||||||
|
table: node_field_data
|
||||||
|
field: nid
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
label: ''
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: false
|
||||||
|
text: ''
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: true
|
||||||
|
ellipsis: true
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: false
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
click_sort_column: value
|
||||||
|
type: number_integer
|
||||||
|
settings:
|
||||||
|
thousand_separator: ''
|
||||||
|
prefix_suffix: false
|
||||||
|
group_column: value
|
||||||
|
group_columns: { }
|
||||||
|
group_rows: true
|
||||||
|
delta_limit: 0
|
||||||
|
delta_offset: 0
|
||||||
|
delta_reversed: false
|
||||||
|
delta_first_last: false
|
||||||
|
multi_type: separator
|
||||||
|
separator: ', '
|
||||||
|
field_api_classes: false
|
||||||
|
entity_type: node
|
||||||
|
entity_field: nid
|
||||||
|
plugin_id: field
|
||||||
|
filters:
|
||||||
|
moderation_state:
|
||||||
|
id: moderation_state
|
||||||
|
table: node_field_data
|
||||||
|
field: moderation_state
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
operator: in
|
||||||
|
value: { }
|
||||||
|
group: 1
|
||||||
|
exposed: true
|
||||||
|
expose:
|
||||||
|
operator_id: moderation_state_op
|
||||||
|
label: 'Default Revision State'
|
||||||
|
description: ''
|
||||||
|
use_operator: false
|
||||||
|
operator: moderation_state_op
|
||||||
|
identifier: default_revision_state
|
||||||
|
required: false
|
||||||
|
remember: false
|
||||||
|
multiple: false
|
||||||
|
remember_roles:
|
||||||
|
authenticated: authenticated
|
||||||
|
anonymous: '0'
|
||||||
|
administrator: '0'
|
||||||
|
reduce: false
|
||||||
|
is_grouped: false
|
||||||
|
group_info:
|
||||||
|
label: ''
|
||||||
|
description: ''
|
||||||
|
identifier: ''
|
||||||
|
optional: true
|
||||||
|
widget: select
|
||||||
|
multiple: false
|
||||||
|
remember: false
|
||||||
|
default_group: All
|
||||||
|
default_group_multiple: { }
|
||||||
|
group_items: { }
|
||||||
|
entity_type: node
|
||||||
|
plugin_id: moderation_state_filter
|
||||||
|
moderation_state_1:
|
||||||
|
id: moderation_state_1
|
||||||
|
table: node_field_data
|
||||||
|
field: moderation_state
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
operator: 'not empty'
|
||||||
|
value: { }
|
||||||
|
group: 1
|
||||||
|
exposed: false
|
||||||
|
expose:
|
||||||
|
operator_id: ''
|
||||||
|
label: ''
|
||||||
|
description: ''
|
||||||
|
use_operator: false
|
||||||
|
operator: ''
|
||||||
|
identifier: ''
|
||||||
|
required: false
|
||||||
|
remember: false
|
||||||
|
multiple: false
|
||||||
|
remember_roles:
|
||||||
|
authenticated: authenticated
|
||||||
|
reduce: false
|
||||||
|
is_grouped: false
|
||||||
|
group_info:
|
||||||
|
label: ''
|
||||||
|
description: ''
|
||||||
|
identifier: ''
|
||||||
|
optional: true
|
||||||
|
widget: select
|
||||||
|
multiple: false
|
||||||
|
remember: false
|
||||||
|
default_group: All
|
||||||
|
default_group_multiple: { }
|
||||||
|
group_items: { }
|
||||||
|
entity_type: node
|
||||||
|
plugin_id: moderation_state_filter
|
||||||
|
sorts:
|
||||||
|
nid:
|
||||||
|
id: nid
|
||||||
|
table: node_field_data
|
||||||
|
field: nid
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
order: ASC
|
||||||
|
exposed: false
|
||||||
|
expose:
|
||||||
|
label: ''
|
||||||
|
entity_type: node
|
||||||
|
entity_field: nid
|
||||||
|
plugin_id: standard
|
||||||
|
header: { }
|
||||||
|
footer: { }
|
||||||
|
empty: { }
|
||||||
|
relationships: { }
|
||||||
|
arguments: { }
|
||||||
|
display_extenders: { }
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
tags:
|
||||||
|
- 'config:workflow_list'
|
||||||
|
page_1:
|
||||||
|
display_plugin: page
|
||||||
|
id: page_1
|
||||||
|
display_title: Page
|
||||||
|
position: 1
|
||||||
|
display_options:
|
||||||
|
display_extenders: { }
|
||||||
|
path: filter-test-path
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
tags:
|
||||||
|
- 'config:workflow_list'
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
langcode: en
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- content_moderation
|
||||||
|
- node
|
||||||
|
- user
|
||||||
|
id: test_content_moderation_state_filter_base_table_filter_on_revision
|
||||||
|
label: test_content_moderation_state_filter_base_table_filter_on_revision
|
||||||
|
module: views
|
||||||
|
description: ''
|
||||||
|
tag: ''
|
||||||
|
base_table: node_field_data
|
||||||
|
base_field: nid
|
||||||
|
core: 8.x
|
||||||
|
display:
|
||||||
|
default:
|
||||||
|
display_plugin: default
|
||||||
|
id: default
|
||||||
|
display_title: Master
|
||||||
|
position: 0
|
||||||
|
display_options:
|
||||||
|
access:
|
||||||
|
type: perm
|
||||||
|
options:
|
||||||
|
perm: 'access content'
|
||||||
|
cache:
|
||||||
|
type: tag
|
||||||
|
options: { }
|
||||||
|
query:
|
||||||
|
type: views_query
|
||||||
|
options:
|
||||||
|
disable_sql_rewrite: false
|
||||||
|
distinct: false
|
||||||
|
replica: false
|
||||||
|
query_comment: ''
|
||||||
|
query_tags: { }
|
||||||
|
exposed_form:
|
||||||
|
type: basic
|
||||||
|
options:
|
||||||
|
submit_button: Apply
|
||||||
|
reset_button: false
|
||||||
|
reset_button_label: Reset
|
||||||
|
exposed_sorts_label: 'Sort by'
|
||||||
|
expose_sort_order: true
|
||||||
|
sort_asc_label: Asc
|
||||||
|
sort_desc_label: Desc
|
||||||
|
pager:
|
||||||
|
type: none
|
||||||
|
options:
|
||||||
|
offset: 0
|
||||||
|
style:
|
||||||
|
type: default
|
||||||
|
options:
|
||||||
|
grouping: { }
|
||||||
|
row_class: ''
|
||||||
|
default_row_class: true
|
||||||
|
uses_fields: false
|
||||||
|
row:
|
||||||
|
type: fields
|
||||||
|
options:
|
||||||
|
inline: { }
|
||||||
|
separator: ''
|
||||||
|
hide_empty: false
|
||||||
|
default_field_elements: true
|
||||||
|
fields:
|
||||||
|
nid:
|
||||||
|
id: nid
|
||||||
|
table: node_field_data
|
||||||
|
field: nid
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
label: ''
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: false
|
||||||
|
text: ''
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: true
|
||||||
|
ellipsis: true
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: false
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
click_sort_column: value
|
||||||
|
type: number_integer
|
||||||
|
settings:
|
||||||
|
thousand_separator: ''
|
||||||
|
prefix_suffix: false
|
||||||
|
group_column: value
|
||||||
|
group_columns: { }
|
||||||
|
group_rows: true
|
||||||
|
delta_limit: 0
|
||||||
|
delta_offset: 0
|
||||||
|
delta_reversed: false
|
||||||
|
delta_first_last: false
|
||||||
|
multi_type: separator
|
||||||
|
separator: ', '
|
||||||
|
field_api_classes: false
|
||||||
|
entity_type: node
|
||||||
|
entity_field: nid
|
||||||
|
plugin_id: field
|
||||||
|
filters:
|
||||||
|
moderation_state:
|
||||||
|
id: moderation_state
|
||||||
|
table: node_field_revision
|
||||||
|
field: moderation_state
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
operator: in
|
||||||
|
value: { }
|
||||||
|
group: 1
|
||||||
|
exposed: true
|
||||||
|
expose:
|
||||||
|
operator_id: moderation_state_op
|
||||||
|
label: 'Moderation state'
|
||||||
|
description: ''
|
||||||
|
use_operator: false
|
||||||
|
operator: moderation_state_op
|
||||||
|
identifier: ''
|
||||||
|
required: false
|
||||||
|
remember: false
|
||||||
|
multiple: false
|
||||||
|
remember_roles:
|
||||||
|
authenticated: authenticated
|
||||||
|
anonymous: '0'
|
||||||
|
administrator: '0'
|
||||||
|
reduce: false
|
||||||
|
is_grouped: false
|
||||||
|
group_info:
|
||||||
|
label: ''
|
||||||
|
description: ''
|
||||||
|
identifier: ''
|
||||||
|
optional: true
|
||||||
|
widget: select
|
||||||
|
multiple: false
|
||||||
|
remember: false
|
||||||
|
default_group: All
|
||||||
|
default_group_multiple: { }
|
||||||
|
group_items: { }
|
||||||
|
entity_type: node
|
||||||
|
plugin_id: moderation_state_filter
|
||||||
|
sorts:
|
||||||
|
nid:
|
||||||
|
id: nid
|
||||||
|
table: node_field_data
|
||||||
|
field: nid
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
order: ASC
|
||||||
|
exposed: false
|
||||||
|
expose:
|
||||||
|
label: ''
|
||||||
|
entity_type: node
|
||||||
|
entity_field: nid
|
||||||
|
plugin_id: standard
|
||||||
|
header: { }
|
||||||
|
footer: { }
|
||||||
|
empty: { }
|
||||||
|
relationships: { }
|
||||||
|
arguments: { }
|
||||||
|
display_extenders: { }
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
tags:
|
||||||
|
- 'config:workflow_list'
|
||||||
|
page_1:
|
||||||
|
display_plugin: page
|
||||||
|
id: page_1
|
||||||
|
display_title: Page
|
||||||
|
position: 1
|
||||||
|
display_options:
|
||||||
|
display_extenders: { }
|
||||||
|
path: filter-on-revision-test-path
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
tags:
|
||||||
|
- 'config:workflow_list'
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
langcode: en
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- content_moderation
|
||||||
|
- entity_test
|
||||||
|
id: test_content_moderation_state_filter_entity_test
|
||||||
|
label: test_content_moderation_state_filter_entity_test
|
||||||
|
module: views
|
||||||
|
description: ''
|
||||||
|
tag: ''
|
||||||
|
base_table: entity_test_no_bundle
|
||||||
|
base_field: id
|
||||||
|
core: 8.x
|
||||||
|
display:
|
||||||
|
default:
|
||||||
|
display_plugin: default
|
||||||
|
id: default
|
||||||
|
display_title: Master
|
||||||
|
position: 0
|
||||||
|
display_options:
|
||||||
|
access:
|
||||||
|
type: none
|
||||||
|
options: { }
|
||||||
|
cache:
|
||||||
|
type: tag
|
||||||
|
options: { }
|
||||||
|
query:
|
||||||
|
type: views_query
|
||||||
|
options:
|
||||||
|
disable_sql_rewrite: false
|
||||||
|
distinct: false
|
||||||
|
replica: false
|
||||||
|
query_comment: ''
|
||||||
|
query_tags: { }
|
||||||
|
exposed_form:
|
||||||
|
type: basic
|
||||||
|
options:
|
||||||
|
submit_button: Apply
|
||||||
|
reset_button: false
|
||||||
|
reset_button_label: Reset
|
||||||
|
exposed_sorts_label: 'Sort by'
|
||||||
|
expose_sort_order: true
|
||||||
|
sort_asc_label: Asc
|
||||||
|
sort_desc_label: Desc
|
||||||
|
pager:
|
||||||
|
type: none
|
||||||
|
options:
|
||||||
|
offset: 0
|
||||||
|
style:
|
||||||
|
type: default
|
||||||
|
options:
|
||||||
|
grouping: { }
|
||||||
|
row_class: ''
|
||||||
|
default_row_class: true
|
||||||
|
uses_fields: false
|
||||||
|
row:
|
||||||
|
type: fields
|
||||||
|
options:
|
||||||
|
inline: { }
|
||||||
|
separator: ''
|
||||||
|
hide_empty: false
|
||||||
|
default_field_elements: true
|
||||||
|
fields:
|
||||||
|
entity_id:
|
||||||
|
id: entity_id
|
||||||
|
table: content_revision_tracker
|
||||||
|
field: entity_id
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
label: ''
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: false
|
||||||
|
text: ''
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: true
|
||||||
|
ellipsis: true
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: false
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
plugin_id: standard
|
||||||
|
filters:
|
||||||
|
moderation_state:
|
||||||
|
id: moderation_state
|
||||||
|
table: entity_test_no_bundle
|
||||||
|
field: moderation_state
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
operator: in
|
||||||
|
value: { }
|
||||||
|
group: 1
|
||||||
|
exposed: true
|
||||||
|
expose:
|
||||||
|
operator_id: moderation_state_op
|
||||||
|
label: 'Moderation state'
|
||||||
|
description: ''
|
||||||
|
use_operator: false
|
||||||
|
operator: moderation_state_op
|
||||||
|
identifier: moderation_state
|
||||||
|
required: false
|
||||||
|
remember: false
|
||||||
|
multiple: false
|
||||||
|
remember_roles:
|
||||||
|
authenticated: authenticated
|
||||||
|
anonymous: '0'
|
||||||
|
administrator: '0'
|
||||||
|
reduce: false
|
||||||
|
is_grouped: false
|
||||||
|
group_info:
|
||||||
|
label: ''
|
||||||
|
description: ''
|
||||||
|
identifier: ''
|
||||||
|
optional: true
|
||||||
|
widget: select
|
||||||
|
multiple: false
|
||||||
|
remember: false
|
||||||
|
default_group: All
|
||||||
|
default_group_multiple: { }
|
||||||
|
group_items: { }
|
||||||
|
entity_type: entity_test_no_bundle
|
||||||
|
plugin_id: moderation_state_filter
|
||||||
|
sorts: { }
|
||||||
|
header: { }
|
||||||
|
footer: { }
|
||||||
|
empty: { }
|
||||||
|
relationships: { }
|
||||||
|
arguments: { }
|
||||||
|
display_extenders: { }
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
tags: { }
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
langcode: en
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- content_moderation
|
||||||
|
- user
|
||||||
|
id: test_content_moderation_state_filter_revision_table
|
||||||
|
label: test_content_moderation_state_filter_revision_table
|
||||||
|
module: views
|
||||||
|
description: ''
|
||||||
|
tag: ''
|
||||||
|
base_table: node_field_revision
|
||||||
|
base_field: vid
|
||||||
|
core: 8.x
|
||||||
|
display:
|
||||||
|
default:
|
||||||
|
display_plugin: default
|
||||||
|
id: default
|
||||||
|
display_title: Master
|
||||||
|
position: 0
|
||||||
|
display_options:
|
||||||
|
access:
|
||||||
|
type: perm
|
||||||
|
options:
|
||||||
|
perm: 'view all revisions'
|
||||||
|
cache:
|
||||||
|
type: tag
|
||||||
|
options: { }
|
||||||
|
query:
|
||||||
|
type: views_query
|
||||||
|
options:
|
||||||
|
disable_sql_rewrite: false
|
||||||
|
distinct: false
|
||||||
|
replica: false
|
||||||
|
query_comment: ''
|
||||||
|
query_tags: { }
|
||||||
|
exposed_form:
|
||||||
|
type: basic
|
||||||
|
options:
|
||||||
|
submit_button: Apply
|
||||||
|
reset_button: false
|
||||||
|
reset_button_label: Reset
|
||||||
|
exposed_sorts_label: 'Sort by'
|
||||||
|
expose_sort_order: true
|
||||||
|
sort_asc_label: Asc
|
||||||
|
sort_desc_label: Desc
|
||||||
|
pager:
|
||||||
|
type: mini
|
||||||
|
options:
|
||||||
|
items_per_page: 10
|
||||||
|
offset: 0
|
||||||
|
id: 0
|
||||||
|
total_pages: null
|
||||||
|
expose:
|
||||||
|
items_per_page: false
|
||||||
|
items_per_page_label: 'Items per page'
|
||||||
|
items_per_page_options: '5, 10, 25, 50'
|
||||||
|
items_per_page_options_all: false
|
||||||
|
items_per_page_options_all_label: '- All -'
|
||||||
|
offset: false
|
||||||
|
offset_label: Offset
|
||||||
|
tags:
|
||||||
|
previous: ‹‹
|
||||||
|
next: ››
|
||||||
|
style:
|
||||||
|
type: default
|
||||||
|
options:
|
||||||
|
grouping: { }
|
||||||
|
row_class: ''
|
||||||
|
default_row_class: true
|
||||||
|
uses_fields: false
|
||||||
|
row:
|
||||||
|
type: fields
|
||||||
|
options:
|
||||||
|
inline: { }
|
||||||
|
separator: ''
|
||||||
|
hide_empty: false
|
||||||
|
default_field_elements: true
|
||||||
|
fields:
|
||||||
|
nid:
|
||||||
|
id: nid
|
||||||
|
table: node_field_revision
|
||||||
|
field: nid
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
label: ''
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: false
|
||||||
|
text: ''
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: true
|
||||||
|
ellipsis: true
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: false
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
click_sort_column: value
|
||||||
|
type: number_integer
|
||||||
|
settings:
|
||||||
|
thousand_separator: ''
|
||||||
|
prefix_suffix: true
|
||||||
|
group_column: value
|
||||||
|
group_columns: { }
|
||||||
|
group_rows: true
|
||||||
|
delta_limit: 0
|
||||||
|
delta_offset: 0
|
||||||
|
delta_reversed: false
|
||||||
|
delta_first_last: false
|
||||||
|
multi_type: separator
|
||||||
|
separator: ', '
|
||||||
|
field_api_classes: false
|
||||||
|
entity_type: node
|
||||||
|
entity_field: nid
|
||||||
|
plugin_id: field
|
||||||
|
filters:
|
||||||
|
moderation_state:
|
||||||
|
id: moderation_state
|
||||||
|
table: node_field_revision
|
||||||
|
field: moderation_state
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
operator: in
|
||||||
|
value: { }
|
||||||
|
group: 1
|
||||||
|
exposed: true
|
||||||
|
expose:
|
||||||
|
operator_id: moderation_state_op
|
||||||
|
label: 'Moderation state'
|
||||||
|
description: ''
|
||||||
|
use_operator: false
|
||||||
|
operator: moderation_state_op
|
||||||
|
identifier: moderation_state
|
||||||
|
required: false
|
||||||
|
remember: false
|
||||||
|
multiple: false
|
||||||
|
remember_roles:
|
||||||
|
authenticated: authenticated
|
||||||
|
anonymous: '0'
|
||||||
|
administrator: '0'
|
||||||
|
reduce: false
|
||||||
|
is_grouped: false
|
||||||
|
group_info:
|
||||||
|
label: ''
|
||||||
|
description: ''
|
||||||
|
identifier: ''
|
||||||
|
optional: true
|
||||||
|
widget: select
|
||||||
|
multiple: false
|
||||||
|
remember: false
|
||||||
|
default_group: All
|
||||||
|
default_group_multiple: { }
|
||||||
|
group_items: { }
|
||||||
|
entity_type: node
|
||||||
|
plugin_id: moderation_state_filter
|
||||||
|
sorts:
|
||||||
|
vid:
|
||||||
|
id: vid
|
||||||
|
table: node_field_revision
|
||||||
|
field: vid
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
order: ASC
|
||||||
|
exposed: false
|
||||||
|
expose:
|
||||||
|
label: ''
|
||||||
|
entity_type: node
|
||||||
|
entity_field: vid
|
||||||
|
plugin_id: standard
|
||||||
|
header: { }
|
||||||
|
footer: { }
|
||||||
|
empty: { }
|
||||||
|
relationships: { }
|
||||||
|
arguments: { }
|
||||||
|
display_extenders: { }
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
tags: { }
|
||||||
|
|
|
@ -8,3 +8,4 @@ dependencies:
|
||||||
- content_moderation
|
- content_moderation
|
||||||
- node
|
- node
|
||||||
- views
|
- views
|
||||||
|
- entity_test
|
||||||
|
|
|
@ -0,0 +1,310 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\content_moderation\Functional;
|
||||||
|
|
||||||
|
use Drupal\node\Entity\NodeType;
|
||||||
|
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||||
|
use Drupal\views\ViewExecutable;
|
||||||
|
use Drupal\views\Views;
|
||||||
|
use Drupal\workflows\Entity\Workflow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the views 'moderation_state_filter' filter plugin.
|
||||||
|
*
|
||||||
|
* @coversDefaultClass \Drupal\content_moderation\Plugin\views\filter\ModerationStateFilter
|
||||||
|
*
|
||||||
|
* @group content_moderation
|
||||||
|
*/
|
||||||
|
class ViewsModerationStateFilterTest extends ViewTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = [
|
||||||
|
'content_moderation_test_views',
|
||||||
|
'node',
|
||||||
|
'content_moderation',
|
||||||
|
'workflows',
|
||||||
|
'workflow_type_test',
|
||||||
|
'entity_test',
|
||||||
|
'language',
|
||||||
|
'content_translation',
|
||||||
|
'views_ui',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp($import_test_views = TRUE) {
|
||||||
|
parent::setUp(FALSE);
|
||||||
|
|
||||||
|
NodeType::create([
|
||||||
|
'type' => 'example_a',
|
||||||
|
])->save();
|
||||||
|
NodeType::create([
|
||||||
|
'type' => 'example_b',
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
$new_workflow = Workflow::create([
|
||||||
|
'type' => 'content_moderation',
|
||||||
|
'id' => 'new_workflow',
|
||||||
|
'label' => 'New workflow',
|
||||||
|
]);
|
||||||
|
$new_workflow->getTypePlugin()->addState('bar', 'Bar');
|
||||||
|
$new_workflow->save();
|
||||||
|
|
||||||
|
$this->drupalLogin($this->drupalCreateUser(['administer workflows', 'administer views']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the dependency handling of the moderation state filter.
|
||||||
|
*
|
||||||
|
* @covers ::calculateDependencies
|
||||||
|
* @covers ::onDependencyRemoval
|
||||||
|
*/
|
||||||
|
public function testModerationStateFilterDependencyHandling() {
|
||||||
|
// First, check that the view doesn't have any config dependency when there
|
||||||
|
// are no states configured in the filter.
|
||||||
|
$view_id = 'test_content_moderation_state_filter_base_table';
|
||||||
|
$view = Views::getView($view_id);
|
||||||
|
|
||||||
|
$this->assertWorkflowDependencies([], $view);
|
||||||
|
$this->assertTrue($view->storage->status());
|
||||||
|
|
||||||
|
// Configure the Editorial workflow for a node bundle, set the filter value
|
||||||
|
// to use one of its states and check that the workflow is now a dependency
|
||||||
|
// of the view.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||||
|
'bundles[example_a]' => TRUE,
|
||||||
|
], 'Save');
|
||||||
|
|
||||||
|
$edit['options[value][]'] = ['editorial-published'];
|
||||||
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
|
||||||
|
$view = Views::getView($view_id);
|
||||||
|
$this->assertWorkflowDependencies(['editorial'], $view);
|
||||||
|
$this->assertTrue($view->storage->status());
|
||||||
|
|
||||||
|
// Create another workflow and repeat the checks above.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/add', [
|
||||||
|
'label' => 'Translation',
|
||||||
|
'id' => 'translation',
|
||||||
|
'workflow_type' => 'content_moderation',
|
||||||
|
], 'Save');
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/translation/add_state', [
|
||||||
|
'label' => 'Needs Review',
|
||||||
|
'id' => 'needs_review',
|
||||||
|
], 'Save');
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/translation/type/node', [
|
||||||
|
'bundles[example_b]' => TRUE,
|
||||||
|
], 'Save');
|
||||||
|
|
||||||
|
$edit['options[value][]'] = ['editorial-published', 'translation-needs_review'];
|
||||||
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
|
||||||
|
$view = Views::getView($view_id);
|
||||||
|
$this->assertWorkflowDependencies(['editorial', 'translation'], $view);
|
||||||
|
$this->assertTrue(isset($view->storage->getDisplay('default')['display_options']['filters']['moderation_state']));
|
||||||
|
$this->assertTrue($view->storage->status());
|
||||||
|
|
||||||
|
// Remove the 'Translation' workflow.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/translation/delete', [], 'Delete');
|
||||||
|
|
||||||
|
// Check that the view has been disabled, the filter has been deleted, the
|
||||||
|
// view can be saved and there are no more config dependencies.
|
||||||
|
$view = Views::getView($view_id);
|
||||||
|
$this->assertFalse($view->storage->status());
|
||||||
|
$this->assertFalse(isset($view->storage->getDisplay('default')['display_options']['filters']['moderation_state']));
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
$this->assertWorkflowDependencies([], $view);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the moderation state filter when the configured workflow is changed.
|
||||||
|
*
|
||||||
|
* @dataProvider providerTestWorkflowChanges
|
||||||
|
*/
|
||||||
|
public function testWorkflowChanges($view_id, $filter_name) {
|
||||||
|
// Update the view and make the default filter not exposed anymore,
|
||||||
|
// otherwise all results will be shown when there are no more moderated
|
||||||
|
// bundles left.
|
||||||
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", [], 'Hide filter');
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
|
||||||
|
// First, apply the Editorial workflow to both of our content types.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||||
|
'bundles[example_a]' => TRUE,
|
||||||
|
'bundles[example_b]' => TRUE,
|
||||||
|
], 'Save');
|
||||||
|
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||||
|
|
||||||
|
// Add a few nodes in various moderation states.
|
||||||
|
$this->createNode(['type' => 'example_a', 'moderation_state' => 'published']);
|
||||||
|
$this->createNode(['type' => 'example_b', 'moderation_state' => 'published']);
|
||||||
|
$archived_node_a = $this->createNode(['type' => 'example_a', 'moderation_state' => 'archived']);
|
||||||
|
$archived_node_b = $this->createNode(['type' => 'example_b', 'moderation_state' => 'archived']);
|
||||||
|
|
||||||
|
// Configure the view to only show nodes in the 'archived' moderation state.
|
||||||
|
$edit['options[value][]'] = ['editorial-archived'];
|
||||||
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
|
||||||
|
// Check that only the archived nodes from both bundles are displayed by the
|
||||||
|
// view.
|
||||||
|
$view = Views::getView($view_id);
|
||||||
|
$this->executeView($view);
|
||||||
|
$this->assertIdenticalResultset($view, [['nid' => $archived_node_a->id()], ['nid' => $archived_node_b->id()]], ['nid' => 'nid']);
|
||||||
|
|
||||||
|
// Remove the Editorial workflow from one of the bundles.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||||
|
'bundles[example_a]' => TRUE,
|
||||||
|
'bundles[example_b]' => FALSE,
|
||||||
|
], 'Save');
|
||||||
|
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||||
|
|
||||||
|
$view = Views::getView($view_id);
|
||||||
|
$this->executeView($view);
|
||||||
|
$this->assertIdenticalResultset($view, [['nid' => $archived_node_a->id()]], ['nid' => 'nid']);
|
||||||
|
|
||||||
|
// Check that the view can still be edited and saved without any
|
||||||
|
// intervention.
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
|
||||||
|
// Remove the Editorial workflow from both bundles.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||||
|
'bundles[example_a]' => FALSE,
|
||||||
|
'bundles[example_b]' => FALSE,
|
||||||
|
], 'Save');
|
||||||
|
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||||
|
|
||||||
|
$view = Views::getView($view_id);
|
||||||
|
$this->executeView($view);
|
||||||
|
|
||||||
|
// Check that the view doesn't return any result.
|
||||||
|
$this->assertEmpty($view->result);
|
||||||
|
|
||||||
|
// Check that the view can not be edited without any intervention anymore
|
||||||
|
// because the user needs to fix the filter.
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
$this->assertSession()->pageTextContains("No valid values found on filter: $filter_name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for testWorkflowChanges.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* An array of view IDs.
|
||||||
|
*/
|
||||||
|
public function providerTestWorkflowChanges() {
|
||||||
|
return [
|
||||||
|
'view on base table, filter on base table' => [
|
||||||
|
'test_content_moderation_state_filter_base_table',
|
||||||
|
'Content: Moderation state'
|
||||||
|
],
|
||||||
|
'view on base table, filter on revision table' => [
|
||||||
|
'test_content_moderation_state_filter_base_table_filter_on_revision',
|
||||||
|
'Content revision: Moderation state'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the content moderation state filter caching is correct.
|
||||||
|
*/
|
||||||
|
public function testFilterRenderCache() {
|
||||||
|
// Initially all states of the workflow are displayed.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', [
|
||||||
|
'bundles[example_a]' => TRUE,
|
||||||
|
], 'Save');
|
||||||
|
$this->assertFilterStates(['All', 'editorial-draft', 'editorial-published', 'editorial-archived']);
|
||||||
|
|
||||||
|
// Adding a new state to the editorial workflow will display that state in
|
||||||
|
// the list of filters.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/add_state', [
|
||||||
|
'label' => 'Foo',
|
||||||
|
'id' => 'foo',
|
||||||
|
], 'Save');
|
||||||
|
$this->assertFilterStates(['All', 'editorial-draft', 'editorial-published', 'editorial-archived', 'editorial-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', 'editorial-draft', 'editorial-published', 'editorial-archived', 'editorial-foo', 'new_workflow-draft', 'new_workflow-published', 'new_workflow-bar']);
|
||||||
|
|
||||||
|
// Add a few more states and change the exposed filter to allow multiple
|
||||||
|
// selections so we can check that the size of the select element does not
|
||||||
|
// exceed 8 options.
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/add_state', [
|
||||||
|
'label' => 'Foo 2',
|
||||||
|
'id' => 'foo2',
|
||||||
|
], 'Save');
|
||||||
|
$this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/add_state', [
|
||||||
|
'label' => 'Foo 3',
|
||||||
|
'id' => 'foo3',
|
||||||
|
], 'Save');
|
||||||
|
|
||||||
|
$view_id = 'test_content_moderation_state_filter_base_table';
|
||||||
|
$edit['options[expose][multiple]'] = TRUE;
|
||||||
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$view_id/default/filter/moderation_state", $edit, 'Apply');
|
||||||
|
$this->drupalPostForm("admin/structure/views/view/$view_id", [], 'Save');
|
||||||
|
|
||||||
|
$this->assertFilterStates(['editorial-draft', 'editorial-published', 'editorial-archived', 'editorial-foo', 'editorial-foo2', 'editorial-foo3', 'new_workflow-draft', 'new_workflow-published', 'new_workflow-bar'], TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert the states which appear in the filter.
|
||||||
|
*
|
||||||
|
* @param array $states
|
||||||
|
* The states which should appear in the filter.
|
||||||
|
* @param bool $check_size
|
||||||
|
* (optional) Whether to check that size of the select element is not
|
||||||
|
* greater than 8. Defaults to FALSE.
|
||||||
|
*/
|
||||||
|
protected function assertFilterStates($states, $check_size = FALSE) {
|
||||||
|
$this->drupalGet('/filter-test-path');
|
||||||
|
|
||||||
|
$assert_session = $this->assertSession();
|
||||||
|
|
||||||
|
// Check that the select contains the correct number of options.
|
||||||
|
$assert_session->elementsCount('css', '#edit-default-revision-state option', count($states));
|
||||||
|
|
||||||
|
// Check that the size of the select element does not exceed 8 options.
|
||||||
|
if ($check_size) {
|
||||||
|
$this->assertGreaterThan(8, count($states));
|
||||||
|
$assert_session->elementAttributeContains('css', '#edit-default-revision-state', 'size', 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that an option exists for each of the expected states.
|
||||||
|
foreach ($states as $state) {
|
||||||
|
$assert_session->optionExists('Default Revision State', $state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts the views dependencies on workflow config entities.
|
||||||
|
*
|
||||||
|
* @param string[] $workflow_ids
|
||||||
|
* An array of workflow IDs to check.
|
||||||
|
* @param \Drupal\views\ViewExecutable $view
|
||||||
|
* An executable View object.
|
||||||
|
*/
|
||||||
|
protected function assertWorkflowDependencies(array $workflow_ids, ViewExecutable $view) {
|
||||||
|
$dependencies = $view->getDependencies();
|
||||||
|
|
||||||
|
$expected = [];
|
||||||
|
foreach (Workflow::loadMultiple($workflow_ids) as $workflow) {
|
||||||
|
$expected[] = $workflow->getConfigDependencyName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($expected) {
|
||||||
|
$this->assertSame($expected, $dependencies['config']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->assertTrue(!isset($dependencies['config']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,298 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\content_moderation\Kernel;
|
||||||
|
|
||||||
|
use Drupal\entity_test\Entity\EntityTestNoBundle;
|
||||||
|
use Drupal\language\Entity\ConfigurableLanguage;
|
||||||
|
use Drupal\node\Entity\Node;
|
||||||
|
use Drupal\node\Entity\NodeType;
|
||||||
|
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||||
|
use Drupal\views\Views;
|
||||||
|
use Drupal\workflows\Entity\Workflow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the views 'moderation_state_filter' filter plugin.
|
||||||
|
*
|
||||||
|
* @coversDefaultClass \Drupal\content_moderation\Plugin\views\filter\ModerationStateFilter
|
||||||
|
*
|
||||||
|
* @group content_moderation
|
||||||
|
*/
|
||||||
|
class ViewsModerationStateFilterTest extends ViewsKernelTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = [
|
||||||
|
'content_moderation_test_views',
|
||||||
|
'node',
|
||||||
|
'content_moderation',
|
||||||
|
'workflows',
|
||||||
|
'workflow_type_test',
|
||||||
|
'entity_test',
|
||||||
|
'language',
|
||||||
|
'content_translation',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp($import_test_views = TRUE) {
|
||||||
|
parent::setUp(FALSE);
|
||||||
|
|
||||||
|
$this->installEntitySchema('user');
|
||||||
|
$this->installEntitySchema('node');
|
||||||
|
$this->installEntitySchema('content_moderation_state');
|
||||||
|
$this->installEntitySchema('entity_test_no_bundle');
|
||||||
|
$this->installSchema('node', 'node_access');
|
||||||
|
$this->installConfig('content_moderation_test_views');
|
||||||
|
$this->installConfig('content_moderation');
|
||||||
|
|
||||||
|
$node_type = NodeType::create([
|
||||||
|
'type' => 'example',
|
||||||
|
]);
|
||||||
|
$node_type->save();
|
||||||
|
|
||||||
|
$node_type = NodeType::create([
|
||||||
|
'type' => 'another_example',
|
||||||
|
]);
|
||||||
|
$node_type->save();
|
||||||
|
|
||||||
|
$node_type = NodeType::create([
|
||||||
|
'type' => 'example_non_moderated',
|
||||||
|
]);
|
||||||
|
$node_type->save();
|
||||||
|
|
||||||
|
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the content moderation state filter.
|
||||||
|
*/
|
||||||
|
public function testStateFilterViewsRelationship() {
|
||||||
|
$workflow = Workflow::load('editorial');
|
||||||
|
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||||
|
$workflow->getTypePlugin()->addState('translated_draft', 'Bar');
|
||||||
|
$configuration = $workflow->getTypePlugin()->getConfiguration();
|
||||||
|
$configuration['states']['translated_draft'] += [
|
||||||
|
'published' => FALSE,
|
||||||
|
'default_revision' => FALSE,
|
||||||
|
];
|
||||||
|
$workflow->getTypePlugin()->setConfiguration($configuration);
|
||||||
|
$workflow->save();
|
||||||
|
|
||||||
|
// Create a published default revision and one forward draft revision.
|
||||||
|
$node = Node::create([
|
||||||
|
'type' => 'example',
|
||||||
|
'title' => 'Test Node',
|
||||||
|
'moderation_state' => 'published',
|
||||||
|
]);
|
||||||
|
$node->save();
|
||||||
|
$node->setNewRevision();
|
||||||
|
$node->moderation_state = 'draft';
|
||||||
|
$node->save();
|
||||||
|
|
||||||
|
// Create a draft default revision.
|
||||||
|
$second_node = Node::create([
|
||||||
|
'type' => 'example',
|
||||||
|
'title' => 'Second Node',
|
||||||
|
'moderation_state' => 'draft',
|
||||||
|
]);
|
||||||
|
$second_node->save();
|
||||||
|
|
||||||
|
// Create a published default revision.
|
||||||
|
$third_node = Node::create([
|
||||||
|
'type' => 'example',
|
||||||
|
'title' => 'Third node',
|
||||||
|
'moderation_state' => 'published',
|
||||||
|
]);
|
||||||
|
$third_node->save();
|
||||||
|
|
||||||
|
// Add a non-moderated node.
|
||||||
|
$fourth_node = Node::create([
|
||||||
|
'type' => 'example_non_moderated',
|
||||||
|
'title' => 'Fourth node',
|
||||||
|
]);
|
||||||
|
$fourth_node->save();
|
||||||
|
|
||||||
|
// Create a translated published revision.
|
||||||
|
$translated_forward_revision = $third_node->addTranslation('fr');
|
||||||
|
$translated_forward_revision->title = 'Translated Node';
|
||||||
|
$translated_forward_revision->setNewRevision(TRUE);
|
||||||
|
$translated_forward_revision->moderation_state = 'translated_draft';
|
||||||
|
$translated_forward_revision->save();
|
||||||
|
|
||||||
|
// Four revisions for the nodes when no filter.
|
||||||
|
$this->assertNodesWithFilters([$node, $second_node, $third_node, $third_node], []);
|
||||||
|
|
||||||
|
// The default revision of node one and three is published.
|
||||||
|
$this->assertNodesWithFilters([$node, $third_node], [
|
||||||
|
'default_revision_state' => 'editorial-published',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// The default revision of node two is draft.
|
||||||
|
$this->assertNodesWithFilters([$second_node], [
|
||||||
|
'default_revision_state' => 'editorial-draft',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Test the same three revisions on a view displaying content revisions.
|
||||||
|
// Both nodes have one draft revision.
|
||||||
|
$this->assertNodesWithFilters([$node, $second_node], [
|
||||||
|
'moderation_state' => 'editorial-draft',
|
||||||
|
], 'test_content_moderation_state_filter_revision_table');
|
||||||
|
// Creating a new forward revision of node three, creates a second published
|
||||||
|
// revision of of the original language, hence there are two published
|
||||||
|
// revisions of node three.
|
||||||
|
$this->assertNodesWithFilters([$node, $third_node, $third_node], [
|
||||||
|
'moderation_state' => 'editorial-published',
|
||||||
|
], 'test_content_moderation_state_filter_revision_table');
|
||||||
|
// There is a single forward translated revision with a new state, which is
|
||||||
|
// also filterable.
|
||||||
|
$this->assertNodesWithFilters([$translated_forward_revision], [
|
||||||
|
'moderation_state' => 'editorial-translated_draft',
|
||||||
|
], 'test_content_moderation_state_filter_revision_table');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the moderation filter with a non-translatable entity type.
|
||||||
|
*/
|
||||||
|
public function testNonTranslatableEntityType() {
|
||||||
|
$workflow = Workflow::load('editorial');
|
||||||
|
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_no_bundle', 'entity_test_no_bundle');
|
||||||
|
$workflow->save();
|
||||||
|
|
||||||
|
$test_entity = EntityTestNoBundle::create([
|
||||||
|
'moderation_state' => 'draft',
|
||||||
|
]);
|
||||||
|
$test_entity->save();
|
||||||
|
|
||||||
|
$view = Views::getView('test_content_moderation_state_filter_entity_test');
|
||||||
|
$view->setExposedInput([
|
||||||
|
'moderation_state' => 'editorial-draft',
|
||||||
|
]);
|
||||||
|
$view->execute();
|
||||||
|
$this->assertIdenticalResultset($view, [['id' => $test_entity->id()]], ['id' => 'id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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([
|
||||||
|
'Editorial' => [
|
||||||
|
'editorial-draft' => 'Draft',
|
||||||
|
'editorial-published' => 'Published',
|
||||||
|
'editorial-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([
|
||||||
|
'Editorial' => [
|
||||||
|
'editorial-draft' => 'Draft',
|
||||||
|
'editorial-published' => 'Published',
|
||||||
|
'editorial-archived' => 'Archived',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Adding a new content moderation workflow will add additional states to
|
||||||
|
// filter.
|
||||||
|
$workflow = Workflow::create(['id' => 'moderation_test', 'type' => 'content_moderation', 'label' => 'Moderation test']);
|
||||||
|
$workflow->getTypePlugin()->addState('foo', 'Foo State');
|
||||||
|
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
|
||||||
|
$workflow->save();
|
||||||
|
$this->assertPluginStates([
|
||||||
|
'Editorial' => [
|
||||||
|
'editorial-draft' => 'Draft',
|
||||||
|
'editorial-published' => 'Published',
|
||||||
|
'editorial-archived' => 'Archived',
|
||||||
|
],
|
||||||
|
'Moderation test' => [
|
||||||
|
'moderation_test-foo' => 'Foo State',
|
||||||
|
'moderation_test-draft' => 'Draft',
|
||||||
|
'moderation_test-published' => 'Published',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Deleting a workflow will remove the states from the filter.
|
||||||
|
$workflow = Workflow::load('moderation_test');
|
||||||
|
$workflow->delete();
|
||||||
|
$this->assertPluginStates([
|
||||||
|
'Editorial' => [
|
||||||
|
'editorial-draft' => 'Draft',
|
||||||
|
'editorial-published' => 'Published',
|
||||||
|
'editorial-archived' => 'Archived',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 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([
|
||||||
|
'Editorial' => [
|
||||||
|
'editorial-draft' => 'Draft',
|
||||||
|
'editorial-published' => 'Published',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert the plugin states.
|
||||||
|
*
|
||||||
|
* @param string[] $states
|
||||||
|
* The states which should appear in the filter.
|
||||||
|
*/
|
||||||
|
protected function assertPluginStates($states) {
|
||||||
|
$plugin = Views::pluginManager('filter')->createInstance('moderation_state_filter', []);
|
||||||
|
$view = Views::getView('test_content_moderation_state_filter_base_table');
|
||||||
|
$plugin->init($view, $view->getDisplay());
|
||||||
|
$this->assertEquals($states, $plugin->getValueOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert the nodes appear when the test view is executed.
|
||||||
|
*
|
||||||
|
* @param \Drupal\node\NodeInterface[] $nodes
|
||||||
|
* Nodes to assert are in the views result.
|
||||||
|
* @param array $filters
|
||||||
|
* An array of filters to apply to the view.
|
||||||
|
* @param string $view_id
|
||||||
|
* The view to execute for the results.
|
||||||
|
*/
|
||||||
|
protected function assertNodesWithFilters(array $nodes, array $filters, $view_id = 'test_content_moderation_state_filter_base_table') {
|
||||||
|
$view = Views::getView($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()];
|
||||||
|
}
|
||||||
|
$this->assertIdenticalResultset($view, $expected_result, ['nid' => 'nid']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,9 @@ namespace Drupal\entity_test\Entity;
|
||||||
* id = "entity_test_no_bundle",
|
* id = "entity_test_no_bundle",
|
||||||
* label = @Translation("Entity Test without bundle"),
|
* label = @Translation("Entity Test without bundle"),
|
||||||
* base_table = "entity_test_no_bundle",
|
* base_table = "entity_test_no_bundle",
|
||||||
|
* handlers = {
|
||||||
|
* "views_data" = "Drupal\views\EntityViewsData"
|
||||||
|
* },
|
||||||
* entity_keys = {
|
* entity_keys = {
|
||||||
* "id" = "id",
|
* "id" = "id",
|
||||||
* "revision" = "revision_id",
|
* "revision" = "revision_id",
|
||||||
|
|
|
@ -229,7 +229,9 @@ class InOperator extends FilterPluginBase {
|
||||||
'#default_value' => $default_value,
|
'#default_value' => $default_value,
|
||||||
// These are only valid for 'select' type, but do no harm to checkboxes.
|
// These are only valid for 'select' type, but do no harm to checkboxes.
|
||||||
'#multiple' => TRUE,
|
'#multiple' => TRUE,
|
||||||
'#size' => count($options) > 8 ? 8 : count($options),
|
// The value options can be a multidimensional array if the value form
|
||||||
|
// type is a select list, so make sure that they are counted correctly.
|
||||||
|
'#size' => min(count($options, COUNT_RECURSIVE), 8),
|
||||||
];
|
];
|
||||||
$user_input = $form_state->getUserInput();
|
$user_input = $form_state->getUserInput();
|
||||||
if ($exposed && !isset($user_input[$identifier])) {
|
if ($exposed && !isset($user_input[$identifier])) {
|
||||||
|
|
|
@ -124,7 +124,7 @@ interface WorkflowTypeInterface extends PluginWithFormsInterface, DerivativeInsp
|
||||||
* A list of state IDs to get. If NULL then all states will be returned.
|
* A list of state IDs to get. If NULL then all states will be returned.
|
||||||
*
|
*
|
||||||
* @return \Drupal\workflows\StateInterface[]
|
* @return \Drupal\workflows\StateInterface[]
|
||||||
* An array of workflow states.
|
* An array of workflow states, keyed by state IDs.
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
* Thrown if $state_ids contains a state ID that does not exist.
|
* Thrown if $state_ids contains a state ID that does not exist.
|
||||||
|
|
Loading…
Reference in New Issue