/** * {@inheritdoc} */ public function view(FieldItemListInterface $items, $langcode = NULL) { // Default the language to the current content language. if (empty($langcode)) { $langcode = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(); } $elements = $this->viewElements($items, $langcode); // If there are actual renderable children, use #theme => field, otherwise, // let access cacheability metadata pass through for correct bubbling. if (Element::children($elements)) { $entity = $items->getEntity(); $entity_type = $entity->getEntityTypeId(); $field_name = $this->fieldDefinition->getName(); $info = array('#theme' => 'field', '#title' => $this->fieldDefinition->getLabel(), '#label_display' => $this->label, '#view_mode' => $this->viewMode, '#language' => $items->getLangcode(), '#field_name' => $field_name, '#field_type' => $this->fieldDefinition->getType(), '#field_translatable' => $this->fieldDefinition->isTranslatable(), '#entity_type' => $entity_type, '#bundle' => $entity->bundle(), '#object' => $entity, '#items' => $items, '#formatter' => $this->getPluginId(), '#is_multiple' => $this->fieldDefinition->getFieldStorageDefinition()->isMultiple()); $elements = array_merge($info, $elements); } return $elements; }
/** * {@inheritdoc} */ public function view(FieldItemListInterface $items) { $addition = array(); $elements = $this->viewElements($items); if ($elements) { $entity = $items->getEntity(); $entity_type = $entity->getEntityTypeId(); $field_name = $this->fieldDefinition->getName(); $info = array('#theme' => 'field', '#title' => $this->fieldDefinition->getLabel(), '#label_display' => $this->label, '#view_mode' => $this->viewMode, '#language' => $items->getLangcode(), '#field_name' => $field_name, '#field_type' => $this->fieldDefinition->getType(), '#field_translatable' => $this->fieldDefinition->isTranslatable(), '#entity_type' => $entity_type, '#bundle' => $entity->bundle(), '#object' => $entity, '#items' => $items, '#formatter' => $this->getPluginId()); $addition = array_merge($info, $elements); } return $addition; }
/** * Creates a new field item definition. * * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition the item definition belongs to. * * @return static */ public static function create($field_definition) { $definition['type'] = 'field_item:' . $field_definition->getType(); $item_definition = new static($definition); $item_definition->fieldDefinition = $field_definition; return $item_definition; }
/** * {@inheritdoc} */ public function form(FieldItemListInterface $items, array &$form, FormStateInterface $form_state, $get_delta = NULL) { $field_name = $this->fieldDefinition->getName(); $parents = $form['#parents']; // Store field information in $form_state. if (!static::getWidgetState($parents, $field_name, $form_state)) { $field_state = array('items_count' => count($items), 'array_parents' => array()); static::setWidgetState($parents, $field_name, $form_state, $field_state); } // Collect widget elements. $elements = array(); // If the widget is handling multiple values (e.g Options), or if we are // displaying an individual element, just get a single form element and make // it the $delta value. if ($this->handlesMultipleValues() || isset($get_delta)) { $delta = isset($get_delta) ? $get_delta : 0; $element = array('#title' => $this->fieldDefinition->getLabel(), '#description' => FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription()))); $element = $this->formSingleElement($items, $delta, $element, $form, $form_state); if ($element) { if (isset($get_delta)) { // If we are processing a specific delta value for a field where the // field module handles multiples, set the delta in the result. $elements[$delta] = $element; } else { // For fields that handle their own processing, we cannot make // assumptions about how the field is structured, just merge in the // returned element. $elements = $element; } } } else { $elements = $this->formMultipleElements($items, $form, $form_state); } // Populate the 'array_parents' information in $form_state->get('field') // after the form is built, so that we catch changes in the form structure // performed in alter() hooks. $elements['#after_build'][] = array(get_class($this), 'afterBuild'); $elements['#field_name'] = $field_name; $elements['#field_parents'] = $parents; // Enforce the structure of submitted values. $elements['#parents'] = array_merge($parents, array($field_name)); // Most widgets need their internal structure preserved in submitted values. $elements += array('#tree' => TRUE); return array('#type' => 'container', '#parents' => array_merge($parents, array($field_name . '_wrapper')), '#attributes' => array('class' => array('field--type-' . Html::getClass($this->fieldDefinition->getType()), 'field--name-' . Html::getClass($field_name), 'field--widget-' . Html::getClass($this->getPluginId()))), 'widget' => $elements); }
/** * Check if a field on the entity type to update is a possible destination field. * * @todo Should this be on our FieldManager service? * * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition * Field definition on entity type to update to check. * @param \Drupal\Core\Field\FieldDefinitionInterface $source_field * Source field to check compatibility against. If none then check generally. * * @return bool */ protected function isDestinationFieldCompatible(FieldStorageDefinitionInterface $definition, FieldDefinitionInterface $source_field = NULL) { // @todo Create field definition wrapper class to treat FieldDefinitionInterface and FieldStorageDefinitionInterface the same. if ($definition instanceof BaseFieldDefinition && $definition->isReadOnly()) { return FALSE; } // Don't allow updates on updates! if ($definition->getType() == 'entity_reference') { if ($definition->getSetting('target_type') == 'scheduled_update') { return FALSE; } } if ($source_field) { $matching_types = $this->getMatchingFieldTypes($source_field->getType()); if (!in_array($definition->getType(), $matching_types)) { return FALSE; } // Check cardinality $destination_cardinality = $definition->getCardinality(); $source_cardinality = $source_field->getFieldStorageDefinition()->getCardinality(); // $destination_cardinality is unlimited. It doesn't matter what source is. if ($destination_cardinality != -1) { if ($source_cardinality == -1) { return FALSE; } if ($source_cardinality > $destination_cardinality) { return FALSE; } } switch ($definition->getType()) { case 'entity_reference': // Entity reference field must match entity target types. if ($definition->getSetting('target_type') != $source_field->getSetting('target_type')) { return FALSE; } // @todo Check bundles break; // @todo Other type specific conditions? } } return TRUE; }
/** * Returns an array of applicable widget or formatter options for a field. * * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition. * * @return array * An array of applicable widget or formatter options. */ protected function getApplicablePluginOptions(FieldDefinitionInterface $field_definition) { $options = $this->pluginManager->getOptions($field_definition->getType()); $applicable_options = array(); foreach ($options as $option => $label) { $plugin_class = DefaultFactory::getPluginClass($option, $this->pluginManager->getDefinition($option)); if ($plugin_class::isApplicable($field_definition)) { $applicable_options[$option] = $label; } } return $applicable_options; }
/** * Puts the views data for a single field onto the views data. * * @param string $table * The table of the field to handle. * @param string $field_name * The name of the field to handle. * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition defined in Entity::baseFieldDefinitions() * @param \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping * The table mapping information * @param array $table_data * A reference to a specific entity table (for example data_table) inside * the views data. */ protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterface $field_definition, TableMappingInterface $table_mapping, &$table_data) { // Create a dummy instance to retrieve property definitions. $field_column_mapping = $table_mapping->getColumnNames($field_name); $field_schema = $this->getFieldStorageDefinitions()[$field_name]->getSchema(); $field_definition_type = $field_definition->getType(); // Add all properties to views table data. We need an entry for each // column of each field, with the first one given special treatment. // @todo Introduce concept of the "main" column for a field, rather than // assuming the first one is the main column. See also what the // mapSingleFieldViewsData() method does with $first. $multiple = count($field_column_mapping) > 1; $first = TRUE; foreach ($field_column_mapping as $field_column_name => $schema_field_name) { $views_field_name = $multiple ? $field_name . '__' . $field_column_name : $field_name; $table_data[$views_field_name] = $this->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition); $table_data[$views_field_name]['entity field'] = $field_name; $first = FALSE; } }
/** * Get the widget that should used for the default value. * * Returns null to use the default for the field. * @todo This is in here specifically to look at a solution for Workbench Moderation. * Should this be function on the runner plugin? * Or an old school alter hook? * @param $definition * * @return WidgetBase|null */ protected function getWidgetOverride(FieldDefinitionInterface $definition) { if ($definition->getType() == 'entity_reference' && $definition->getSetting('target_type') == 'moderation_state') { $definition->setRequired(FALSE); $definition->setDescription(''); return \Drupal::service('plugin.manager.field.widget')->getInstance(array('field_definition' => $definition)); } return NUll; }
/** * {@inheritdoc} */ public function getType() { return $this->field->getType(); }
/** * Builds the table row structure for a single field. * * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition. * @param \Drupal\Core\Entity\Display\EntityDisplayInterface $entity_display * The entity display. * @param array $form * An associative array containing the structure of the form. * @param array $form_state * A reference to a keyed array containing the current state of the form. * * @return array * A table row array. */ protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, array &$form_state) { $field_name = $field_definition->getName(); $display_options = $entity_display->getComponent($field_name); $label = $field_definition->getLabel(); $regions = array_keys($this->getRegions()); $field_row = array('#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#row_type' => 'field', '#region_callback' => array($this, 'getRowRegion'), '#js_settings' => array('rowHandler' => 'field', 'defaultPlugin' => $this->getDefaultPlugin($field_definition->getType())), 'human_name' => array('#markup' => String::checkPlain($label)), 'weight' => array('#type' => 'textfield', '#title' => $this->t('Weight for @title', array('@title' => $label)), '#title_display' => 'invisible', '#default_value' => $display_options ? $display_options['weight'] : '0', '#size' => 3, '#attributes' => array('class' => array('field-weight'))), 'parent_wrapper' => array('parent' => array('#type' => 'select', '#title' => $this->t('Label display for @title', array('@title' => $label)), '#title_display' => 'invisible', '#options' => array_combine($regions, $regions), '#empty_value' => '', '#attributes' => array('class' => array('field-parent')), '#parents' => array('fields', $field_name, 'parent')), 'hidden_name' => array('#type' => 'hidden', '#default_value' => $field_name, '#attributes' => array('class' => array('field-name'))))); $field_row['plugin'] = array('type' => array('#type' => 'select', '#title' => $this->t('Plugin for @title', array('@title' => $label)), '#title_display' => 'invisible', '#options' => $this->getPluginOptions($field_definition->getType()), '#default_value' => $display_options ? $display_options['type'] : 'hidden', '#parents' => array('fields', $field_name, 'type'), '#attributes' => array('class' => array('field-plugin-type'))), 'settings_edit_form' => array()); // Check the currently selected plugin, and merge persisted values for its // settings. if (isset($form_state['values']['fields'][$field_name]['type'])) { $display_options['type'] = $form_state['values']['fields'][$field_name]['type']; } if (isset($form_state['plugin_settings'][$field_name]['settings'])) { $display_options['settings'] = $form_state['plugin_settings'][$field_name]['settings']; } if (isset($form_state['plugin_settings'][$field_name]['third_party_settings'])) { $display_options['third_party_settings'] = $form_state['plugin_settings'][$field_name]['third_party_settings']; } // Get the corresponding plugin object. $plugin = $this->getPlugin($field_definition, $display_options); // Base button element for the various plugin settings actions. $base_button = array('#submit' => array(array($this, 'multistepSubmit')), '#ajax' => array('callback' => array($this, 'multistepAjax'), 'wrapper' => 'field-display-overview-wrapper', 'effect' => 'fade'), '#field_name' => $field_name); if ($form_state['plugin_settings_edit'] == $field_name) { // We are currently editing this field's plugin settings. Display the // settings form and submit buttons. $field_row['plugin']['settings_edit_form'] = array(); if ($plugin) { // Generate the settings form and allow other modules to alter it. $settings_form = $plugin->settingsForm($form, $form_state); $third_party_settings_form = $this->thirdPartySettingsForm($plugin, $field_definition, $form, $form_state); if ($settings_form || $third_party_settings_form) { $field_row['plugin']['#cell_attributes'] = array('colspan' => 3); $field_row['plugin']['settings_edit_form'] = array('#type' => 'container', '#attributes' => array('class' => array('field-plugin-settings-edit-form')), '#parents' => array('fields', $field_name, 'settings_edit_form'), 'label' => array('#markup' => $this->t('Plugin settings')), 'settings' => $settings_form, 'third_party_settings' => $third_party_settings_form, 'actions' => array('#type' => 'actions', 'save_settings' => $base_button + array('#type' => 'submit', '#button_type' => 'primary', '#name' => $field_name . '_plugin_settings_update', '#value' => $this->t('Update'), '#op' => 'update'), 'cancel_settings' => $base_button + array('#type' => 'submit', '#name' => $field_name . '_plugin_settings_cancel', '#value' => $this->t('Cancel'), '#op' => 'cancel', '#limit_validation_errors' => array(array('fields', $field_name, 'type'))))); $field_row['#attributes']['class'][] = 'field-plugin-settings-editing'; } } } else { $field_row['settings_summary'] = array(); $field_row['settings_edit'] = array(); if ($plugin) { // Display a summary of the current plugin settings, and (if the // summary is not empty) a button to edit them. $summary = $plugin->settingsSummary(); // Allow other modules to alter the summary. $this->alterSettingsSummary($summary, $plugin, $field_definition); if (!empty($summary)) { $summary_escaped = ''; $separator = ''; foreach ($summary as $summary_item) { $summary_escaped .= $separator . SafeMarkup::escape($summary_item); $separator = '<br />'; } $field_row['settings_summary'] = array('#markup' => SafeMarkup::set('<div class="field-plugin-summary">' . $summary_escaped . '</div>'), '#cell_attributes' => array('class' => array('field-plugin-summary-cell'))); } // Check selected plugin settings to display edit link or not. $settings_form = $plugin->settingsForm($form, $form_state); $third_party_settings_form = $this->thirdPartySettingsForm($plugin, $field_definition, $form, $form_state); if (!empty($settings_form) || !empty($third_party_settings_form)) { $field_row['settings_edit'] = $base_button + array('#type' => 'image_button', '#name' => $field_name . '_settings_edit', '#src' => 'core/misc/configure-dark.png', '#attributes' => array('class' => array('field-plugin-settings-edit'), 'alt' => $this->t('Edit')), '#op' => 'edit', '#limit_validation_errors' => array(array('fields', $field_name, 'type')), '#prefix' => '<div class="field-plugin-settings-edit-wrapper">', '#suffix' => '</div>'); } } } return $field_row; }
/** * {@inheritdoc} */ public function view(FieldItemListInterface $items) { $elements = $this->viewElements($items); // If there are actual renderable children, use #theme => field, otherwise, // let access cacheability metadata pass through for correct bubbling. if (Element::children($elements)) { $entity = $items->getEntity(); $entity_type = $entity->getEntityTypeId(); $field_name = $this->fieldDefinition->getName(); $info = array('#theme' => 'field', '#title' => $this->fieldDefinition->getLabel(), '#label_display' => $this->label, '#view_mode' => $this->viewMode, '#language' => $items->getLangcode(), '#field_name' => $field_name, '#field_type' => $this->fieldDefinition->getType(), '#field_translatable' => $this->fieldDefinition->isTranslatable(), '#entity_type' => $entity_type, '#bundle' => $entity->bundle(), '#object' => $entity, '#items' => $items, '#formatter' => $this->getPluginId()); $elements = array_merge($info, $elements); } return $elements; }