Link from entities to their referenced terms and show entity views on taxonomy terms #458

**Why?** Make it possible for novice users to find data and explore connections
between assets/logs without needing to totally grok the farmOS data model first.

i.e.

* Navigate from a plant asset to a list of all the seed/plant assets with the same crop/variety
* Navigate from a plant asset to a list of all the seed/plant assets from the same season
* Navigate from a log in the compost category to a list of all the logs in the compost category
* Navigate from a material asset to a list of all the materials with the same material type
This commit is contained in:
Symbioquine 2021-10-20 22:09:12 -07:00
parent 3cebccc2d1
commit a760005c7c
14 changed files with 877 additions and 2 deletions

View File

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- [Link from entities to their referenced terms and show entity views on taxonomy terms #458](https://github.com/farmOS/farmOS/pull/458).
- [Encourage GEOS PHP extension use #521](https://github.com/farmOS/farmOS/pull/521)
### Changed

View File

@ -351,7 +351,7 @@ class FarmFieldFactory implements FarmFieldFactoryInterface {
'type' => 'entity_reference_label',
'weight' => $options['weight']['view'] ?? 0,
'settings' => [
'link' => FALSE,
'link' => TRUE,
],
];
break;

View File

@ -9,6 +9,7 @@ dependencies:
- csv_serialization
- entity_browser
- farm_location
- farm_ui_views
- image
- options
- rest
@ -1593,6 +1594,111 @@ display:
- url.query_args
- user.permissions
tags: { }
page_term:
display_plugin: page
id: page_term
display_title: 'By term (page)'
position: 4
display_options:
display_extenders: { }
display_description: ''
path: taxonomy/term/%taxonomy_term/assets/%entity_bundle
arguments:
asset_taxonomy_term_reference:
id: asset_taxonomy_term_reference
table: asset_field_data
field: asset_taxonomy_term_reference
relationship: none
group_type: group
admin_label: ''
break_phrase: false
default_action: 'not found'
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
default_argument_type: fixed
default_argument_options:
argument: ''
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: true
validate:
type: 'entity:taxonomy_term'
fail: 'not found'
validate_options:
operation: view
access: false
multiple: 0
bundles: {}
entity_type: asset
plugin_id: entity_taxonomy_term_reference
type:
id: type
table: asset_field_data
field: type
relationship: none
group_type: group
admin_label: ''
default_action: 'not found'
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
default_argument_type: fixed
default_argument_options:
argument: all
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: true
validate:
type: 'entity:asset_type'
fail: 'not found'
validate_options:
operation: view
multiple: 0
access: false
bundles: { }
glossary: false
limit: 0
case: none
path_case: none
transform_dash: false
break_phrase: false
entity_type: asset
entity_field: type
plugin_id: string
defaults:
arguments: false
cache_metadata:
max-age: 0
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user.permissions
tags: { }
page_children:
id: page_children
display_title: 'Children (page)'

View File

@ -2471,7 +2471,7 @@ display:
entity_type: log
entity_field: type
plugin_id: string
default_action: ignore
default_action: 'not found'
exception:
value: all
title_enable: false
@ -2521,6 +2521,112 @@ display:
- user
- user.permissions
tags: { }
page_term:
display_plugin: page
id: page_term
display_title: 'By term (page)'
position: 2
display_options:
display_extenders: { }
display_description: ''
path: taxonomy/term/%taxonomy_term/logs/%entity_bundle
arguments:
log_taxonomy_term_reference:
id: log_taxonomy_term_reference
table: log_field_data
field: log_taxonomy_term_reference
relationship: none
group_type: group
admin_label: ''
break_phrase: false
default_action: 'not found'
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
default_argument_type: fixed
default_argument_options:
argument: ''
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: true
validate:
type: 'entity:taxonomy_term'
fail: 'not found'
validate_options:
operation: view
access: false
multiple: 0
bundles: {}
entity_type: log
plugin_id: entity_taxonomy_term_reference
type:
id: type
table: log_field_data
field: type
relationship: none
group_type: group
admin_label: ''
default_action: 'not found'
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
default_argument_type: fixed
default_argument_options:
argument: all
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: true
validate:
type: 'entity:log_type'
fail: 'not found'
validate_options:
operation: view
multiple: 0
access: false
bundles: { }
glossary: false
limit: 0
case: none
path_case: none
transform_dash: false
break_phrase: false
entity_type: log
entity_field: type
plugin_id: string
defaults:
arguments: false
cache_metadata:
max-age: 0
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- user.permissions
tags: { }
page_type:
id: page_type
display_title: 'By type (page)'

View File

@ -1,3 +1,4 @@
# Add log view tabs to assets.
farm.asset.logs:
title: 'Logs'
route_name: view.farm_log.page_asset
@ -13,3 +14,21 @@ farm.asset.logs.all:
parent_id: farm.asset.logs
farm.asset.logs.type:
deriver: Drupal\farm_ui_views\Plugin\Derivative\FarmLogViewsTaskLink
# Add asset/log view tabs to taxonomy terms.
farm.taxonomy_term.assets:
title: 'Assets'
route_name: view.farm_asset.page_term
route_parameters:
entity_bundle: 'all'
base_route: entity.taxonomy_term.canonical
weight: 50
farm.taxonomy_term.logs:
title: 'Logs'
route_name: view.farm_log.page_term
route_parameters:
entity_bundle: 'all'
base_route: entity.taxonomy_term.canonical
weight: 50
farm.taxonomy_term.entities.type:
deriver: Drupal\farm_ui_views\Plugin\Derivative\FarmTaxonomyTermViewsTaskLink

View File

@ -278,5 +278,8 @@ function farm_ui_views_get_bundle_argument(ViewExecutable $view, string $display
elseif ($view->id() == 'farm_log' && $display_id == 'page_asset' && !empty($args[1]) && $args[1] != 'all') {
$bundle = $args[1];
}
elseif (in_array($view->id(), ['farm_asset', 'farm_log']) && $display_id == 'page_term' && !empty($args[1]) && $args[1] != 'all') {
$bundle = $args[1];
}
return $bundle;
}

View File

@ -13,6 +13,24 @@ services:
arguments: [ '@entity_type.manager', '@asset.location' ]
tags:
- { name: access_check, applies_to: _asset_children_access }
farm_ui_views.asset_term_access:
class: Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck
arguments:
- 'asset'
- '@entity_type.manager'
- '@entity_type.bundle.info'
- '@entity_field.manager'
tags:
- { name: access_check, applies_to: _asset_term_access }
farm_ui_views.log_term_access:
class: Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck
arguments:
- 'log'
- '@entity_type.manager'
- '@entity_type.bundle.info'
- '@entity_field.manager'
tags:
- { name: access_check, applies_to: _log_term_access }
farm_ui_views.asset_inventory_access:
class: Drupal\farm_ui_views\Access\FarmInventoryAssetViewsAccessCheck
arguments: [ '@entity_type.manager' ]

View File

@ -20,4 +20,26 @@ function farm_ui_views_views_data_alter(array &$data) {
],
];
}
// Provide an asset_taxonomy_term_reference argument for views of assets.
if (isset($data['asset_field_data'])) {
$data['asset_field_data']['asset_taxonomy_term_reference'] = [
'title' => t('Asset Taxonomy Term Reference'),
'help' => t('Taxonomy Terms that are referenced by the asset.'),
'argument' => [
'id' => 'entity_taxonomy_term_reference',
],
];
}
// Provide a log_taxonomy_term_reference argument for views of logs.
if (isset($data['log_field_data'])) {
$data['log_field_data']['log_taxonomy_term_reference'] = [
'title' => t('Log Taxonomy Term Reference'),
'help' => t('Taxonomy Terms that are referenced by the log.'),
'argument' => [
'id' => 'entity_taxonomy_term_reference',
],
];
}
}

View File

@ -129,6 +129,41 @@ function farm_ui_views_views_pre_render(ViewExecutable $view) {
}
}
// If this is the farm_asset/farm_log View and page_term display, include
// the term's name.
if (in_array($view->id(), ['farm_asset', 'farm_log']) && $view->current_display == 'page_term') {
$term_id = $view->args[0];
$entity_bundle = $view->args[1];
$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($term_id);
if (!empty($term)) {
$vocabulary = \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary')->load($term->bundle());
$entity_bundle_label = '';
if ($entity_bundle != 'all') {
$bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($view->getBaseEntityType()->id());
if (!empty($bundles[$entity_bundle])) {
$entity_bundle_label = $bundles[$entity_bundle]['label'] . ' ' . $view->getBaseEntityType()->getPluralLabel();
}
}
if (!empty($entity_bundle_label)) {
$title = t('%bundle with %vocab term %term', [
'%bundle' => $entity_bundle_label,
'%vocab' => $vocabulary->label(),
'%term' => $term->label(),
]);
}
else {
$title = t('%base_type with %vocab term %term', [
'%base_type' => $view->getBaseEntityType()->getCollectionLabel(),
'%vocab' => $vocabulary->label(),
'%term' => $term->label(),
]);
}
}
}
// Set the title, if so desired.
if (!empty($title)) {
$view->setTitle($title);

View File

@ -0,0 +1,111 @@
<?php
namespace Drupal\farm_ui_views\Access;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Access\AccessResult;
/**
* Checks access for displaying Views of entities that reference taxonomy terms.
*/
class FarmTaxonomyTermEntityViewsAccessCheck implements AccessInterface {
/**
* The base entity type of the views this access check will be applied to.
*
* @var string
*/
protected $baseEntityType;
/**
* The taxonomy term storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $taxonomyTermStorage;
/**
* The entity type bundle info.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* The entity field manager service.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* FarmTaxonomyTermEntityViewsAccessCheck constructor.
*
* @param string $base_entity_type
* The base entity type of the views this access check will be applied to.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
* The entity type bundle info service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager service.
*/
public function __construct($base_entity_type,
EntityTypeManagerInterface $entity_type_manager,
EntityTypeBundleInfoInterface $entity_bundle_info,
EntityFieldManagerInterface $entity_field_manager) {
$this->baseEntityType = $base_entity_type;
$this->taxonomyTermStorage = $entity_type_manager->getStorage('taxonomy_term');
$this->entityTypeBundleInfo = $entity_bundle_info;
$this->entityFieldManager = $entity_field_manager;
}
/**
* A custom access check to filter out irrelevant entity bundles.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match.
*/
public function access(RouteMatchInterface $route_match) {
// If there is no "taxonomy_term" or "asset_type" parameter, bail.
$term_id = $route_match->getParameter('taxonomy_term');
$entity_bundle = $route_match->getParameter('entity_bundle');
if (empty($term_id) || empty($entity_bundle)) {
return AccessResult::forbidden();
}
$term = $this->taxonomyTermStorage->load($term_id);
// Loop through all the entity bundles of the base entity type for the view
// and only return AccessResult::allowed() for those which have a taxonomy
// term entity reference field referencing the taxonomy term bundle of the
// term we loaded above.
$bundles = $this->entityTypeBundleInfo->getBundleInfo($this->baseEntityType);
foreach (array_keys($bundles) as $type) {
// If the route argument is 'all' then we check all the bundles, otherwise
// only check the one that matches.
if ($entity_bundle == 'all' || $type == $entity_bundle) {
$field_definitions = $this->entityFieldManager->getFieldDefinitions($this->baseEntityType, $type);
foreach (array_values($field_definitions) as $field_definition) {
if ($field_definition->getType() == "entity_reference" && $field_definition->getSetting('target_type') == "taxonomy_term") {
$handler_settings = $field_definition->getSetting('handler_settings') ?? [];
if (in_array($term->bundle(), $handler_settings['target_bundles'] ?? [])) {
return AccessResult::allowed();
}
}
}
}
}
return AccessResult::forbidden();
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace Drupal\farm_ui_views\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides task links for farmOS Taxonomy Term Views.
*/
class FarmTaxonomyTermViewsTaskLink extends DeriverBase implements ContainerDeriverInterface {
use StringTranslationTrait;
/**
* The entity type bundle info.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* Constructs a FarmTaxonomyTermViewsTaskLink instance.
*
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
* The entity type bundle info service.
*/
public function __construct(EntityTypeBundleInfoInterface $entity_bundle_info) {
$this->entityTypeBundleInfo = $entity_bundle_info;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
$container->get('entity_type.bundle.info')
);
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$links = [];
foreach (['asset', 'log'] as $entity_type) {
$links["farm.taxonomy_term.{$entity_type}s.all"] = [
'id' => "farm.taxonomy_term.{$entity_type}s.all",
'title' => 'All',
'parent_id' => "farm.taxonomy_term.{$entity_type}s",
'route_name' => "view.farm_$entity_type.page_term",
'route_parameters' => [
'entity_bundle' => 'all',
],
] + $base_plugin_definition;
// Add links for each entity bundle.
$entity_bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type);
foreach ($entity_bundles as $entity_bundle => $info) {
$links["farm.taxonomy_term.{$entity_type}s.$entity_bundle"] = [
'id' => "farm.taxonomy_term.{$entity_type}s.$entity_bundle",
'title' => $info['label'],
'parent_id' => "farm.taxonomy_term.{$entity_type}s",
'route_name' => "view.farm_$entity_type.page_term",
'route_parameters' => [
'entity_bundle' => $entity_bundle,
],
] + $base_plugin_definition;
}
}
return $links;
}
}

View File

@ -0,0 +1,194 @@
<?php
namespace Drupal\farm_ui_views\Plugin\views\argument;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\taxonomy\Plugin\views\argument\Taxonomy;
use Drupal\views\Views;
/**
* Argument handler for taxonomy term references from an arbitrary entity field.
*
* @ingroup views_argument_handlers
*
* @ViewsArgument("entity_taxonomy_term_reference")
*/
class EntityTaxonomyTermReferenceArgument extends Taxonomy {
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity type bundle info.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* The entity field manager service.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* EntityTaxonomyTermReferenceArgument constructor.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityStorageInterface $term_storage
* The taxonomy term storage service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
* The entity type bundle info service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager service.
*/
public function __construct(array $configuration,
$plugin_id,
$plugin_definition,
EntityStorageInterface $term_storage,
EntityTypeManagerInterface $entity_type_manager,
EntityTypeBundleInfoInterface $entity_bundle_info,
EntityFieldManagerInterface $entity_field_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $term_storage);
$this->entityTypeManager = $entity_type_manager;
$this->entityTypeBundleInfo = $entity_bundle_info;
$this->entityFieldManager = $entity_field_manager;
}
/**
* {@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')->getStorage('taxonomy_term'),
$container->get('entity_type.manager'),
$container->get('entity_type.bundle.info'),
$container->get('entity_field.manager'));
}
/**
* {@inheritdoc}
*/
public function query($group_by = FALSE) {
// Getting the arguments through views rather than
// from the Drupal route is important since it allows
// the contextual filter previews in the views UI to
// work correctly.
$term_id = $this->argument;
$entity_bundle = $this->view->args[1] ?: 'all';
if (empty($term_id)) {
return;
}
$term = $this->termStorage->load($term_id);
// This is a value like 'asset' or 'log'.
$base_entity_type = $this->view->getBaseEntityType()->id();
$entity_storage = $this->entityTypeManager->getStorage($base_entity_type);
if (!($entity_storage instanceof SqlContentEntityStorage)) {
return;
}
$entity_data_table = $entity_storage->getDataTable();
$entity_table_mapping = $entity_storage->getTableMapping();
$conditions = [];
// Keep track of which field tables we've already joined with since some
// assets share the same field e.g. plant and seed assets.
$already_joined_term_field_tables = [];
// Loop through all the bundles of the base entity type for this view.
$bundles = $this->entityTypeBundleInfo->getBundleInfo($base_entity_type);
foreach (array_keys($bundles) as $type) {
// Consider either all of them or just the one matching the
// bundle argument.
if ($entity_bundle == 'all' || $type == $entity_bundle) {
$field_definitions = $this->entityFieldManager->getFieldDefinitions($base_entity_type, $type);
foreach ($field_definitions as $field_id => $field_definition) {
// Look for taxonomy term entity reference fields which reference the
// target bundle of the term we loaded above.
if ($field_definition->getType() == "entity_reference" && $field_definition->getSetting('target_type') == "taxonomy_term") {
$handler_settings = $field_definition->getSetting('handler_settings') ?? [];
if (in_array($term->bundle(), $handler_settings['target_bundles'] ?? [])) {
// Now that we have found such a field, get the parameters to
// construct a join to allow us to filter only those entities
// which actually reference the term we loaded above.
$field_table_name = $entity_table_mapping->getFieldTableName($field_id);
// Don't add the same join more than once.
if (array_key_exists($field_table_name, $already_joined_term_field_tables)) {
continue;
}
$column_names = $entity_table_mapping->getColumnNames($field_id);
$target_id_column_name = $column_names['target_id'];
// Join the taxonomy reference field table with the entity.
/** @var \Drupal\views\Plugin\views\join\JoinPluginBase $join */
$join = Views::pluginManager('join')->createInstance('standard', [
'table' => $field_table_name,
'field' => 'entity_id',
'left_table' => $entity_data_table,
'left_field' => 'id',
'extra' => [
[
'field' => 'deleted',
'value' => 0,
],
[
'field' => $target_id_column_name,
'value' => $term->id(),
],
],
]);
// Add the relationship.
$relationship_alias = $this->query->addRelationship($field_table_name, $join, $entity_data_table);
// Keep track that we've now joined with that field table.
$already_joined_term_field_tables[$field_table_name] = 1;
// Add a condition to our final WHERE statement that the joined
// taxonomy term reference target id is not NULL.
$conditions[] = "$relationship_alias.$target_id_column_name IS NOT NULL";
}
}
}
}
}
if (!empty($conditions)) {
$combined_conditions = implode(" OR ", $conditions);
$this->query->addWhereExpression(0, "$entity_data_table.id IS NOT NULL AND ($combined_conditions)");
}
}
}

View File

@ -28,6 +28,18 @@ class RouteSubscriber extends RouteSubscriberBase {
$route->setRequirement('_asset_children_access', 'Drupal\farm_ui_views\Access\FarmAssetChildrenViewsAccessCheck::access');
}
// Add our _asset_term_access requirement to
// view.farm_asset.page_term.
if ($route = $collection->get('view.farm_asset.page_term')) {
$route->setRequirement('_asset_term_access', 'Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck::access');
}
// Add our _log_term_access requirement to
// view.farm_log.page_term.
if ($route = $collection->get('view.farm_log.page_term')) {
$route->setRequirement('_log_term_access', 'Drupal\farm_ui_views\Access\FarmTaxonomyTermEntityViewsAccessCheck::access');
}
// Add our _location_assets_access requirement to
// view.farm_asset.page_location.
if ($route = $collection->get('view.farm_asset.page_location')) {

View File

@ -0,0 +1,166 @@
<?php
namespace Drupal\Tests\farm_ui_views\Functional;
use Drupal\asset\Entity\Asset;
use Drupal\Tests\farm_test\Functional\FarmBrowserTestBase;
/**
* Tests the farm_ui_views taxonomy views routes.
*
* @group farm
*/
class TaxonomyTermTasksTest extends FarmBrowserTestBase {
/**
* Test user.
*
* @var \Drupal\user\Entity\User
*/
protected $user;
/**
* Test animal asset.
*
* @var \Drupal\asset\Entity\Asset
*/
protected $favaPlantType;
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'classy';
/**
* {@inheritdoc}
*/
protected static $modules = [
'block',
'farm_plant',
'farm_seed',
'farm_ui_views',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->drupalPlaceBlock('local_tasks_block');
// Create/login a user with permission to access taxonomy pages and assets.
$this->user = $this->createUser(['administer taxonomy', 'view any asset']);
$this->drupalLogin($this->user);
$entity_type_manager = $this->container->get('entity_type.manager');
$term_storage = $entity_type_manager->getStorage('taxonomy_term');
// Create a "Oat" plant type term.
$oat_plant_type = $term_storage->create([
'name' => 'Oat',
'vid' => 'plant_type',
]);
$oat_plant_type->save();
// Create a oat plant.
Asset::create([
'name' => 'Pringle\'s Progress Oat Planting',
'type' => 'plant',
'plant_type' => ['target_id' => $oat_plant_type->id()],
])->save();
// Create a "Fava Bean" plant type term.
$this->favaPlantType = $term_storage->create([
'name' => 'Fava Bean',
'vid' => 'plant_type',
]);
$this->favaPlantType->save();
// Create a fava plant.
Asset::create([
'name' => 'Red Flowering Fava Planting',
'type' => 'plant',
'plant_type' => ['target_id' => $this->favaPlantType->id()],
])->save();
// Create a fava seed.
Asset::create([
'name' => 'Red Flowering Fava Seeds',
'type' => 'seed',
'plant_type' => ['target_id' => $this->favaPlantType->id()],
])->save();
}
/**
* Test that the asset view task links appear on taxonomy term pages.
*/
public function testTaxonomyTermAssetTaskTabsAppear() {
$fava_term_url = 'taxonomy/term/' . $this->favaPlantType->id();
$this->drupalGet($fava_term_url);
$this->assertSession()->statusCodeEquals(200);
$get_array_of_link_text_by_url = function ($elems) {
$result = [];
foreach ($elems as $elem) {
$result[$elem->getAttribute('href')] = $elem->getText();
}
return $result;
};
$primary_tab_links = $get_array_of_link_text_by_url($this->xpath('//*[contains(@class, :class)]//a', [
':class' => 'tabs primary',
]));
$assert_has_link = function ($elements, $url, $label) {
$this->assertArrayHasKey($url, $elements, "No link exists with url '$url' among: " . print_r($elements, TRUE));
$this->assertEquals($label, $elements[$url], "Link label not as expected.");
};
$assert_has_link($primary_tab_links, "/$fava_term_url/assets/all", 'Assets');
$this->drupalGet("$fava_term_url/assets/all");
$this->assertSession()->statusCodeEquals(200);
$secondary_tab_links = $get_array_of_link_text_by_url($this->xpath('//*[contains(@class, :class)]//a', [
':class' => 'tabs secondary',
]));
$this->assertCount(3, $secondary_tab_links, 'Only 3 secondary tabs appear.');
$assert_has_link($secondary_tab_links, "/$fava_term_url/assets/all", 'All(active tab)');
$assert_has_link($secondary_tab_links, "/$fava_term_url/assets/plant", 'Plant');
$assert_has_link($secondary_tab_links, "/$fava_term_url/assets/seed", 'Seed');
}
/**
* Test that the views of assets for terms show the correct assets.
*/
public function testTaxonomyTermAssetViews() {
$fava_term_url = 'taxonomy/term/' . $this->favaPlantType->id();
$this->drupalGet("$fava_term_url/assets/all");
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Red Flowering Fava Planting');
$this->assertSession()->pageTextContains('Red Flowering Fava Seeds');
$this->assertSession()->pageTextNotContains('Pringle\'s Progress Oat Planting');
$this->drupalGet("$fava_term_url/assets/plant");
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Red Flowering Fava Planting');
$this->assertSession()->pageTextNotContains('Red Flowering Fava Seeds');
$this->assertSession()->pageTextNotContains('Pringle\'s Progress Oat Planting');
$this->drupalGet("$fava_term_url/assets/seed");
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextNotContains('Red Flowering Fava Planting');
$this->assertSession()->pageTextContains('Red Flowering Fava Seeds');
$this->assertSession()->pageTextNotContains('Pringle\'s Progress Oat Planting');
}
}