Commit dd8f5660 authored by alexpott's avatar alexpott

Issue #2529034 by penyaskito, vijaycs85, yched: Replace direct access to...

Issue #2529034 by penyaskito, vijaycs85, yched: Replace direct access to FieldConfigBase::default_value with methods
parent e249d759
......@@ -427,16 +427,30 @@ public function isDisplayConfigurable($display_context) {
return isset($this->definition['display'][$display_context]['configurable']) ? $this->definition['display'][$display_context]['configurable'] : FALSE;
}
/**
* {@inheritdoc}
*/
public function getDefaultValueLiteral() {
return isset($this->definition['default_value']) ? $this->definition['default_value'] : [];
}
/**
* {@inheritdoc}
*/
public function getDefaultValueCallback() {
return isset($this->definition['default_value_callback']) ? $this->definition['default_value_callback'] : NULL;
}
/**
* {@inheritdoc}
*/
public function getDefaultValue(FieldableEntityInterface $entity) {
// Allow custom default values function.
if (!empty($this->definition['default_value_callback'])) {
$value = call_user_func($this->definition['default_value_callback'], $entity, $this);
if ($callback = $this->getDefaultValueCallback()) {
$value = call_user_func($callback, $entity, $this);
}
else {
$value = isset($this->definition['default_value']) ? $this->definition['default_value'] : NULL;
$value = $this->getDefaultValueLiteral();
}
// Normalize into the "array keyed by delta" format.
if (isset($value) && !is_array($value)) {
......@@ -452,56 +466,18 @@ public function getDefaultValue(FieldableEntityInterface $entity) {
}
/**
* Sets a custom default value callback.
*
* If set, the callback overrides any set default value.
*
* @param string|null $callback
* The callback to invoke for getting the default value (pass NULL to unset
* a previously set callback). The callback will be invoked with the
* following arguments:
* - \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity being created.
* - \Drupal\Core\Field\FieldDefinitionInterface $definition
* The field definition.
* It should return the default value in the format accepted by the
* setDefaultValue() method.
*
* @return $this
*/
public function setDefaultValueCallback($callback) {
if (isset($callback) && !is_string($callback)) {
throw new \InvalidArgumentException('Default value callback must be a string, like "function_name" or "ClassName::methodName"');
}
$this->definition['default_value_callback'] = $callback;
return $this;
}
/**
* Sets a default value.
*
* Note that if a default value callback is set, it will take precedence over
* any value set here.
*
* @param mixed $value
* The default value for the field. This can be either:
* - a literal, in which case it will be assigned to the first property of
* the first item.
* - a numerically indexed array of items, each item being a property/value
* array.
* - a non-numerically indexed array, in which case the array is assumed to
* be a property/value array and used as the first item
* - NULL or array() for no default value.
*
* @return $this
* {@inheritdoc}
*/
public function setDefaultValue($value) {
// Unless the value is NULL or an empty array, we may need to transform it.
if (!(is_null($value) || (is_array($value) && empty($value)))) {
if ($value === NULL) {
$value = [];
}
// Unless the value is an empty array, we may need to transform it.
if (!is_array($value) || !empty($value)) {
if (!is_array($value)) {
$value = array(array($this->getMainPropertyName() => $value));
}
elseif (!is_numeric(array_keys($value)[0])) {
elseif (is_array($value) && !is_numeric(array_keys($value)[0])) {
$value = array(0 => $value);
}
}
......@@ -509,6 +485,17 @@ public function setDefaultValue($value) {
return $this;
}
/**
* {@inheritdoc}
*/
public function setDefaultValueCallback($callback) {
if (isset($callback) && !is_string($callback)) {
throw new \InvalidArgumentException('Default value callback must be a string, like "function_name" or "ClassName::methodName"');
}
$this->definition['default_value_callback'] = $callback;
return $this;
}
/**
* {@inheritdoc}
*/
......
......@@ -145,7 +145,7 @@ abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigIn
*
* @var array
*/
public $default_value = array();
protected $default_value = array();
/**
* The name of a callback function that returns default values.
......@@ -393,25 +393,58 @@ public function setRequired($required) {
*/
public function getDefaultValue(FieldableEntityInterface $entity) {
// Allow custom default values function.
if ($callback = $this->default_value_callback) {
if ($callback = $this->getDefaultValueCallback()) {
$value = call_user_func($callback, $entity, $this);
}
else {
$value = $this->default_value;
}
// Normalize into the "array keyed by delta" format.
if (isset($value) && !is_array($value)) {
$properties = $this->getFieldStorageDefinition()->getPropertyNames();
$property = reset($properties);
$value = array(
array($property => $value),
);
$value = $this->getDefaultValueLiteral();
}
// Allow the field type to process default values.
$field_item_list_class = $this->getClass();
return $field_item_list_class::processDefaultValue($value, $entity, $this);
}
/**
* {@inheritdoc}
*/
public function getDefaultValueLiteral() {
return $this->default_value;
}
/**
* {@inheritdoc}
*/
public function setDefaultValue($value) {
if (!is_array($value)) {
if ($value === NULL) {
$value = [];
}
$key = $this->getFieldStorageDefinition()->getPropertyNames()[0];
// Convert to the multi value format to support fields with a cardinality
// greater than 1.
$value = array(
array($key => $value),
);
}
$this->default_value = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function getDefaultValueCallback() {
return $this->default_value_callback;
}
/**
* {@inheritdoc}
*/
public function setDefaultValueCallback($callback) {
$this->default_value_callback = $callback;
return $this;
}
/**
* Implements the magic __sleep() method.
*
......@@ -495,22 +528,6 @@ public function getItemDefinition() {
return $this->itemDefinition;
}
/**
* {@inheritdoc}
*/
public function setDefaultValue($value) {
if (!is_array($value)) {
$key = $this->getFieldStorageDefinition()->getPropertyNames()[0];
// Convert to the multi value format to support fields with a cardinality
// greater than 1.
$value = array(
array($key => $value),
);
}
$this->default_value = $value;
return $this;
}
/**
* {@inheritdoc}
*/
......
......@@ -100,13 +100,39 @@ public function setRequired($required);
* any value set here.
*
* @param mixed $value
* The default value in the format as returned by
* \Drupal\Core\Field\FieldDefinitionInterface::getDefaultValue().
* The default value for the field. This can be either:
* - a literal, in which case it will be assigned to the first property of
* the first item.
* - a numerically indexed array of items, each item being a property/value
* array.
* - a non-numerically indexed array, in which case the array is assumed to
* be a property/value array and used as the first item
* - NULL or array() for no default value.
*
* @return $this
*/
public function setDefaultValue($value);
/**
* Sets a custom default value callback.
*
* If set, the callback overrides any set default value.
*
* @param string|null $callback
* The callback to invoke for getting the default value (pass NULL to unset
* a previously set callback). The callback will be invoked with the
* following arguments:
* - \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity being created.
* - \Drupal\Core\Field\FieldDefinitionInterface $definition
* The field definition.
* It should return the default value in the format accepted by the
* setDefaultValue() method.
*
* @return $this
*/
public function setDefaultValueCallback($callback);
/**
* Sets constraints for a given field item property.
*
......
......@@ -178,15 +178,54 @@ public function getDisplayOptions($display_context);
*/
public function isRequired();
/**
* Returns the default value literal for the field.
*
* This method retrieves the raw property assigned to the field definition.
* When computing the runtime default value for a field in a given entity,
* ::getDefaultValue() should be used instead.
*
* @return array
* The default value for the field, as a numerically indexed array of items,
* each item being a property/value array (array() for no default value).
*
* @see FieldDefinitionInterface::getDefaultValue()
* @see FieldDefinitionInterface::getDefaultValueCallback()
*/
public function getDefaultValueLiteral();
/**
* Returns the default value callback for the field.
*
* This method retrieves the raw property assigned to the field definition.
* When computing the runtime default value for a field in a given entity,
* ::getDefaultValue() should be used instead.
*
* @return string|null
* The default value callback for the field.
*
* @see FieldDefinitionInterface::getDefaultValue()
* @see FieldDefinitionInterface::getDefaultValueLiteral()
*/
public function getDefaultValueCallback();
/**
* Returns the default value for the field in a newly created entity.
*
* This method computes the runtime default value for a field in a given
* entity. To access the raw properties assigned to the field definition,
* ::getDefaultValueLiteral() or ::getDefaultValueCallback() should be used
* instead.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity for which the default value is generated.
*
* @return array
* The default value for the field, as a numerically indexed array of items,
* each item being a property/value array (array() for no default value).
*
* @see FieldDefinitionInterface::getDefaultValueLiteral()
* @see FieldDefinitionInterface::getDefaultValueCallback()
*/
public function getDefaultValue(FieldableEntityInterface $entity);
......
......@@ -296,7 +296,7 @@ public function getConstraints() {
* {@inheritdoc}
*/
public function defaultValuesForm(array &$form, FormStateInterface $form_state) {
if (empty($this->getFieldDefinition()->default_value_callback)) {
if (empty($this->getFieldDefinition()->getDefaultValueCallback())) {
// Place the input in a separate place in the submitted values tree.
$widget = $this->defaultValueWidget($form_state);
......
......@@ -285,11 +285,11 @@ public function hasNewEntity() {
*/
public static function calculateDependencies(FieldDefinitionInterface $field_definition) {
$dependencies = [];
if (is_array($field_definition->default_value) && count($field_definition->default_value)) {
if ($default_value = $field_definition->getDefaultValueLiteral()) {
$target_entity_type = \Drupal::entityManager()->getDefinition($field_definition->getFieldStorageDefinition()->getSetting('target_type'));
foreach ($field_definition->default_value 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']);
foreach ($default_value as $value) {
if (is_array($value) && isset($value['target_uuid'])) {
$entity = \Drupal::entityManager()->loadEntityByUuid($target_entity_type->id(), $value['target_uuid']);
// If the entity does not exist do not create the dependency.
// @see \Drupal\Core\Field\EntityReferenceFieldItemList::processDefaultValue()
if ($entity) {
......@@ -306,18 +306,21 @@ public static function calculateDependencies(FieldDefinitionInterface $field_def
*/
public static function onDependencyRemoval(FieldDefinitionInterface $field_definition, array $dependencies) {
$changed = FALSE;
if (!empty($field_definition->default_value)) {
if ($default_value = $field_definition->getDefaultValueLiteral()) {
$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']);
foreach ($default_value as $key => $value) {
if (is_array($value) && isset($value['target_uuid'])) {
$entity = \Drupal::entityManager()->loadEntityByUuid($target_entity_type->id(), $value['target_uuid']);
// @see \Drupal\Core\Field\EntityReferenceFieldItemList::processDefaultValue()
if ($entity && isset($dependencies[$entity->getConfigDependencyKey()][$entity->getConfigDependencyName()])) {
unset($field_definition->default_value[$key]);
unset($default_value[$key]);
$changed = TRUE;
}
}
}
if ($changed) {
$field_definition->setDefaultValue($default_value);
}
}
return $changed;
}
......
......@@ -145,11 +145,9 @@ function comment_theme() {
function comment_field_config_create(FieldConfigInterface $field) {
if ($field->getType() == 'comment' && !$field->isSyncing()) {
// Assign default values for the field.
if (!isset($field->default_value)) {
$field->setDefaultValue(array());
}
$field->default_value += array(array());
$field->default_value[0] += array(
$default_value = $field->getDefaultValueLiteral();
$default_value += array(array());
$default_value[0] += array(
'status' => CommentItemInterface::OPEN,
'cid' => 0,
'last_comment_timestamp' => 0,
......@@ -157,6 +155,7 @@ function comment_field_config_create(FieldConfigInterface $field) {
'last_comment_uid' => 0,
'comment_count' => 0,
);
$field->setDefaultValue($default_value);
}
}
......
......@@ -60,8 +60,8 @@ function testCommentDefaultFields() {
// Test adding a field that defaults to CommentItemInterface::CLOSED.
$this->addDefaultCommentField('node', 'test_node_type', 'who_likes_ponies', CommentItemInterface::CLOSED, 'who_likes_ponies');
$field = FieldConfig::load('node.test_node_type.who_likes_ponies');
$this->assertEqual($field->default_value[0]['status'], CommentItemInterface::CLOSED);
$field = FieldConfig::load('node.test_node_type.who_likes_ponies');;
$this->assertEqual($field->getDefaultValueLiteral()[0]['status'], CommentItemInterface::CLOSED);
}
/**
......
......@@ -32,8 +32,8 @@ class DateTimeFieldItemList extends FieldItemList {
* {@inheritdoc}
*/
public function defaultValuesForm(array &$form, FormStateInterface $form_state) {
if (empty($this->getFieldDefinition()->default_value_callback)) {
$default_value = $this->getFieldDefinition()->default_value;
if (empty($this->getFieldDefinition()->getDefaultValueCallback())) {
$default_value = $this->getFieldDefinition()->getDefaultValueLiteral();
$element = array(
'#parents' => array('default_value_input'),
......
<?php
/**
* @file
* Contains \Drupal\field\Tests\FieldDefaultValueCallbackProvider.
*/
namespace Drupal\field\Tests;
/**
* Helper class for \Drupal\field\Tests\FieldDefaultValueCallbackTest.
*/
class FieldDefaultValueCallbackProvider {
/**
* Helper callback calculating a default value.
*/
public static function calculateDefaultValue() {
return [['value' => 'Calculated default value']];
}
}
<?php
/**
* @file
* Contains \Drupal\field\Tests\FieldDefaultValueCallbackTest.
*/
namespace Drupal\field\Tests;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\WebTestBase;
/**
* Tests the default value callback.
*
* @group field
*/
class FieldDefaultValueCallbackTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node', 'field_test', 'field_ui');
/**
* The field name.
*
* @var string
*/
private $fieldName;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->fieldName = 'field_test';
// Create Article node types.
if ($this->profile != 'standard') {
$this->drupalCreateContentType(array(
'type' => 'article',
'name' => 'Article',
));
}
}
public function testDefaultValueCallbackForm() {
// Create a field and storage for checking.
/** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'node',
'type' => 'text',
])->save();
/** @var \Drupal\field\Entity\FieldConfig $field_config */
$field_config = FieldConfig::create([
'entity_type' => 'node',
'field_name' => $this->fieldName,
'bundle' => 'article',
]);
$field_config->save();
$this->drupalLogin($this->rootUser);
// Check that the default field form is visible when no callback is set.
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertFieldByName('default_value_input[field_test][0][value]', NULL, 'The default field form is visible.');
// Set a different field value, it should be on the field.
$default_value = $this->randomString();
$field_config->setDefaultValue([['value' => $default_value]])->save();
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertFieldByName('default_value_input[field_test][0][value]', $default_value, 'The default field form is visible.');
// Set a different field value to the field directly, instead of an array.
$default_value = $this->randomString();
$field_config->setDefaultValue($default_value)->save();
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertFieldByName('default_value_input[field_test][0][value]', $default_value, 'The default field form is visible.');
// Set a default value callback instead, and the default field form should
// not be visible.
$field_config->setDefaultValueCallback('\Drupal\field\Tests\FieldDefaultValueCallbackProvider::calculateDefaultValue')->save();
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertNoFieldByName('default_value_input[field_test][0][value]', 'Calculated default value', 'The default field form is not visible when a callback is defined.');
}
}
......@@ -613,7 +613,7 @@ function testHiddenField() {
// Update the field to remove the default value, and switch to the default
// widget.
$this->field->default_value = array();
$this->field->setDefaultValue(array());
$this->field->save();
entity_get_form_display($entity_type, $this->field->getTargetBundle(), 'default')
->setComponent($this->field->getName(), array(
......
......@@ -170,7 +170,7 @@ function testTranslatableFieldSaveLoad() {
// @todo Test every translation once the Entity Translation API allows for
// multilingual defaults.
$langcode = $entity->language()->getId();
$this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $field->default_value, format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
$this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $field->getDefaultValueLiteral(), format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
// Check that explicit empty values are not overridden with default values.
foreach (array(NULL, array()) as $empty_items) {
......
......@@ -172,7 +172,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
$items = $form['#entity']->get($this->entity->getName());
$default_value = $items->defaultValuesFormSubmit($form['default_value'], $form, $form_state);
}
$this->entity->default_value = $default_value;
$this->entity->setDefaultValue($default_value);
}
/**
......
......@@ -402,7 +402,7 @@ function testDefaultValue() {
$this->drupalPostForm($admin_path, $edit, t('Save settings'));
$this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
$field = FieldConfig::loadByName('node', $this->contentType, $field_name);
$this->assertEqual($field->default_value, array(array('value' => 1)), 'The default value was correctly saved.');
$this->assertEqual($field->getDefaultValueLiteral(), array(array('value' => 1)), 'The default value was correctly saved.');
// Check that the default value shows up in the form
$this->drupalGet($admin_path);
......@@ -413,7 +413,7 @@ function testDefaultValue() {
$this->drupalPostForm(NULL, $edit, t('Save settings'));
$this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
$field = FieldConfig::loadByName('node', $this->contentType, $field_name);
$this->assertEqual($field->default_value, NULL, 'The default value was correctly saved.');
$this->assertEqual($field->getDefaultValueLiteral(), NULL, 'The default value was correctly saved.');
// Check that the default value can be empty when the field is marked as
// required and can store unlimited values.
......@@ -431,7 +431,7 @@ function testDefaultValue() {
$this->drupalPostForm(NULL, array(), t('Save settings'));
$this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
$field = FieldConfig::loadByName('node', $this->contentType, $field_name);
$this->assertEqual($field->default_value, NULL, 'The default value was correctly saved.');
$this->assertEqual($field->getDefaultValueLiteral(), NULL, 'The default value was correctly saved.');
// Check that the default widget is used when the field is hidden.
entity_get_form_display($field->getTargetEntityTypeId(), $field->getTargetBundle(), 'default')
......
......@@ -85,7 +85,7 @@ public function testTypeHandling() {
public function testMarkFieldForDeletion() {
// Add a default value for a field.
$field = FieldConfig::loadByName('entity_test', 'entity_test', 'field_test_text');
$field->default_value = array(array('value' => 'Llama'));
$field->setDefaultValue(array(array('value' => 'Llama')));
$field->save();
// Denormalize data that contains no entry for the field, and check that
......
......@@ -196,7 +196,7 @@ public function testFieldDefaultValue() {
// Set default value with NULL.
$definition->setDefaultValue(NULL);
$this->assertEquals(NULL, $definition->getDefaultValue($entity));
$this->assertEquals([], $definition->getDefaultValue($entity));
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment