3 namespace Drupal\taxonomy\Entity;
5 use Drupal\Core\Entity\ContentEntityBase;
6 use Drupal\Core\Entity\EntityChangedTrait;
7 use Drupal\Core\Entity\EntityStorageInterface;
8 use Drupal\Core\Entity\EntityTypeInterface;
9 use Drupal\Core\Field\BaseFieldDefinition;
10 use Drupal\taxonomy\TermInterface;
13 * Defines the taxonomy term entity.
16 * id = "taxonomy_term",
17 * label = @Translation("Taxonomy term"),
18 * bundle_label = @Translation("Vocabulary"),
20 * "storage" = "Drupal\taxonomy\TermStorage",
21 * "storage_schema" = "Drupal\taxonomy\TermStorageSchema",
22 * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
23 * "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
24 * "access" = "Drupal\taxonomy\TermAccessControlHandler",
25 * "views_data" = "Drupal\taxonomy\TermViewsData",
27 * "default" = "Drupal\taxonomy\TermForm",
28 * "delete" = "Drupal\taxonomy\Form\TermDeleteForm"
30 * "translation" = "Drupal\taxonomy\TermTranslationHandler"
32 * base_table = "taxonomy_term_data",
33 * data_table = "taxonomy_term_field_data",
34 * uri_callback = "taxonomy_term_uri",
35 * translatable = TRUE,
40 * "langcode" = "langcode",
43 * bundle_entity_type = "taxonomy_vocabulary",
44 * field_ui_base_route = "entity.taxonomy_vocabulary.overview_form",
45 * common_reference_target = TRUE,
47 * "canonical" = "/taxonomy/term/{taxonomy_term}",
48 * "delete-form" = "/taxonomy/term/{taxonomy_term}/delete",
49 * "edit-form" = "/taxonomy/term/{taxonomy_term}/edit",
50 * "create" = "/taxonomy/term",
52 * permission_granularity = "bundle"
55 class Term extends ContentEntityBase implements TermInterface {
57 use EntityChangedTrait;
62 public static function postDelete(EntityStorageInterface $storage, array $entities) {
63 parent::postDelete($storage, $entities);
65 // See if any of the term's children are about to be become orphans.
67 foreach (array_keys($entities) as $tid) {
68 if ($children = $storage->loadChildren($tid)) {
69 foreach ($children as $child) {
70 // If the term has multiple parents, we don't delete it.
71 $parents = $storage->loadParents($child->id());
72 if (empty($parents)) {
79 // Delete term hierarchy information after looking up orphans but before
80 // deleting them so that their children/parent information is consistent.
81 $storage->deleteTermHierarchy(array_keys($entities));
83 if (!empty($orphans)) {
84 $storage->delete($orphans);
91 public function postSave(EntityStorageInterface $storage, $update = TRUE) {
92 parent::postSave($storage, $update);
94 // Only change the parents if a value is set, keep the existing values if
96 if (isset($this->parent->target_id)) {
97 $storage->deleteTermHierarchy([$this->id()]);
98 $storage->updateTermHierarchy($this);
105 public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
106 /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
107 $fields = parent::baseFieldDefinitions($entity_type);
109 $fields['tid']->setLabel(t('Term ID'))
110 ->setDescription(t('The term ID.'));
112 $fields['uuid']->setDescription(t('The term UUID.'));
114 $fields['vid']->setLabel(t('Vocabulary'))
115 ->setDescription(t('The vocabulary to which the term is assigned.'));
117 $fields['langcode']->setDescription(t('The term language code.'));
119 $fields['name'] = BaseFieldDefinition::create('string')
120 ->setLabel(t('Name'))
121 ->setTranslatable(TRUE)
123 ->setSetting('max_length', 255)
124 ->setDisplayOptions('view', [
129 ->setDisplayOptions('form', [
130 'type' => 'string_textfield',
133 ->setDisplayConfigurable('form', TRUE);
135 $fields['description'] = BaseFieldDefinition::create('text_long')
136 ->setLabel(t('Description'))
137 ->setTranslatable(TRUE)
138 ->setDisplayOptions('view', [
140 'type' => 'text_default',
143 ->setDisplayConfigurable('view', TRUE)
144 ->setDisplayOptions('form', [
145 'type' => 'text_textfield',
148 ->setDisplayConfigurable('form', TRUE);
150 $fields['weight'] = BaseFieldDefinition::create('integer')
151 ->setLabel(t('Weight'))
152 ->setDescription(t('The weight of this term in relation to other terms.'))
153 ->setDefaultValue(0);
155 $fields['parent'] = BaseFieldDefinition::create('entity_reference')
156 ->setLabel(t('Term Parents'))
157 ->setDescription(t('The parents of this term.'))
158 ->setSetting('target_type', 'taxonomy_term')
159 ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
160 ->setCustomStorage(TRUE);
162 $fields['changed'] = BaseFieldDefinition::create('changed')
163 ->setLabel(t('Changed'))
164 ->setDescription(t('The time that the term was last edited.'))
165 ->setTranslatable(TRUE);
173 public function getDescription() {
174 return $this->get('description')->value;
180 public function setDescription($description) {
181 $this->set('description', $description);
188 public function getFormat() {
189 return $this->get('description')->format;
195 public function setFormat($format) {
196 $this->get('description')->format = $format;
203 public function getName() {
204 return $this->label();
210 public function setName($name) {
211 $this->set('name', $name);
218 public function getWeight() {
219 return $this->get('weight')->value;
225 public function setWeight($weight) {
226 $this->set('weight', $weight);
233 public function getVocabularyId() {
234 @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);
235 return $this->bundle();
241 protected function getFieldsToSkipFromTranslationChangesCheck() {
242 // @todo the current implementation of the parent field makes it impossible
243 // for ::hasTranslationChanges() to correctly check the field for changes,
244 // so it is currently skipped from the comparision and has to be fixed by
245 // https://www.drupal.org/node/2843060.
246 $fields = parent::getFieldsToSkipFromTranslationChangesCheck();
247 $fields[] = 'parent';