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\taxonomy\TermViewBuilder",
23 * "access" = "Drupal\taxonomy\TermAccessControlHandler",
24 * "views_data" = "Drupal\taxonomy\TermViewsData",
26 * "default" = "Drupal\taxonomy\TermForm",
27 * "delete" = "Drupal\taxonomy\Form\TermDeleteForm"
29 * "translation" = "Drupal\taxonomy\TermTranslationHandler"
31 * base_table = "taxonomy_term_data",
32 * data_table = "taxonomy_term_field_data",
33 * uri_callback = "taxonomy_term_uri",
34 * translatable = TRUE,
39 * "langcode" = "langcode",
42 * bundle_entity_type = "taxonomy_vocabulary",
43 * field_ui_base_route = "entity.taxonomy_vocabulary.overview_form",
44 * common_reference_target = TRUE,
46 * "canonical" = "/taxonomy/term/{taxonomy_term}",
47 * "delete-form" = "/taxonomy/term/{taxonomy_term}/delete",
48 * "edit-form" = "/taxonomy/term/{taxonomy_term}/edit",
49 * "create" = "/taxonomy/term",
51 * permission_granularity = "bundle"
54 class Term extends ContentEntityBase implements TermInterface {
56 use EntityChangedTrait;
61 public static function postDelete(EntityStorageInterface $storage, array $entities) {
62 parent::postDelete($storage, $entities);
64 // See if any of the term's children are about to be become orphans.
66 foreach (array_keys($entities) as $tid) {
67 if ($children = $storage->loadChildren($tid)) {
68 foreach ($children as $child) {
69 // If the term has multiple parents, we don't delete it.
70 $parents = $storage->loadParents($child->id());
71 if (empty($parents)) {
78 // Delete term hierarchy information after looking up orphans but before
79 // deleting them so that their children/parent information is consistent.
80 $storage->deleteTermHierarchy(array_keys($entities));
82 if (!empty($orphans)) {
83 $storage->delete($orphans);
90 public function postSave(EntityStorageInterface $storage, $update = TRUE) {
91 parent::postSave($storage, $update);
93 // Only change the parents if a value is set, keep the existing values if
95 if (isset($this->parent->target_id)) {
96 $storage->deleteTermHierarchy([$this->id()]);
97 $storage->updateTermHierarchy($this);
104 public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
105 /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
106 $fields = parent::baseFieldDefinitions($entity_type);
108 $fields['tid']->setLabel(t('Term ID'))
109 ->setDescription(t('The term ID.'));
111 $fields['uuid']->setDescription(t('The term UUID.'));
113 $fields['vid']->setLabel(t('Vocabulary'))
114 ->setDescription(t('The vocabulary to which the term is assigned.'));
116 $fields['langcode']->setDescription(t('The term language code.'));
118 $fields['name'] = BaseFieldDefinition::create('string')
119 ->setLabel(t('Name'))
120 ->setTranslatable(TRUE)
122 ->setSetting('max_length', 255)
123 ->setDisplayOptions('view', [
128 ->setDisplayOptions('form', [
129 'type' => 'string_textfield',
132 ->setDisplayConfigurable('form', TRUE);
134 $fields['description'] = BaseFieldDefinition::create('text_long')
135 ->setLabel(t('Description'))
136 ->setTranslatable(TRUE)
137 ->setDisplayOptions('view', [
139 'type' => 'text_default',
142 ->setDisplayConfigurable('view', TRUE)
143 ->setDisplayOptions('form', [
144 'type' => 'text_textfield',
147 ->setDisplayConfigurable('form', TRUE);
149 $fields['weight'] = BaseFieldDefinition::create('integer')
150 ->setLabel(t('Weight'))
151 ->setDescription(t('The weight of this term in relation to other terms.'))
152 ->setDefaultValue(0);
154 $fields['parent'] = BaseFieldDefinition::create('entity_reference')
155 ->setLabel(t('Term Parents'))
156 ->setDescription(t('The parents of this term.'))
157 ->setSetting('target_type', 'taxonomy_term')
158 ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
159 ->setCustomStorage(TRUE);
161 $fields['changed'] = BaseFieldDefinition::create('changed')
162 ->setLabel(t('Changed'))
163 ->setDescription(t('The time that the term was last edited.'))
164 ->setTranslatable(TRUE);
172 public function getDescription() {
173 return $this->get('description')->value;
179 public function setDescription($description) {
180 $this->set('description', $description);
187 public function getFormat() {
188 return $this->get('description')->format;
194 public function setFormat($format) {
195 $this->get('description')->format = $format;
202 public function getName() {
203 return $this->label();
209 public function setName($name) {
210 $this->set('name', $name);
217 public function getWeight() {
218 return $this->get('weight')->value;
224 public function setWeight($weight) {
225 $this->set('weight', $weight);
232 public function getVocabularyId() {
233 @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);
234 return $this->bundle();
240 protected function getFieldsToSkipFromTranslationChangesCheck() {
241 // @todo the current implementation of the parent field makes it impossible
242 // for ::hasTranslationChanges() to correctly check the field for changes,
243 // so it is currently skipped from the comparision and has to be fixed by
244 // https://www.drupal.org/node/2843060.
245 $fields = parent::getFieldsToSkipFromTranslationChangesCheck();
246 $fields[] = 'parent';