Issue #3051981 by andypost, alexpott, amateescu, kim.pepper, Berdir, voleger, larowlan, claudiu.cristea, martin107: Deprecate drupal_schema_get_field_value()

merge-requests/1119/head
Alex Pott 2019-05-07 11:00:58 +01:00
parent d9e8e19c29
commit ecf0410252
No known key found for this signature in database
GPG Key ID: 31905460D4A69276
5 changed files with 192 additions and 16 deletions

View File

@ -5,6 +5,8 @@
* Schema API handling functions. * Schema API handling functions.
*/ */
use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
/** /**
* @addtogroup schemaapi * @addtogroup schemaapi
* @{ * @{
@ -215,21 +217,15 @@ function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRU
* *
* @return mixed * @return mixed
* The converted value. * The converted value.
*
* @deprecated in drupal:8.8.0 and will be removed from drupal:9.0.0. Use
* \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue() instead.
*
* @see https://www.drupal.org/node/3051983
*/ */
function drupal_schema_get_field_value(array $info, $value) { function drupal_schema_get_field_value(array $info, $value) {
// Preserve legal NULL values. @trigger_error('drupal_schema_get_field_value() is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Use \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue($info, $value) instead. See https://www.drupal.org/node/3051983', E_USER_DEPRECATED);
if (isset($value) || !empty($info['not null'])) { return SqlContentEntityStorageSchema::castValue($info, $value);
if ($info['type'] == 'int' || $info['type'] == 'serial') {
$value = (int) $value;
}
elseif ($info['type'] == 'float') {
$value = (float) $value;
}
elseif (!is_array($value)) {
$value = (string) $value;
}
}
return $value;
} }
/** /**

View File

@ -1097,7 +1097,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
// Do not set serial fields if we do not have a value. This supports all // Do not set serial fields if we do not have a value. This supports all
// SQL database drivers. // SQL database drivers.
// @see https://www.drupal.org/node/2279395 // @see https://www.drupal.org/node/2279395
$value = drupal_schema_get_field_value($definition->getSchema()['columns'][$column_name], $value); $value = SqlContentEntityStorageSchema::castValue($definition->getSchema()['columns'][$column_name], $value);
if (!(empty($value) && $this->isColumnSerial($table_name, $schema_name))) { if (!(empty($value) && $this->isColumnSerial($table_name, $schema_name))) {
$record->$schema_name = $value; $record->$schema_name = $value;
} }
@ -1398,7 +1398,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
if (!empty($attributes['serialize'])) { if (!empty($attributes['serialize'])) {
$value = serialize($value); $value = serialize($value);
} }
$record[$column_name] = drupal_schema_get_field_value($attributes, $value); $record[$column_name] = SqlContentEntityStorageSchema::castValue($attributes, $value);
} }
$query->values($record); $query->values($record);
if ($this->entityType->isRevisionable()) { if ($this->entityType->isRevisionable()) {

View File

@ -2099,7 +2099,7 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
// Use the initial value of the field storage, if available. // Use the initial value of the field storage, if available.
if ($initial_value && isset($initial_value[$field_column_name])) { 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]); $schema['fields'][$schema_field_name]['initial'] = SqlContentEntityStorageSchema::castValue($column_schema, $initial_value[$field_column_name]);
} }
if (!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]; $schema['fields'][$schema_field_name]['initial_from_field'] = $initial_value_from_field[$field_column_name];
@ -2506,4 +2506,40 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
$schema_handler->addUniqueKey($table, $name, $specifier); $schema_handler->addUniqueKey($table, $name, $specifier);
} }
/**
* Typecasts values to proper datatypes.
*
* MySQL PDO silently casts, e.g. FALSE and '' to 0, when inserting the value
* into an integer column, but PostgreSQL PDO does not. Use the schema
* information to correctly typecast the value.
*
* @param array $info
* An array describing the schema field info. See hook_schema() and
* https://www.drupal.org/node/146843 for details.
* @param mixed $value
* The value to be converted.
*
* @return mixed
* The converted value.
*
* @internal
*
* @see hook_schema()
* @see https://www.drupal.org/node/146843
*/
public static function castValue(array $info, $value) {
// Preserve legal NULL values.
if (isset($value) || !empty($info['not null'])) {
if ($info['type'] === 'int' || $info['type'] === 'serial') {
return (int) $value;
}
elseif ($info['type'] === 'float') {
return (float) $value;
}
return (string) $value;
}
return $value;
}
} }

View File

@ -0,0 +1,26 @@
<?php
namespace Drupal\KernelTests\Core\Database;
use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
use Drupal\KernelTests\KernelTestBase;
/**
* Deprecation tests cases for the schema API.
*
* @group legacy
*/
class SchemaLegacyTest extends KernelTestBase {
/**
* Tests deprecation of the drupal_schema_get_field_value() function.
*
* @expectedDeprecation drupal_schema_get_field_value() is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Use \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue($info, $value) instead. See https://www.drupal.org/node/3051983
*/
public function testSchemaGetFieldValue() {
$info = ['type' => 'int'];
$value = 1.1;
$this->assertEquals(SqlContentEntityStorageSchema::castValue($info, $value), drupal_schema_get_field_value($info, $value));
}
}

View File

@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface; use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManager; use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\Sql\DefaultTableMapping; use Drupal\Core\Entity\Sql\DefaultTableMapping;
use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
@ -1562,4 +1563,121 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
); );
} }
/**
* Tests various value casts depending on column schema.
*
* @param mixed $expected
* The expected value.
* @param mixed $value
* The tested value.
* @param array $schema
* The schema for the table column.
*
* @dataProvider providerSchemaCastValue
* @covers ::castValue
*/
public function testCastValue($expected, $value, array $schema) {
$this->assertSame($expected, SqlContentEntityStorageSchema::castValue($schema, $value));
}
/**
* Provides data for testCastValue().
*/
public function providerSchemaCastValue() {
$cases = [];
// Tests NULL values.
$cases[] = [
NULL,
NULL,
[
'not null' => FALSE,
],
];
$cases[] = [
0,
NULL,
[
'not null' => TRUE,
'type' => 'int',
],
];
$cases[] = [
0,
NULL,
[
'not null' => TRUE,
'type' => 'serial',
],
];
$cases[] = [
0.0,
NULL,
[
'not null' => TRUE,
'type' => 'float',
],
];
$cases[] = [
'',
NULL,
[
'not null' => TRUE,
'type' => 'varchar',
],
];
// Tests cast to int and serial.
$cases[] = [
1,
'1.001',
[
'type' => 'int',
],
];
$cases[] = [
2,
2.6,
[
'type' => 'int',
],
];
$cases[] = [
3,
'3.6',
[
'type' => 'serial',
],
];
// Tests float.
$cases[] = [
1.001,
'1.001',
[
'type' => 'float',
],
];
$cases[] = [
2.6,
2.6,
[
'type' => 'float',
],
];
// Tests other column types casts to string.
$cases[] = [
'1',
1,
[
'type' => 'varchar',
],
];
$cases[] = [
'2',
'2',
[
'type' => 'varchar',
],
];
return $cases;
}
} }