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.
* @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" = {
* "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",
* "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"
* )
class Term extends ContentEntityBase implements TermInterface {
use EntityChangedTrait;
+ use EntityPublishedTrait;
/**
* {@inheritdoc}
// 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);
}
/**
* {@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;
}
}
/** @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.'));
->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'))
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}
*/
* {@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();
}
}