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",
50 * permission_granularity = "bundle"
53 class Term extends ContentEntityBase implements TermInterface {
55 use EntityChangedTrait;
60 public static function postDelete(EntityStorageInterface $storage, array $entities) {
61 parent::postDelete($storage, $entities);
63 // See if any of the term's children are about to be become orphans.
65 foreach (array_keys($entities) as $tid) {
66 if ($children = $storage->loadChildren($tid)) {
67 foreach ($children as $child) {
68 // If the term has multiple parents, we don't delete it.
69 $parents = $storage->loadParents($child->id());
70 if (empty($parents)) {
77 // Delete term hierarchy information after looking up orphans but before
78 // deleting them so that their children/parent information is consistent.
79 $storage->deleteTermHierarchy(array_keys($entities));
81 if (!empty($orphans)) {
82 $storage->delete($orphans);
89 public function postSave(EntityStorageInterface $storage, $update = TRUE) {
90 parent::postSave($storage, $update);
92 // Only change the parents if a value is set, keep the existing values if
94 if (isset($this->parent->target_id)) {
95 $storage->deleteTermHierarchy([$this->id()]);
96 $storage->updateTermHierarchy($this);
103 public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
104 /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
105 $fields = parent::baseFieldDefinitions($entity_type);
107 $fields['tid']->setLabel(t('Term ID'))
108 ->setDescription(t('The term ID.'));
110 $fields['uuid']->setDescription(t('The term UUID.'));
112 $fields['vid']->setLabel(t('Vocabulary'))
113 ->setDescription(t('The vocabulary to which the term is assigned.'));
115 $fields['langcode']->setDescription(t('The term language code.'));
117 $fields['name'] = BaseFieldDefinition::create('string')
118 ->setLabel(t('Name'))
119 ->setTranslatable(TRUE)
121 ->setSetting('max_length', 255)
122 ->setDisplayOptions('view', [
127 ->setDisplayOptions('form', [
128 'type' => 'string_textfield',
131 ->setDisplayConfigurable('form', TRUE);
133 $fields['description'] = BaseFieldDefinition::create('text_long')
134 ->setLabel(t('Description'))
135 ->setTranslatable(TRUE)
136 ->setDisplayOptions('view', [
138 'type' => 'text_default',
141 ->setDisplayConfigurable('view', TRUE)
142 ->setDisplayOptions('form', [
143 'type' => 'text_textfield',
146 ->setDisplayConfigurable('form', TRUE);
148 $fields['weight'] = BaseFieldDefinition::create('integer')
149 ->setLabel(t('Weight'))
150 ->setDescription(t('The weight of this term in relation to other terms.'))
151 ->setDefaultValue(0);
153 $fields['parent'] = BaseFieldDefinition::create('entity_reference')
154 ->setLabel(t('Term Parents'))
155 ->setDescription(t('The parents of this term.'))
156 ->setSetting('target_type', 'taxonomy_term')
157 ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
158 ->setCustomStorage(TRUE);
160 $fields['changed'] = BaseFieldDefinition::create('changed')
161 ->setLabel(t('Changed'))
162 ->setDescription(t('The time that the term was last edited.'))
163 ->setTranslatable(TRUE);
171 public function getDescription() {
172 return $this->get('description')->value;
178 public function setDescription($description) {
179 $this->set('description', $description);
186 public function getFormat() {
187 return $this->get('description')->format;
193 public function setFormat($format) {
194 $this->get('description')->format = $format;
201 public function getName() {
202 return $this->label();
208 public function setName($name) {
209 $this->set('name', $name);
216 public function getWeight() {
217 return $this->get('weight')->value;
223 public function setWeight($weight) {
224 $this->set('weight', $weight);
231 public function getVocabularyId() {
232 return $this->get('vid')->target_id;
238 protected function getFieldsToSkipFromTranslationChangesCheck() {
239 // @todo the current implementation of the parent field makes it impossible
240 // for ::hasTranslationChanges() to correctly check the field for changes,
241 // so it is currently skipped from the comparision and has to be fixed by
242 // https://www.drupal.org/node/2843060.
243 $fields = parent::getFieldsToSkipFromTranslationChangesCheck();
244 $fields[] = 'parent';