View source
<?php
namespace Drupal\Tests\json_field\Kernel;
use Drupal\Core\Database\Connection;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\Core\Validation\Plugin\Validation\Constraint\LengthConstraint;
use Drupal\json_field\Plugin\Field\FieldType\JSONItem;
class JsonItemTest extends KernelTestBase {
public function testFieldCreate() {
$this
->createTestField();
$entity = EntityTest::create([
'test_json_field' => json_encode([]),
]);
$entity
->save();
$this
->assertEquals(json_encode([]), $entity->test_json_field->value);
}
public function testFieldCreateWithDefaultValue() {
$field_settings = [
'default_value' => [
0 => [
'value' => json_encode([
'hey' => 'joe',
]),
],
],
];
$this
->createTestField([], $field_settings);
$entity = EntityTest::create([]);
$entity
->save();
$this
->assertEquals(json_encode([
'hey' => 'joe',
]), $entity->test_json_field->value);
}
public function testValidation() {
$this
->createTestField();
$entity = EntityTest::create([
'test_json_field' => "this-is-not-valid-json';2';12'3;12'3;",
]);
$entity
->save();
$constraint_list = $entity
->validate()
->getByField('test_json_field');
$this
->assertEquals(1, $constraint_list
->count());
$this
->assertEquals('The supplied text is not valid JSON data (@error).', $constraint_list
->get(0)
->getMessage()
->getUntranslatedString());
}
public function testCharacterLimit($size, $limit) {
$storage = [
'settings' => [
'size' => $size,
],
];
$this
->createTestField($storage);
$entity = EntityTest::create([
'test_json_field' => '"' . str_repeat('x', $limit - 1) . '"',
]);
$constraint_list = $entity
->validate()
->getByField('test_json_field');
$this
->assertEquals(1, $constraint_list
->count());
$violation = $constraint_list
->get(0);
$this
->assertTrue($violation
->getConstraint() instanceof LengthConstraint);
}
public function providerTestCharacterLimit() {
return [
[
JSONItem::SIZE_SMALL,
JSONItem::SIZE_SMALL,
],
[
JSONItem::SIZE_NORMAL,
JSONItem::SIZE_NORMAL / 4,
],
[
JSONItem::SIZE_MEDIUM,
JSONItem::SIZE_MEDIUM / 4,
],
];
}
public function testSchemaSize($size, array $expected) {
$storage = [
'settings' => [
'size' => $size,
],
];
$this
->createTestField($storage);
$schema = $this
->getTableSchema(\Drupal::database(), 'entity_test__test_json_field');
$this
->assertEquals($expected, $schema['fields']['test_json_field_value']);
}
public function providerTestSchemaSize() {
$data = [];
$data[] = [
JSONItem::SIZE_SMALL,
[
'type' => 'varchar',
'not null' => 1,
'length' => 255,
],
];
$data[] = [
JSONItem::SIZE_NORMAL,
[
'type' => 'text',
'not null' => 1,
'size' => 'normal',
],
];
$data[] = [
JSONItem::SIZE_MEDIUM,
[
'type' => 'text',
'not null' => 1,
'size' => 'medium',
],
];
$data[] = [
JSONItem::SIZE_BIG,
[
'type' => 'text',
'not null' => 1,
'size' => 'big',
],
];
return $data;
}
protected function getTableSchema(Connection $connection, $table) {
if ($connection
->databaseType() !== 'mysql') {
throw new \RuntimeException('This script can only be used with MySQL database backends.');
}
$query = $connection
->query("SHOW FULL COLUMNS FROM {" . $table . "}");
$definition = [];
while (($row = $query
->fetchAssoc()) !== FALSE) {
$name = $row['Field'];
preg_match('@([a-z]+)(?:\\((\\d+)(?:,(\\d+))?\\))?\\s*(unsigned)?@', $row['Type'], $matches);
$type = $this
->fieldTypeMap($connection, $matches[1]);
if ($row['Extra'] === 'auto_increment') {
$type = 'serial';
}
$definition['fields'][$name] = [
'type' => $type,
'not null' => $row['Null'] === 'NO',
];
if ($size = $this
->fieldSizeMap($connection, $matches[1])) {
$definition['fields'][$name]['size'] = $size;
}
if (isset($matches[2]) && $type === 'numeric') {
$definition['fields'][$name]['precision'] = $matches[2];
$definition['fields'][$name]['scale'] = $matches[3];
}
elseif ($type === 'time' || $type === 'datetime') {
$definition['fields'][$name]['type'] = 'varchar';
$definition['fields'][$name]['length'] = '100';
}
elseif (!isset($definition['fields'][$name]['size'])) {
$definition['fields'][$name]['length'] = isset($matches[2]) ? $matches[2] : 100;
}
if (isset($row['Default'])) {
$definition['fields'][$name]['default'] = $row['Default'];
}
if (isset($matches[4])) {
$definition['fields'][$name]['unsigned'] = TRUE;
}
if (isset($row['Collation']) && $row['Collation'] == 'ascii_bin') {
$definition['fields'][$name]['type'] = 'varchar_ascii';
$definition['fields'][$name]['binary'] = TRUE;
}
if (isset($row['Collation']) && $row['Collation'] == 'ascii_general_ci') {
$definition['fields'][$name]['type'] = 'varchar_ascii';
}
if (isset($row['Collation']) && $row['Collation'] == 'utf8_bin') {
$definition['fields'][$name]['binary'] = TRUE;
}
}
$this
->getTableIndexes($connection, $table, $definition);
$this
->getTableCollation($connection, $table, $definition);
return $definition;
}
protected function getTableIndexes(Connection $connection, $table, &$definition) {
$query = $connection
->query("SHOW INDEX FROM {" . $table . "}");
while (($row = $query
->fetchAssoc()) !== FALSE) {
$index_name = $row['Key_name'];
$column = $row['Column_name'];
$order = $row['Seq_in_index'] - 1;
if ($row['Sub_part']) {
$column = [
$column,
$row['Sub_part'],
];
}
if ($index_name === 'PRIMARY') {
$definition['primary key'][$order] = $column;
}
elseif ($row['Non_unique'] == 0) {
$definition['unique keys'][$index_name][$order] = $column;
}
else {
$definition['indexes'][$index_name][$order] = $column;
}
}
}
protected function getTableCollation(Connection $connection, $table, &$definition) {
$query = $connection
->query("SHOW TABLE STATUS LIKE '{" . $table . "}'");
$data = $query
->fetchAssoc();
if (isset($data['Collation'])) {
$definition['mysql_character_set'] = str_replace('_general_ci', '', $data['Collation']);
}
}
protected function getTableData(Connection $connection, $table) {
$order = $this
->getFieldOrder($connection, $table);
$query = $connection
->query("SELECT * FROM {" . $table . "} " . $order);
$results = [];
while (($row = $query
->fetchAssoc()) !== FALSE) {
$results[] = $row;
}
return $results;
}
protected function fieldTypeMap(Connection $connection, $type) {
$map = array_map('strtolower', $connection
->schema()
->getFieldTypeMap());
$map = array_flip($map);
return isset($map[$type]) ? explode(':', $map[$type])[0] : $type;
}
protected function fieldSizeMap(Connection $connection, $type) {
$map = array_map('strtolower', $connection
->schema()
->getFieldTypeMap());
$map = array_flip($map);
$schema_type = explode(':', $map[$type])[0];
if (in_array($schema_type, [
'blob',
'float',
'int',
'text',
])) {
return explode(':', $map[$type])[1];
}
}
protected function getFieldOrder(Connection $connection, $table) {
$connection_info = $connection
->getConnectionOptions();
$order = '';
$query = "SELECT `COLUMN_NAME`\n FROM `information_schema`.`COLUMNS`\n WHERE (`TABLE_SCHEMA` = '" . $connection_info['database'] . "')\n AND (`TABLE_NAME` = '{" . $table . "}')\n AND (`COLUMN_KEY` = 'PRI')\n ORDER BY COLUMN_NAME";
$results = $connection
->query($query);
while (($row = $results
->fetchAssoc()) !== FALSE) {
$order .= $row['COLUMN_NAME'] . ', ';
}
if (!empty($order)) {
$order = ' ORDER BY ' . rtrim($order, ', ');
}
return $order;
}
}