/** * {@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; }
/** * Special handling to create form elements for multiple values. * * Handles generic features for multiple fields: * - number of widgets * - AHAH-'add more' button * - table display and drag-n-drop value reordering */ protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) { $field_name = $this->fieldDefinition->getName(); $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality(); $parents = $form['#parents']; // Determine the number of widgets to display. switch ($cardinality) { case FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED: $field_state = static::getWidgetState($parents, $field_name, $form_state); $max = $field_state['items_count']; $is_multiple = TRUE; break; default: $max = $cardinality - 1; $is_multiple = $cardinality > 1; break; } $title = $this->fieldDefinition->getLabel(); $description = FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription())); $elements = array(); for ($delta = 0; $delta <= $max; $delta++) { // Add a new empty item if it doesn't exist yet at this delta. if (!isset($items[$delta])) { $items->appendItem(); } // For multiple fields, title and description are handled by the wrapping // table. if ($is_multiple) { $element = ['#title' => $this->t('@title (value @number)', ['@title' => $title, '@number' => $delta + 1]), '#title_display' => 'invisible', '#description' => '']; } else { $element = ['#title' => $title, '#title_display' => 'before', '#description' => $description]; } $element = $this->formSingleElement($items, $delta, $element, $form, $form_state); if ($element) { // Input field for the delta (drag-n-drop reordering). if ($is_multiple) { // We name the element '_weight' to avoid clashing with elements // defined by widget. $element['_weight'] = array('#type' => 'weight', '#title' => $this->t('Weight for row @number', array('@number' => $delta + 1)), '#title_display' => 'invisible', '#delta' => $max, '#default_value' => $items[$delta]->_weight ?: $delta, '#weight' => 100); } $elements[$delta] = $element; } } if ($elements) { $elements += array('#theme' => 'field_multiple_value_form', '#field_name' => $field_name, '#cardinality' => $cardinality, '#cardinality_multiple' => $this->fieldDefinition->getFieldStorageDefinition()->isMultiple(), '#required' => $this->fieldDefinition->isRequired(), '#title' => $title, '#description' => $description, '#max_delta' => $max); // Add 'add more' button, if not working with a programmed form. if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && !$form_state->isProgrammed()) { $id_prefix = implode('-', array_merge($parents, array($field_name))); $wrapper_id = Html::getUniqueId($id_prefix . '-add-more-wrapper'); $elements['#prefix'] = '<div id="' . $wrapper_id . '">'; $elements['#suffix'] = '</div>'; $elements['add_more'] = array('#type' => 'submit', '#name' => strtr($id_prefix, '-', '_') . '_add_more', '#value' => t('Add another item'), '#attributes' => array('class' => array('field-add-more-submit')), '#limit_validation_errors' => array(array_merge($parents, array($field_name))), '#submit' => array(array(get_class($this), 'addMoreSubmit')), '#ajax' => array('callback' => array(get_class($this), 'addMoreAjax'), 'wrapper' => $wrapper_id, 'effect' => 'fade')); } } return $elements; }
/** * {@inheritdoc} */ public function createPayment(FieldDefinitionInterface $field_definition) { /** @var \Drupal\payment\Entity\PaymentInterface $payment */ $payment = $this->entityManager->getStorage('payment')->create(['bundle' => 'payment_reference']); /** @var \Drupal\payment_reference\Plugin\Payment\Type\PaymentReference $payment_type */ $payment_type = $payment->getPaymentType(); $payment_type->setEntityTypeId($field_definition->getFieldStorageDefinition()->getTargetEntityTypeId()); $payment_type->setBundle($field_definition->getTargetBundle()); $payment_type->setFieldName($field_definition->getName()); $payment->setCurrencyCode($field_definition->getSetting('currency_code')); foreach ($field_definition->getSetting('line_items_data') as $line_item_data) { $line_item = $this->paymentLineItemManager->createInstance($line_item_data['plugin_id'], $line_item_data['plugin_configuration']); $payment->setLineItem($line_item); } return $payment; }
public function getOptions(FieldDefinitionInterface $field, $component) { $fs = $field->getFieldStorageDefinition()->getSettings(); $options = $fs[$component . '_options']; foreach ($options as $index => $opt) { if (preg_match('/^\\[vocabulary:([0-9a-z\\_]{1,})\\]/', trim($opt), $matches)) { unset($options[$index]); if ($this->termStorage && $this->vocabularyStorage) { $vocabulary = $this->vocabularyStorage->load($matches[1]); if ($vocabulary) { $max_length = isset($fs['max_length'][$component]) ? $fs['max_length'][$component] : 255; foreach ($this->termStorage->loadTree($vocabulary->id()) as $term) { if (Unicode::strlen($term->name) <= $max_length) { $options[] = $term->name; } } } } } } // Options could come from multiple sources, filter duplicates. $options = array_unique($options); if (isset($fs['sort_options']) && !empty($fs['sort_options'][$component])) { natcasesort($options); } $default = FALSE; foreach ($options as $index => $opt) { if (strpos($opt, '--') === 0) { unset($options[$index]); $default = trim(Unicode::substr($opt, 2)); } } $options = array_map('trim', $options); $options = array_combine($options, $options); if ($default !== FALSE) { $options = array('' => $default) + $options; } return $options; }
/** * {@inheritdoc} */ public static function isApplicable(FieldDefinitionInterface $field_definition) { // This formatter is only available for entity types that have a view // builder. $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type'); return \Drupal::entityManager()->getDefinition($target_type)->hasViewBuilderClass(); }
/** * {@inheritdoc} */ public static function onDependencyRemoval(FieldDefinitionInterface $field_definition, array $dependencies) { $changed = FALSE; if (!empty($field_definition->default_value)) { $target_entity_type = \Drupal::entityManager()->getDefinition($field_definition->getFieldStorageDefinition()->getSetting('target_type')); foreach ($field_definition->default_value as $key => $default_value) { if (is_array($default_value) && isset($default_value['target_uuid'])) { $entity = \Drupal::entityManager()->loadEntityByUuid($target_entity_type->id(), $default_value['target_uuid']); // @see \Drupal\Core\Field\EntityReferenceFieldItemList::processDefaultValue() if ($entity && isset($dependencies[$entity->getConfigDependencyKey()][$entity->getConfigDependencyName()])) { unset($field_definition->default_value[$key]); $changed = TRUE; } } } } return $changed; }
/** * Get matches for the autocompletion of name components. * * @param FieldDefinitionInterface $field * The field definition. * * @param $target * The name field component. * * @param string $string * The string to match for the name field component. * * @return array * An array containing the matching values. */ public function getMatches(FieldDefinitionInterface $field, $target, $string) { $matches = array(); $limit = 10; if (empty($string)) { return $matches; } $settings = $field->getFieldStorageDefinition()->getSettings(); foreach ($this->allComponents as $component) { if (!isset($settings['autocomplete_source'][$component])) { $settings['autocomplete_source'][$component] = array(); } $settings['autocomplete_source'][$component] = array_filter($settings['autocomplete_source'][$component]); } $action = array(); switch ($target) { case 'name': $action['components'] = $this->mapAssoc(array('given', 'middle', 'family')); break; case 'name-all': $action['components'] = $this->mapAssoc($this->allComponents); break; case 'title': case 'given': case 'middle': case 'family': case 'credentials': case 'generational': $action['components'] = array($target => $target); break; default: $action['components'] = array(); foreach (explode('-', $target) as $component) { if (in_array($component, array('title', 'given', 'middle', 'family', 'credentials', 'generational'))) { $action['components'][$component] = $component; } } break; } $action['source'] = array('title' => array(), 'generational' => array()); $action['separater'] = ''; foreach ($action['components'] as $component) { if (empty($settings['autocomplete_source'][$component])) { unset($action['components'][$component]); } else { $sep = (string) $settings['autocomplete_separator'][$component]; if (empty($sep)) { $sep = ' '; } for ($i = 0; $i < count($sep); $i++) { if (strpos($action['separater'], $sep[$i]) === FALSE) { $action['separater'] .= $sep[$i]; } } $found_source = FALSE; foreach ((array) $settings['autocomplete_source'][$component] as $src) { if ($src == 'data' && !$field) { continue; } if ($src == 'title' || $src == 'generational') { if (!$field || $component != $src) { continue; } } $found_source = TRUE; $action['source'][$src][] = $component; } if (!$found_source) { unset($action['components'][$component]); } } } /** * @todo: preg_split fails with a notice if $action['separater'] == ' '. */ @($pieces = preg_split('/[' . preg_quote($action['separater']) . ']+/', $string)); // We should have nice clean parameters to query. if (!empty($pieces) && !empty($action['components'])) { $test_string = Unicode::strtolower(array_pop($pieces)); $base_string = Unicode::substr($string, 0, Unicode::strlen($string) - Unicode::strlen($test_string)); if ($limit > 0 && count($action['source']['title'])) { $options = $this->optionsProvider->getOptions($field, 'title'); foreach ($options as $key => $option) { if (strpos(Unicode::strtolower($key), $test_string) === 0 || strpos(Unicode::strtolower($option), $test_string) === 0) { $matches[$base_string . $key] = $key; $limit--; } } } if ($limit > 0 && count($action['source']['generational'])) { $options = $this->optionsProvider->getOptions($field, 'generational'); foreach ($options as $key => $option) { if (strpos(Unicode::strtolower($key), $test_string) === 0 || strpos(Unicode::strtolower($option), $test_string) === 0) { $matches[$base_string . $key] = $key; $limit--; } } } } return $matches; }
/** * {@inheritdoc} */ public static function generateSampleValue(FieldDefinitionInterface $field_definition) { $manager = \Drupal::service('plugin.manager.entity_reference_selection'); // Instead of calling $manager->getSelectionHandler($field_definition) // replicate the behavior to be able to override the sorting settings. $options = array('target_type' => $field_definition->getFieldStorageDefinition()->getSetting('target_type'), 'handler' => $field_definition->getSetting('handler'), 'handler_settings' => $field_definition->getSetting('handler_settings') ?: array(), 'entity' => NULL); $entity_type = \Drupal::entityManager()->getDefinition($options['target_type']); $options['handler_settings']['sort'] = ['field' => $entity_type->getKey('id'), 'direction' => 'DESC']; $selection_handler = $manager->getInstance($options); // Select a random number of references between the last 50 referenceable // entities created. if ($referenceable = $selection_handler->getReferenceableEntities(NULL, 'CONTAINS', 50)) { $group = array_rand($referenceable); $values['target_id'] = array_rand($referenceable[$group]); return $values; } }
/** * {@inheritdoc} */ public static function isApplicable(FieldDefinitionInterface $field_definition) { return $field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'user'; }
/** * {@inheritdoc} */ public function getSelectionHandler(FieldDefinitionInterface $field_definition, EntityInterface $entity = NULL) { $options = array('target_type' => $field_definition->getFieldStorageDefinition()->getSetting('target_type'), 'handler' => $field_definition->getSetting('handler'), 'handler_settings' => $field_definition->getSetting('handler_settings') ?: array(), 'entity' => $entity); return $this->getInstance($options); }
/** * {@inheritdoc} */ public static function calculateDependencies(FieldDefinitionInterface $field_definition) { $dependencies = []; if (is_array($field_definition->getDefaultValueLiteral()) && count($field_definition->getDefaultValueLiteral())) { $target_entity_type = \Drupal::entityManager()->getDefinition($field_definition->getFieldStorageDefinition()->getSetting('target_type')); foreach ($field_definition->getDefaultValueLiteral() as $default_value) { if (is_array($default_value) && isset($default_value['target_uuid'])) { $entity = \Drupal::entityManager()->loadEntityByUuid($target_entity_type->id(), $default_value['target_uuid']); // If the entity does not exist do not create the dependency. // @see \Drupal\Core\Field\EntityReferenceFieldItemList::processDefaultValue() if ($entity) { $dependencies[$target_entity_type->getConfigDependencyKey()][] = $entity->getConfigDependencyName(); } } } } return $dependencies; }
/** * Determine if we should try to make a default value widget. * * @param \Drupal\Core\Field\FieldDefinitionInterface $definition * * @return bool */ private function isDefaultCompatible(FieldDefinitionInterface $definition) { $class = $definition->getClass(); $type = $definition->getType(); $compatible_types = [ 'boolean', 'list_float', 'list_integer', 'list_string', ]; if (in_array($type, $compatible_types)) { return TRUE; } if ('entity_reference' == $type) { // We should only store a default value in the special case // where the target is a config entity. // Otherwise we would have config that pointed to content. // The site-builder could still do this in manage fields for the Update type // but should not en-courage this practice. $target_type = $definition->getFieldStorageDefinition()->getSetting('target_type'); $definition = $this->entityTypeManager->getDefinition($target_type); if ($this->definitionClassImplementsInterface($definition, ['Drupal\Core\Config\Entity\ConfigEntityInterface'])) { return TRUE; } } return FALSE; }
/** * {@inheritdoc} */ public static function isApplicable(FieldDefinitionInterface $field_definition) { // This formatter is only available for taxonomy terms. return $field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'taxonomy_term'; }
/** * {@inheritdoc} */ public static function generateSampleValue(FieldDefinitionInterface $field_definition) { $allowed_options = options_allowed_values($field_definition->getFieldStorageDefinition()); $values['value'] = array_rand($allowed_options); return $values; }
/** * {@inheritdoc} */ public function getMainPropertyName() { return $this->fieldDefinition->getFieldStorageDefinition()->getMainPropertyName(); }
/** * {@inheritdoc} */ protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefinitionInterface $field_definition) { $storage_definition = $field_definition->getFieldStorageDefinition(); $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); $table_mapping = $this->getTableMapping(); $table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $is_deleted); $revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $is_deleted); $revision_id = $this->entityType->isRevisionable() ? $entity->getRevisionId() : $entity->id(); $this->database->delete($table_name)->condition('revision_id', $revision_id)->execute(); if ($this->entityType->isRevisionable()) { $this->database->delete($revision_name)->condition('revision_id', $revision_id)->execute(); } }
/** * {@inheritdoc} */ public static function settingsForm(FieldDefinitionInterface $field_definition) { $entity_manager = \Drupal::entityManager(); $entity_type_id = $field_definition->getSetting('target_type'); $selection_handler_settings = $field_definition->getSetting('handler_settings') ?: array(); $entity_type = $entity_manager->getDefinition($entity_type_id); $bundles = $entity_manager->getBundleInfo($entity_type_id); // Merge-in default values. $selection_handler_settings += array('target_bundles' => array(), 'sort' => array('field' => '_none'), 'auto_create' => FALSE); if ($entity_type->hasKey('bundle')) { $bundle_options = array(); foreach ($bundles as $bundle_name => $bundle_info) { $bundle_options[$bundle_name] = $bundle_info['label']; } $target_bundles_title = t('Bundles'); // Default core entity types with sensible labels. if ($entity_type_id == 'node') { $target_bundles_title = t('Content types'); } elseif ($entity_type_id == 'taxonomy_term') { $target_bundles_title = t('Vocabularies'); } $form['target_bundles'] = array('#type' => 'checkboxes', '#title' => $target_bundles_title, '#options' => $bundle_options, '#default_value' => !empty($selection_handler_settings['target_bundles']) ? $selection_handler_settings['target_bundles'] : array(), '#required' => TRUE, '#size' => 6, '#multiple' => TRUE, '#element_validate' => array('_entity_reference_element_validate_filter')); } else { $form['target_bundles'] = array('#type' => 'value', '#value' => array()); } if ($entity_type->isSubclassOf('\\Drupal\\Core\\Entity\\FieldableEntityInterface')) { $fields = array(); foreach (array_keys($bundles) as $bundle) { $bundle_fields = array_filter($entity_manager->getFieldDefinitions($entity_type_id, $bundle), function ($field_definition) { return !$field_definition->isComputed(); }); foreach ($bundle_fields as $field_name => $field_definition) { /* @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */ $columns = $field_definition->getFieldStorageDefinition()->getColumns(); // If there is more than one column, display them all, otherwise just // display the field label. // @todo: Use property labels instead of the column name. if (count($columns) > 1) { foreach ($columns as $column_name => $column_info) { $fields[$field_name . '.' . $column_name] = t('@label (@column)', array('@label' => $field_definition->getLabel(), '@column' => $column_name)); } } else { $fields[$field_name] = t('@label', array('@label' => $field_definition->getLabel())); } } } $form['sort']['field'] = array('#type' => 'select', '#title' => t('Sort by'), '#options' => array('_none' => t('- None -')) + $fields, '#ajax' => TRUE, '#limit_validation_errors' => array(), '#default_value' => $selection_handler_settings['sort']['field']); $form['sort']['settings'] = array('#type' => 'container', '#attributes' => array('class' => array('entity_reference-settings')), '#process' => array('_entity_reference_form_process_merge_parent')); if ($selection_handler_settings['sort']['field'] != '_none') { // Merge-in default values. $selection_handler_settings['sort'] += array('direction' => 'ASC'); $form['sort']['settings']['direction'] = array('#type' => 'select', '#title' => t('Sort direction'), '#required' => TRUE, '#options' => array('ASC' => t('Ascending'), 'DESC' => t('Descending')), '#default_value' => $selection_handler_settings['sort']['direction']); } } return $form; }
/** * 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; }
/** * {@inheritdoc} */ public static function isApplicable(FieldDefinitionInterface $field_definition) { // This formatter is only available for entity types that reference // media entities. $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type'); return $target_type == 'media'; }