Commit eecd7570 authored by catch's avatar catch

Issue #2951242 by alexpott, amateescu, bmunslow, Berdir, greg606, donaldp:...

Issue #2951242 by alexpott, amateescu, bmunslow, Berdir, greg606, donaldp: Allow BaseFieldDefinition::setInitialValueFromField() to set a default value - this fixes issues with block_content_update_8400()
parent cebca298
......@@ -434,8 +434,16 @@ public function addField($table, $field, $spec, $keys_new = []) {
->execute();
}
if (isset($spec['initial_from_field'])) {
if (isset($spec['initial'])) {
$expression = 'COALESCE(' . $spec['initial_from_field'] . ', :default_initial_value)';
$arguments = [':default_initial_value' => $spec['initial']];
}
else {
$expression = $spec['initial_from_field'];
$arguments = [];
}
$this->connection->update($table)
->expression($field, $spec['initial_from_field'])
->expression($field, $expression, $arguments)
->execute();
}
if ($fixnull) {
......
......@@ -568,8 +568,16 @@ public function addField($table, $field, $spec, $new_keys = []) {
->execute();
}
if (isset($spec['initial_from_field'])) {
if (isset($spec['initial'])) {
$expression = 'COALESCE(' . $spec['initial_from_field'] . ', :default_initial_value)';
$arguments = [':default_initial_value' => $spec['initial']];
}
else {
$expression = $spec['initial_from_field'];
$arguments = [];
}
$this->connection->update($table)
->expression($field, $spec['initial_from_field'])
->expression($field, $expression, $arguments)
->execute();
}
if ($fixnull) {
......
......@@ -333,8 +333,16 @@ public function addField($table, $field, $specification, $keys_new = []) {
->execute();
}
if (isset($specification['initial_from_field'])) {
if (isset($specification['initial'])) {
$expression = 'COALESCE(' . $specification['initial_from_field'] . ', :default_initial_value)';
$arguments = [':default_initial_value' => $specification['initial']];
}
else {
$expression = $specification['initial_from_field'];
$arguments = [];
}
$this->connection->update($table)
->expression($field, $specification['initial_from_field'])
->expression($field, $expression, $arguments)
->execute();
}
}
......@@ -358,9 +366,17 @@ public function addField($table, $field, $specification, $keys_new = []) {
}
elseif (isset($specification['initial_from_field'])) {
// If we have a initial value, copy it over.
if (isset($specification['initial'])) {
$expression = 'COALESCE(' . $specification['initial_from_field'] . ', :default_initial_value)';
$arguments = [':default_initial_value' => $specification['initial']];
}
else {
$expression = $specification['initial_from_field'];
$arguments = [];
}
$mapping[$field] = [
'expression' => $specification['initial_from_field'],
'arguments' => [],
'expression' => $expression,
'arguments' => $arguments,
];
}
else {
......
......@@ -1881,7 +1881,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
if ($initial_value && isset($initial_value[$field_column_name])) {
$schema['fields'][$schema_field_name]['initial'] = drupal_schema_get_field_value($column_schema, $initial_value[$field_column_name]);
}
elseif (!empty($initial_value_from_field)) {
if (!empty($initial_value_from_field)) {
$schema['fields'][$schema_field_name]['initial_from_field'] = $initial_value_from_field[$field_column_name];
}
}
......
......@@ -588,12 +588,24 @@ public function getInitialValueFromField() {
*
* @param string $field_name
* The name of the field that will be used for getting initial values.
* @param mixed $default_value
* (optional) The default value for the field, in case the inherited value
* is NULL. 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;
* - an empty array for no initial value.
* If the field being added is required or an entity key, it is recommended
* to provide a default value.
*
* @return $this
*/
public function setInitialValueFromField($field_name) {
public function setInitialValueFromField($field_name, $default_value = NULL) {
$this->definition['initial_value_from_field'] = $field_name;
$this->setInitialValue($default_value);
return $this;
}
......
......@@ -112,7 +112,7 @@ function block_content_update_8400() {
$has_content_translation_status_field = \Drupal::moduleHandler()->moduleExists('content_translation') && $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'block_content');
if ($has_content_translation_status_field) {
$status->setInitialValueFromField('content_translation_status');
$status->setInitialValueFromField('content_translation_status', TRUE);
}
else {
$status->setInitialValue(TRUE);
......
......@@ -528,6 +528,11 @@ public function testSchemaAddField() {
['not null' => TRUE, 'initial' => 1],
['not null' => TRUE, 'initial' => 1, 'default' => 7],
['not null' => TRUE, 'initial_from_field' => 'serial_column'],
[
'not null' => TRUE,
'initial_from_field' => 'test_nullable_field',
'initial' => 100,
],
];
foreach ($variations as $variation) {
......@@ -581,6 +586,7 @@ protected function assertFieldAdditionRemoval($field_spec) {
$table_spec = [
'fields' => [
'serial_column' => ['type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE],
'test_nullable_field' => ['type' => 'int', 'not null' => FALSE],
'test_field' => $field_spec,
],
'primary key' => ['serial_column'],
......@@ -599,6 +605,7 @@ protected function assertFieldAdditionRemoval($field_spec) {
$table_spec = [
'fields' => [
'serial_column' => ['type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE],
'test_nullable_field' => ['type' => 'int', 'not null' => FALSE],
],
'primary key' => ['serial_column'],
];
......@@ -609,9 +616,15 @@ protected function assertFieldAdditionRemoval($field_spec) {
for ($i = 0; $i < 3; $i++) {
db_insert($table_name)
->useDefaults(['serial_column'])
->fields(['test_nullable_field' => 100])
->execute();
}
// Add another row with no value for the 'test_nullable_field' column.
db_insert($table_name)
->useDefaults(['serial_column'])
->execute();
db_add_field($table_name, 'test_field', $field_spec);
$this->pass(format_string('Column %column created.', ['%column' => 'test_field']));
......@@ -645,7 +658,7 @@ protected function assertFieldCharacteristics($table_name, $field_name, $field_s
}
// Check that the initial value from another field has been registered.
if (isset($field_spec['initial_from_field'])) {
if (isset($field_spec['initial_from_field']) && !isset($field_spec['initial'])) {
// There should be no row with a value different than
// $field_spec['initial_from_field'].
$count = db_select($table_name)
......@@ -656,6 +669,16 @@ protected function assertFieldCharacteristics($table_name, $field_name, $field_s
->fetchField();
$this->assertEqual($count, 0, 'Initial values from another field filled out.');
}
elseif (isset($field_spec['initial_from_field']) && isset($field_spec['initial'])) {
// There should be no row with a value different than '100'.
$count = db_select($table_name)
->fields($table_name, ['serial_column'])
->condition($field_name, 100, '<>')
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, 'Initial values from another field or a default value filled out.');
}
// Check that the default value has been registered.
if (isset($field_spec['default'])) {
......
......@@ -1049,31 +1049,78 @@ public function testInitialValue() {
/**
* Tests adding a base field with initial values inherited from another field.
*
* @dataProvider initialValueFromFieldTestCases
*/
public function testInitialValueFromField() {
public function testInitialValueFromField($default_initial_value, $expected_value) {
$storage = \Drupal::entityTypeManager()->getStorage('entity_test_update');
$db_schema = $this->database->schema();
// Create two entities before adding the base field.
/** @var \Drupal\entity_test\Entity\EntityTestUpdate $entity */
$storage->create(['name' => 'First entity'])->save();
$storage->create(['name' => 'Second entity'])->save();
/** @var \Drupal\entity_test_update\Entity\EntityTestUpdate $entity */
$storage->create([
'name' => 'First entity',
'test_single_property' => 'test existing value',
])->save();
// The second entity does not have any value for the 'test_single_property'
// field, allowing us to test the 'default_value' parameter of
// \Drupal\Core\Field\BaseFieldDefinition::setInitialValueFromField().
$storage->create([
'name' => 'Second entity'
])->save();
// Add a base field with an initial value inherited from another field.
$this->addBaseField();
$storage_definition = BaseFieldDefinition::create('string')
->setLabel(t('A new base field'))
$definitions['new_base_field'] = BaseFieldDefinition::create('string')
->setName('new_base_field')
->setLabel('A new base field')
->setInitialValueFromField('name');
$definitions['another_base_field'] = BaseFieldDefinition::create('string')
->setName('another_base_field')
->setLabel('Another base field')
->setInitialValueFromField('test_single_property', $default_initial_value);
$this->state->set('entity_test_update.additional_base_field_definitions', $definitions);
$this->assertFalse($db_schema->fieldExists('entity_test_update', 'new_base_field'), "New field 'new_base_field' does not exist before applying the update.");
$this->entityDefinitionUpdateManager->installFieldStorageDefinition('new_base_field', 'entity_test_update', 'entity_test', $storage_definition);
$this->assertFalse($db_schema->fieldExists('entity_test_update', 'another_base_field'), "New field 'another_base_field' does not exist before applying the update.");
$this->entityDefinitionUpdateManager->installFieldStorageDefinition('new_base_field', 'entity_test_update', 'entity_test', $definitions['new_base_field']);
$this->entityDefinitionUpdateManager->installFieldStorageDefinition('another_base_field', 'entity_test_update', 'entity_test', $definitions['another_base_field']);
$this->assertTrue($db_schema->fieldExists('entity_test_update', 'new_base_field'), "New field 'new_base_field' has been created on the 'entity_test_update' table.");
$this->assertTrue($db_schema->fieldExists('entity_test_update', 'another_base_field'), "New field 'another_base_field' has been created on the 'entity_test_update' table.");
// Check that the initial values have been applied.
$storage = \Drupal::entityTypeManager()->getStorage('entity_test_update');
$entities = $storage->loadMultiple();
$this->assertEquals('First entity', $entities[1]->get('new_base_field')->value);
$this->assertEquals('Second entity', $entities[2]->get('new_base_field')->value);
$this->assertEquals('test existing value', $entities[1]->get('another_base_field')->value);
$this->assertEquals($expected_value, $entities[2]->get('another_base_field')->value);
}
/**
* Test cases for ::testInitialValueFromField.
*/
public function initialValueFromFieldTestCases() {
return [
'literal value' => [
'test initial value',
'test initial value',
],
'indexed array' => [
['value' => 'test initial value'],
'test initial value',
],
'empty array' => [
[],
NULL,
],
'null' => [
NULL,
NULL,
],
];
}
/**
......
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