Chris@0: save()); the default value is Chris@0: * added if the $entity object provides no explicit entry (actual values or Chris@0: * "the field is empty") for the field. Chris@0: * Chris@0: * The default value is expressed as a numerically indexed array of items, Chris@0: * each item being an array of key/value pairs matching the set of 'columns' Chris@0: * defined by the "field schema" for the field type, as exposed in Chris@0: * hook_field_schema(). If the number of items exceeds the cardinality of the Chris@0: * field, extraneous items will be ignored. Chris@0: * Chris@0: * This property is overlooked if the $default_value_callback is non-empty. Chris@0: * Chris@0: * Example for a integer field: Chris@0: * @code Chris@0: * array( Chris@0: * array('value' => 1), Chris@0: * array('value' => 2), Chris@0: * ) Chris@0: * @endcode Chris@0: * Chris@0: * @var array Chris@0: */ Chris@0: protected $default_value = []; Chris@0: Chris@0: /** Chris@0: * The name of a callback function that returns default values. Chris@0: * Chris@0: * The function will be called with the following arguments: Chris@0: * - \Drupal\Core\Entity\FieldableEntityInterface $entity Chris@0: * The entity being created. Chris@0: * - \Drupal\Core\Field\FieldDefinitionInterface $definition Chris@0: * The field definition. Chris@0: * It should return an array of default values, in the same format as the Chris@0: * $default_value property. Chris@0: * Chris@0: * This property takes precedence on the list of fixed values specified in the Chris@0: * $default_value property. Chris@0: * Chris@0: * @var string Chris@0: */ Chris@0: protected $default_value_callback = ''; Chris@0: Chris@0: /** Chris@0: * The field storage object. Chris@0: * Chris@0: * @var \Drupal\Core\Field\FieldStorageDefinitionInterface Chris@0: */ Chris@0: protected $fieldStorage; Chris@0: Chris@0: /** Chris@0: * The data definition of a field item. Chris@0: * Chris@0: * @var \Drupal\Core\Field\TypedData\FieldItemDataDefinition Chris@0: */ Chris@0: protected $itemDefinition; Chris@0: Chris@0: /** Chris@0: * Array of constraint options keyed by constraint plugin ID. Chris@0: * Chris@0: * @var array Chris@0: */ Chris@0: protected $constraints = []; Chris@0: Chris@0: /** Chris@0: * Array of property constraint options keyed by property ID. The values are Chris@0: * associative array of constraint options keyed by constraint plugin ID. Chris@0: * Chris@0: * @var array[] Chris@0: */ Chris@0: protected $propertyConstraints = []; Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function id() { Chris@0: return $this->entity_type . '.' . $this->bundle . '.' . $this->field_name; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getName() { Chris@0: return $this->field_name; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getType() { Chris@0: return $this->field_type; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getTargetEntityTypeId() { Chris@0: return $this->entity_type; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getTargetBundle() { Chris@0: return $this->bundle; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function calculateDependencies() { Chris@0: parent::calculateDependencies(); Chris@0: // Add dependencies from the field type plugin. We can not use Chris@0: // self::calculatePluginDependencies() because instantiation of a field item Chris@0: // plugin requires a parent entity. Chris@0: /** @var $field_type_manager \Drupal\Core\Field\FieldTypePluginManagerInterface */ Chris@0: $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); Chris@0: $definition = $field_type_manager->getDefinition($this->getType()); Chris@0: $this->addDependency('module', $definition['provider']); Chris@0: // Plugins can declare additional dependencies in their definition. Chris@0: if (isset($definition['config_dependencies'])) { Chris@0: $this->addDependencies($definition['config_dependencies']); Chris@0: } Chris@0: // Let the field type plugin specify its own dependencies. Chris@0: // @see \Drupal\Core\Field\FieldItemInterface::calculateDependencies() Chris@0: $this->addDependencies($definition['class']::calculateDependencies($this)); Chris@0: Chris@0: // Create dependency on the bundle. Chris@18: $bundle_config_dependency = $this->entityTypeManager()->getDefinition($this->entity_type)->getBundleConfigDependency($this->bundle); Chris@0: $this->addDependency($bundle_config_dependency['type'], $bundle_config_dependency['name']); Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function onDependencyRemoval(array $dependencies) { Chris@0: $changed = parent::onDependencyRemoval($dependencies); Chris@0: $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); Chris@0: $definition = $field_type_manager->getDefinition($this->getType()); Chris@0: if ($definition['class']::onDependencyRemoval($this, $dependencies)) { Chris@0: $changed = TRUE; Chris@0: } Chris@0: return $changed; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function postCreate(EntityStorageInterface $storage) { Chris@0: parent::postCreate($storage); Chris@0: // If it was not present in the $values passed to create(), (e.g. for Chris@0: // programmatic creation), populate the denormalized field_type property Chris@0: // from the field storage, so that it gets saved in the config record. Chris@0: if (empty($this->field_type)) { Chris@0: $this->field_type = $this->getFieldStorageDefinition()->getType(); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function postSave(EntityStorageInterface $storage, $update = TRUE) { Chris@0: // Clear the cache. Chris@18: \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); Chris@0: Chris@0: // Invalidate the render cache for all affected entities. Chris@0: $entity_type = $this->getFieldStorageDefinition()->getTargetEntityTypeId(); Chris@18: if ($this->entityTypeManager()->hasHandler($entity_type, 'view_builder')) { Chris@18: $this->entityTypeManager()->getViewBuilder($entity_type)->resetCache(); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getLabel() { Chris@0: return $this->label(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setLabel($label) { Chris@0: $this->label = $label; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getDescription() { Chris@0: return $this->description; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setDescription($description) { Chris@0: $this->description = $description; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isTranslatable() { Chris@0: // A field can be enabled for translation only if translation is supported. Chris@0: return $this->translatable && $this->getFieldStorageDefinition()->isTranslatable(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setTranslatable($translatable) { Chris@0: $this->translatable = $translatable; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getSettings() { Chris@0: return $this->settings + $this->getFieldStorageDefinition()->getSettings(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setSettings(array $settings) { Chris@0: $this->settings = $settings + $this->settings; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getSetting($setting_name) { Chris@0: if (array_key_exists($setting_name, $this->settings)) { Chris@0: return $this->settings[$setting_name]; Chris@0: } Chris@0: else { Chris@0: return $this->getFieldStorageDefinition()->getSetting($setting_name); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setSetting($setting_name, $value) { Chris@0: $this->settings[$setting_name] = $value; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isRequired() { Chris@0: return $this->required; Chris@0: } Chris@0: Chris@0: /** Chris@0: * [@inheritdoc} Chris@0: */ Chris@0: public function setRequired($required) { Chris@0: $this->required = $required; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getDefaultValue(FieldableEntityInterface $entity) { Chris@0: // Allow custom default values function. Chris@0: if ($callback = $this->getDefaultValueCallback()) { Chris@0: $value = call_user_func($callback, $entity, $this); Chris@17: $value = $this->normalizeValue($value, $this->getFieldStorageDefinition()->getMainPropertyName()); Chris@0: } Chris@0: else { Chris@0: $value = $this->getDefaultValueLiteral(); Chris@0: } Chris@0: // Allow the field type to process default values. Chris@0: $field_item_list_class = $this->getClass(); Chris@0: return $field_item_list_class::processDefaultValue($value, $entity, $this); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getDefaultValueLiteral() { Chris@0: return $this->default_value; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setDefaultValue($value) { Chris@17: $this->default_value = $this->normalizeValue($value, $this->getFieldStorageDefinition()->getMainPropertyName()); Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getDefaultValueCallback() { Chris@0: return $this->default_value_callback; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setDefaultValueCallback($callback) { Chris@0: $this->default_value_callback = $callback; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Implements the magic __sleep() method. Chris@0: * Chris@0: * Using the Serialize interface and serialize() / unserialize() methods Chris@0: * breaks entity forms in PHP 5.4. Chris@0: * @todo Investigate in https://www.drupal.org/node/2074253. Chris@0: */ Chris@0: public function __sleep() { Chris@0: // Only serialize necessary properties, excluding those that can be Chris@0: // recalculated. Chris@0: $properties = get_object_vars($this); Chris@0: unset($properties['fieldStorage'], $properties['itemDefinition'], $properties['original']); Chris@0: return array_keys($properties); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function createFromItemType($item_type) { Chris@0: // Forward to the field definition class for creating new data definitions Chris@0: // via the typed manager. Chris@0: return BaseFieldDefinition::createFromItemType($item_type); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function createFromDataType($type) { Chris@0: // Forward to the field definition class for creating new data definitions Chris@0: // via the typed manager. Chris@0: return BaseFieldDefinition::createFromDataType($type); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getDataType() { Chris@0: return 'list'; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isList() { Chris@0: return TRUE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getClass() { Chris@0: // Derive list class from the field type. Chris@0: $type_definition = \Drupal::service('plugin.manager.field.field_type') Chris@0: ->getDefinition($this->getType()); Chris@0: return $type_definition['list_class']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getConstraints() { Chris@0: return \Drupal::typedDataManager()->getDefaultConstraints($this) + $this->constraints; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getConstraint($constraint_name) { Chris@0: $constraints = $this->getConstraints(); Chris@0: return isset($constraints[$constraint_name]) ? $constraints[$constraint_name] : NULL; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getItemDefinition() { Chris@0: if (!isset($this->itemDefinition)) { Chris@0: $this->itemDefinition = FieldItemDataDefinition::create($this) Chris@0: ->setSettings($this->getSettings()); Chris@0: Chris@0: // Add any custom property constraints, overwriting as required. Chris@0: $item_constraints = $this->itemDefinition->getConstraint('ComplexData') ?: []; Chris@0: foreach ($this->propertyConstraints as $name => $constraints) { Chris@0: if (isset($item_constraints[$name])) { Chris@0: $item_constraints[$name] = $constraints + $item_constraints[$name]; Chris@0: } Chris@0: else { Chris@0: $item_constraints[$name] = $constraints; Chris@0: } Chris@0: $this->itemDefinition->addConstraint('ComplexData', $item_constraints); Chris@0: } Chris@0: } Chris@0: Chris@0: return $this->itemDefinition; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getConfig($bundle) { Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setConstraints(array $constraints) { Chris@0: $this->constraints = $constraints; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addConstraint($constraint_name, $options = NULL) { Chris@0: $this->constraints[$constraint_name] = $options; Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setPropertyConstraints($name, array $constraints) { Chris@0: $this->propertyConstraints[$name] = $constraints; Chris@0: Chris@0: // Reset the field item definition so the next time it is instantiated it Chris@0: // will receive the new constraints. Chris@0: $this->itemDefinition = NULL; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function addPropertyConstraints($name, array $constraints) { Chris@0: foreach ($constraints as $constraint_name => $options) { Chris@0: $this->propertyConstraints[$name][$constraint_name] = $options; Chris@0: } Chris@0: Chris@0: // Reset the field item definition so the next time it is instantiated it Chris@0: // will receive the new constraints. Chris@0: $this->itemDefinition = NULL; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: public function isInternal() { Chris@14: // Respect the definition, otherwise default to TRUE for computed fields. Chris@14: if (isset($this->definition['internal'])) { Chris@14: return $this->definition['internal']; Chris@14: } Chris@14: return $this->isComputed(); Chris@14: } Chris@14: Chris@0: }