Skip to content

Commit efb07e1

Browse files
authored
Adding basic JSON column type support (#168)
* Adding "json" type * testing disabling emulated prepares * more work on json field * expanding json field return types some * Changing json value on set to be consistent * fixing phpstan errors, reverting some test changes * improving error detection around json_encode/decode
1 parent 6214da4 commit efb07e1

File tree

13 files changed

+128
-41
lines changed

13 files changed

+128
-41
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"php-cs-fixer.executablePath": "${workspaceFolder}/vendor/bin/php-cs-fixer"
3+
}

lib/Doctrine/Data/Import.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,16 @@ protected function _processRow($rowKey, $row)
230230
$func = 'set' . Doctrine_Inflector::classify($key);
231231
$obj->$func($value);
232232
} elseif ($obj->getTable()->hasField($key)) {
233-
if ($obj->getTable()->getTypeOf($key) == 'object') {
233+
$type = $obj->getTable()->getTypeOf($key);
234+
if ($type == 'object') {
234235
$value = unserialize($value);
236+
} elseif ($type == 'json') {
237+
$value = json_decode($value);
238+
if ($value === null && json_last_error() !== JSON_ERROR_NONE) {
239+
throw new Doctrine_Record_Exception(
240+
'Error encountered decoding Json: ' . json_last_error_msg()
241+
);
242+
}
235243
}
236244
$obj->set($key, $value);
237245
} elseif ($obj->getTable()->hasRelation($key)) {

lib/Doctrine/DataDict/Mssql.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public function getNativeDeclaration($field)
6767
// no break
6868
case 'array':
6969
case 'object':
70+
case 'json':
7071
case 'text':
7172
case 'char':
7273
case 'varchar':

lib/Doctrine/DataDict/Mysql.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ public function getNativeDeclaration($field)
197197
}
198198
}
199199
return 'LONGTEXT';
200+
case 'json':
201+
return 'JSON';
200202
case 'blob':
201203
if (! empty($field['length'])) {
202204
$length = $field['length'];

lib/Doctrine/DataDict/Oracle.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public function getNativeDeclaration(array $field)
6464
case 'string':
6565
case 'array':
6666
case 'object':
67+
case 'json':
6768
case 'gzip':
6869
case 'char':
6970
case 'varchar':

lib/Doctrine/DataDict/Pgsql.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ public function getNativeDeclaration(array $field)
386386
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->conn->varchar_max_length . ')')
387387
: ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
388388

389+
case 'json':
390+
return 'JSONB';
389391
case 'clob':
390392
return 'TEXT';
391393
case 'blob':

lib/Doctrine/DataDict/Sqlite.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public function getNativeDeclaration(array $field)
6565
// no break
6666
case 'text':
6767
case 'object':
68+
case 'json':
6869
case 'array':
6970
case 'string':
7071
case 'char':

lib/Doctrine/Formatter.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ public function quote($input, $type = null)
181181
case 'decimal':
182182
case 'int':
183183
return $input;
184+
case 'json':
185+
$input = json_encode($input);
186+
if ($input === false) {
187+
throw new Doctrine_Exception('Error encountered encoding $input: ' . json_last_error_msg());
188+
}
189+
return $input;
184190
case 'array':
185191
case 'object':
186192
$input = serialize($input);

lib/Doctrine/Import/Builder.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,9 @@ public function buildPhpDocs(array $definition)
705705
case 'gzip':
706706
$type = 'string';
707707
break;
708+
case 'json':
709+
$type = 'stdClass|array|null|string|bool|int|float';
710+
break;
708711
}
709712

710713
// Add "null" union types for columns that aren't marked as notnull = true

lib/Doctrine/Record.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,15 @@ public function __serialize(): array
893893
unset($vars['_data'][$k]);
894894
} else {
895895
switch ($this->_table->getTypeOf($k)) {
896+
case 'json':
897+
$value = json_encode($vars['_data'][$k]);
898+
if ($value === false) {
899+
throw new Doctrine_Record_Exception(
900+
'Error encountered encoding value: ' . json_last_error_msg()
901+
);
902+
}
903+
$vars['_data'][$k] = $value;
904+
break;
896905
case 'gzip':
897906
$vars['_data'][$k] = gzcompress($vars['_data'][$k]);
898907
break;
@@ -941,6 +950,15 @@ public function __unserialize(array $array): void
941950
case 'gzip':
942951
$this->_data[$k] = gzuncompress($this->_data[$k]);
943952
break;
953+
case 'json':
954+
$value = json_decode($this->_data[$k]);
955+
if ($value === null && json_last_error() !== JSON_ERROR_NONE) {
956+
throw new Doctrine_Record_Exception(
957+
'Error encountered decoding Json: ' . json_last_error_msg()
958+
);
959+
}
960+
$this->_data[$k] = $value;
961+
break;
944962
case 'enum':
945963
$this->_data[$k] = $this->_table->enumValue($k, $this->_data[$k]);
946964
break;
@@ -1559,6 +1577,23 @@ protected function _set($fieldName, $value, $load = true)
15591577
$this->_values[$fieldName] = $value;
15601578
} elseif (array_key_exists($fieldName, $this->_data)) {
15611579
$type = $this->_table->getTypeOf($fieldName);
1580+
if ($type === 'json') {
1581+
// Doing this so that the stored value on the model, and the value retrieved from the database
1582+
// will match types (mainly so associative arrays are converted to stdClass objects)
1583+
$value = json_encode($value);
1584+
if ($value === false) {
1585+
throw new Doctrine_Record_Exception(
1586+
'Error encountered when encoding $value: ' . json_last_error_msg()
1587+
);
1588+
}
1589+
$value = json_decode($value);
1590+
if ($value === null && json_last_error() !== JSON_ERROR_NONE) {
1591+
throw new Doctrine_Record_Exception(
1592+
'Error encountered decoding Json: ' . json_last_error_msg()
1593+
);
1594+
}
1595+
}
1596+
15621597
if ($value instanceof Doctrine_Record) {
15631598
$id = $value->getIncremented();
15641599

@@ -1938,6 +1973,15 @@ public function getPrepared(array $array = array())
19381973
case 'object':
19391974
$a[$field] = serialize($this->_data[$field]);
19401975
break;
1976+
case 'json':
1977+
$value = json_encode($this->_data[$field]);
1978+
if ($value === false) {
1979+
throw new Doctrine_Record_Exception(
1980+
'Error encountered when encoding $value: ' . json_last_error_msg()
1981+
);
1982+
}
1983+
$a[$field] = $value;
1984+
break;
19411985
case 'gzip':
19421986
$a[$field] = gzcompress($this->_data[$field], 5);
19431987
break;

0 commit comments

Comments
 (0)