Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -1,34 +0,0 @@
|
|||
id: d6_vocabulary_entity_display
|
||||
label: Vocabulary display configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary_per_type
|
||||
constants:
|
||||
entity_type: node
|
||||
view_mode: default
|
||||
options:
|
||||
label: hidden
|
||||
type: entity_reference_label
|
||||
weight: 20
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
view_mode: 'constants/view_mode'
|
||||
options: 'constants/options'
|
||||
bundle:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node_type
|
||||
source: type
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
field_name:
|
||||
plugin: migration_lookup
|
||||
migration: d6_taxonomy_vocabulary
|
||||
source: vid
|
||||
destination:
|
||||
plugin: component_entity_display
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_vocabulary_field_instance
|
|
@ -1,38 +0,0 @@
|
|||
id: d6_vocabulary_entity_form_display
|
||||
label: Vocabulary form display configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary_per_type
|
||||
constants:
|
||||
entity_type: node
|
||||
form_mode: default
|
||||
options:
|
||||
weight: 20
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
form_mode: 'constants/form_mode'
|
||||
options/type:
|
||||
plugin: static_map
|
||||
source: tags
|
||||
map:
|
||||
0: options_select
|
||||
1: entity_reference_autocomplete_tags
|
||||
options/weight: 'constants/options/weight'
|
||||
bundle:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node_type
|
||||
source: type
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
field_name:
|
||||
plugin: migration_lookup
|
||||
migration: d6_taxonomy_vocabulary
|
||||
source: vid
|
||||
destination:
|
||||
plugin: component_entity_form_display
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_vocabulary_field_instance
|
|
@ -1,39 +0,0 @@
|
|||
id: d6_vocabulary_field_instance
|
||||
label: Vocabulary field instance configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary_per_type
|
||||
constants:
|
||||
entity_type: node
|
||||
auto_create: true
|
||||
selection_handler: 'default:taxonomy_term'
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
bundle:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node_type
|
||||
source: type
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_taxonomy_vocabulary
|
||||
source: vid
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
label: name
|
||||
'settings/handler': 'constants/selection_handler'
|
||||
'settings/handler_settings/target_bundles/0': '@field_name'
|
||||
'settings/handler_settings/auto_create': 'constants/auto_create'
|
||||
required: required
|
||||
destination:
|
||||
plugin: entity:field_config
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_node_type
|
||||
- d6_vocabulary_field
|
|
@ -1,7 +1,9 @@
|
|||
id: d6_taxonomy_term
|
||||
label: Taxonomy terms
|
||||
audit: true
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Content
|
||||
source:
|
||||
plugin: d6_taxonomy_term
|
||||
process:
|
|
@ -2,6 +2,7 @@ id: d6_taxonomy_vocabulary
|
|||
label: Taxonomy vocabularies
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary
|
||||
process:
|
||||
|
@ -15,6 +16,12 @@ process:
|
|||
field: vid
|
||||
length: 32
|
||||
migrated: true
|
||||
-
|
||||
# This plugin checks if the vocabulary being migrated is the one used by
|
||||
# Forum. If so, we use the machine name that Forum expects. Otherwise, we
|
||||
# leave it unchanged.
|
||||
plugin: forum_vocabulary
|
||||
machine_name: forums
|
||||
label: name
|
||||
name: name
|
||||
description: description
|
|
@ -2,6 +2,7 @@ id: d6_term_node
|
|||
label: Term/node relationships
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Content
|
||||
deriver: Drupal\taxonomy\Plugin\migrate\D6TermNodeDeriver
|
||||
source:
|
||||
plugin: d6_term_node
|
|
@ -1,7 +1,9 @@
|
|||
id: d6_term_node_revision
|
||||
label: Term/node relationship revisions
|
||||
audit: true
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Content
|
||||
deriver: Drupal\taxonomy\Plugin\migrate\D6TermNodeDeriver
|
||||
source:
|
||||
plugin: d6_term_node_revision
|
||||
|
@ -9,7 +11,7 @@ process:
|
|||
vid:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node
|
||||
migration: d6_node_revision
|
||||
source: vid
|
||||
-
|
||||
plugin: skip_on_empty
|
|
@ -0,0 +1,58 @@
|
|||
id: d6_vocabulary_entity_display
|
||||
label: Vocabulary display configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary_per_type
|
||||
constants:
|
||||
entity_type: node
|
||||
view_mode: default
|
||||
options:
|
||||
label: hidden
|
||||
type: entity_reference_label
|
||||
weight: 20
|
||||
field_prefix: field_
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
view_mode: 'constants/view_mode'
|
||||
options: 'constants/options'
|
||||
bundle:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node_type
|
||||
source: type
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
# This value is only used in the 'field_name' process pipeline below.
|
||||
raw_field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_taxonomy_vocabulary
|
||||
source: vid
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
field_name:
|
||||
# Prepend field_ to avoid conflicts with base fields, and make sure the
|
||||
# result is no longer than 32 characters.
|
||||
-
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/field_prefix
|
||||
- '@raw_field_name'
|
||||
-
|
||||
plugin: substr
|
||||
length: 32
|
||||
-
|
||||
# This plugin checks if the vocabulary being migrated is the one used by
|
||||
# Forum. If so, we use the machine name that Forum expects. Otherwise, we
|
||||
# leave it unchanged.
|
||||
plugin: forum_vocabulary
|
||||
machine_name: taxonomy_forums
|
||||
destination:
|
||||
plugin: component_entity_display
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_vocabulary_field_instance
|
|
@ -0,0 +1,62 @@
|
|||
id: d6_vocabulary_entity_form_display
|
||||
label: Vocabulary form display configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary_per_type
|
||||
constants:
|
||||
entity_type: node
|
||||
form_mode: default
|
||||
options:
|
||||
weight: 20
|
||||
field_prefix: field_
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
form_mode: 'constants/form_mode'
|
||||
options/type:
|
||||
plugin: static_map
|
||||
source: tags
|
||||
map:
|
||||
0: options_select
|
||||
1: entity_reference_autocomplete_tags
|
||||
options/weight: 'constants/options/weight'
|
||||
bundle:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node_type
|
||||
source: type
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
# This value is only used in the 'field_name' process pipeline below.
|
||||
raw_field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_taxonomy_vocabulary
|
||||
source: vid
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
field_name:
|
||||
# Prepend field_ to avoid conflicts with base fields, and make sure the
|
||||
# result is no longer than 32 characters.
|
||||
-
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/field_prefix
|
||||
- '@raw_field_name'
|
||||
-
|
||||
plugin: substr
|
||||
length: 32
|
||||
-
|
||||
# This plugin checks if the vocabulary being migrated is the one used by
|
||||
# Forum. If so, we use the machine name that Forum expects. Otherwise, we
|
||||
# leave it unchanged.
|
||||
plugin: forum_vocabulary
|
||||
machine_name: taxonomy_forums
|
||||
destination:
|
||||
plugin: component_entity_form_display
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_vocabulary_field_instance
|
|
@ -2,16 +2,19 @@ id: d6_vocabulary_field
|
|||
label: Vocabulary field configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary
|
||||
constants:
|
||||
entity_type: node
|
||||
type: entity_reference
|
||||
target_entity_type: taxonomy_term
|
||||
field_prefix: field_
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
type: 'constants/type'
|
||||
field_name:
|
||||
# This value is only used in the 'field_name' process pipeline below.
|
||||
raw_field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_taxonomy_vocabulary
|
||||
|
@ -19,6 +22,23 @@ process:
|
|||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
field_name:
|
||||
# Prepend field_ to avoid conflicts with base fields, and make sure the
|
||||
# result is no longer than 32 characters.
|
||||
-
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/field_prefix
|
||||
- '@raw_field_name'
|
||||
-
|
||||
plugin: substr
|
||||
length: 32
|
||||
-
|
||||
# This plugin checks if the vocabulary being migrated is the one used by
|
||||
# Forum. If so, we use the machine name that Forum expects. Otherwise, we
|
||||
# leave it unchanged.
|
||||
plugin: forum_vocabulary
|
||||
machine_name: taxonomy_forums
|
||||
'settings/target_type': 'constants/target_entity_type'
|
||||
cardinality: cardinality
|
||||
destination:
|
|
@ -0,0 +1,74 @@
|
|||
id: d6_vocabulary_field_instance
|
||||
label: Vocabulary field instance configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: d6_taxonomy_vocabulary_per_type
|
||||
constants:
|
||||
entity_type: node
|
||||
auto_create: true
|
||||
selection_handler: 'default:taxonomy_term'
|
||||
field_prefix: field_
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
bundle:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_node_type
|
||||
source: type
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
# This value is only used in the 'field_name' process pipeline below.
|
||||
raw_field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: d6_taxonomy_vocabulary
|
||||
source: vid
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
field_name:
|
||||
# Prepend field_ to avoid conflicts with base fields, and make sure the
|
||||
# result is no longer than 32 characters.
|
||||
-
|
||||
plugin: concat
|
||||
source:
|
||||
- constants/field_prefix
|
||||
- '@raw_field_name'
|
||||
-
|
||||
plugin: substr
|
||||
length: 32
|
||||
-
|
||||
# This plugin checks if the vocabulary being migrated is the one used by
|
||||
# Forum. If so, we use the machine name that Forum expects. Otherwise, we
|
||||
# leave it unchanged.
|
||||
plugin: forum_vocabulary
|
||||
machine_name: taxonomy_forums
|
||||
label: name
|
||||
'settings/handler': 'constants/selection_handler'
|
||||
'settings/handler_settings/target_bundles/0': '@field_name'
|
||||
'settings/handler_settings/auto_create': 'constants/auto_create'
|
||||
required: required
|
||||
# Get the i18n taxonomy translation setting for this vocabulary.
|
||||
# 0 - No multilingual options
|
||||
# 1 - Localizable terms. Run through the localization system.
|
||||
# 2 - Predefined language for a vocabulary and its terms.
|
||||
# 3 - Per-language terms, translatable (referencing terms with different
|
||||
# languages) but not localizable.
|
||||
translatable:
|
||||
plugin: static_map
|
||||
source: i18ntaxonomy_vocabulary
|
||||
default_value: 0
|
||||
map:
|
||||
0: false
|
||||
1: false
|
||||
2: false
|
||||
3: true
|
||||
destination:
|
||||
plugin: entity:field_config
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_node_type
|
||||
- d6_vocabulary_field
|
|
@ -1,7 +1,9 @@
|
|||
id: d7_taxonomy_term
|
||||
label: Taxonomy terms
|
||||
audit: true
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Content
|
||||
deriver: Drupal\taxonomy\Plugin\migrate\D7TaxonomyTermDeriver
|
||||
source:
|
||||
plugin: d7_taxonomy_term
|
||||
|
@ -30,7 +32,9 @@ process:
|
|||
plugin: default_value
|
||||
default_value: 0
|
||||
source: '@parent_id'
|
||||
forum_container: is_container
|
||||
changed: timestamp
|
||||
langcode: language
|
||||
destination:
|
||||
plugin: entity:taxonomy_term
|
||||
migration_dependencies:
|
|
@ -2,19 +2,24 @@ id: d7_taxonomy_vocabulary
|
|||
label: Taxonomy vocabularies
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: d7_taxonomy_vocabulary
|
||||
process:
|
||||
vid:
|
||||
-
|
||||
plugin: machine_name
|
||||
source: name
|
||||
-
|
||||
plugin: make_unique_entity_field
|
||||
source: machine_name
|
||||
entity_type: taxonomy_vocabulary
|
||||
field: vid
|
||||
length: 32
|
||||
migrated: true
|
||||
-
|
||||
# This plugin checks if the vocabulary being migrated is the one used by
|
||||
# Forum. If so, we use the machine name that Forum expects. Otherwise, we
|
||||
# leave it unchanged.
|
||||
plugin: forum_vocabulary
|
||||
machine_name: forums
|
||||
label: name
|
||||
name: name
|
||||
description: description
|
|
@ -3,11 +3,13 @@ label: Taxonomy configuration
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- taxonomy_override_selector
|
||||
- taxonomy_terms_per_page_admin
|
||||
source_module: taxonomy
|
||||
process:
|
||||
override_selector: taxonomy_override_selector
|
||||
terms_per_page_admin: taxonomy_terms_per_page_admin
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Entity\Routing;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
class VocabularyRouteProvider extends AdminHtmlRouteProvider {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRoutes(EntityTypeInterface $entity_type) {
|
||||
|
||||
$collection = parent::getRoutes($entity_type);
|
||||
|
||||
if ($reset_page_route = $this->getResetPageRoute($entity_type)) {
|
||||
$collection->add("entity.taxonomy_vocabulary.reset_form", $reset_page_route);
|
||||
}
|
||||
|
||||
if ($overview_page_route = $this->getOverviewPageRoute($entity_type)) {
|
||||
$collection->add("entity.taxonomy_vocabulary.overview_form", $overview_page_route);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCollectionRoute(EntityTypeInterface $entity_type) {
|
||||
if ($route = parent::getCollectionRoute($entity_type)) {
|
||||
$route->setRequirement('_permission', 'access taxonomy overview+administer taxonomy');
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reset page route.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return \Symfony\Component\Routing\Route|null
|
||||
* The generated route, if available.
|
||||
*/
|
||||
protected function getResetPageRoute(EntityTypeInterface $entity_type) {
|
||||
$route = new Route('/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/reset');
|
||||
$route->setDefault('_entity_form', 'taxonomy_vocabulary.reset');
|
||||
$route->setDefault('_title', 'Reset');
|
||||
$route->setRequirement('_permission', $entity_type->getAdminPermission());
|
||||
$route->setOption('_admin_route', TRUE);
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the overview page route.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return \Symfony\Component\Routing\Route|null
|
||||
* The generated route, if available.
|
||||
*/
|
||||
protected function getOverviewPageRoute(EntityTypeInterface $entity_type) {
|
||||
$route = new Route('/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview');
|
||||
$route->setDefault('_title_callback', 'Drupal\taxonomy\Controller\TaxonomyController::vocabularyTitle');
|
||||
$route->setDefault('_form', 'Drupal\taxonomy\Form\OverviewTerms');
|
||||
$route->setRequirement('_entity_access', 'taxonomy_vocabulary.access taxonomy overview');
|
||||
$route->setOption('_admin_route', TRUE);
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,10 +4,12 @@ namespace Drupal\taxonomy\Entity;
|
|||
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
use Drupal\Core\Entity\EntityChangedTrait;
|
||||
use Drupal\Core\Entity\EntityPublishedTrait;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Drupal\user\StatusItem;
|
||||
|
||||
/**
|
||||
* Defines the taxonomy term entity.
|
||||
|
@ -15,11 +17,19 @@ use Drupal\taxonomy\TermInterface;
|
|||
* @ContentEntityType(
|
||||
* id = "taxonomy_term",
|
||||
* label = @Translation("Taxonomy term"),
|
||||
* label_collection = @Translation("Taxonomy terms"),
|
||||
* label_singular = @Translation("taxonomy term"),
|
||||
* label_plural = @Translation("taxonomy terms"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count taxonomy term",
|
||||
* plural = "@count taxonomy terms",
|
||||
* ),
|
||||
* bundle_label = @Translation("Vocabulary"),
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\taxonomy\TermStorage",
|
||||
* "storage_schema" = "Drupal\taxonomy\TermStorageSchema",
|
||||
* "view_builder" = "Drupal\taxonomy\TermViewBuilder",
|
||||
* "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
|
||||
* "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
|
||||
* "access" = "Drupal\taxonomy\TermAccessControlHandler",
|
||||
* "views_data" = "Drupal\taxonomy\TermViewsData",
|
||||
* "form" = {
|
||||
|
@ -37,7 +47,8 @@ use Drupal\taxonomy\TermInterface;
|
|||
* "bundle" = "vid",
|
||||
* "label" = "name",
|
||||
* "langcode" = "langcode",
|
||||
* "uuid" = "uuid"
|
||||
* "uuid" = "uuid",
|
||||
* "published" = "status",
|
||||
* },
|
||||
* bundle_entity_type = "taxonomy_vocabulary",
|
||||
* field_ui_base_route = "entity.taxonomy_vocabulary.overview_form",
|
||||
|
@ -46,6 +57,7 @@ use Drupal\taxonomy\TermInterface;
|
|||
* "canonical" = "/taxonomy/term/{taxonomy_term}",
|
||||
* "delete-form" = "/taxonomy/term/{taxonomy_term}/delete",
|
||||
* "edit-form" = "/taxonomy/term/{taxonomy_term}/edit",
|
||||
* "create" = "/taxonomy/term",
|
||||
* },
|
||||
* permission_granularity = "bundle"
|
||||
* )
|
||||
|
@ -53,6 +65,7 @@ use Drupal\taxonomy\TermInterface;
|
|||
class Term extends ContentEntityBase implements TermInterface {
|
||||
|
||||
use EntityChangedTrait;
|
||||
use EntityPublishedTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -62,22 +75,28 @@ class Term extends ContentEntityBase implements TermInterface {
|
|||
|
||||
// See if any of the term's children are about to be become orphans.
|
||||
$orphans = [];
|
||||
foreach (array_keys($entities) as $tid) {
|
||||
if ($children = $storage->loadChildren($tid)) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
foreach ($entities as $tid => $term) {
|
||||
if ($children = $storage->getChildren($term)) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $child */
|
||||
foreach ($children as $child) {
|
||||
$parent = $child->get('parent');
|
||||
// Update child parents item list.
|
||||
$parent->filter(function ($item) use ($tid) {
|
||||
return $item->target_id != $tid;
|
||||
});
|
||||
|
||||
// If the term has multiple parents, we don't delete it.
|
||||
$parents = $storage->loadParents($child->id());
|
||||
if (empty($parents)) {
|
||||
if ($parent->count()) {
|
||||
$child->save();
|
||||
}
|
||||
else {
|
||||
$orphans[] = $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete term hierarchy information after looking up orphans but before
|
||||
// deleting them so that their children/parent information is consistent.
|
||||
$storage->deleteTermHierarchy(array_keys($entities));
|
||||
|
||||
if (!empty($orphans)) {
|
||||
$storage->delete($orphans);
|
||||
}
|
||||
|
@ -86,14 +105,11 @@ class Term extends ContentEntityBase implements TermInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
parent::postSave($storage, $update);
|
||||
|
||||
// Only change the parents if a value is set, keep the existing values if
|
||||
// not.
|
||||
if (isset($this->parent->target_id)) {
|
||||
$storage->deleteTermHierarchy([$this->id()]);
|
||||
$storage->updateTermHierarchy($this);
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
// Terms with no parents are mandatory children of <root>.
|
||||
if (!$this->get('parent')->count()) {
|
||||
$this->parent->target_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +120,12 @@ class Term extends ContentEntityBase implements TermInterface {
|
|||
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
|
||||
// Add the published field.
|
||||
$fields += static::publishedBaseFieldDefinitions($entity_type);
|
||||
// @todo Remove the usage of StatusItem in
|
||||
// https://www.drupal.org/project/drupal/issues/2936864.
|
||||
$fields['status']->getItemDefinition()->setClass(StatusItem::class);
|
||||
|
||||
$fields['tid']->setLabel(t('Term ID'))
|
||||
->setDescription(t('The term ID.'));
|
||||
|
||||
|
@ -154,8 +176,7 @@ class Term extends ContentEntityBase implements TermInterface {
|
|||
->setLabel(t('Term Parents'))
|
||||
->setDescription(t('The parents of this term.'))
|
||||
->setSetting('target_type', 'taxonomy_term')
|
||||
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
|
||||
->setCustomStorage(TRUE);
|
||||
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED);
|
||||
|
||||
$fields['changed'] = BaseFieldDefinition::create('changed')
|
||||
->setLabel(t('Changed'))
|
||||
|
@ -165,6 +186,16 @@ class Term extends ContentEntityBase implements TermInterface {
|
|||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
|
||||
// Only terms in the same bundle can be a parent.
|
||||
$fields['parent'] = clone $base_field_definitions['parent'];
|
||||
$fields['parent']->setSetting('handler_settings', ['target_bundles' => [$bundle => $bundle]]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -229,20 +260,8 @@ class Term extends ContentEntityBase implements TermInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVocabularyId() {
|
||||
return $this->get('vid')->target_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getFieldsToSkipFromTranslationChangesCheck() {
|
||||
// @todo the current implementation of the parent field makes it impossible
|
||||
// for ::hasTranslationChanges() to correctly check the field for changes,
|
||||
// so it is currently skipped from the comparision and has to be fixed by
|
||||
// https://www.drupal.org/node/2843060.
|
||||
$fields = parent::getFieldsToSkipFromTranslationChangesCheck();
|
||||
$fields[] = 'parent';
|
||||
return $fields;
|
||||
@trigger_error('The ' . __METHOD__ . ' method is deprecated since version 8.4.0 and will be removed before 9.0.0. Use ' . __CLASS__ . '::bundle() instead to get the vocabulary ID.', E_USER_DEPRECATED);
|
||||
return $this->bundle();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,13 +12,25 @@ use Drupal\taxonomy\VocabularyInterface;
|
|||
* @ConfigEntityType(
|
||||
* id = "taxonomy_vocabulary",
|
||||
* label = @Translation("Taxonomy vocabulary"),
|
||||
* label_singular = @Translation("vocabulary"),
|
||||
* label_plural = @Translation("vocabularies"),
|
||||
* label_collection = @Translation("Taxonomy"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count vocabulary",
|
||||
* plural = "@count vocabularies"
|
||||
* ),
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\taxonomy\VocabularyStorage",
|
||||
* "list_builder" = "Drupal\taxonomy\VocabularyListBuilder",
|
||||
* "access" = "Drupal\taxonomy\VocabularyAccessControlHandler",
|
||||
* "form" = {
|
||||
* "default" = "Drupal\taxonomy\VocabularyForm",
|
||||
* "reset" = "Drupal\taxonomy\Form\VocabularyResetForm",
|
||||
* "delete" = "Drupal\taxonomy\Form\VocabularyDeleteForm"
|
||||
* "delete" = "Drupal\taxonomy\Form\VocabularyDeleteForm",
|
||||
* "overview" = "Drupal\taxonomy\Form\OverviewTerms"
|
||||
* },
|
||||
* "route_provider" = {
|
||||
* "html" = "Drupal\taxonomy\Entity\Routing\VocabularyRouteProvider",
|
||||
* }
|
||||
* },
|
||||
* admin_permission = "administer taxonomy",
|
||||
|
@ -30,7 +42,7 @@ use Drupal\taxonomy\VocabularyInterface;
|
|||
* "weight" = "weight"
|
||||
* },
|
||||
* links = {
|
||||
* "add-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/add",
|
||||
* "add-form" = "/admin/structure/taxonomy/add",
|
||||
* "delete-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/delete",
|
||||
* "reset-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/reset",
|
||||
* "overview-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview",
|
||||
|
@ -75,7 +87,7 @@ class Vocabulary extends ConfigEntityBundleBase implements VocabularyInterface {
|
|||
* Possible values:
|
||||
* - VocabularyInterface::HIERARCHY_DISABLED: No parents.
|
||||
* - VocabularyInterface::HIERARCHY_SINGLE: Single parent.
|
||||
* - VocabularyInterface::HIERARCHY_MULTIPL: Multiple parents.
|
||||
* - VocabularyInterface::HIERARCHY_MULTIPLE: Multiple parents.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
|
|
|
@ -2,15 +2,20 @@
|
|||
|
||||
namespace Drupal\taxonomy\Form;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\taxonomy\VocabularyInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides terms overview form for a taxonomy vocabulary.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class OverviewTerms extends FormBase {
|
||||
|
||||
|
@ -35,6 +40,20 @@ class OverviewTerms extends FormBase {
|
|||
*/
|
||||
protected $storageController;
|
||||
|
||||
/**
|
||||
* The term list builder.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityListBuilderInterface
|
||||
*/
|
||||
protected $termListBuilder;
|
||||
|
||||
/**
|
||||
* The renderer service.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Constructs an OverviewTerms object.
|
||||
*
|
||||
|
@ -42,11 +61,15 @@ class OverviewTerms extends FormBase {
|
|||
* The module handler service.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer service.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager) {
|
||||
public function __construct(ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, RendererInterface $renderer = NULL) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->storageController = $entity_manager->getStorage('taxonomy_term');
|
||||
$this->termListBuilder = $entity_manager->getListBuilder('taxonomy_term');
|
||||
$this->renderer = $renderer ?: \Drupal::service('renderer');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +78,8 @@ class OverviewTerms extends FormBase {
|
|||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('module_handler'),
|
||||
$container->get('entity.manager')
|
||||
$container->get('entity.manager'),
|
||||
$container->get('renderer')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -204,18 +228,39 @@ class OverviewTerms extends FormBase {
|
|||
}
|
||||
|
||||
$errors = $form_state->getErrors();
|
||||
$destination = $this->getDestinationArray();
|
||||
$row_position = 0;
|
||||
// Build the actual form.
|
||||
$access_control_handler = $this->entityManager->getAccessControlHandler('taxonomy_term');
|
||||
$create_access = $access_control_handler->createAccess($taxonomy_vocabulary->id(), NULL, [], TRUE);
|
||||
if ($create_access->isAllowed()) {
|
||||
$empty = $this->t('No terms available. <a href=":link">Add term</a>.', [':link' => Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $taxonomy_vocabulary->id()])->toString()]);
|
||||
}
|
||||
else {
|
||||
$empty = $this->t('No terms available.');
|
||||
}
|
||||
$form['terms'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => [$this->t('Name'), $this->t('Weight'), $this->t('Operations')],
|
||||
'#empty' => $this->t('No terms available. <a href=":link">Add term</a>.', [':link' => $this->url('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $taxonomy_vocabulary->id()])]),
|
||||
'#empty' => $empty,
|
||||
'#header' => [
|
||||
'term' => $this->t('Name'),
|
||||
'operations' => $this->t('Operations'),
|
||||
'weight' => $this->t('Weight'),
|
||||
],
|
||||
'#attributes' => [
|
||||
'id' => 'taxonomy',
|
||||
],
|
||||
];
|
||||
$this->renderer->addCacheableDependency($form['terms'], $create_access);
|
||||
|
||||
// Only allow access to changing weights if the user has update access for
|
||||
// all terms.
|
||||
$change_weight_access = AccessResult::allowed();
|
||||
foreach ($current_page as $key => $term) {
|
||||
$form['terms'][$key] = [
|
||||
'term' => [],
|
||||
'operations' => [],
|
||||
'weight' => [],
|
||||
];
|
||||
/** @var $term \Drupal\Core\Entity\EntityInterface */
|
||||
$term = $this->entityManager->getTranslationFromContext($term);
|
||||
$form['terms'][$key]['#term'] = $term;
|
||||
|
@ -227,7 +272,7 @@ class OverviewTerms extends FormBase {
|
|||
];
|
||||
}
|
||||
$form['terms'][$key]['term'] = [
|
||||
'#prefix' => !empty($indentation) ? drupal_render($indentation) : '',
|
||||
'#prefix' => !empty($indentation) ? \Drupal::service('renderer')->render($indentation) : '',
|
||||
'#type' => 'link',
|
||||
'#title' => $term->getName(),
|
||||
'#url' => $term->urlInfo(),
|
||||
|
@ -260,39 +305,26 @@ class OverviewTerms extends FormBase {
|
|||
],
|
||||
];
|
||||
}
|
||||
$form['terms'][$key]['weight'] = [
|
||||
'#type' => 'weight',
|
||||
'#delta' => $delta,
|
||||
'#title' => $this->t('Weight for added term'),
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $term->getWeight(),
|
||||
'#attributes' => [
|
||||
'class' => ['term-weight'],
|
||||
],
|
||||
];
|
||||
$operations = [
|
||||
'edit' => [
|
||||
'title' => $this->t('Edit'),
|
||||
'query' => $destination,
|
||||
'url' => $term->urlInfo('edit-form'),
|
||||
],
|
||||
'delete' => [
|
||||
'title' => $this->t('Delete'),
|
||||
'query' => $destination,
|
||||
'url' => $term->urlInfo('delete-form'),
|
||||
],
|
||||
];
|
||||
if ($this->moduleHandler->moduleExists('content_translation') && content_translation_translate_access($term)->isAllowed()) {
|
||||
$operations['translate'] = [
|
||||
'title' => $this->t('Translate'),
|
||||
'query' => $destination,
|
||||
'url' => $term->urlInfo('drupal:content-translation-overview'),
|
||||
$update_access = $term->access('update', NULL, TRUE);
|
||||
$change_weight_access = $change_weight_access->andIf($update_access);
|
||||
|
||||
if ($update_access->isAllowed()) {
|
||||
$form['terms'][$key]['weight'] = [
|
||||
'#type' => 'weight',
|
||||
'#delta' => $delta,
|
||||
'#title' => $this->t('Weight for added term'),
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $term->getWeight(),
|
||||
'#attributes' => ['class' => ['term-weight']],
|
||||
];
|
||||
}
|
||||
|
||||
if ($operations = $this->termListBuilder->getOperations($term)) {
|
||||
$form['terms'][$key]['operations'] = [
|
||||
'#type' => 'operations',
|
||||
'#links' => $operations,
|
||||
];
|
||||
}
|
||||
$form['terms'][$key]['operations'] = [
|
||||
'#type' => 'operations',
|
||||
'#links' => $operations,
|
||||
];
|
||||
|
||||
$form['terms'][$key]['#attributes']['class'] = [];
|
||||
if ($parent_fields) {
|
||||
|
@ -322,34 +354,37 @@ class OverviewTerms extends FormBase {
|
|||
$row_position++;
|
||||
}
|
||||
|
||||
if ($parent_fields) {
|
||||
$this->renderer->addCacheableDependency($form['terms'], $change_weight_access);
|
||||
if ($change_weight_access->isAllowed()) {
|
||||
if ($parent_fields) {
|
||||
$form['terms']['#tabledrag'][] = [
|
||||
'action' => 'match',
|
||||
'relationship' => 'parent',
|
||||
'group' => 'term-parent',
|
||||
'subgroup' => 'term-parent',
|
||||
'source' => 'term-id',
|
||||
'hidden' => FALSE,
|
||||
];
|
||||
$form['terms']['#tabledrag'][] = [
|
||||
'action' => 'depth',
|
||||
'relationship' => 'group',
|
||||
'group' => 'term-depth',
|
||||
'hidden' => FALSE,
|
||||
];
|
||||
$form['terms']['#attached']['library'][] = 'taxonomy/drupal.taxonomy';
|
||||
$form['terms']['#attached']['drupalSettings']['taxonomy'] = [
|
||||
'backStep' => $back_step,
|
||||
'forwardStep' => $forward_step,
|
||||
];
|
||||
}
|
||||
$form['terms']['#tabledrag'][] = [
|
||||
'action' => 'match',
|
||||
'relationship' => 'parent',
|
||||
'group' => 'term-parent',
|
||||
'subgroup' => 'term-parent',
|
||||
'source' => 'term-id',
|
||||
'hidden' => FALSE,
|
||||
];
|
||||
$form['terms']['#tabledrag'][] = [
|
||||
'action' => 'depth',
|
||||
'relationship' => 'group',
|
||||
'group' => 'term-depth',
|
||||
'hidden' => FALSE,
|
||||
];
|
||||
$form['terms']['#attached']['library'][] = 'taxonomy/drupal.taxonomy';
|
||||
$form['terms']['#attached']['drupalSettings']['taxonomy'] = [
|
||||
'backStep' => $back_step,
|
||||
'forwardStep' => $forward_step,
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'term-weight',
|
||||
];
|
||||
}
|
||||
$form['terms']['#tabledrag'][] = [
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'term-weight',
|
||||
];
|
||||
|
||||
if ($taxonomy_vocabulary->getHierarchy() != VocabularyInterface::HIERARCHY_MULTIPLE && count($tree) > 1) {
|
||||
if (($taxonomy_vocabulary->getHierarchy() !== VocabularyInterface::HIERARCHY_MULTIPLE && count($tree) > 1) && $change_weight_access->isAllowed()) {
|
||||
$form['actions'] = ['#type' => 'actions', '#tree' => FALSE];
|
||||
$form['actions']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
|
@ -462,7 +497,7 @@ class OverviewTerms extends FormBase {
|
|||
$vocabulary->setHierarchy($hierarchy);
|
||||
$vocabulary->save();
|
||||
}
|
||||
drupal_set_message($this->t('The configuration options have been saved.'));
|
||||
$this->messenger()->addStatus($this->t('The configuration options have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,8 @@ use Drupal\Core\Url;
|
|||
|
||||
/**
|
||||
* Provides a deletion confirmation form for taxonomy term.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TermDeleteForm extends ContentEntityDeleteForm {
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ use Drupal\Core\Entity\EntityDeleteForm;
|
|||
|
||||
/**
|
||||
* Provides a deletion confirmation form for taxonomy vocabulary.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class VocabularyDeleteForm extends EntityDeleteForm {
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Provides confirmation form for resetting a vocabulary to alphabetical order.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class VocabularyResetForm extends EntityConfirmFormBase {
|
||||
|
||||
|
@ -80,7 +82,7 @@ class VocabularyResetForm extends EntityConfirmFormBase {
|
|||
parent::submitForm($form, $form_state);
|
||||
$this->termStorage->resetWeights($this->entity->id());
|
||||
|
||||
drupal_set_message($this->t('Reset vocabulary %name to alphabetical order.', ['%name' => $this->entity->label()]));
|
||||
$this->messenger()->addStatus($this->t('Reset vocabulary %name to alphabetical order.', ['%name' => $this->entity->label()]));
|
||||
$this->logger('taxonomy')->notice('Reset vocabulary %name to alphabetical order.', ['%name' => $this->entity->label()]);
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\taxonomy\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
@ -24,8 +23,13 @@ class TermSelection extends DefaultSelection {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function entityQueryAlter(SelectInterface $query) {
|
||||
// @todo: How to set access, as vocabulary is now config?
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'sort' => [
|
||||
'field' => 'name',
|
||||
'direction' => 'asc',
|
||||
],
|
||||
] + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,8 +38,6 @@ class TermSelection extends DefaultSelection {
|
|||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
$form['target_bundles']['#title'] = $this->t('Available Vocabularies');
|
||||
|
||||
// Sorting is not possible for taxonomy terms because we use
|
||||
// \Drupal\taxonomy\TermStorageInterface::loadTree() to retrieve matches.
|
||||
$form['sort']['#access'] = FALSE;
|
||||
|
@ -49,20 +51,25 @@ class TermSelection extends DefaultSelection {
|
|||
*/
|
||||
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
|
||||
if ($match || $limit) {
|
||||
$this->configuration['handler_settings']['sort'] = ['field' => 'name', 'direction' => 'asc'];
|
||||
return parent::getReferenceableEntities($match, $match_operator, $limit);
|
||||
}
|
||||
|
||||
$options = [];
|
||||
|
||||
$bundles = $this->entityManager->getBundleInfo('taxonomy_term');
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
$bundle_names = !empty($handler_settings['target_bundles']) ? $handler_settings['target_bundles'] : array_keys($bundles);
|
||||
$bundle_names = $this->getConfiguration()['target_bundles'] ?: array_keys($bundles);
|
||||
|
||||
$has_admin_access = $this->currentUser->hasPermission('administer taxonomy');
|
||||
$unpublished_terms = [];
|
||||
foreach ($bundle_names as $bundle) {
|
||||
if ($vocabulary = Vocabulary::load($bundle)) {
|
||||
/** @var \Drupal\taxonomy\TermInterface[] $terms */
|
||||
if ($terms = $this->entityManager->getStorage('taxonomy_term')->loadTree($vocabulary->id(), 0, NULL, TRUE)) {
|
||||
foreach ($terms as $term) {
|
||||
if (!$has_admin_access && (!$term->isPublished() || in_array($term->parent->target_id, $unpublished_terms))) {
|
||||
$unpublished_terms[] = $term->id();
|
||||
continue;
|
||||
}
|
||||
$options[$vocabulary->id()][$term->id()] = str_repeat('-', $term->depth) . Html::escape($this->entityManager->getTranslationFromContext($term)->label());
|
||||
}
|
||||
}
|
||||
|
@ -72,4 +79,63 @@ class TermSelection extends DefaultSelection {
|
|||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
|
||||
if ($match) {
|
||||
return parent::countReferenceableEntities($match, $match_operator);
|
||||
}
|
||||
|
||||
$total = 0;
|
||||
$referenceable_entities = $this->getReferenceableEntities($match, $match_operator, 0);
|
||||
foreach ($referenceable_entities as $bundle => $entities) {
|
||||
$total += count($entities);
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = parent::buildEntityQuery($match, $match_operator);
|
||||
|
||||
// Adding the 'taxonomy_term_access' tag is sadly insufficient for terms:
|
||||
// core requires us to also know about the concept of 'published' and
|
||||
// 'unpublished'.
|
||||
if (!$this->currentUser->hasPermission('administer taxonomy')) {
|
||||
$query->condition('status', 1);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createNewEntity($entity_type_id, $bundle, $label, $uid) {
|
||||
$term = parent::createNewEntity($entity_type_id, $bundle, $label, $uid);
|
||||
|
||||
// In order to create a referenceable term, it needs to published.
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
$term->setPublished();
|
||||
|
||||
return $term;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateReferenceableNewEntities(array $entities) {
|
||||
$entities = parent::validateReferenceableNewEntities($entities);
|
||||
// Mirror the conditions checked in buildEntityQuery().
|
||||
if (!$this->currentUser->hasPermission('administer taxonomy')) {
|
||||
$entities = array_filter($entities, function ($term) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
return $term->isPublished();
|
||||
});
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ class D7TaxonomyTermDeriver extends DeriverBase implements ContainerDeriverInter
|
|||
$this->fieldPluginCache[$field_type] = $this->fieldPluginManager->createInstance($plugin_id, ['core' => 7], $migration);
|
||||
}
|
||||
$this->fieldPluginCache[$field_type]
|
||||
->processFieldValues($migration, $field_name, $info);
|
||||
->defineValueProcessPipeline($migration, $field_name, $info);
|
||||
}
|
||||
catch (PluginNotFoundException $ex) {
|
||||
try {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\cckfield;
|
||||
|
||||
@trigger_error('TaxonomyTermReference is deprecated in Drupal 8.4.x and will be removed before Drupal 9.0.x. Use \Drupal\taxonomy\Plugin\migrate\field\TaxonomyTermReference instead.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
|
||||
|
||||
|
@ -11,24 +13,24 @@ use Drupal\migrate_drupal\Plugin\migrate\cckfield\CckFieldPluginBase;
|
|||
* type_map = {
|
||||
* "taxonomy_term_reference" = "entity_reference"
|
||||
* },
|
||||
* core = {6,7}
|
||||
* core = {6,7},
|
||||
* source_module = "taxonomy",
|
||||
* destination_module = "core",
|
||||
* )
|
||||
*
|
||||
* @deprecated in Drupal 8.4.x, to be removed before Drupal 9.0.x. Use
|
||||
* \Drupal\taxonomy\Plugin\migrate\field\TaxonomyTermReference instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2751897
|
||||
*/
|
||||
class TaxonomyTermReference extends CckFieldPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldFormatterMap() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) {
|
||||
$process = [
|
||||
'plugin' => 'iterator',
|
||||
'plugin' => 'sub_process',
|
||||
'source' => $field_name,
|
||||
'process' => [
|
||||
'target_id' => 'tid',
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\field;
|
||||
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\field\FieldPluginBase;
|
||||
|
||||
/**
|
||||
* @MigrateField(
|
||||
* id = "taxonomy_term_reference",
|
||||
* type_map = {
|
||||
* "taxonomy_term_reference" = "entity_reference"
|
||||
* },
|
||||
* core = {6,7},
|
||||
* source_module = "taxonomy",
|
||||
* destination_module = "core",
|
||||
* )
|
||||
*/
|
||||
class TaxonomyTermReference extends FieldPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldFormatterMap() {
|
||||
return [
|
||||
'taxonomy_term_reference_link' => 'entity_reference_label',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defineValueProcessPipeline(MigrationInterface $migration, $field_name, $data) {
|
||||
$process = [
|
||||
'plugin' => 'sub_process',
|
||||
'source' => $field_name,
|
||||
'process' => [
|
||||
'target_id' => 'tid',
|
||||
],
|
||||
];
|
||||
$migration->setProcessOfProperty($field_name, $process);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Checks if the vocabulary being migrated is the one used for forums.
|
||||
*
|
||||
* Drupal 8 Forum is expecting specific machine names for its field and
|
||||
* vocabulary names. This process plugin forces a given machine name to the
|
||||
* field or vocabulary that is being migrated.
|
||||
*
|
||||
* The 'forum_vocabulary' source property is evaluated in the
|
||||
* d6_taxonomy_vocabulary or d7_taxonomy_vocabulary source plugins and is set to
|
||||
* true if the vocabulary vid being migrated is the same as the one in the
|
||||
* 'forum_nav_vocabulary' variable on the source site.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* @code
|
||||
* process:
|
||||
* field_name:
|
||||
* plugin: forum_vocabulary
|
||||
* machine_name: taxonomy_forums
|
||||
* @endcode
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "forum_vocabulary"
|
||||
* )
|
||||
*/
|
||||
class ForumVocabulary extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if ($row->getSourceProperty('forum_vocabulary') && !empty($this->configuration['machine_name'])) {
|
||||
$value = $this->configuration['machine_name'];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "taxonomy_term",
|
||||
* source_provider = "taxonomy"
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*
|
||||
* @deprecated in Drupal 8.3.0, intended to be removed in Drupal 9.0.0.
|
||||
|
|
|
@ -12,7 +12,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_taxonomy_term",
|
||||
* source_provider = "taxonomy"
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class Term extends DrupalSqlBase {
|
||||
|
@ -45,6 +45,10 @@ class Term extends DrupalSqlBase {
|
|||
'weight' => $this->t('Weight'),
|
||||
'parent' => $this->t("The Drupal term IDs of the term's parents."),
|
||||
];
|
||||
if (isset($this->configuration['translations'])) {
|
||||
$fields['language'] = $this->t('The term language.');
|
||||
$fields['trid'] = $this->t('Translation ID.');
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_term_node",
|
||||
* source_provider = "taxonomy"
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class TermNode extends DrupalSqlBase {
|
||||
|
|
|
@ -6,7 +6,8 @@ namespace Drupal\taxonomy\Plugin\migrate\source\d6;
|
|||
* Source returning tids from the term_node table for the non-current revision.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_term_node_revision"
|
||||
* id = "d6_term_node_revision",
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class TermNodeRevision extends TermNode {
|
||||
|
|
|
@ -11,7 +11,7 @@ use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_taxonomy_vocabulary",
|
||||
* source_provider = "taxonomy"
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class Vocabulary extends DrupalSqlBase {
|
||||
|
@ -69,6 +69,14 @@ class Vocabulary extends DrupalSqlBase {
|
|||
->fetchCol();
|
||||
$row->setSourceProperty('node_types', $node_types);
|
||||
$row->setSourceProperty('cardinality', ($row->getSourceProperty('tags') == 1 || $row->getSourceProperty('multiple') == 1) ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : 1);
|
||||
|
||||
// If the vocabulary being migrated is the one defined in the
|
||||
// 'forum_nav_vocabulary' variable, set the 'forum_vocabulary' source
|
||||
// property to true so we know this is the vocabulary used by Forum.
|
||||
if ($this->variableGet('forum_nav_vocabulary', 0) == $row->getSourceProperty('vid')) {
|
||||
$row->setSourceProperty('forum_vocabulary', TRUE);
|
||||
}
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Gets all the vocabularies based on the node types that have Taxonomy enabled.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_taxonomy_vocabulary_per_type",
|
||||
* source_provider = "taxonomy"
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class VocabularyPerType extends Vocabulary {
|
||||
|
@ -22,6 +24,26 @@ class VocabularyPerType extends Vocabulary {
|
|||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
// Get the i18n taxonomy translation setting for this vocabulary.
|
||||
// 0 - No multilingual options
|
||||
// 1 - Localizable terms. Run through the localization system.
|
||||
// 2 - Predefined language for a vocabulary and its terms.
|
||||
// 3 - Per-language terms, translatable (referencing terms with different
|
||||
// languages) but not localizable.
|
||||
$i18ntaxonomy_vocab = $this->variableGet('i18ntaxonomy_vocabulary', NULL);
|
||||
$vid = $row->getSourceProperty('vid');
|
||||
$i18ntaxonomy_vocabulary = FALSE;
|
||||
if (array_key_exists($vid, $i18ntaxonomy_vocab)) {
|
||||
$i18ntaxonomy_vocabulary = $i18ntaxonomy_vocab[$vid];
|
||||
}
|
||||
$row->setSourceProperty('i18ntaxonomy_vocabulary', $i18ntaxonomy_vocabulary);
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 6 vocabulary translations from source database.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_taxonomy_vocabulary_translation",
|
||||
* source_module = "i18ntaxonomy"
|
||||
* )
|
||||
*/
|
||||
class VocabularyTranslation extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('vocabulary', 'v')
|
||||
->fields('v', ['vid', 'name', 'description'])
|
||||
->fields('i18n', ['lid', 'type', 'property', 'objectid'])
|
||||
->fields('lt', ['lid', 'translation'])
|
||||
->condition('i18n.type', 'vocabulary');
|
||||
$query->addField('lt', 'language', 'language');
|
||||
// The i18n_strings table has two columns containing the object ID, objectid
|
||||
// and objectindex. The objectid column is a text field. Therefore, for the
|
||||
// join to work in PostgreSQL, use the objectindex field as this is numeric
|
||||
// like the vid field.
|
||||
$query->join('i18n_strings', 'i18n', 'v.vid = i18n.objectindex');
|
||||
$query->leftJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'vid' => $this->t('The vocabulary ID.'),
|
||||
'language' => $this->t('Language for this field.'),
|
||||
'property' => $this->t('Name of property being translated.'),
|
||||
'translation' => $this->t('Translation of either the title or explanation.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['vid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_taxonomy_term",
|
||||
* source_provider = "taxonomy"
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class Term extends FieldableEntity {
|
||||
|
@ -56,10 +56,26 @@ class Term extends FieldableEntity {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
$tid = $row->getSourceProperty('tid');
|
||||
$vocabulary = $row->getSourceProperty('machine_name');
|
||||
$default_language = (array) $this->variableGet('language_default', ['language' => 'en']);
|
||||
|
||||
// If this entity was translated using Entity Translation, we need to get
|
||||
// its source language to get the field values in the right language.
|
||||
// The translations will be migrated by the d7_node_entity_translation
|
||||
// migration.
|
||||
$translatable_vocabularies = array_keys(array_filter($this->variableGet('entity_translation_taxonomy', [])));
|
||||
$entity_translatable = $this->isEntityTranslatable('taxonomy_term') && in_array($vocabulary, $translatable_vocabularies, TRUE);
|
||||
$source_language = $this->getEntityTranslationSourceLanguage('taxonomy_term', $tid);
|
||||
$language = $entity_translatable && $source_language ? $source_language : $default_language['language'];
|
||||
$row->setSourceProperty('language', $language);
|
||||
|
||||
// Get Field API field values.
|
||||
foreach (array_keys($this->getFields('taxonomy_term', $row->getSourceProperty('machine_name'))) as $field) {
|
||||
$tid = $row->getSourceProperty('tid');
|
||||
$row->setSourceProperty($field, $this->getFieldValues('taxonomy_term', $field, $tid));
|
||||
foreach ($this->getFields('taxonomy_term', $vocabulary) as $field_name => $field) {
|
||||
// Ensure we're using the right language if the entity and the field are
|
||||
// translatable.
|
||||
$field_language = $entity_translatable && $field['translatable'] ? $language : NULL;
|
||||
$row->setSourceProperty($field_name, $this->getFieldValues('taxonomy_term', $field_name, $tid, NULL, $field_language));
|
||||
}
|
||||
|
||||
// Find parents for this row.
|
||||
|
@ -70,6 +86,28 @@ class Term extends FieldableEntity {
|
|||
->fetchCol();
|
||||
$row->setSourceProperty('parent', $parents);
|
||||
|
||||
// Determine if this is a forum container.
|
||||
$forum_container_tids = $this->variableGet('forum_containers', []);
|
||||
$current_tid = $row->getSourceProperty('tid');
|
||||
$row->setSourceProperty('is_container', in_array($current_tid, $forum_container_tids));
|
||||
|
||||
// If the term name or term description were replaced by real fields using
|
||||
// the Drupal 7 Title module, use the fields value instead of the term name
|
||||
// or term description.
|
||||
if ($this->moduleExists('title')) {
|
||||
$name_field = $row->getSourceProperty('name_field');
|
||||
if (isset($name_field[0]['value'])) {
|
||||
$row->setSourceProperty('name', $name_field[0]['value']);
|
||||
}
|
||||
$description_field = $row->getSourceProperty('description_field');
|
||||
if (isset($description_field[0]['value'])) {
|
||||
$row->setSourceProperty('description', $description_field[0]['value']);
|
||||
}
|
||||
if (isset($description_field[0]['format'])) {
|
||||
$row->setSourceProperty('format', $description_field[0]['format']);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
|
||||
|
||||
/**
|
||||
* Provides Drupal 7 taxonomy term entity translation source plugin.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_taxonomy_term_entity_translation",
|
||||
* source_module = "entity_translation"
|
||||
* )
|
||||
*/
|
||||
class TermEntityTranslation extends FieldableEntity {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('entity_translation', 'et')
|
||||
->fields('et')
|
||||
->fields('td', [
|
||||
'name',
|
||||
'description',
|
||||
'format',
|
||||
])
|
||||
->fields('tv', [
|
||||
'machine_name',
|
||||
])
|
||||
->condition('et.entity_type', 'taxonomy_term')
|
||||
->condition('et.source', '', '<>');
|
||||
|
||||
$query->innerJoin('taxonomy_term_data', 'td', 'td.tid = et.entity_id');
|
||||
$query->innerJoin('taxonomy_vocabulary', 'tv', 'td.vid = tv.vid');
|
||||
|
||||
if (isset($this->configuration['bundle'])) {
|
||||
$query->condition('tv.machine_name', (array) $this->configuration['bundle'], 'IN');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
$tid = $row->getSourceProperty('entity_id');
|
||||
$vocabulary = $row->getSourceProperty('machine_name');
|
||||
$language = $row->getSourceProperty('language');
|
||||
|
||||
// Get Field API field values.
|
||||
foreach ($this->getFields('taxonomy_term', $vocabulary) as $field_name => $field) {
|
||||
// Ensure we're using the right language if the entity is translatable.
|
||||
$field_language = $field['translatable'] ? $language : NULL;
|
||||
$row->setSourceProperty($field_name, $this->getFieldValues('taxonomy_term', $field_name, $tid, NULL, $field_language));
|
||||
}
|
||||
|
||||
// If the term name or term description were replaced by real fields using
|
||||
// the Drupal 7 Title module, use the fields value instead of the term name
|
||||
// or term description.
|
||||
if ($this->moduleExists('title')) {
|
||||
$name_field = $row->getSourceProperty('name_field');
|
||||
if (isset($name_field[0]['value'])) {
|
||||
$row->setSourceProperty('name', $name_field[0]['value']);
|
||||
}
|
||||
$description_field = $row->getSourceProperty('description_field');
|
||||
if (isset($description_field[0]['value'])) {
|
||||
$row->setSourceProperty('description', $description_field[0]['value']);
|
||||
}
|
||||
if (isset($description_field[0]['format'])) {
|
||||
$row->setSourceProperty('format', $description_field[0]['format']);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if this is a forum container.
|
||||
$forum_container_tids = $this->variableGet('forum_containers', []);
|
||||
$row->setSourceProperty('is_container', in_array($tid, $forum_container_tids));
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'entity_type' => $this->t('The entity type this translation relates to'),
|
||||
'entity_id' => $this->t('The entity ID this translation relates to'),
|
||||
'revision_id' => $this->t('The entity revision ID this translation relates to'),
|
||||
'language' => $this->t('The target language for this translation.'),
|
||||
'source' => $this->t('The source language from which this translation was created.'),
|
||||
'uid' => $this->t('The author of this translation.'),
|
||||
'status' => $this->t('Boolean indicating whether the translation is published (visible to non-administrators).'),
|
||||
'translate' => $this->t('A boolean indicating whether this translation needs to be updated.'),
|
||||
'created' => $this->t('The Unix timestamp when the translation was created.'),
|
||||
'changed' => $this->t('The Unix timestamp when the translation was most recently saved.'),
|
||||
'name' => $this->t('The name of the term.'),
|
||||
'description' => $this->t('The term description.'),
|
||||
'format' => $this->t('Format of the term description.'),
|
||||
'machine_name' => $this->t('Vocabulary machine name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'entity_id' => [
|
||||
'type' => 'integer',
|
||||
'alias' => 'et',
|
||||
],
|
||||
'language' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'et',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\taxonomy\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
|
@ -9,7 +10,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_taxonomy_vocabulary",
|
||||
* source_provider = "taxonomy"
|
||||
* source_module = "taxonomy"
|
||||
* )
|
||||
*/
|
||||
class Vocabulary extends DrupalSqlBase {
|
||||
|
@ -42,10 +43,24 @@ class Vocabulary extends DrupalSqlBase {
|
|||
'hierarchy' => $this->t('The type of hierarchy allowed within the vocabulary. (0 = disabled, 1 = single, 2 = multiple)'),
|
||||
'module' => $this->t('Module responsible for the vocabulary.'),
|
||||
'weight' => $this->t('The weight of the vocabulary in relation to other vocabularies.'),
|
||||
'machine_name' => $this->t('Unique machine name of the vocabulary.')
|
||||
'machine_name' => $this->t('Unique machine name of the vocabulary.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
// If the vocabulary being migrated is the one defined in the
|
||||
// 'forum_nav_vocabulary' variable, set the 'forum_vocabulary' source
|
||||
// property to true so we know this is the vocabulary used by Forum.
|
||||
if ($this->variableGet('forum_nav_vocabulary', 0) == $row->getSourceProperty('vid')) {
|
||||
$row->setSourceProperty('forum_vocabulary', TRUE);
|
||||
}
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\taxonomy\Plugin\views\argument;
|
||||
|
||||
use Drupal\Core\Database\Query\Condition;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
|
@ -21,7 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
class IndexTidDepth extends ArgumentPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var EntityStorageInterface
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $termStorage;
|
||||
|
||||
|
@ -106,22 +107,23 @@ class IndexTidDepth extends ArgumentPluginBase implements ContainerFactoryPlugin
|
|||
// Now build the subqueries.
|
||||
$subquery = db_select('taxonomy_index', 'tn');
|
||||
$subquery->addField('tn', 'nid');
|
||||
$where = db_or()->condition('tn.tid', $tids, $operator);
|
||||
$where = (new Condition('OR'))->condition('tn.tid', $tids, $operator);
|
||||
$last = "tn";
|
||||
|
||||
if ($this->options['depth'] > 0) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', 'th', "th.tid = tn.tid");
|
||||
$subquery->leftJoin('taxonomy_term__parent', 'th', "th.entity_id = tn.tid");
|
||||
$last = "th";
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.parent = th$count.tid");
|
||||
$where->condition("th$count.tid", $tids, $operator);
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.parent_target_id = th$count.entity_id");
|
||||
$where->condition("th$count.entity_id", $tids, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
elseif ($this->options['depth'] < 0) {
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.tid = th$count.parent");
|
||||
$where->condition("th$count.tid", $tids, $operator);
|
||||
$field = $count == 1 ? 'tid' : 'entity_id';
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.$field = th$count.parent_target_id");
|
||||
$where->condition("th$count.entity_id", $tids, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
|
|||
*/
|
||||
class IndexTidDepthModifier extends ArgumentPluginBase {
|
||||
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) { }
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {}
|
||||
|
||||
public function query($group_by = FALSE) { }
|
||||
public function query($group_by = FALSE) {}
|
||||
|
||||
public function preQuery() {
|
||||
// We don't know our argument yet, but it's based upon our position:
|
||||
|
|
|
@ -17,7 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
class Taxonomy extends NumericArgument implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var EntityStorageInterface
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $termStorage;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ class VocabularyVid extends NumericArgument {
|
|||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param VocabularyStorageInterface $vocabulary_storage
|
||||
* @param \Drupal\taxonomy\VocabularyStorageInterface $vocabulary_storage
|
||||
* The vocabulary storage.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, VocabularyStorageInterface $vocabulary_storage) {
|
||||
|
|
|
@ -34,7 +34,7 @@ class Tid extends ArgumentDefaultPluginBase implements CacheableDependencyInterf
|
|||
/**
|
||||
* The vocabulary storage.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface.
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface
|
||||
*/
|
||||
protected $vocabularyStorage;
|
||||
|
||||
|
@ -116,7 +116,7 @@ class Tid extends ArgumentDefaultPluginBase implements CacheableDependencyInterf
|
|||
];
|
||||
$form['node'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Load default filter from node page, that\'s good for related taxonomy blocks'),
|
||||
'#title' => $this->t("Load default filter from node page, that's good for related taxonomy blocks"),
|
||||
'#default_value' => $this->options['node'],
|
||||
];
|
||||
|
||||
|
@ -194,7 +194,7 @@ class Tid extends ArgumentDefaultPluginBase implements CacheableDependencyInterf
|
|||
$taxonomy_terms = $node->{$field->getName()}->referencedEntities();
|
||||
/** @var \Drupal\taxonomy\TermInterface $taxonomy_term */
|
||||
foreach ($taxonomy_terms as $taxonomy_term) {
|
||||
$taxonomy[$taxonomy_term->id()] = $taxonomy_term->getVocabularyId();
|
||||
$taxonomy[$taxonomy_term->id()] = $taxonomy_term->bundle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class TaxonomyIndexTid extends PrerenderList {
|
|||
/**
|
||||
* The vocabulary storage.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface.
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface
|
||||
*/
|
||||
protected $vocabularyStorage;
|
||||
|
||||
|
@ -145,8 +145,8 @@ class TaxonomyIndexTid extends PrerenderList {
|
|||
foreach ($data as $tid => $term) {
|
||||
$this->items[$node_nid][$tid]['name'] = \Drupal::entityManager()->getTranslationFromContext($term)->label();
|
||||
$this->items[$node_nid][$tid]['tid'] = $tid;
|
||||
$this->items[$node_nid][$tid]['vocabulary_vid'] = $term->getVocabularyId();
|
||||
$this->items[$node_nid][$tid]['vocabulary'] = $vocabularies[$term->getVocabularyId()]->label();
|
||||
$this->items[$node_nid][$tid]['vocabulary_vid'] = $term->bundle();
|
||||
$this->items[$node_nid][$tid]['vocabulary'] = $vocabularies[$term->bundle()]->label();
|
||||
|
||||
if (!empty($this->options['link_to_taxonomy'])) {
|
||||
$this->items[$node_nid][$tid]['make_link'] = TRUE;
|
||||
|
|
|
@ -31,7 +31,6 @@ class TermName extends EntityField {
|
|||
return $items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -82,7 +82,9 @@ class TaxonomyIndexTid extends ManyToOne {
|
|||
}
|
||||
}
|
||||
|
||||
public function hasExtraOptions() { return TRUE; }
|
||||
public function hasExtraOptions() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\taxonomy\Plugin\views\filter;
|
||||
|
||||
use Drupal\Core\Database\Query\Condition;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
|
@ -54,7 +55,7 @@ class TaxonomyIndexTidDepth extends TaxonomyIndexTid {
|
|||
$operator = '=';
|
||||
}
|
||||
else {
|
||||
$operator = 'IN';# " IN (" . implode(', ', array_fill(0, sizeof($this->value), '%d')) . ")";
|
||||
$operator = 'IN';
|
||||
}
|
||||
|
||||
// The normal use of ensureMyTable() here breaks Views.
|
||||
|
@ -72,22 +73,23 @@ class TaxonomyIndexTidDepth extends TaxonomyIndexTid {
|
|||
// Now build the subqueries.
|
||||
$subquery = db_select('taxonomy_index', 'tn');
|
||||
$subquery->addField('tn', 'nid');
|
||||
$where = db_or()->condition('tn.tid', $this->value, $operator);
|
||||
$where = (new Condition('OR'))->condition('tn.tid', $this->value, $operator);
|
||||
$last = "tn";
|
||||
|
||||
if ($this->options['depth'] > 0) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', 'th', "th.tid = tn.tid");
|
||||
$subquery->leftJoin('taxonomy_term__parent', 'th', "th.entity_id = tn.tid");
|
||||
$last = "th";
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.parent = th$count.tid");
|
||||
$where->condition("th$count.tid", $this->value, $operator);
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.parent_target_id = th$count.entity_id");
|
||||
$where->condition("th$count.entity_id", $this->value, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
elseif ($this->options['depth'] < 0) {
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.tid = th$count.parent");
|
||||
$where->condition("th$count.tid", $this->value, $operator);
|
||||
$field = $count == 1 ? 'tid' : 'entity_id';
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.$field = th$count.parent_target_id");
|
||||
$where->condition("th$count.entity_id", $this->value, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Drupal\taxonomy;
|
|||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -48,19 +49,30 @@ class TaxonomyPermissions implements ContainerInjectionInterface {
|
|||
*/
|
||||
public function permissions() {
|
||||
$permissions = [];
|
||||
foreach ($this->entityManager->getStorage('taxonomy_vocabulary')->loadMultiple() as $vocabulary) {
|
||||
$permissions += [
|
||||
'edit terms in ' . $vocabulary->id() => [
|
||||
'title' => $this->t('Edit terms in %vocabulary', ['%vocabulary' => $vocabulary->label()]),
|
||||
],
|
||||
];
|
||||
$permissions += [
|
||||
'delete terms in ' . $vocabulary->id() => [
|
||||
'title' => $this->t('Delete terms from %vocabulary', ['%vocabulary' => $vocabulary->label()]),
|
||||
],
|
||||
];
|
||||
foreach (Vocabulary::loadMultiple() as $vocabulary) {
|
||||
$permissions += $this->buildPermissions($vocabulary);
|
||||
}
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a standard list of taxonomy term permissions for a given vocabulary.
|
||||
*
|
||||
* @param \Drupal\taxonomy\VocabularyInterface $vocabulary
|
||||
* The vocabulary.
|
||||
*
|
||||
* @return array
|
||||
* An array of permission names and descriptions.
|
||||
*/
|
||||
protected function buildPermissions(VocabularyInterface $vocabulary) {
|
||||
$id = $vocabulary->id();
|
||||
$args = ['%vocabulary' => $vocabulary->label()];
|
||||
|
||||
return [
|
||||
"create terms in $id" => ['title' => $this->t('%vocabulary: Create terms', $args)],
|
||||
"delete terms in $id" => ['title' => $this->t('%vocabulary: Delete terms', $args)],
|
||||
"edit terms in $id" => ['title' => $this->t('%vocabulary: Edit terms', $args)],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,19 +18,37 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
if ($account->hasPermission('administer taxonomy')) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
|
||||
switch ($operation) {
|
||||
case 'view':
|
||||
return AccessResult::allowedIfHasPermission($account, 'access content');
|
||||
$access_result = AccessResult::allowedIf($account->hasPermission('access content') && $entity->isPublished())
|
||||
->cachePerPermissions()
|
||||
->addCacheableDependency($entity);
|
||||
if (!$access_result->isAllowed()) {
|
||||
$access_result->setReason("The 'access content' permission is required and the taxonomy term must be published.");
|
||||
}
|
||||
return $access_result;
|
||||
|
||||
case 'update':
|
||||
return AccessResult::allowedIfHasPermissions($account, ["edit terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
|
||||
if ($account->hasPermission("edit terms in {$entity->bundle()}")) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
|
||||
return AccessResult::neutral()->setReason("The following permissions are required: 'edit terms in {$entity->bundle()}' OR 'administer taxonomy'.");
|
||||
|
||||
case 'delete':
|
||||
return AccessResult::allowedIfHasPermissions($account, ["delete terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
|
||||
if ($account->hasPermission("delete terms in {$entity->bundle()}")) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
|
||||
return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in {$entity->bundle()}' OR 'administer taxonomy'.");
|
||||
|
||||
default:
|
||||
// No opinion.
|
||||
return AccessResult::neutral();
|
||||
return AccessResult::neutral()->cachePerPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +56,7 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
|
||||
return AccessResult::allowedIfHasPermission($account, 'administer taxonomy');
|
||||
return AccessResult::allowedIfHasPermissions($account, ["create terms in $entity_bundle", 'administer taxonomy'], 'OR');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Base for handler for taxonomy term edit forms.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TermForm extends ContentEntityForm {
|
||||
|
||||
|
@ -36,14 +38,17 @@ class TermForm extends ContentEntityForm {
|
|||
// before loading the full vocabulary. Contrib modules can then intercept
|
||||
// before hook_form_alter to provide scalable alternatives.
|
||||
if (!$this->config('taxonomy.settings')->get('override_selector')) {
|
||||
$parent = array_keys($taxonomy_storage->loadParents($term->id()));
|
||||
$children = $taxonomy_storage->loadTree($vocabulary->id(), $term->id());
|
||||
$exclude = [];
|
||||
if (!$term->isNew()) {
|
||||
$parent = array_keys($taxonomy_storage->loadParents($term->id()));
|
||||
$children = $taxonomy_storage->loadTree($vocabulary->id(), $term->id());
|
||||
|
||||
// A term can't be the child of itself, nor of its children.
|
||||
foreach ($children as $child) {
|
||||
$exclude[] = $child->tid;
|
||||
// A term can't be the child of itself, nor of its children.
|
||||
foreach ($children as $child) {
|
||||
$exclude[] = $child->tid;
|
||||
}
|
||||
$exclude[] = $term->id();
|
||||
}
|
||||
$exclude[] = $term->id();
|
||||
|
||||
$tree = $taxonomy_storage->loadTree($vocabulary->id());
|
||||
$options = ['<' . $this->t('root') . '>'];
|
||||
|
@ -85,7 +90,7 @@ class TermForm extends ContentEntityForm {
|
|||
'#value' => $term->id(),
|
||||
];
|
||||
|
||||
return parent::form($form, $form_state, $term);
|
||||
return parent::form($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -127,11 +132,11 @@ class TermForm extends ContentEntityForm {
|
|||
$view_link = $term->link($term->getName());
|
||||
switch ($result) {
|
||||
case SAVED_NEW:
|
||||
drupal_set_message($this->t('Created new term %term.', ['%term' => $view_link]));
|
||||
$this->messenger()->addStatus($this->t('Created new term %term.', ['%term' => $view_link]));
|
||||
$this->logger('taxonomy')->notice('Created new term %term.', ['%term' => $term->getName(), 'link' => $edit_link]);
|
||||
break;
|
||||
case SAVED_UPDATED:
|
||||
drupal_set_message($this->t('Updated term %term.', ['%term' => $view_link]));
|
||||
$this->messenger()->addStatus($this->t('Updated term %term.', ['%term' => $view_link]));
|
||||
$this->logger('taxonomy')->notice('Updated term %term.', ['%term' => $term->getName(), 'link' => $edit_link]);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,11 +4,12 @@ namespace Drupal\taxonomy;
|
|||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityChangedInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a taxonomy term entity.
|
||||
*/
|
||||
interface TermInterface extends ContentEntityInterface, EntityChangedInterface {
|
||||
interface TermInterface extends ContentEntityInterface, EntityChangedInterface, EntityPublishedInterface {
|
||||
|
||||
/**
|
||||
* Gets the term's description.
|
||||
|
@ -57,7 +58,7 @@ interface TermInterface extends ContentEntityInterface, EntityChangedInterface {
|
|||
/**
|
||||
* Sets the name of the term.
|
||||
*
|
||||
* @param int $name
|
||||
* @param string $name
|
||||
* The term's name.
|
||||
*
|
||||
* @return $this
|
||||
|
@ -87,6 +88,9 @@ interface TermInterface extends ContentEntityInterface, EntityChangedInterface {
|
|||
*
|
||||
* @return string
|
||||
* The id of the vocabulary.
|
||||
*
|
||||
* @deprecated Scheduled for removal before Drupal 9.0.0. Use
|
||||
* TermInterface::bundle() instead.
|
||||
*/
|
||||
public function getVocabularyId();
|
||||
|
||||
|
|
|
@ -2,35 +2,14 @@
|
|||
|
||||
namespace Drupal\taxonomy;
|
||||
|
||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||
|
||||
/**
|
||||
* Defines a Controller class for taxonomy terms.
|
||||
*/
|
||||
class TermStorage extends SqlContentEntityStorage implements TermStorageInterface {
|
||||
|
||||
/**
|
||||
* Array of loaded parents keyed by child term ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parents = [];
|
||||
|
||||
/**
|
||||
* Array of all loaded term ancestry keyed by ancestor term ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parentsAll = [];
|
||||
|
||||
/**
|
||||
* Array of child terms keyed by parent term ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $children = [];
|
||||
|
||||
/**
|
||||
* Array of term parents keyed by vocabulary ID and child term ID.
|
||||
*
|
||||
|
@ -59,6 +38,14 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
*/
|
||||
protected $trees = [];
|
||||
|
||||
/**
|
||||
* Array of all loaded term ancestry keyed by ancestor term ID, keyed by term
|
||||
* ID.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermInterface[][]
|
||||
*/
|
||||
protected $ancestors;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
|
@ -80,9 +67,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
*/
|
||||
public function resetCache(array $ids = NULL) {
|
||||
drupal_static_reset('taxonomy_term_count_nodes');
|
||||
$this->parents = [];
|
||||
$this->parentsAll = [];
|
||||
$this->children = [];
|
||||
$this->ancestors = [];
|
||||
$this->treeChildren = [];
|
||||
$this->treeParents = [];
|
||||
$this->treeTerms = [];
|
||||
|
@ -93,100 +78,125 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteTermHierarchy($tids) {
|
||||
$this->database->delete('taxonomy_term_hierarchy')
|
||||
->condition('tid', $tids, 'IN')
|
||||
->execute();
|
||||
}
|
||||
public function deleteTermHierarchy($tids) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateTermHierarchy(EntityInterface $term) {
|
||||
$query = $this->database->insert('taxonomy_term_hierarchy')
|
||||
->fields(['tid', 'parent']);
|
||||
|
||||
foreach ($term->parent as $parent) {
|
||||
$query->values([
|
||||
'tid' => $term->id(),
|
||||
'parent' => (int) $parent->target_id,
|
||||
]);
|
||||
}
|
||||
$query->execute();
|
||||
}
|
||||
public function updateTermHierarchy(EntityInterface $term) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadParents($tid) {
|
||||
if (!isset($this->parents[$tid])) {
|
||||
$parents = [];
|
||||
$query = $this->database->select('taxonomy_term_field_data', 't');
|
||||
$query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
|
||||
$query->addField('t', 'tid');
|
||||
$query->condition('h.tid', $tid);
|
||||
$query->condition('t.default_langcode', 1);
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$query->orderBy('t.weight');
|
||||
$query->orderBy('t.name');
|
||||
if ($ids = $query->execute()->fetchCol()) {
|
||||
$parents = $this->loadMultiple($ids);
|
||||
$terms = [];
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
if ($tid && $term = $this->load($tid)) {
|
||||
foreach ($this->getParents($term) as $id => $parent) {
|
||||
// This method currently doesn't return the <root> parent.
|
||||
// @see https://www.drupal.org/node/2019905
|
||||
if (!empty($id)) {
|
||||
$terms[$id] = $parent;
|
||||
}
|
||||
}
|
||||
$this->parents[$tid] = $parents;
|
||||
}
|
||||
return $this->parents[$tid];
|
||||
|
||||
return $terms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of parents of this term.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* The parent taxonomy term entities keyed by term ID. If this term has a
|
||||
* <root> parent, that item is keyed with 0 and will have NULL as value.
|
||||
*
|
||||
* @internal
|
||||
* @todo Refactor away when TreeInterface is introduced.
|
||||
*/
|
||||
protected function getParents(TermInterface $term) {
|
||||
$parents = $ids = [];
|
||||
// Cannot use $this->get('parent')->referencedEntities() here because that
|
||||
// strips out the '0' reference.
|
||||
foreach ($term->get('parent') as $item) {
|
||||
if ($item->target_id == 0) {
|
||||
// The <root> parent.
|
||||
$parents[0] = NULL;
|
||||
continue;
|
||||
}
|
||||
$ids[] = $item->target_id;
|
||||
}
|
||||
|
||||
// @todo Better way to do this? AND handle the NULL/0 parent?
|
||||
// Querying the terms again so that the same access checks are run when
|
||||
// getParents() is called as in Drupal version prior to 8.3.
|
||||
$loaded_parents = [];
|
||||
|
||||
if ($ids) {
|
||||
$query = \Drupal::entityQuery('taxonomy_term')
|
||||
->condition('tid', $ids, 'IN');
|
||||
|
||||
$loaded_parents = static::loadMultiple($query->execute());
|
||||
}
|
||||
|
||||
return $parents + $loaded_parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadAllParents($tid) {
|
||||
if (!isset($this->parentsAll[$tid])) {
|
||||
$parents = [];
|
||||
if ($term = $this->load($tid)) {
|
||||
$parents[$term->id()] = $term;
|
||||
$terms_to_search[] = $term->id();
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
return (!empty($tid) && $term = $this->load($tid)) ? $this->getAncestors($term) : [];
|
||||
}
|
||||
|
||||
while ($tid = array_shift($terms_to_search)) {
|
||||
if ($new_parents = $this->loadParents($tid)) {
|
||||
foreach ($new_parents as $new_parent) {
|
||||
if (!isset($parents[$new_parent->id()])) {
|
||||
$parents[$new_parent->id()] = $new_parent;
|
||||
$terms_to_search[] = $new_parent->id();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns all ancestors of this term.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* A list of ancestor taxonomy term entities keyed by term ID.
|
||||
*
|
||||
* @internal
|
||||
* @todo Refactor away when TreeInterface is introduced.
|
||||
*/
|
||||
protected function getAncestors(TermInterface $term) {
|
||||
if (!isset($this->ancestors[$term->id()])) {
|
||||
$this->ancestors[$term->id()] = [$term->id() => $term];
|
||||
$search[] = $term->id();
|
||||
|
||||
while ($tid = array_shift($search)) {
|
||||
foreach ($this->getParents(static::load($tid)) as $id => $parent) {
|
||||
if ($parent && !isset($this->ancestors[$term->id()][$id])) {
|
||||
$this->ancestors[$term->id()][$id] = $parent;
|
||||
$search[] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->parentsAll[$tid] = $parents;
|
||||
}
|
||||
return $this->parentsAll[$tid];
|
||||
return $this->ancestors[$term->id()];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadChildren($tid, $vid = NULL) {
|
||||
if (!isset($this->children[$tid])) {
|
||||
$children = [];
|
||||
$query = $this->database->select('taxonomy_term_field_data', 't');
|
||||
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
|
||||
$query->addField('t', 'tid');
|
||||
$query->condition('h.parent', $tid);
|
||||
if ($vid) {
|
||||
$query->condition('t.vid', $vid);
|
||||
}
|
||||
$query->condition('t.default_langcode', 1);
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$query->orderBy('t.weight');
|
||||
$query->orderBy('t.name');
|
||||
if ($ids = $query->execute()->fetchCol()) {
|
||||
$children = $this->loadMultiple($ids);
|
||||
}
|
||||
$this->children[$tid] = $children;
|
||||
}
|
||||
return $this->children[$tid];
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
return (!empty($tid) && $term = $this->load($tid)) ? $this->getChildren($term) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all children terms of this term.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* A list of children taxonomy term entities keyed by term ID.
|
||||
*
|
||||
* @internal
|
||||
* @todo Refactor away when TreeInterface is introduced.
|
||||
*/
|
||||
public function getChildren(TermInterface $term) {
|
||||
$query = \Drupal::entityQuery('taxonomy_term')
|
||||
->condition('parent', $term->id());
|
||||
return static::loadMultiple($query->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,12 +211,12 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
$this->treeChildren[$vid] = [];
|
||||
$this->treeParents[$vid] = [];
|
||||
$this->treeTerms[$vid] = [];
|
||||
$query = $this->database->select('taxonomy_term_field_data', 't');
|
||||
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
|
||||
$query = $this->database->select($this->getDataTable(), 't');
|
||||
$query->join('taxonomy_term__parent', 'p', 't.tid = p.entity_id');
|
||||
$query->addExpression('parent_target_id', 'parent');
|
||||
$result = $query
|
||||
->addTag('taxonomy_term_access')
|
||||
->fields('t')
|
||||
->fields('h', ['parent'])
|
||||
->condition('t.vid', $vid)
|
||||
->condition('t.default_langcode', 1)
|
||||
->orderBy('t.weight')
|
||||
|
@ -254,7 +264,9 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
$term = clone $term;
|
||||
}
|
||||
$term->depth = $depth;
|
||||
unset($term->parent);
|
||||
if (!$load_entities) {
|
||||
unset($term->parent);
|
||||
}
|
||||
$tid = $load_entities ? $term->id() : $term->tid;
|
||||
$term->parents = $this->treeParents[$vid][$tid];
|
||||
$tree[] = $term;
|
||||
|
@ -293,7 +305,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
public function nodeCount($vid) {
|
||||
$query = $this->database->select('taxonomy_index', 'ti');
|
||||
$query->addExpression('COUNT(DISTINCT ti.nid)');
|
||||
$query->leftJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid');
|
||||
$query->leftJoin($this->getBaseTable(), 'td', 'ti.tid = td.tid');
|
||||
$query->condition('td.vid', $vid);
|
||||
$query->addTag('vocabulary_node_count');
|
||||
return $query->execute()->fetchField();
|
||||
|
@ -303,7 +315,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetWeights($vid) {
|
||||
$this->database->update('taxonomy_term_field_data')
|
||||
$this->database->update($this->getDataTable())
|
||||
->fields(['weight' => 0])
|
||||
->condition('vid', $vid)
|
||||
->execute();
|
||||
|
@ -313,7 +325,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNodeTerms(array $nids, array $vocabs = [], $langcode = NULL) {
|
||||
$query = db_select('taxonomy_term_field_data', 'td');
|
||||
$query = db_select($this->getDataTable(), 'td');
|
||||
$query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid');
|
||||
$query->fields('td', ['tid']);
|
||||
$query->addField('tn', 'nid', 'node_nid');
|
||||
|
@ -351,7 +363,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
public function __sleep() {
|
||||
$vars = parent::__sleep();
|
||||
// Do not serialize static cache.
|
||||
unset($vars['parents'], $vars['parentsAll'], $vars['children'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
|
||||
unset($vars['ancestors'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
|
||||
return $vars;
|
||||
}
|
||||
|
||||
|
@ -361,9 +373,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
|||
public function __wakeup() {
|
||||
parent::__wakeup();
|
||||
// Initialize static caches.
|
||||
$this->parents = [];
|
||||
$this->parentsAll = [];
|
||||
$this->children = [];
|
||||
$this->ancestors = [];
|
||||
$this->treeChildren = [];
|
||||
$this->treeParents = [];
|
||||
$this->treeTerms = [];
|
||||
|
|
|
@ -15,6 +15,10 @@ interface TermStorageInterface extends ContentEntityStorageInterface {
|
|||
*
|
||||
* @param array $tids
|
||||
* Array of terms that need to be removed from hierarchy.
|
||||
*
|
||||
* @todo Remove this method in Drupal 9.0.x. Now the parent references are
|
||||
* automatically cleared when deleting a taxonomy term.
|
||||
* https://www.drupal.org/node/2785693
|
||||
*/
|
||||
public function deleteTermHierarchy($tids);
|
||||
|
||||
|
@ -23,6 +27,10 @@ interface TermStorageInterface extends ContentEntityStorageInterface {
|
|||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $term
|
||||
* Term entity that needs to be added to term hierarchy information.
|
||||
*
|
||||
* @todo remove this method Drupal 9.0.x. Now the parent references are
|
||||
* automatically updates when when a taxonomy term is added/updated.
|
||||
* https://www.drupal.org/node/2785693
|
||||
*/
|
||||
public function updateTermHierarchy(EntityInterface $term);
|
||||
|
||||
|
@ -52,7 +60,7 @@ interface TermStorageInterface extends ContentEntityStorageInterface {
|
|||
* Finds all children of a term ID.
|
||||
*
|
||||
* @param int $tid
|
||||
* Term ID to retrieve parents for.
|
||||
* Term ID to retrieve children for.
|
||||
* @param string $vid
|
||||
* An optional vocabulary ID to restrict the child search.
|
||||
*
|
||||
|
|
|
@ -15,42 +15,14 @@ class TermStorageSchema extends SqlContentEntityStorageSchema {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
|
||||
$schema = parent::getEntitySchema($entity_type, $reset = FALSE);
|
||||
$schema = parent::getEntitySchema($entity_type, $reset);
|
||||
|
||||
$schema['taxonomy_term_field_data']['indexes'] += [
|
||||
'taxonomy_term__tree' => ['vid', 'weight', 'name'],
|
||||
'taxonomy_term__vid_name' => ['vid', 'name'],
|
||||
];
|
||||
|
||||
$schema['taxonomy_term_hierarchy'] = [
|
||||
'description' => 'Stores the hierarchical relationship between terms.',
|
||||
'fields' => [
|
||||
'tid' => [
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Primary Key: The {taxonomy_term_data}.tid of the term.',
|
||||
],
|
||||
'parent' => [
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "Primary Key: The {taxonomy_term_data}.tid of the term's parent. 0 indicates no parent.",
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
'parent' => ['parent'],
|
||||
],
|
||||
'foreign keys' => [
|
||||
'taxonomy_term_data' => [
|
||||
'table' => 'taxonomy_term_data',
|
||||
'columns' => ['tid' => 'tid'],
|
||||
],
|
||||
],
|
||||
'primary key' => ['tid', 'parent'],
|
||||
];
|
||||
if ($data_table = $this->storage->getDataTable()) {
|
||||
$schema[$data_table]['indexes'] += [
|
||||
'taxonomy_term__tree' => ['vid', 'weight', 'name'],
|
||||
'taxonomy_term__vid_name' => ['vid', 'name'],
|
||||
];
|
||||
}
|
||||
|
||||
$schema['taxonomy_index'] = [
|
||||
'description' => 'Maintains denormalized information about node/term relationships.',
|
||||
|
|
|
@ -2,24 +2,17 @@
|
|||
|
||||
namespace Drupal\taxonomy;
|
||||
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
@trigger_error(__NAMESPACE__ . '\TermViewBuilder is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. Use \Drupal\Core\Entity\EntityViewBuilder instead. See https://www.drupal.org/node/2924233.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\Core\Entity\EntityViewBuilder;
|
||||
|
||||
/**
|
||||
* View builder handler for taxonomy terms.
|
||||
*
|
||||
* @deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\Core\Entity\EntityViewBuilder instead.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityViewBuilder
|
||||
* @see https://www.drupal.org/node/2924233
|
||||
*/
|
||||
class TermViewBuilder extends EntityViewBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function alterBuild(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
|
||||
parent::alterBuild($build, $entity, $display, $view_mode);
|
||||
$build['#contextual_links']['taxonomy_term'] = [
|
||||
'route_parameters' => ['taxonomy_term' => $entity->id()],
|
||||
'metadata' => ['changed' => $entity->getChangedTime()],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
class TermViewBuilder extends EntityViewBuilder {}
|
||||
|
|
|
@ -36,7 +36,7 @@ class TermViewsData extends EntityViewsData {
|
|||
$data['taxonomy_term_field_data']['tid']['filter']['id'] = 'taxonomy_index_tid';
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['title'] = $this->t('Term');
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['help'] = $this->t('Taxonomy term chosen from autocomplete or select widget.');
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['hierarchy table'] = 'taxonomy_term_hierarchy';
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['hierarchy table'] = 'taxonomy_term__parent';
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['numeric'] = TRUE;
|
||||
|
||||
$data['taxonomy_term_field_data']['tid_raw'] = [
|
||||
|
@ -61,12 +61,12 @@ class TermViewsData extends EntityViewsData {
|
|||
'argument field' => 'tid',
|
||||
'base' => 'node_field_data',
|
||||
'field' => 'nid',
|
||||
'relationship' => 'node_field_data:term_node_tid'
|
||||
'relationship' => 'node_field_data:term_node_tid',
|
||||
],
|
||||
];
|
||||
|
||||
$data['taxonomy_term_field_data']['vid']['help'] = $this->t('Filter the results of "Taxonomy: Term" to a particular vocabulary.');
|
||||
unset($data['taxonomy_term_field_data']['vid']['field']);
|
||||
$data['taxonomy_term_field_data']['vid']['field']['help'] = t('The vocabulary name.');
|
||||
$data['taxonomy_term_field_data']['vid']['argument']['id'] = 'vocabulary_vid';
|
||||
unset($data['taxonomy_term_field_data']['vid']['sort']);
|
||||
|
||||
|
@ -133,7 +133,7 @@ class TermViewsData extends EntityViewsData {
|
|||
],
|
||||
];
|
||||
|
||||
$data['taxonomy_index']['table']['group'] = $this->t('Taxonomy term');
|
||||
$data['taxonomy_index']['table']['group'] = $this->t('Taxonomy term');
|
||||
|
||||
$data['taxonomy_index']['table']['join'] = [
|
||||
'taxonomy_term_field_data' => [
|
||||
|
@ -146,8 +146,8 @@ class TermViewsData extends EntityViewsData {
|
|||
'left_field' => 'nid',
|
||||
'field' => 'nid',
|
||||
],
|
||||
'taxonomy_term_hierarchy' => [
|
||||
'left_field' => 'tid',
|
||||
'taxonomy_term__parent' => [
|
||||
'left_field' => 'entity_id',
|
||||
'field' => 'tid',
|
||||
],
|
||||
];
|
||||
|
@ -181,7 +181,7 @@ class TermViewsData extends EntityViewsData {
|
|||
'filter' => [
|
||||
'title' => $this->t('Has taxonomy term'),
|
||||
'id' => 'taxonomy_index_tid',
|
||||
'hierarchy table' => 'taxonomy_term_hierarchy',
|
||||
'hierarchy table' => 'taxonomy_term__parent',
|
||||
'numeric' => TRUE,
|
||||
'skip base' => 'taxonomy_term_field_data',
|
||||
'allow empty' => TRUE,
|
||||
|
@ -216,47 +216,22 @@ class TermViewsData extends EntityViewsData {
|
|||
'title' => $this->t('Post date'),
|
||||
'help' => $this->t('The date the content related to a term was posted.'),
|
||||
'sort' => [
|
||||
'id' => 'date'
|
||||
'id' => 'date',
|
||||
],
|
||||
'filter' => [
|
||||
'id' => 'date',
|
||||
],
|
||||
];
|
||||
|
||||
$data['taxonomy_term_hierarchy']['table']['group'] = $this->t('Taxonomy term');
|
||||
$data['taxonomy_term_hierarchy']['table']['provider'] = 'taxonomy';
|
||||
|
||||
$data['taxonomy_term_hierarchy']['table']['join'] = [
|
||||
'taxonomy_term_hierarchy' => [
|
||||
// Link to self through left.parent = right.tid (going down in depth).
|
||||
'left_field' => 'tid',
|
||||
'field' => 'parent',
|
||||
],
|
||||
'taxonomy_term_field_data' => [
|
||||
// Link directly to taxonomy_term_field_data via tid.
|
||||
'left_field' => 'tid',
|
||||
'field' => 'tid',
|
||||
],
|
||||
// Link to self through left.parent = right.tid (going down in depth).
|
||||
$data['taxonomy_term__parent']['table']['join']['taxonomy_term__parent'] = [
|
||||
'left_field' => 'entity_id',
|
||||
'field' => 'parent_target_id',
|
||||
];
|
||||
|
||||
$data['taxonomy_term_hierarchy']['parent'] = [
|
||||
'title' => $this->t('Parent term'),
|
||||
'help' => $this->t('The parent term of the term. This can produce duplicate entries if you are using a vocabulary that allows multiple parents.'),
|
||||
'relationship' => [
|
||||
'base' => 'taxonomy_term_field_data',
|
||||
'field' => 'parent',
|
||||
'label' => $this->t('Parent'),
|
||||
'id' => 'standard',
|
||||
],
|
||||
'filter' => [
|
||||
'help' => $this->t('Filter the results of "Taxonomy: Term" by the parent pid.'),
|
||||
'id' => 'numeric',
|
||||
],
|
||||
'argument' => [
|
||||
'help' => $this->t('The parent term of the term.'),
|
||||
'id' => 'taxonomy',
|
||||
],
|
||||
];
|
||||
$data['taxonomy_term__parent']['parent_target_id']['help'] = $this->t('The parent term of the term. This can produce duplicate entries if you are using a vocabulary that allows multiple parents.');
|
||||
$data['taxonomy_term__parent']['parent_target_id']['relationship']['label'] = $this->t('Parent');
|
||||
$data['taxonomy_term__parent']['parent_target_id']['argument']['id'] = 'taxonomy';
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
namespace Drupal\taxonomy\Tests;
|
||||
|
||||
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
|
||||
@trigger_error(__NAMESPACE__ . '\TaxonomyTestBase is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\taxonomy\Functional\TaxonomyTestBase', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
|
||||
use Drupal\Tests\taxonomy\Functional\TaxonomyTestTrait;
|
||||
|
||||
/**
|
||||
* Provides common helper methods for Taxonomy module tests.
|
||||
|
|
|
@ -2,13 +2,17 @@
|
|||
|
||||
namespace Drupal\taxonomy\Tests;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
@trigger_error(__NAMESPACE__ . '\TaxonomyTestTrait is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\taxonomy\Functional\TaxonomyTestTrait', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
|
||||
/**
|
||||
* Provides common helper methods for Taxonomy module tests.
|
||||
*
|
||||
* @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\taxonomy\Functional\TaxonomyTestTrait
|
||||
*/
|
||||
trait TaxonomyTestTrait {
|
||||
|
||||
|
@ -20,7 +24,7 @@ trait TaxonomyTestTrait {
|
|||
$vocabulary = Vocabulary::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'description' => $this->randomMachineName(),
|
||||
'vid' => Unicode::strtolower($this->randomMachineName()),
|
||||
'vid' => mb_strtolower($this->randomMachineName()),
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'weight' => mt_rand(0, 10),
|
||||
]);
|
||||
|
|
|
@ -2,13 +2,18 @@
|
|||
|
||||
namespace Drupal\taxonomy\Tests;
|
||||
|
||||
@trigger_error(__NAMESPACE__ . '\TaxonomyTranslationTestTrait is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\taxonomy\Functional\TaxonomyTranslationTestTrait', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
|
||||
|
||||
/**
|
||||
* Provides common testing base for translated taxonomy terms.
|
||||
*
|
||||
* @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\taxonomy\Functional\TaxonomyTranslationTestTrait
|
||||
*/
|
||||
trait TaxonomyTranslationTestTrait {
|
||||
|
||||
|
@ -17,7 +22,7 @@ trait TaxonomyTranslationTestTrait {
|
|||
/**
|
||||
* The vocabulary.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Vocabulary;
|
||||
* @var \Drupal\taxonomy\Entity\Vocabulary
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
|
@ -73,10 +78,6 @@ trait TaxonomyTranslationTestTrait {
|
|||
|
||||
/**
|
||||
* Adds term reference field for the article content type.
|
||||
*
|
||||
* @param bool $translatable
|
||||
* (optional) If TRUE, create a translatable term reference field. Defaults
|
||||
* to FALSE.
|
||||
*/
|
||||
protected function setUpTermReferenceField() {
|
||||
$handler_settings = [
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\taxonomy;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the taxonomy vocabulary entity type.
|
||||
*
|
||||
* @see \Drupal\taxonomy\Entity\Vocabulary
|
||||
*/
|
||||
class VocabularyAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
switch ($operation) {
|
||||
case 'access taxonomy overview':
|
||||
case 'view':
|
||||
return AccessResult::allowedIfHasPermissions($account, ['access taxonomy overview', 'administer taxonomy'], 'OR');
|
||||
|
||||
default:
|
||||
return parent::checkAccess($entity, $operation, $account);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,13 +11,15 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Base form for vocabulary edit forms.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class VocabularyForm extends BundleEntityFormBase {
|
||||
|
||||
/**
|
||||
* The vocabulary storage.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface.
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface
|
||||
*/
|
||||
protected $vocabularyStorage;
|
||||
|
||||
|
@ -87,7 +89,7 @@ class VocabularyForm extends BundleEntityFormBase {
|
|||
if ($this->moduleHandler->moduleExists('language')) {
|
||||
$form['default_terms_language'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Terms language'),
|
||||
'#title' => $this->t('Term language'),
|
||||
'#open' => TRUE,
|
||||
];
|
||||
$form['default_terms_language']['default_language'] = [
|
||||
|
@ -123,13 +125,13 @@ class VocabularyForm extends BundleEntityFormBase {
|
|||
$edit_link = $this->entity->link($this->t('Edit'));
|
||||
switch ($status) {
|
||||
case SAVED_NEW:
|
||||
drupal_set_message($this->t('Created new vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->messenger()->addStatus($this->t('Created new vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->logger('taxonomy')->notice('Created new vocabulary %name.', ['%name' => $vocabulary->label(), 'link' => $edit_link]);
|
||||
$form_state->setRedirectUrl($vocabulary->urlInfo('overview-form'));
|
||||
break;
|
||||
|
||||
case SAVED_UPDATED:
|
||||
drupal_set_message($this->t('Updated vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->messenger()->addStatus($this->t('Updated vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->logger('taxonomy')->notice('Updated vocabulary %name.', ['%name' => $vocabulary->label(), 'link' => $edit_link]);
|
||||
$form_state->setRedirectUrl($vocabulary->urlInfo('collection'));
|
||||
break;
|
||||
|
|
|
@ -4,8 +4,14 @@ namespace Drupal\taxonomy;
|
|||
|
||||
use Drupal\Core\Config\Entity\DraggableListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Messenger\MessengerInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of taxonomy vocabulary entities.
|
||||
|
@ -19,6 +25,74 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
|||
*/
|
||||
protected $entitiesKey = 'vocabularies';
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The renderer service.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* The messenger.
|
||||
*
|
||||
* @var \Drupal\Core\Messenger\MessengerInterface
|
||||
*/
|
||||
protected $messenger;
|
||||
|
||||
/**
|
||||
* Constructs a new VocabularyListBuilder object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type definition.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer service.
|
||||
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
|
||||
* The messenger.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type,
|
||||
AccountInterface $current_user,
|
||||
EntityTypeManagerInterface $entity_type_manager,
|
||||
RendererInterface $renderer = NULL,
|
||||
MessengerInterface $messenger) {
|
||||
parent::__construct($entity_type, $entity_type_manager->getStorage($entity_type->id()));
|
||||
|
||||
$this->currentUser = $current_user;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->renderer = $renderer;
|
||||
$this->messenger = $messenger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('current_user'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('renderer'),
|
||||
$container->get('messenger')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -36,16 +110,23 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
|||
$operations['edit']['title'] = t('Edit vocabulary');
|
||||
}
|
||||
|
||||
$operations['list'] = [
|
||||
'title' => t('List terms'),
|
||||
'weight' => 0,
|
||||
'url' => $entity->urlInfo('overview-form'),
|
||||
];
|
||||
$operations['add'] = [
|
||||
'title' => t('Add terms'),
|
||||
'weight' => 10,
|
||||
'url' => Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $entity->id()]),
|
||||
];
|
||||
if ($entity->access('access taxonomy overview')) {
|
||||
$operations['list'] = [
|
||||
'title' => t('List terms'),
|
||||
'weight' => 0,
|
||||
'url' => $entity->toUrl('overview-form'),
|
||||
];
|
||||
}
|
||||
|
||||
$taxonomy_term_access_control_handler = $this->entityTypeManager->getAccessControlHandler('taxonomy_term');
|
||||
if ($taxonomy_term_access_control_handler->createAccess($entity->id())) {
|
||||
$operations['add'] = [
|
||||
'title' => t('Add terms'),
|
||||
'weight' => 10,
|
||||
'url' => Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $entity->id()]),
|
||||
];
|
||||
}
|
||||
|
||||
unset($operations['delete']);
|
||||
|
||||
return $operations;
|
||||
|
@ -57,6 +138,11 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
|||
public function buildHeader() {
|
||||
$header['label'] = t('Vocabulary name');
|
||||
$header['description'] = t('Description');
|
||||
|
||||
if ($this->currentUser->hasPermission('administer vocabularies') && !empty($this->weightKey)) {
|
||||
$header['weight'] = t('Weight');
|
||||
}
|
||||
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
|
@ -80,7 +166,25 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
|||
unset($this->weightKey);
|
||||
}
|
||||
$build = parent::render();
|
||||
$build['table']['#empty'] = t('No vocabularies available. <a href=":link">Add vocabulary</a>.', [':link' => \Drupal::url('entity.taxonomy_vocabulary.add_form')]);
|
||||
|
||||
// If the weight key was unset then the table is in the 'table' key,
|
||||
// otherwise in vocabularies. The empty message is only needed if the table
|
||||
// is possibly empty, so there is no need to support the vocabularies key
|
||||
// here.
|
||||
if (isset($build['table'])) {
|
||||
$access_control_handler = $this->entityTypeManager->getAccessControlHandler('taxonomy_vocabulary');
|
||||
$create_access = $access_control_handler->createAccess(NULL, NULL, [], TRUE);
|
||||
$this->renderer->addCacheableDependency($build['table'], $create_access);
|
||||
if ($create_access->isAllowed()) {
|
||||
$build['table']['#empty'] = t('No vocabularies available. <a href=":link">Add vocabulary</a>.', [
|
||||
':link' => Url::fromRoute('entity.taxonomy_vocabulary.add_form')->toString(),
|
||||
]);
|
||||
}
|
||||
else {
|
||||
$build['table']['#empty'] = t('No vocabularies available.');
|
||||
}
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
|
@ -101,7 +205,7 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
|||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
drupal_set_message(t('The configuration options have been saved.'));
|
||||
$this->messenger->addStatus($this->t('The configuration options have been saved.'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,12 @@ class VocabularyStorage extends ConfigEntityStorage implements VocabularyStorage
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToplevelTids($vids) {
|
||||
return db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid IN ( :vids[] ) AND th.parent = 0', [':vids[]' => $vids])->fetchCol();
|
||||
$tids = \Drupal::entityQuery('taxonomy_term')
|
||||
->condition('vid', $vids, 'IN')
|
||||
->condition('parent.target_id', 0)
|
||||
->execute();
|
||||
|
||||
return array_values($tids);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
62
web/core/modules/taxonomy/taxonomy.es6.js
Normal file
62
web/core/modules/taxonomy/taxonomy.es6.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* @file
|
||||
* Taxonomy behaviors.
|
||||
*/
|
||||
|
||||
(function($, Drupal) {
|
||||
/**
|
||||
* Move a block in the blocks table from one region to another.
|
||||
*
|
||||
* This behavior is dependent on the tableDrag behavior, since it uses the
|
||||
* objects initialized in that behavior to update the row.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the drag behavior to a applicable table element.
|
||||
*/
|
||||
Drupal.behaviors.termDrag = {
|
||||
attach(context, settings) {
|
||||
const backStep = settings.taxonomy.backStep;
|
||||
const forwardStep = settings.taxonomy.forwardStep;
|
||||
// Get the blocks tableDrag object.
|
||||
const tableDrag = Drupal.tableDrag.taxonomy;
|
||||
const $table = $('#taxonomy');
|
||||
const rows = $table.find('tr').length;
|
||||
|
||||
// When a row is swapped, keep previous and next page classes set.
|
||||
tableDrag.row.prototype.onSwap = function(swappedRow) {
|
||||
$table
|
||||
.find('tr.taxonomy-term-preview')
|
||||
.removeClass('taxonomy-term-preview');
|
||||
$table
|
||||
.find('tr.taxonomy-term-divider-top')
|
||||
.removeClass('taxonomy-term-divider-top');
|
||||
$table
|
||||
.find('tr.taxonomy-term-divider-bottom')
|
||||
.removeClass('taxonomy-term-divider-bottom');
|
||||
|
||||
const tableBody = $table[0].tBodies[0];
|
||||
if (backStep) {
|
||||
for (let n = 0; n < backStep; n++) {
|
||||
$(tableBody.rows[n]).addClass('taxonomy-term-preview');
|
||||
}
|
||||
$(tableBody.rows[backStep - 1]).addClass('taxonomy-term-divider-top');
|
||||
$(tableBody.rows[backStep]).addClass('taxonomy-term-divider-bottom');
|
||||
}
|
||||
|
||||
if (forwardStep) {
|
||||
for (let k = rows - forwardStep - 1; k < rows - 1; k++) {
|
||||
$(tableBody.rows[k]).addClass('taxonomy-term-preview');
|
||||
}
|
||||
$(tableBody.rows[rows - forwardStep - 2]).addClass(
|
||||
'taxonomy-term-divider-top',
|
||||
);
|
||||
$(tableBody.rows[rows - forwardStep - 1]).addClass(
|
||||
'taxonomy-term-divider-bottom',
|
||||
);
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal);
|
|
@ -5,6 +5,6 @@ package: Core
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- node
|
||||
- text
|
||||
- drupal:node
|
||||
- drupal:text
|
||||
configure: entity.taxonomy_vocabulary.collection
|
||||
|
|
188
web/core/modules/taxonomy/taxonomy.install
Normal file
188
web/core/modules/taxonomy/taxonomy.install
Normal file
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the taxonomy module.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Site\Settings;
|
||||
|
||||
/**
|
||||
* Convert the custom taxonomy term hierarchy storage to a default storage.
|
||||
*/
|
||||
function taxonomy_update_8501() {
|
||||
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
|
||||
|
||||
/** @var \Drupal\Core\Field\BaseFieldDefinition $field_storage_definition */
|
||||
$field_storage_definition = $definition_update_manager->getFieldStorageDefinition('parent', 'taxonomy_term');
|
||||
$field_storage_definition->setCustomStorage(FALSE);
|
||||
$definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy hierarchy from {taxonomy_term_hierarchy} to {taxonomy_term__parent}.
|
||||
*/
|
||||
function taxonomy_update_8502(&$sandbox) {
|
||||
$database = \Drupal::database();
|
||||
|
||||
if (!isset($sandbox['current'])) {
|
||||
// Set batch ops sandbox.
|
||||
$sandbox['current'] = 0;
|
||||
$sandbox['tid'] = -1;
|
||||
$sandbox['delta'] = 0;
|
||||
$sandbox['limit'] = Settings::get('entity_update_batch_size', 50);
|
||||
|
||||
// Count records using a join, as there might be orphans in the hierarchy
|
||||
// table. See https://www.drupal.org/project/drupal/issues/2997982.
|
||||
$select = $database->select('taxonomy_term_hierarchy', 'h');
|
||||
$select->join('taxonomy_term_data', 'd', 'h.tid = d.tid');
|
||||
$sandbox['max'] = $select
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
// Save the hierarchy.
|
||||
$select = $database->select('taxonomy_term_hierarchy', 'h');
|
||||
$select->join('taxonomy_term_data', 'd', 'h.tid = d.tid');
|
||||
$hierarchy = $select
|
||||
->fields('h', ['tid', 'parent'])
|
||||
->fields('d', ['vid', 'langcode'])
|
||||
->range($sandbox['current'], $sandbox['limit'])
|
||||
->orderBy('tid', 'ASC')
|
||||
->orderBy('parent', 'ASC')
|
||||
->execute()
|
||||
->fetchAll();
|
||||
|
||||
// Restore data.
|
||||
$insert = $database->insert('taxonomy_term__parent')
|
||||
->fields(['bundle', 'entity_id', 'revision_id', 'langcode', 'delta', 'parent_target_id']);
|
||||
|
||||
foreach ($hierarchy as $row) {
|
||||
if ($row->tid !== $sandbox['tid']) {
|
||||
$sandbox['delta'] = 0;
|
||||
$sandbox['tid'] = $row->tid;
|
||||
}
|
||||
|
||||
$insert->values([
|
||||
'bundle' => $row->vid,
|
||||
'entity_id' => $row->tid,
|
||||
'revision_id' => $row->tid,
|
||||
'langcode' => $row->langcode,
|
||||
'delta' => $sandbox['delta'],
|
||||
'parent_target_id' => $row->parent,
|
||||
]);
|
||||
|
||||
$sandbox['delta']++;
|
||||
$sandbox['current']++;
|
||||
}
|
||||
|
||||
$insert->execute();
|
||||
|
||||
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']);
|
||||
|
||||
if ($sandbox['#finished'] >= 1) {
|
||||
// Update the entity type because the 'taxonomy_term_hierarchy' table is no
|
||||
// longer part of its shared tables schema.
|
||||
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
|
||||
$definition_update_manager->updateEntityType($definition_update_manager->getEntityType('taxonomy_term'));
|
||||
|
||||
// \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::onEntityTypeUpdate()
|
||||
// only deletes *known* entity tables (i.e. the base, data and revision
|
||||
// tables), so we have to drop it manually.
|
||||
$database->schema()->dropTable('taxonomy_term_hierarchy');
|
||||
|
||||
return t('Taxonomy term hierarchy has been converted to default entity reference storage.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update views to use {taxonomy_term__parent} in relationships.
|
||||
*/
|
||||
function taxonomy_update_8503() {
|
||||
$config_factory = \Drupal::configFactory();
|
||||
|
||||
foreach ($config_factory->listAll('views.view.') as $id) {
|
||||
$view = $config_factory->getEditable($id);
|
||||
|
||||
foreach (array_keys($view->get('display')) as $display_id) {
|
||||
$changed = FALSE;
|
||||
|
||||
foreach (['relationships', 'filters', 'arguments'] as $handler_type) {
|
||||
$base_path = "display.$display_id.display_options.$handler_type";
|
||||
$handlers = $view->get($base_path);
|
||||
|
||||
if (!$handlers) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($handlers as $handler_key => $handler_config) {
|
||||
$table_path = "$base_path.$handler_key.table";
|
||||
$field_path = "$base_path.$handler_key.field";
|
||||
$table = $view->get($table_path);
|
||||
$field = $view->get($field_path);
|
||||
|
||||
if (($table && ($table === 'taxonomy_term_hierarchy')) && ($field && ($field === 'parent'))) {
|
||||
$view->set($table_path, 'taxonomy_term__parent');
|
||||
$view->set($field_path, 'parent_target_id');
|
||||
|
||||
$changed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
$view->save(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the publishing status fields to taxonomy terms.
|
||||
*/
|
||||
function taxonomy_update_8601() {
|
||||
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
|
||||
$entity_type = $definition_update_manager->getEntityType('taxonomy_term');
|
||||
|
||||
// Bail out early if a field named 'status' is already installed.
|
||||
if ($definition_update_manager->getFieldStorageDefinition('status', 'taxonomy_term')) {
|
||||
$message = \Drupal::state()->get('taxonomy_update_8601_skip_message', t('The publishing status field has <strong>not</strong> been added to taxonomy terms. See <a href=":link">this page</a> for more information on how to install it.', [
|
||||
':link' => 'https://www.drupal.org/node/2985366',
|
||||
]));
|
||||
return $message;
|
||||
}
|
||||
|
||||
// Add the 'published' entity key to the taxonomy_term entity type.
|
||||
$entity_keys = $entity_type->getKeys();
|
||||
$entity_keys['published'] = 'status';
|
||||
$entity_type->set('entity_keys', $entity_keys);
|
||||
|
||||
$definition_update_manager->updateEntityType($entity_type);
|
||||
|
||||
// Add the status field.
|
||||
$status = BaseFieldDefinition::create('boolean')
|
||||
->setLabel(t('Publishing status'))
|
||||
->setDescription(t('A boolean indicating the published state.'))
|
||||
->setRevisionable(TRUE)
|
||||
->setTranslatable(TRUE)
|
||||
->setDefaultValue(TRUE);
|
||||
|
||||
$has_content_translation_status_field = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term');
|
||||
if ($has_content_translation_status_field) {
|
||||
$status->setInitialValueFromField('content_translation_status', TRUE);
|
||||
}
|
||||
else {
|
||||
$status->setInitialValue(TRUE);
|
||||
}
|
||||
$definition_update_manager->installFieldStorageDefinition('status', 'taxonomy_term', 'taxonomy_term', $status);
|
||||
|
||||
// Uninstall the 'content_translation_status' field if needed.
|
||||
if ($has_content_translation_status_field) {
|
||||
$content_translation_status = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term');
|
||||
$definition_update_manager->uninstallFieldStorageDefinition($content_translation_status);
|
||||
}
|
||||
|
||||
return t('The publishing status field has been added to taxonomy terms.');
|
||||
}
|
|
@ -1,33 +1,20 @@
|
|||
/**
|
||||
* @file
|
||||
* Taxonomy behaviors.
|
||||
*/
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Move a block in the blocks table from one region to another.
|
||||
*
|
||||
* This behavior is dependent on the tableDrag behavior, since it uses the
|
||||
* objects initialized in that behavior to update the row.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the drag behavior to a applicable table element.
|
||||
*/
|
||||
Drupal.behaviors.termDrag = {
|
||||
attach: function (context, settings) {
|
||||
attach: function attach(context, settings) {
|
||||
var backStep = settings.taxonomy.backStep;
|
||||
var forwardStep = settings.taxonomy.forwardStep;
|
||||
// Get the blocks tableDrag object.
|
||||
|
||||
var tableDrag = Drupal.tableDrag.taxonomy;
|
||||
var $table = $('#taxonomy');
|
||||
var rows = $table.find('tr').length;
|
||||
|
||||
// When a row is swapped, keep previous and next page classes set.
|
||||
tableDrag.row.prototype.onSwap = function (swappedRow) {
|
||||
$table.find('tr.taxonomy-term-preview').removeClass('taxonomy-term-preview');
|
||||
$table.find('tr.taxonomy-term-divider-top').removeClass('taxonomy-term-divider-top');
|
||||
|
@ -52,5 +39,4 @@
|
|||
};
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
||||
})(jQuery, Drupal);
|
|
@ -22,6 +22,8 @@ use Drupal\taxonomy\VocabularyInterface;
|
|||
*
|
||||
* @deprecated in Drupal 8.2.x and will be removed before 9.0.0. Use
|
||||
* \Drupal\taxonomy\VocabularyInterface::HIERARCHY_DISABLED instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2807795
|
||||
*/
|
||||
const TAXONOMY_HIERARCHY_DISABLED = 0;
|
||||
|
||||
|
@ -30,6 +32,8 @@ const TAXONOMY_HIERARCHY_DISABLED = 0;
|
|||
*
|
||||
* @deprecated in Drupal 8.2.x and will be removed before 9.0.0. Use
|
||||
* \Drupal\taxonomy\VocabularyInterface::HIERARCHY_SINGLE instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2807795
|
||||
*/
|
||||
const TAXONOMY_HIERARCHY_SINGLE = 1;
|
||||
|
||||
|
@ -38,6 +42,8 @@ const TAXONOMY_HIERARCHY_SINGLE = 1;
|
|||
*
|
||||
* @deprecated in Drupal 8.2.x and will be removed before 9.0.0. Use
|
||||
* \Drupal\taxonomy\VocabularyInterface::HIERARCHY_MULTIPLE instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2807795
|
||||
*/
|
||||
const TAXONOMY_HIERARCHY_MULTIPLE = 2;
|
||||
|
||||
|
@ -61,7 +67,7 @@ function taxonomy_help($route_name, RouteMatchInterface $route_match) {
|
|||
$output .= '<dt>' . t('Classifying entity content') . '</dt>';
|
||||
$output .= '<dd>' . t('A user with the <em>Administer fields</em> permission for a certain entity type may add <em>Taxonomy term</em> reference fields to the entity type, which will allow entities to be classified using taxonomy terms. See the <a href=":entity_reference">Entity Reference help</a> for more information about reference fields. See the <a href=":field">Field module help</a> and the <a href=":field_ui">Field UI help</a> pages for general information on fields and how to create and manage them.', [':field_ui' => $field_ui_url, ':field' => \Drupal::url('help.page', ['name' => 'field']), ':entity_reference' => \Drupal::url('help.page', ['name' => 'entity_reference'])]) . '</dd>';
|
||||
$output .= '<dt>' . t('Adding new terms during content creation') . '</dt>';
|
||||
$output .= '<dd>' . t('Allowing users to add new terms gradually builds a vocabulary as content is added and edited. Users can add new terms if either of the two <em>Autocomplete</em> widgets is chosen for the Taxonomy term reference field in the <em>Manage form display</em> page for the field. You will also need to enable the <em>Create referenced entities if they don\'t already exist</em> option, and restrict the field to one vocabulary.') . '</dd>';
|
||||
$output .= '<dd>' . t("Allowing users to add new terms gradually builds a vocabulary as content is added and edited. Users can add new terms if either of the two <em>Autocomplete</em> widgets is chosen for the Taxonomy term reference field in the <em>Manage form display</em> page for the field. You will also need to enable the <em>Create referenced entities if they don't already exist</em> option, and restrict the field to one vocabulary.") . '</dd>';
|
||||
$output .= '<dt>' . t('Configuring displays and form displays') . '</dt>';
|
||||
$output .= '<dd>' . t('See the <a href=":entity_reference">Entity Reference help</a> page for the field widgets and formatters that can be configured for any reference field on the <em>Manage display</em> and <em>Manage form display</em> pages. Taxonomy additionally provides an <em>RSS category</em> formatter that displays nothing when the entity item is displayed as HTML, but displays an RSS category instead of a list when the entity item is displayed in an RSS feed.', [':entity_reference' => \Drupal::url('help.page', ['name' => 'entity_reference'])]) . '</li>';
|
||||
$output .= '</ul>';
|
||||
|
@ -75,13 +81,25 @@ function taxonomy_help($route_name, RouteMatchInterface $route_match) {
|
|||
|
||||
case 'entity.taxonomy_vocabulary.overview_form':
|
||||
$vocabulary = $route_match->getParameter('taxonomy_vocabulary');
|
||||
switch ($vocabulary->getHierarchy()) {
|
||||
case VocabularyInterface::HIERARCHY_DISABLED:
|
||||
return '<p>' . t('You can reorganize the terms in %capital_name using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.', ['%capital_name' => Unicode::ucfirst($vocabulary->label()), '%name' => $vocabulary->label()]) . '</p>';
|
||||
case VocabularyInterface::HIERARCHY_SINGLE:
|
||||
return '<p>' . t('%capital_name contains terms grouped under parent terms. You can reorganize the terms in %capital_name using their drag-and-drop handles.', ['%capital_name' => Unicode::ucfirst($vocabulary->label()), '%name' => $vocabulary->label()]) . '</p>';
|
||||
case VocabularyInterface::HIERARCHY_MULTIPLE:
|
||||
return '<p>' . t('%capital_name contains terms with multiple parents. Drag and drop of terms with multiple parents is not supported, but you can re-enable drag-and-drop support by editing each term to include only a single parent.', ['%capital_name' => Unicode::ucfirst($vocabulary->label())]) . '</p>';
|
||||
if (\Drupal::currentUser()->hasPermission('administer taxonomy') || \Drupal::currentUser()->hasPermission('edit terms in ' . $vocabulary->id())) {
|
||||
switch ($vocabulary->getHierarchy()) {
|
||||
case VocabularyInterface::HIERARCHY_DISABLED:
|
||||
return '<p>' . t('You can reorganize the terms in %capital_name using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.', ['%capital_name' => Unicode::ucfirst($vocabulary->label()), '%name' => $vocabulary->label()]) . '</p>';
|
||||
case VocabularyInterface::HIERARCHY_SINGLE:
|
||||
return '<p>' . t('%capital_name contains terms grouped under parent terms. You can reorganize the terms in %capital_name using their drag-and-drop handles.', ['%capital_name' => Unicode::ucfirst($vocabulary->label()), '%name' => $vocabulary->label()]) . '</p>';
|
||||
case VocabularyInterface::HIERARCHY_MULTIPLE:
|
||||
return '<p>' . t('%capital_name contains terms with multiple parents. Drag and drop of terms with multiple parents is not supported, but you can re-enable drag-and-drop support by editing each term to include only a single parent.', ['%capital_name' => Unicode::ucfirst($vocabulary->label())]) . '</p>';
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch ($vocabulary->getHierarchy()) {
|
||||
case VocabularyInterface::HIERARCHY_DISABLED:
|
||||
return '<p>' . t('%capital_name contains the following terms.', ['%capital_name' => Unicode::ucfirst($vocabulary->label())]) . '</p>';
|
||||
case VocabularyInterface::HIERARCHY_SINGLE:
|
||||
return '<p>' . t('%capital_name contains terms grouped under parent terms', ['%capital_name' => Unicode::ucfirst($vocabulary->label())]) . '</p>';
|
||||
case VocabularyInterface::HIERARCHY_MULTIPLE:
|
||||
return '<p>' . t('%capital_name contains terms with multiple parents.', ['%capital_name' => Unicode::ucfirst($vocabulary->label())]) . '</p>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +213,8 @@ function taxonomy_check_vocabulary_hierarchy(VocabularyInterface $vocabulary, $c
|
|||
* content language of the current request.
|
||||
*
|
||||
* @return array
|
||||
* A $page element suitable for use by drupal_render().
|
||||
* A $page element suitable for use by
|
||||
* \Drupal\Core\Render\RendererInterface::render().
|
||||
*/
|
||||
function taxonomy_term_view(Term $term, $view_mode = 'full', $langcode = NULL) {
|
||||
return entity_view($term, $view_mode, $langcode);
|
||||
|
@ -213,7 +232,8 @@ function taxonomy_term_view(Term $term, $view_mode = 'full', $langcode = NULL) {
|
|||
* content language of the current request.
|
||||
*
|
||||
* @return array
|
||||
* An array in the format expected by drupal_render().
|
||||
* An array in the format expected by
|
||||
* \Drupal\Core\Render\RendererInterface::render().
|
||||
*/
|
||||
function taxonomy_term_view_multiple(array $terms, $view_mode = 'full', $langcode = NULL) {
|
||||
return entity_view_multiple($terms, $view_mode, $langcode);
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
administer taxonomy:
|
||||
title: 'Administer vocabularies and terms'
|
||||
|
||||
access taxonomy overview:
|
||||
title: 'Access the taxonomy vocabulary overview page'
|
||||
description: 'Get an overview of all taxonomy vocabularies.'
|
||||
|
||||
permission_callbacks:
|
||||
- Drupal\taxonomy\TaxonomyPermissions::permissions
|
||||
|
|
127
web/core/modules/taxonomy/taxonomy.post_update.php
Normal file
127
web/core/modules/taxonomy/taxonomy.post_update.php
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Post update functions for Taxonomy.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* Clear caches due to updated taxonomy entity views data.
|
||||
*/
|
||||
function taxonomy_post_update_clear_views_data_cache() {
|
||||
// An empty update will flush caches.
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear entity_bundle_field_definitions cache for new parent field settings.
|
||||
*/
|
||||
function taxonomy_post_update_clear_entity_bundle_field_definitions_cache() {
|
||||
// An empty update will flush caches.
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a 'published' = TRUE filter for all Taxonomy term views and converts
|
||||
* existing ones that were using the 'content_translation_status' field.
|
||||
*/
|
||||
function taxonomy_post_update_handle_publishing_status_addition_in_views(&$sandbox = NULL) {
|
||||
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
|
||||
$entity_type = $definition_update_manager->getEntityType('taxonomy_term');
|
||||
$published_key = $entity_type->getKey('published');
|
||||
|
||||
$status_filter = [
|
||||
'id' => 'status',
|
||||
'table' => 'taxonomy_term_field_data',
|
||||
'field' => $published_key,
|
||||
'relationship' => 'none',
|
||||
'group_type' => 'group',
|
||||
'admin_label' => '',
|
||||
'operator' => '=',
|
||||
'value' => '1',
|
||||
'group' => 1,
|
||||
'exposed' => FALSE,
|
||||
'expose' => [
|
||||
'operator_id' => '',
|
||||
'label' => '',
|
||||
'description' => '',
|
||||
'use_operator' => FALSE,
|
||||
'operator' => '',
|
||||
'identifier' => '',
|
||||
'required' => FALSE,
|
||||
'remember' => FALSE,
|
||||
'multiple' => FALSE,
|
||||
'remember_roles' => [
|
||||
'authenticated' => 'authenticated',
|
||||
'anonymous' => '0',
|
||||
'administrator' => '0',
|
||||
],
|
||||
],
|
||||
'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' => 'taxonomy_term',
|
||||
'entity_field' => $published_key,
|
||||
'plugin_id' => 'boolean',
|
||||
];
|
||||
|
||||
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($published_key, $status_filter) {
|
||||
/** @var \Drupal\views\ViewEntityInterface $view */
|
||||
// Only alter taxonomy term views.
|
||||
if ($view->get('base_table') !== 'taxonomy_term_field_data') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$displays = $view->get('display');
|
||||
foreach ($displays as $display_name => &$display) {
|
||||
// Update any existing 'content_translation_status fields.
|
||||
$fields = isset($display['display_options']['fields']) ? $display['display_options']['fields'] : [];
|
||||
foreach ($fields as $id => $field) {
|
||||
if (isset($field['field']) && $field['field'] == 'content_translation_status') {
|
||||
$fields[$id]['field'] = $published_key;
|
||||
}
|
||||
}
|
||||
$display['display_options']['fields'] = $fields;
|
||||
|
||||
// Update any existing 'content_translation_status sorts.
|
||||
$sorts = isset($display['display_options']['sorts']) ? $display['display_options']['sorts'] : [];
|
||||
foreach ($sorts as $id => $sort) {
|
||||
if (isset($sort['field']) && $sort['field'] == 'content_translation_status') {
|
||||
$sorts[$id]['field'] = $published_key;
|
||||
}
|
||||
}
|
||||
$display['display_options']['sorts'] = $sorts;
|
||||
|
||||
// Update any existing 'content_translation_status' filters or add a new
|
||||
// one if necessary.
|
||||
$filters = isset($display['display_options']['filters']) ? $display['display_options']['filters'] : [];
|
||||
$has_status_filter = FALSE;
|
||||
foreach ($filters as $id => $filter) {
|
||||
if (isset($filter['field']) && $filter['field'] == 'content_translation_status') {
|
||||
$filters[$id]['field'] = $published_key;
|
||||
$has_status_filter = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$has_status_filter) {
|
||||
$status_filter['id'] = ViewExecutable::generateHandlerId($published_key, $filters);
|
||||
$filters[$status_filter['id']] = $status_filter;
|
||||
}
|
||||
$display['display_options']['filters'] = $filters;
|
||||
}
|
||||
$view->set('display', $displays);
|
||||
|
||||
return TRUE;
|
||||
});
|
||||
}
|
|
@ -1,11 +1,3 @@
|
|||
entity.taxonomy_vocabulary.collection:
|
||||
path: '/admin/structure/taxonomy'
|
||||
defaults:
|
||||
_entity_list: 'taxonomy_vocabulary'
|
||||
_title: 'Taxonomy'
|
||||
requirements:
|
||||
_permission: 'administer taxonomy'
|
||||
|
||||
entity.taxonomy_term.add_form:
|
||||
path: '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/add'
|
||||
defaults:
|
||||
|
@ -36,46 +28,6 @@ entity.taxonomy_term.delete_form:
|
|||
_entity_access: 'taxonomy_term.delete'
|
||||
taxonomy_term: \d+
|
||||
|
||||
entity.taxonomy_vocabulary.add_form:
|
||||
path: '/admin/structure/taxonomy/add'
|
||||
defaults:
|
||||
_entity_form: 'taxonomy_vocabulary'
|
||||
_title: 'Add vocabulary'
|
||||
requirements:
|
||||
_entity_create_access: 'taxonomy_vocabulary'
|
||||
|
||||
entity.taxonomy_vocabulary.edit_form:
|
||||
path: '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}'
|
||||
defaults:
|
||||
_entity_form: 'taxonomy_vocabulary.default'
|
||||
_title_callback: '\Drupal\taxonomy\Controller\TaxonomyController::vocabularyTitle'
|
||||
requirements:
|
||||
_entity_access: 'taxonomy_vocabulary.update'
|
||||
|
||||
entity.taxonomy_vocabulary.delete_form:
|
||||
path: '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/delete'
|
||||
defaults:
|
||||
_entity_form: 'taxonomy_vocabulary.delete'
|
||||
_title: 'Delete vocabulary'
|
||||
requirements:
|
||||
_entity_access: 'taxonomy_vocabulary.delete'
|
||||
|
||||
entity.taxonomy_vocabulary.reset_form:
|
||||
path: '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/reset'
|
||||
defaults:
|
||||
_entity_form: 'taxonomy_vocabulary.reset'
|
||||
_title: 'Reset'
|
||||
requirements:
|
||||
_permission: 'administer taxonomy'
|
||||
|
||||
entity.taxonomy_vocabulary.overview_form:
|
||||
path: '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview'
|
||||
defaults:
|
||||
_form: 'Drupal\taxonomy\Form\OverviewTerms'
|
||||
_title_callback: 'Drupal\taxonomy\Controller\TaxonomyController::vocabularyTitle'
|
||||
requirements:
|
||||
_entity_access: 'taxonomy_vocabulary.view'
|
||||
|
||||
entity.taxonomy_term.canonical:
|
||||
path: '/taxonomy/term/{taxonomy_term}'
|
||||
defaults:
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains database additions to drupal-8.filled.standard.php.gz for testing
|
||||
* the upgrade path of https://www.drupal.org/project/drupal/issues/2981887.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
$view_file = __DIR__ . '/views.view.test_taxonomy_term_view_with_content_translation_status.yml';
|
||||
$view_with_cts_config = Yaml::decode(file_get_contents($view_file));
|
||||
|
||||
$view_file = __DIR__ . '/views.view.test_taxonomy_term_view_without_content_translation_status.yml';
|
||||
$view_without_cts_config = Yaml::decode(file_get_contents($view_file));
|
||||
|
||||
$connection->insert('config')
|
||||
->fields(['collection', 'name', 'data'])
|
||||
->values([
|
||||
'collection' => '',
|
||||
'name' => 'views.view.test_taxonomy_term_view_with_content_translation_status',
|
||||
'data' => serialize($view_with_cts_config),
|
||||
])
|
||||
->values([
|
||||
'collection' => '',
|
||||
'name' => 'views.view.test_taxonomy_term_view_without_content_translation_status',
|
||||
'data' => serialize($view_without_cts_config),
|
||||
])
|
||||
->execute();
|
|
@ -0,0 +1,250 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- taxonomy
|
||||
- user
|
||||
id: test_taxonomy_term_view_with_content_translation_status
|
||||
label: 'Test taxonomy term view with content translation status'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: taxonomy_term_field_data
|
||||
base_field: tid
|
||||
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:
|
||||
name:
|
||||
id: name
|
||||
table: taxonomy_term_field_data
|
||||
field: name
|
||||
entity_type: taxonomy_term
|
||||
entity_field: name
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
type: string
|
||||
settings:
|
||||
link_to_entity: true
|
||||
plugin_id: term_name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
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
|
||||
convert_spaces: false
|
||||
content_translation_status:
|
||||
id: content_translation_status
|
||||
table: taxonomy_term_field_data
|
||||
field: content_translation_status
|
||||
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: boolean
|
||||
settings:
|
||||
format: true-false
|
||||
format_custom_true: ''
|
||||
format_custom_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: taxonomy_term
|
||||
entity_field: content_translation_status
|
||||
plugin_id: field
|
||||
filters:
|
||||
content_translation_status:
|
||||
id: content_translation_status
|
||||
table: taxonomy_term_field_data
|
||||
field: content_translation_status
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: All
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: 'Translation status'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: content_translation_status_op
|
||||
identifier: content_translation_status
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
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: taxonomy_term
|
||||
entity_field: content_translation_status
|
||||
plugin_id: boolean
|
||||
sorts:
|
||||
content_translation_status:
|
||||
id: content_translation_status
|
||||
table: taxonomy_term_field_data
|
||||
field: content_translation_status
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
entity_type: taxonomy_term
|
||||
entity_field: content_translation_status
|
||||
plugin_id: standard
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- user.permissions
|
||||
tags: { }
|
|
@ -0,0 +1,128 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- taxonomy
|
||||
- user
|
||||
id: test_taxonomy_term_view_without_content_translation_status
|
||||
label: 'Test taxonomy term view without content translation status'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: taxonomy_term_field_data
|
||||
base_field: tid
|
||||
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:
|
||||
name:
|
||||
id: name
|
||||
table: taxonomy_term_field_data
|
||||
field: name
|
||||
entity_type: taxonomy_term
|
||||
entity_field: name
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
type: string
|
||||
settings:
|
||||
link_to_entity: true
|
||||
plugin_id: term_name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
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
|
||||
convert_spaces: false
|
||||
filters: { }
|
||||
sorts: { }
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- user.permissions
|
||||
tags: { }
|
|
@ -5,4 +5,4 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- taxonomy
|
||||
- drupal:taxonomy
|
||||
|
|
|
@ -5,5 +5,5 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- taxonomy
|
||||
- migrate
|
||||
- drupal:taxonomy
|
||||
- drupal:migrate
|
||||
|
|
|
@ -5,4 +5,4 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- taxonomy
|
||||
- drupal:taxonomy
|
||||
|
|
|
@ -5,5 +5,5 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- taxonomy
|
||||
- views
|
||||
- drupal:taxonomy
|
||||
- drupal:views
|
||||
|
|
|
@ -171,4 +171,3 @@ display:
|
|||
- url
|
||||
- user.permissions
|
||||
tags: { }
|
||||
|
||||
|
|
|
@ -124,8 +124,8 @@ display:
|
|||
relationships:
|
||||
parent:
|
||||
id: parent
|
||||
table: taxonomy_term_hierarchy
|
||||
field: parent
|
||||
table: taxonomy_term__parent
|
||||
field: parent_target_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: Parent
|
||||
|
|
|
@ -186,8 +186,8 @@ display:
|
|||
plugin_id: standard
|
||||
parent:
|
||||
id: parent
|
||||
table: taxonomy_term_hierarchy
|
||||
field: parent
|
||||
table: taxonomy_term__parent
|
||||
field: parent_target_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: Parent
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- taxonomy
|
||||
- user
|
||||
id: test_taxonomy_vid_field
|
||||
label: test_taxonomy_vid_field
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: taxonomy_term_field_data
|
||||
base_field: tid
|
||||
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: full
|
||||
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: '‹ Previous'
|
||||
next: 'Next ›'
|
||||
first: '« First'
|
||||
last: 'Last »'
|
||||
quantity: 9
|
||||
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:
|
||||
vid:
|
||||
id: vid
|
||||
table: taxonomy_term_field_data
|
||||
field: vid
|
||||
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: target_id
|
||||
type: entity_reference_label
|
||||
settings:
|
||||
link: false
|
||||
group_column: target_id
|
||||
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: taxonomy_term
|
||||
entity_field: vid
|
||||
plugin_id: field
|
||||
filters: { }
|
||||
sorts: { }
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
- user.permissions
|
||||
tags: { }
|
|
@ -4,4 +4,4 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- taxonomy
|
||||
- drupal:taxonomy
|
||||
|
|
|
@ -4,14 +4,14 @@ namespace Drupal\Tests\taxonomy\Functional;
|
|||
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use \Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Posts an article with a taxonomy term and a date prior to 1970.
|
||||
*
|
||||
* @group taxonomy
|
||||
*/
|
||||
class LegacyTest extends TaxonomyTestBase {
|
||||
class EarlyDateTest extends TaxonomyTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
@ -51,7 +51,7 @@ class LegacyTest extends TaxonomyTestBase {
|
|||
/**
|
||||
* Test taxonomy functionality with nodes prior to 1970.
|
||||
*/
|
||||
public function testTaxonomyLegacyNode() {
|
||||
public function testTaxonomyEarlyDateNode() {
|
||||
// Posts an article with a taxonomy term and a date prior to 1970.
|
||||
$date = new DrupalDateTime('1969-01-01 00:00:00');
|
||||
$edit = [];
|
||||
|
@ -60,7 +60,7 @@ class LegacyTest extends TaxonomyTestBase {
|
|||
$edit['created[0][value][time]'] = $date->format('H:i:s');
|
||||
$edit['body[0][value]'] = $this->randomMachineName();
|
||||
$edit['field_tags[target_id]'] = $this->randomMachineName();
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save'));
|
||||
// Checks that the node has been saved.
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$this->assertEqual($node->getCreatedTime(), $date->getTimestamp(), 'Legacy node was saved with the right date.');
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Hal;
|
||||
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\taxonomy\Functional\Rest\TermResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class TermHalJsonAnonTest extends TermResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
// We test with multiple parent terms, and combinations thereof.
|
||||
// @see ::createEntity()
|
||||
// @see ::testGet()
|
||||
// @see ::testGetTermWithParent()
|
||||
// @see ::providerTestGetTermWithParent()
|
||||
// @see ::testGetTermWithParent()
|
||||
$parent_term_ids = [];
|
||||
for ($i = 0; $i < $this->entity->get('parent')->count(); $i++) {
|
||||
$parent_term_ids[$i] = (int) $this->entity->get('parent')[$i]->target_id;
|
||||
}
|
||||
|
||||
$expected_parent_normalization_links = FALSE;
|
||||
$expected_parent_normalization_embedded = FALSE;
|
||||
switch ($parent_term_ids) {
|
||||
case [0]:
|
||||
$expected_parent_normalization_links = [
|
||||
NULL,
|
||||
];
|
||||
$expected_parent_normalization_embedded = [
|
||||
NULL,
|
||||
];
|
||||
break;
|
||||
case [2]:
|
||||
$expected_parent_normalization_links = [
|
||||
[
|
||||
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
|
||||
],
|
||||
];
|
||||
$expected_parent_normalization_embedded = [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => Term::load(2)->uuid()],
|
||||
],
|
||||
],
|
||||
];
|
||||
break;
|
||||
case [0, 2]:
|
||||
$expected_parent_normalization_links = [
|
||||
NULL,
|
||||
[
|
||||
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
|
||||
],
|
||||
];
|
||||
$expected_parent_normalization_embedded = [
|
||||
NULL,
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => Term::load(2)->uuid()],
|
||||
],
|
||||
],
|
||||
];
|
||||
break;
|
||||
case [3, 2]:
|
||||
$expected_parent_normalization_links = [
|
||||
[
|
||||
'href' => $this->baseUrl . '/taxonomy/term/3?_format=hal_json',
|
||||
],
|
||||
[
|
||||
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
|
||||
],
|
||||
];
|
||||
$expected_parent_normalization_embedded = [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/taxonomy/term/3?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => Term::load(3)->uuid()],
|
||||
],
|
||||
],
|
||||
[
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => Term::load(2)->uuid()],
|
||||
],
|
||||
],
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/llama?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
$this->baseUrl . '/rest/relation/taxonomy_term/camelids/parent' => $expected_parent_normalization_links,
|
||||
],
|
||||
'_embedded' => [
|
||||
$this->baseUrl . '/rest/relation/taxonomy_term/camelids/parent' => $expected_parent_normalization_embedded,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class TermHalJsonBasicAuthTest extends TermHalJsonAnonTest {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class TermHalJsonCookieTest extends TermHalJsonAnonTest {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class VocabularyHalJsonAnonTest extends VocabularyResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* @todo Remove this override in https://www.drupal.org/node/2805281.
|
||||
*/
|
||||
public function testGet() {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class VocabularyHalJsonBasicAuthTest extends VocabularyResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class VocabularyHalJsonCookieTest extends VocabularyResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermJsonAnonTest extends TermResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermJsonBasicAuthTest extends TermResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermJsonCookieTest extends TermResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,365 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
|
||||
abstract class TermResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
use BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['taxonomy', 'path'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'taxonomy_term';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'changed' => NULL,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Drupal\taxonomy\TermInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->grantPermissionsToTestedRole(['access content']);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$this->grantPermissionsToTestedRole(['create terms in camelids']);
|
||||
break;
|
||||
|
||||
case 'PATCH':
|
||||
// Grant the 'create url aliases' permission to test the case when
|
||||
// the path field is accessible, see
|
||||
// \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase
|
||||
// for a negative test.
|
||||
$this->grantPermissionsToTestedRole(['edit terms in camelids', 'create url aliases']);
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['delete terms in camelids']);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$vocabulary = Vocabulary::load('camelids');
|
||||
if (!$vocabulary) {
|
||||
// Create a "Camelids" vocabulary.
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Camelids',
|
||||
'vid' => 'camelids',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
}
|
||||
|
||||
// Create a "Llama" taxonomy term.
|
||||
$term = Term::create(['vid' => $vocabulary->id()])
|
||||
->setName('Llama')
|
||||
->setDescription("It is a little known fact that llamas cannot count higher than seven.")
|
||||
->setChangedTime(123456789)
|
||||
->set('path', '/llama');
|
||||
$term->save();
|
||||
|
||||
return $term;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
// We test with multiple parent terms, and combinations thereof.
|
||||
// @see ::createEntity()
|
||||
// @see ::testGet()
|
||||
// @see ::testGetTermWithParent()
|
||||
// @see ::providerTestGetTermWithParent()
|
||||
$parent_term_ids = [];
|
||||
for ($i = 0; $i < $this->entity->get('parent')->count(); $i++) {
|
||||
$parent_term_ids[$i] = (int) $this->entity->get('parent')[$i]->target_id;
|
||||
}
|
||||
|
||||
$expected_parent_normalization = FALSE;
|
||||
switch ($parent_term_ids) {
|
||||
case [0]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => NULL,
|
||||
],
|
||||
];
|
||||
break;
|
||||
case [2]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => 2,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(2)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/2',
|
||||
],
|
||||
];
|
||||
break;
|
||||
case [0, 2]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => NULL,
|
||||
],
|
||||
[
|
||||
'target_id' => 2,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(2)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/2',
|
||||
],
|
||||
];
|
||||
break;
|
||||
case [3, 2]:
|
||||
$expected_parent_normalization = [
|
||||
[
|
||||
'target_id' => 3,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(3)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/3',
|
||||
],
|
||||
[
|
||||
'target_id' => 2,
|
||||
'target_type' => 'taxonomy_term',
|
||||
'target_uuid' => Term::load(2)->uuid(),
|
||||
'url' => base_path() . 'taxonomy/term/2',
|
||||
],
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
'tid' => [
|
||||
['value' => 1],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $this->entity->uuid()],
|
||||
],
|
||||
'vid' => [
|
||||
[
|
||||
'target_id' => 'camelids',
|
||||
'target_type' => 'taxonomy_vocabulary',
|
||||
'target_uuid' => Vocabulary::load('camelids')->uuid(),
|
||||
],
|
||||
],
|
||||
'name' => [
|
||||
['value' => 'Llama'],
|
||||
],
|
||||
'description' => [
|
||||
[
|
||||
'value' => 'It is a little known fact that llamas cannot count higher than seven.',
|
||||
'format' => NULL,
|
||||
'processed' => "<p>It is a little known fact that llamas cannot count higher than seven.</p>\n",
|
||||
],
|
||||
],
|
||||
'parent' => $expected_parent_normalization,
|
||||
'weight' => [
|
||||
['value' => 0],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'changed' => [
|
||||
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
|
||||
],
|
||||
'default_langcode' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'path' => [
|
||||
[
|
||||
'alias' => '/llama',
|
||||
'pid' => 1,
|
||||
'langcode' => 'en',
|
||||
],
|
||||
],
|
||||
'status' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'vid' => [
|
||||
[
|
||||
'target_id' => 'camelids',
|
||||
],
|
||||
],
|
||||
'name' => [
|
||||
[
|
||||
'value' => 'Dramallama',
|
||||
],
|
||||
],
|
||||
'description' => [
|
||||
[
|
||||
'value' => 'Dramallamas are the coolest camelids.',
|
||||
'format' => NULL,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
return "The 'access content' permission is required and the taxonomy term must be published.";
|
||||
case 'POST':
|
||||
return "The following permissions are required: 'create terms in camelids' OR 'administer taxonomy'.";
|
||||
case 'PATCH':
|
||||
return "The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'.";
|
||||
case 'DELETE':
|
||||
return "The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'.";
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests PATCHing a term's path.
|
||||
*
|
||||
* For a negative test, see the similar test coverage for Node.
|
||||
*
|
||||
* @see \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase::testPatchPath()
|
||||
*/
|
||||
public function testPatchPath() {
|
||||
$this->initAuthentication();
|
||||
$this->provisionEntityResource();
|
||||
$this->setUpAuthorization('GET');
|
||||
$this->setUpAuthorization('PATCH');
|
||||
|
||||
$url = $this->getEntityResourceUrl()->setOption('query', ['_format' => static::$format]);
|
||||
|
||||
// GET term's current normalization.
|
||||
$response = $this->request('GET', $url, $this->getAuthenticationRequestOptions('GET'));
|
||||
$normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
|
||||
// Change term's path alias.
|
||||
$normalization['path'][0]['alias'] .= 's-rule-the-world';
|
||||
|
||||
// Create term PATCH request.
|
||||
$request_options = [];
|
||||
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// PATCH request: 200.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$updated_normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
$this->assertSame($normalization['path'], $updated_normalization['path']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text', 'config:filter.settings']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(['url.site'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests GETting a term with a parent term other than the default <root> (0).
|
||||
*
|
||||
* @see ::getExpectedNormalizedEntity()
|
||||
*
|
||||
* @dataProvider providerTestGetTermWithParent
|
||||
*/
|
||||
public function testGetTermWithParent(array $parent_term_ids) {
|
||||
// Create all possible parent terms.
|
||||
Term::create(['vid' => Vocabulary::load('camelids')->id()])
|
||||
->setName('Lamoids')
|
||||
->save();
|
||||
Term::create(['vid' => Vocabulary::load('camelids')->id()])
|
||||
->setName('Wimoids')
|
||||
->save();
|
||||
|
||||
// Modify the entity under test to use the provided parent terms.
|
||||
$this->entity->set('parent', $parent_term_ids)->save();
|
||||
|
||||
$this->initAuthentication();
|
||||
$url = $this->getEntityResourceUrl();
|
||||
$url->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = $this->getAuthenticationRequestOptions('GET');
|
||||
$this->provisionEntityResource();
|
||||
$this->setUpAuthorization('GET');
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$expected = $this->getExpectedNormalizedEntity();
|
||||
static::recursiveKSort($expected);
|
||||
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
static::recursiveKSort($actual);
|
||||
$this->assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
public function providerTestGetTermWithParent() {
|
||||
return [
|
||||
'root parent: [0] (= no parent)' => [
|
||||
[0],
|
||||
],
|
||||
'non-root parent: [2]' => [
|
||||
[2],
|
||||
],
|
||||
'multiple parents: [0,2] (root + non-root parent)' => [
|
||||
[0, 2],
|
||||
],
|
||||
'multiple parents: [3,2] (both non-root parents)' => [
|
||||
[3, 2],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
// @see \Drupal\taxonomy\TermAccessControlHandler::checkAccess()
|
||||
return parent::getExpectedUnauthorizedAccessCacheability()
|
||||
->addCacheTags(['taxonomy_term:1']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermXmlAnonTest extends TermResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchPath() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermXmlBasicAuthTest extends TermResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchPath() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class TermXmlCookieTest extends TermResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchPath() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyJsonAnonTest extends VocabularyResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* Disable the GET test coverage due to bug in taxonomy module.
|
||||
* @todo Fix in https://www.drupal.org/node/2805281: remove this override.
|
||||
*/
|
||||
public function testGet() {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyJsonBasicAuthTest extends VocabularyResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyJsonCookieTest extends VocabularyResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
abstract class VocabularyResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['taxonomy'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'taxonomy_vocabulary';
|
||||
|
||||
/**
|
||||
* @var \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer taxonomy']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => 'Llama',
|
||||
'vid' => 'llama',
|
||||
]);
|
||||
$vocabulary->save();
|
||||
|
||||
return $vocabulary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'vid' => 'llama',
|
||||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'dependencies' => [],
|
||||
'name' => 'Llama',
|
||||
'description' => NULL,
|
||||
'hierarchy' => 0,
|
||||
'weight' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
if ($method === 'GET') {
|
||||
return "The following permissions are required: 'access taxonomy overview' OR 'administer taxonomy'.";
|
||||
}
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\taxonomy\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class VocabularyXmlAnonTest extends VocabularyResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue