460c0df0d4c7ff14ecb6b643f592b8424b91ce43
[yaffs-website] / web / core / modules / menu_link_content / src / Entity / MenuLinkContent.php
1 <?php
2
3 namespace Drupal\menu_link_content\Entity;
4
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\link\LinkItemInterface;
11 use Drupal\menu_link_content\MenuLinkContentInterface;
12
13 /**
14  * Defines the menu link content entity class.
15  *
16  * @property \Drupal\link\LinkItemInterface link
17  * @property \Drupal\Core\Field\FieldItemList rediscover
18  *
19  * @ContentEntityType(
20  *   id = "menu_link_content",
21  *   label = @Translation("Custom menu link"),
22  *   handlers = {
23  *     "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
24  *     "storage_schema" = "Drupal\menu_link_content\MenuLinkContentStorageSchema",
25  *     "access" = "Drupal\menu_link_content\MenuLinkContentAccessControlHandler",
26  *     "form" = {
27  *       "default" = "Drupal\menu_link_content\Form\MenuLinkContentForm",
28  *       "delete" = "Drupal\menu_link_content\Form\MenuLinkContentDeleteForm"
29  *     }
30  *   },
31  *   admin_permission = "administer menu",
32  *   base_table = "menu_link_content",
33  *   data_table = "menu_link_content_data",
34  *   translatable = TRUE,
35  *   entity_keys = {
36  *     "id" = "id",
37  *     "label" = "title",
38  *     "langcode" = "langcode",
39  *     "uuid" = "uuid",
40  *     "bundle" = "bundle"
41  *   },
42  *   links = {
43  *     "canonical" = "/admin/structure/menu/item/{menu_link_content}/edit",
44  *     "edit-form" = "/admin/structure/menu/item/{menu_link_content}/edit",
45  *     "delete-form" = "/admin/structure/menu/item/{menu_link_content}/delete",
46  *   }
47  * )
48  */
49 class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterface {
50
51   use EntityChangedTrait;
52
53   /**
54    * A flag for whether this entity is wrapped in a plugin instance.
55    *
56    * @var bool
57    */
58   protected $insidePlugin = FALSE;
59
60   /**
61    * {@inheritdoc}
62    */
63   public function setInsidePlugin() {
64     $this->insidePlugin = TRUE;
65   }
66
67   /**
68    * {@inheritdoc}
69    */
70   public function getTitle() {
71     return $this->get('title')->value;
72   }
73
74   /**
75    * {@inheritdoc}
76    */
77   public function getUrlObject() {
78     return $this->link->first()->getUrl();
79   }
80
81   /**
82    * {@inheritdoc}
83    */
84   public function getMenuName() {
85     return $this->get('menu_name')->value;
86   }
87
88   /**
89    * {@inheritdoc}
90    */
91   public function getDescription() {
92     return $this->get('description')->value;
93   }
94
95   /**
96    * {@inheritdoc}
97    */
98   public function getPluginId() {
99     return 'menu_link_content:' . $this->uuid();
100   }
101
102   /**
103    * {@inheritdoc}
104    */
105   public function isEnabled() {
106     return (bool) $this->get('enabled')->value;
107   }
108
109   /**
110    * {@inheritdoc}
111    */
112   public function isExpanded() {
113     return (bool) $this->get('expanded')->value;
114   }
115
116   /**
117    * {@inheritdoc}
118    */
119   public function getParentId() {
120     // Cast the parent ID to a string, only an empty string means no parent,
121     // NULL keeps the existing parent.
122     return (string) $this->get('parent')->value;
123   }
124
125   /**
126    * {@inheritdoc}
127    */
128   public function getWeight() {
129     return (int) $this->get('weight')->value;
130   }
131
132   /**
133    * {@inheritdoc}
134    */
135   public function getPluginDefinition() {
136     $definition = [];
137     $definition['class'] = 'Drupal\menu_link_content\Plugin\Menu\MenuLinkContent';
138     $definition['menu_name'] = $this->getMenuName();
139
140     if ($url_object = $this->getUrlObject()) {
141       $definition['url'] = NULL;
142       $definition['route_name'] = NULL;
143       $definition['route_parameters'] = [];
144       if (!$url_object->isRouted()) {
145         $definition['url'] = $url_object->getUri();
146       }
147       else {
148         $definition['route_name'] = $url_object->getRouteName();
149         $definition['route_parameters'] = $url_object->getRouteParameters();
150       }
151       $definition['options'] = $url_object->getOptions();
152     }
153
154     $definition['title'] = $this->getTitle();
155     $definition['description'] = $this->getDescription();
156     $definition['weight'] = $this->getWeight();
157     $definition['id'] = $this->getPluginId();
158     $definition['metadata'] = ['entity_id' => $this->id()];
159     $definition['form_class'] = '\Drupal\menu_link_content\Form\MenuLinkContentForm';
160     $definition['enabled'] = $this->isEnabled() ? 1 : 0;
161     $definition['expanded'] = $this->isExpanded() ? 1 : 0;
162     $definition['provider'] = 'menu_link_content';
163     $definition['discovered'] = 0;
164     $definition['parent'] = $this->getParentId();
165
166     return $definition;
167   }
168
169   /**
170    * {@inheritdoc}
171    */
172   public static function preCreate(EntityStorageInterface $storage, array &$values) {
173     $values += ['bundle' => 'menu_link_content'];
174   }
175
176   /**
177    * {@inheritdoc}
178    */
179   public function preSave(EntityStorageInterface $storage) {
180     parent::preSave($storage);
181
182     if (parse_url($this->link->uri, PHP_URL_SCHEME) === 'internal') {
183       $this->setRequiresRediscovery(TRUE);
184     }
185     else {
186       $this->setRequiresRediscovery(FALSE);
187     }
188   }
189   /**
190    * {@inheritdoc}
191    */
192   public function postSave(EntityStorageInterface $storage, $update = TRUE) {
193     parent::postSave($storage, $update);
194
195     /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
196     $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
197
198     // The menu link can just be updated if there is already an menu link entry
199     // on both entity and menu link plugin level.
200     $definition = $this->getPluginDefinition();
201     // Even when $update is FALSE, for top level links it is possible the link
202     // already is in the storage because of the getPluginDefinition() call
203     // above, see https://www.drupal.org/node/2605684#comment-10515450 for the
204     // call chain. Because of this the $update flag is ignored and only the
205     // existence of the definition (equals to being in the tree storage) is
206     // checked.
207     if ($menu_link_manager->getDefinition($this->getPluginId(), FALSE)) {
208       // When the entity is saved via a plugin instance, we should not call
209       // the menu tree manager to update the definition a second time.
210       if (!$this->insidePlugin) {
211         $menu_link_manager->updateDefinition($this->getPluginId(), $definition, FALSE);
212       }
213     }
214     else {
215       $menu_link_manager->addDefinition($this->getPluginId(), $definition);
216     }
217   }
218
219   /**
220    * {@inheritdoc}
221    */
222   public static function preDelete(EntityStorageInterface $storage, array $entities) {
223     parent::preDelete($storage, $entities);
224
225     /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
226     $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
227
228     foreach ($entities as $menu_link) {
229       /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $menu_link */
230       $menu_link_manager->removeDefinition($menu_link->getPluginId(), FALSE);
231     }
232   }
233
234   /**
235    * {@inheritdoc}
236    */
237   public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
238     /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
239     $fields = parent::baseFieldDefinitions($entity_type);
240
241     $fields['id']->setLabel(t('Entity ID'))
242       ->setDescription(t('The entity ID for this menu link content entity.'));
243
244     $fields['uuid']->setDescription(t('The content menu link UUID.'));
245
246     $fields['langcode']->setDescription(t('The menu link language code.'));
247
248     $fields['bundle']
249       ->setDescription(t('The content menu link bundle.'))
250       ->setSetting('max_length', EntityTypeInterface::BUNDLE_MAX_LENGTH)
251       ->setSetting('is_ascii', TRUE);
252
253     $fields['title'] = BaseFieldDefinition::create('string')
254       ->setLabel(t('Menu link title'))
255       ->setDescription(t('The text to be used for this link in the menu.'))
256       ->setRequired(TRUE)
257       ->setTranslatable(TRUE)
258       ->setSetting('max_length', 255)
259       ->setDisplayOptions('view', [
260         'label' => 'hidden',
261         'type' => 'string',
262         'weight' => -5,
263       ])
264       ->setDisplayOptions('form', [
265         'type' => 'string_textfield',
266         'weight' => -5,
267       ])
268       ->setDisplayConfigurable('form', TRUE);
269
270     $fields['description'] = BaseFieldDefinition::create('string')
271       ->setLabel(t('Description'))
272       ->setDescription(t('Shown when hovering over the menu link.'))
273       ->setTranslatable(TRUE)
274       ->setSetting('max_length', 255)
275       ->setDisplayOptions('view', [
276         'label' => 'hidden',
277         'type' => 'string',
278         'weight' => 0,
279       ])
280       ->setDisplayOptions('form', [
281         'type' => 'string_textfield',
282         'weight' => 0,
283       ]);
284
285     $fields['menu_name'] = BaseFieldDefinition::create('string')
286       ->setLabel(t('Menu name'))
287       ->setDescription(t('The menu name. All links with the same menu name (such as "tools") are part of the same menu.'))
288       ->setDefaultValue('tools')
289       ->setSetting('is_ascii', TRUE);
290
291     $fields['link'] = BaseFieldDefinition::create('link')
292       ->setLabel(t('Link'))
293       ->setDescription(t('The location this menu link points to.'))
294       ->setRequired(TRUE)
295       ->setSettings([
296         'link_type' => LinkItemInterface::LINK_GENERIC,
297         'title' => DRUPAL_DISABLED,
298       ])
299       ->setDisplayOptions('form', [
300         'type' => 'link_default',
301         'weight' => -2,
302       ]);
303
304     $fields['external'] = BaseFieldDefinition::create('boolean')
305       ->setLabel(t('External'))
306       ->setDescription(t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'))
307       ->setDefaultValue(FALSE);
308
309     $fields['rediscover'] = BaseFieldDefinition::create('boolean')
310       ->setLabel(t('Indicates whether the menu link should be rediscovered'))
311       ->setDefaultValue(FALSE);
312
313     $fields['weight'] = BaseFieldDefinition::create('integer')
314       ->setLabel(t('Weight'))
315       ->setDescription(t('Link weight among links in the same menu at the same depth. In the menu, the links with high weight will sink and links with a low weight will be positioned nearer the top.'))
316       ->setDefaultValue(0)
317       ->setDisplayOptions('view', [
318         'label' => 'hidden',
319         'type' => 'number_integer',
320         'weight' => 0,
321       ])
322       ->setDisplayOptions('form', [
323         'type' => 'number',
324         'weight' => 20,
325       ]);
326
327     $fields['expanded'] = BaseFieldDefinition::create('boolean')
328       ->setLabel(t('Show as expanded'))
329       ->setDescription(t('If selected and this menu link has children, the menu will always appear expanded.'))
330       ->setDefaultValue(FALSE)
331       ->setDisplayOptions('view', [
332         'label' => 'hidden',
333         'type' => 'boolean',
334         'weight' => 0,
335       ])
336       ->setDisplayOptions('form', [
337         'settings' => ['display_label' => TRUE],
338         'weight' => 0,
339       ]);
340
341     $fields['enabled'] = BaseFieldDefinition::create('boolean')
342       ->setLabel(t('Enabled'))
343       ->setDescription(t('A flag for whether the link should be enabled in menus or hidden.'))
344       ->setDefaultValue(TRUE)
345       ->setDisplayOptions('view', [
346         'label' => 'hidden',
347         'type' => 'boolean',
348         'weight' => 0,
349       ])
350       ->setDisplayOptions('form', [
351         'settings' => ['display_label' => TRUE],
352         'weight' => -1,
353       ]);
354
355     $fields['parent'] = BaseFieldDefinition::create('string')
356       ->setLabel(t('Parent plugin ID'))
357       ->setDescription(t('The ID of the parent menu link plugin, or empty string when at the top level of the hierarchy.'));
358
359     $fields['changed'] = BaseFieldDefinition::create('changed')
360       ->setLabel(t('Changed'))
361       ->setDescription(t('The time that the menu link was last edited.'))
362       ->setTranslatable(TRUE);
363
364     return $fields;
365   }
366
367   /**
368    * {@inheritdoc}
369    */
370   public function requiresRediscovery() {
371     return $this->get('rediscover')->value;
372   }
373
374   /**
375    * {@inheritdoc}
376    */
377   public function setRequiresRediscovery($rediscovery) {
378     $this->set('rediscover', $rediscovery);
379     return $this;
380   }
381
382 }