You are here

class MenuLinkItem in Menu Link (Field) 2.0.x

Same name and namespace in other branches
  1. 8 src/Plugin/Field/FieldType/MenuLinkItem.php \Drupal\menu_link\Plugin\Field\FieldType\MenuLinkItem

Defines a menu link field type which stores the link, parent and menu.

Plugin annotation


@FieldType(
  id = "menu_link",
  label = @Translation("Menu link"),
  description = @Translation("Stores a title, menu and parent to insert a link to the current entity."),
  default_widget = "menu_link_default",
  list_class = "\Drupal\menu_link\Plugin\Field\MenuLinkItemList",
  default_formatter = "menu_link",
  column_groups = {
    "title" = {
      "label" = @Translation("Title"),
      "translatable" = TRUE
    },
    "description" = {
      "label" = @Translation("Description"),
      "translatable" = TRUE
    },
    "menu_name" = {
      "label" = @Translation("Menu name"),
      "translatable" = TRUE
    },
    "parent" = {
      "label" = @Translation("Parent"),
      "translatable" = TRUE
    },
  },
)

Hierarchy

Expanded class hierarchy of MenuLinkItem

File

src/Plugin/Field/FieldType/MenuLinkItem.php, line 47

Namespace

Drupal\menu_link\Plugin\Field\FieldType
View source
class MenuLinkItem extends FieldItemBase {

  /**
   * The menu plugin manager.
   *
   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
   */
  protected $menuPluginManager;

  /**
   * The menu parent form selector.
   *
   * @var \Drupal\Core\Menu\MenuParentFormSelectorInterface
   */
  protected $menuParentFormSelector;

  /**
   * {@inheritdoc}
   */
  public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) {
    parent::__construct($definition, $name, $parent);
    $this->menuPluginManager = \Drupal::service('plugin.manager.menu.link');
    $this->menuParentFormSelector = \Drupal::service('menu.parent_form_selector');
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultStorageSettings() {
    return [
      'menu_link_per_translation' => FALSE,
    ] + parent::defaultStorageSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
    $element['menu_link_per_translation'] = [
      '#type' => 'checkbox',
      '#title' => t('Expose a menu link per translation'),
      '#default_value' => $this
        ->getSetting('menu_link_per_translation'),
    ];
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultFieldSettings() {
    $settings = parent::defaultFieldSettings();
    $settings['available_menus'] = [
      'main',
    ];
    $settings['default_menu_parent'] = 'main:';
    return $settings;
  }

  /**
   * {@inheritdoc}
   */
  public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
    $form = parent::fieldSettingsForm($form, $form_state);
    $menu_options = $this
      ->getMenuNames();
    $form['available_menus'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('Available menus'),
      '#default_value' => $this
        ->getSetting('available_menus'),
      '#options' => $menu_options,
      '#description' => $this
        ->t('The menus available to place links in for this kind of entity.'),
      '#required' => TRUE,
    ];
    $parent_options = [];

    // Make sure the setting is normalized to an associative array.
    $available_menus = array_filter($this
      ->getSetting('available_menus'));
    $available_menus = array_combine($available_menus, $available_menus);
    foreach ($available_menus as $name) {
      if (isset($menu_options[$name])) {
        $parent_options["{$name}:"] = $menu_options[$name];
      }
    }
    $form['default_menu_parent'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Default menu for new links'),
      '#default_value' => $this
        ->getSetting('default_menu_parent'),
      '#options' => $parent_options,
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $definitions = [];
    $definitions['menu_name'] = DataDefinition::create('string')
      ->setLabel(t('Menu'));
    $definitions['title'] = DataDefinition::create('string')
      ->setLabel(t('Menu link title'));
    $definitions['description'] = DataDefinition::create('string')
      ->setLabel(t('Menu link description'));
    $definitions['parent'] = DataDefinition::create('string')
      ->setLabel(t('Menu link parent'))
      ->setSetting('default', '');
    $definitions['weight'] = DataDefinition::create('integer')
      ->setLabel(t('Menu link weight'));
    return $definitions;
  }

  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    $schema = [];
    $schema['columns']['menu_name'] = [
      'description' => 'The menu of the link',
      'type' => 'varchar',
      'length' => 255,
      'not null' => FALSE,
    ];
    $schema['columns']['title'] = [
      'description' => 'The menu link text.',
      'type' => 'varchar',
      'length' => 255,
      'not null' => FALSE,
    ];
    $schema['columns']['description'] = [
      'description' => 'The description of the menu link.',
      'type' => 'blob',
      'size' => 'big',
      'not null' => FALSE,
    ];
    $schema['columns']['parent'] = [
      'description' => 'The parent of the menu link',
      'type' => 'varchar',
      'length' => 255,
      'not null' => FALSE,
    ];
    $schema['columns']['weight'] = [
      'description' => 'The weight of the menu link',
      'type' => 'int',
    ];
    return $schema;
  }

  /**
   * {@inheritdoc}
   */
  public function postSave($update) {
    if ($this
      ->getEntity()
      ->isDefaultRevision()) {
      $this
        ->doSave();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function delete() {
    parent::delete();
    $plugin_id = $this
      ->getMenuPluginId();
    if ($this->menuPluginManager
      ->hasDefinition($plugin_id)) {
      $this->menuPluginManager
        ->removeDefinition($plugin_id, FALSE);
    }
  }

  /**
   * Saves the plugin definition.
   */
  protected function doSave() {
    $menu_link_per_translation = $this
      ->getSetting('menu_link_per_translation');

    // We only update the menu link definition when working with the original
    // language value of the field, otherwise, we can never properly update or
    // remove the menu link.
    // @todo - use the FieldTranslationSynchronizer
    // https://www.drupal.org/node/2403455
    if (!$menu_link_per_translation && $this
      ->getLangcode() != $this
      ->getEntity()
      ->getUntranslated()
      ->language()
      ->getId()) {
      return;
    }
    $langcode = $menu_link_per_translation ? $this
      ->getLangcode() : LanguageInterface::LANGCODE_NOT_SPECIFIED;
    $plugin_id = $this
      ->getMenuPluginId($langcode);

    // When the entity is saved via a plugin instance, we should not call the
    // menu tree manager to update the definition a second time.
    if ($menu_plugin_definition = $this
      ->getMenuPluginDefinition($langcode)) {
      if (!$this->menuPluginManager
        ->hasDefinition($plugin_id)) {
        $this->menuPluginManager
          ->addDefinition($plugin_id, $menu_plugin_definition);
      }
      else {
        $this->menuPluginManager
          ->updateDefinition($plugin_id, $menu_plugin_definition, FALSE);
      }
    }
    else {
      $this->menuPluginManager
        ->removeDefinition($plugin_id, FALSE);
    }
  }

  /**
   * Generates the plugin ID for the associated menu link.
   *
   * @param string $langcode
   *   (optional) The langcode to take into account.
   *
   * @return string
   *   The Plugin ID.
   */
  public function getMenuPluginId($langcode = NULL) {
    if ($langcode === NULL) {
      $menu_link_per_translation = $this
        ->getSetting('menu_link_per_translation');
      $langcode = $menu_link_per_translation ? $this
        ->getLangcode() : LanguageInterface::LANGCODE_NOT_SPECIFIED;
    }
    $field_name = $this->definition
      ->getFieldDefinition()
      ->getName();
    $entity_type_id = $this
      ->getEntity()
      ->getEntityTypeId();
    return 'menu_link_field:' . "{$entity_type_id}_{$field_name}_{$this->getEntity()->uuid()}_{$langcode}";
  }

  /**
   * Generates the plugin definition of the associated menu link.
   *
   * @return array|false
   *   The menu plugin definition, otherwise FALSE.
   */
  protected function getMenuPluginDefinition($langcode) {
    $menu_definition = [];

    // If there is no menu name selected, you don't have a valid menu plugin.
    if (!$this->values['menu_name']) {
      return FALSE;
    }
    $entity = $this
      ->getEntity();
    $menu_definition['id'] = $this
      ->getMenuPluginId($langcode);
    if ($entity instanceof TranslatableInterface && $entity
      ->hasTranslation($langcode)) {
      $entity = $entity
        ->getTranslation($langcode);
    }
    $menu_definition['title'] = $this->values['title'] ?: $entity
      ->label();
    $menu_definition['description'] = isset($this->values['description']) ? $this->values['description'] : '';
    $menu_definition['title_max_length'] = $this
      ->getFieldDefinition()
      ->getSetting('max_length');
    $menu_definition['menu_name'] = $this->values['menu_name'];
    $menu_definition['parent'] = isset($this->values['parent']) ? $this->values['parent'] : '';
    $menu_definition['weight'] = isset($this->values['weight']) ? $this->values['weight'] : 0;
    $menu_definition['class'] = MenuLinkField::class;
    $menu_definition['form_class'] = MenuLinkFieldForm::class;
    $menu_definition['metadata']['entity_id'] = $entity
      ->id();
    $menu_definition['metadata']['entity_type_id'] = $entity
      ->getEntityTypeId();
    $menu_definition['metadata']['field_name'] = $this->definition
      ->getFieldDefinition()
      ->getName();
    $menu_definition['metadata']['langcode'] = $langcode;
    $menu_definition['metadata']['translatable'] = $entity
      ->getEntityType()
      ->isTranslatable();
    $url = $entity
      ->toUrl('canonical');
    $menu_definition['route_name'] = $url
      ->getRouteName();
    $menu_definition['route_parameters'] = $url
      ->getRouteParameters();
    return $menu_definition;
  }

  /**
   * Returns available menu names.
   *
   * @return string[]
   *   Returns menu labels, keyed by menu ID.
   */
  protected function getMenuNames() {
    if ($custom_menus = Menu::loadMultiple()) {
      foreach ($custom_menus as $menu_name => $menu) {
        $custom_menus[$menu_name] = $menu
          ->label();
      }
      asort($custom_menus);
    }
    return $custom_menus;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
FieldItemBase::calculateDependencies public static function Calculates dependencies for field items. Overrides FieldItemInterface::calculateDependencies 2
FieldItemBase::calculateStorageDependencies public static function Calculates dependencies for field items on the storage level. Overrides FieldItemInterface::calculateStorageDependencies 1
FieldItemBase::deleteRevision public function Defines custom revision delete behavior for field values. Overrides FieldItemInterface::deleteRevision
FieldItemBase::fieldSettingsFromConfigData public static function Returns a settings array in the field type's canonical representation. Overrides FieldItemInterface::fieldSettingsFromConfigData 1
FieldItemBase::fieldSettingsToConfigData public static function Returns a settings array that can be stored as a configuration value. Overrides FieldItemInterface::fieldSettingsToConfigData 1
FieldItemBase::generateSampleValue public static function Generates placeholder field values. Overrides FieldItemInterface::generateSampleValue 18
FieldItemBase::getEntity public function Gets the entity that field belongs to. Overrides FieldItemInterface::getEntity
FieldItemBase::getFieldDefinition public function Gets the field definition. Overrides FieldItemInterface::getFieldDefinition
FieldItemBase::getLangcode public function Gets the langcode of the field values held in the object. Overrides FieldItemInterface::getLangcode
FieldItemBase::getSetting protected function Returns the value of a field setting.
FieldItemBase::getSettings protected function Returns the array of field settings.
FieldItemBase::mainPropertyName public static function Returns the name of the main property, if any. Overrides FieldItemInterface::mainPropertyName 8
FieldItemBase::onDependencyRemoval public static function Informs the plugin that a dependency of the field will be deleted. Overrides FieldItemInterface::onDependencyRemoval 1
FieldItemBase::preSave public function Defines custom presave behavior for field values. Overrides FieldItemInterface::preSave 7
FieldItemBase::setValue public function Sets the data value. Overrides Map::setValue 4
FieldItemBase::storageSettingsFromConfigData public static function Returns a settings array in the field type's canonical representation. Overrides FieldItemInterface::storageSettingsFromConfigData 2
FieldItemBase::storageSettingsToConfigData public static function Returns a settings array that can be stored as a configuration value. Overrides FieldItemInterface::storageSettingsToConfigData 2
FieldItemBase::view public function Returns a renderable array for a single field item. Overrides FieldItemInterface::view
FieldItemBase::writePropertyValue protected function Different to the parent Map class, we avoid creating property objects as far as possible in order to optimize performance. Thus we just update $this->values if no property object has been created yet. Overrides Map::writePropertyValue
FieldItemBase::__get public function Magic method: Gets a property value. Overrides FieldItemInterface::__get 2
FieldItemBase::__isset public function Magic method: Determines whether a property is set. Overrides FieldItemInterface::__isset
FieldItemBase::__set public function Magic method: Sets a property value. Overrides FieldItemInterface::__set 1
FieldItemBase::__unset public function Magic method: Unsets a property. Overrides FieldItemInterface::__unset
Map::$definition protected property The data definition. Overrides TypedData::$definition
Map::$properties protected property The array of properties.
Map::$values protected property An array of values for the contained properties.
Map::applyDefaultValue public function Applies the default value. Overrides TypedData::applyDefaultValue 4
Map::get public function Gets a property object. Overrides ComplexDataInterface::get
Map::getIterator public function
Map::getProperties public function Gets an array of property objects. Overrides ComplexDataInterface::getProperties
Map::getString public function Returns a string representation of the data. Overrides TypedData::getString
Map::getValue public function Gets the data value. Overrides TypedData::getValue 1
Map::isEmpty public function Determines whether the data structure is empty. Overrides ComplexDataInterface::isEmpty 17
Map::onChange public function Overrides TraversableTypedDataInterface::onChange 4
Map::set public function Sets a property value. Overrides ComplexDataInterface::set
Map::toArray public function Returns an array of all property values. Overrides ComplexDataInterface::toArray 1
Map::__clone public function Magic method: Implements a deep clone.
MenuLinkItem::$menuParentFormSelector protected property The menu parent form selector.
MenuLinkItem::$menuPluginManager protected property The menu plugin manager.
MenuLinkItem::defaultFieldSettings public static function Defines the field-level settings for this plugin. Overrides FieldItemBase::defaultFieldSettings
MenuLinkItem::defaultStorageSettings public static function Defines the storage-level settings for this plugin. Overrides FieldItemBase::defaultStorageSettings
MenuLinkItem::delete public function Defines custom delete behavior for field values. Overrides FieldItemBase::delete
MenuLinkItem::doSave protected function Saves the plugin definition.
MenuLinkItem::fieldSettingsForm public function Returns a form for the field-level settings. Overrides FieldItemBase::fieldSettingsForm
MenuLinkItem::getMenuNames protected function Returns available menu names.
MenuLinkItem::getMenuPluginDefinition protected function Generates the plugin definition of the associated menu link.
MenuLinkItem::getMenuPluginId public function Generates the plugin ID for the associated menu link.
MenuLinkItem::postSave public function Defines custom post-save behavior for field values. Overrides FieldItemBase::postSave
MenuLinkItem::propertyDefinitions public static function Defines field item properties. Overrides FieldItemInterface::propertyDefinitions
MenuLinkItem::schema public static function Returns the schema for the field. Overrides FieldItemInterface::schema
MenuLinkItem::storageSettingsForm public function Returns a form for the storage-level settings. Overrides FieldItemBase::storageSettingsForm
MenuLinkItem::__construct public function Constructs a TypedData object given its definition and context. Overrides FieldItemBase::__construct
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
TypedData::$name protected property The property name.
TypedData::$parent protected property The parent typed data object.
TypedData::createInstance public static function Constructs a TypedData object given its definition and context. Overrides TypedDataInterface::createInstance
TypedData::getConstraints public function Gets a list of validation constraints. Overrides TypedDataInterface::getConstraints 9
TypedData::getDataDefinition public function Gets the data definition. Overrides TypedDataInterface::getDataDefinition
TypedData::getName public function Returns the name of a property or item. Overrides TypedDataInterface::getName
TypedData::getParent public function Returns the parent data structure; i.e. either complex data or a list. Overrides TypedDataInterface::getParent
TypedData::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition
TypedData::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
TypedData::getPropertyPath public function Returns the property path of the data. Overrides TypedDataInterface::getPropertyPath
TypedData::getRoot public function Returns the root of the typed data tree. Overrides TypedDataInterface::getRoot
TypedData::setContext public function Sets the context of a property or item via a context aware parent. Overrides TypedDataInterface::setContext
TypedData::validate public function Validates the currently set data value. Overrides TypedDataInterface::validate
TypedDataTrait::$typedDataManager protected property The typed data manager used for creating the data types.
TypedDataTrait::getTypedDataManager public function Gets the typed data manager. 2
TypedDataTrait::setTypedDataManager public function Sets the typed data manager. 2