Skip to content

Commit ccd9267

Browse files
authored
Merge pull request #1283 from bcit-ci/entities
Entities
2 parents 979b606 + b840d0a commit ccd9267

4 files changed

Lines changed: 123 additions & 5 deletions

File tree

system/Entity.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,14 @@ public function __set(string $key, $value = null)
221221
$value = serialize($value);
222222
}
223223

224+
// JSON casting requires that we JSONize the value
225+
// when setting it so that it can easily be stored
226+
// back to the database.
227+
if (function_exists('json_encode') && array_key_exists($key, $this->_options['casts']) && ($this->_options['casts'][$key] === 'json' || $this->_options['casts'][$key] === 'json-array'))
228+
{
229+
$value = json_encode($value);
230+
}
231+
224232
// if a set* method exists for this key,

225233
// use that method to insert this value.

226234
$method = 'set' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $key)));
@@ -360,6 +368,7 @@ protected function mutateDate($value)
360368
*
361369
* @return mixed
362370
*/
371+
363372
protected function castAs($value, string $type)
364373
{
365374
switch($type)
@@ -390,6 +399,12 @@ protected function castAs($value, string $type)
390399

391400
$value = (array)$value;
392401
break;
402+
case 'json':
403+
$value = $this->castAsJson($value, false);
404+
break;
405+
case 'json-array':
406+
$value = $this->castAsJson($value, true);
407+
break;
393408
case 'datetime':
394409
return new \DateTime($value);
395410
break;
@@ -400,4 +415,32 @@ protected function castAs($value, string $type)
400415

401416
return $value;
402417
}
418+
419+
//--------------------------------------------------------------------
420+
421+
/**
422+
* Cast as JSON
423+
*
424+
* @param mixed $value
425+
* @param bool $asArray
426+
*
427+
* @return mixed
428+
*/
429+
private function castAsJson($value, bool $asArray = false)
430+
{
431+
$tmp = !is_null($value) ? ($asArray ? [] : new \stdClass) : null;
432+
if(function_exists('json_decode'))
433+
{
434+
if((is_string($value) && (strpos($value, '[') === 0 || strpos($value, '{') === 0 || (strpos($value, '"') === 0 && strrpos($value, '"') === 0 ))) || is_numeric($value))
435+
{
436+
$tmp = json_decode($value, $asArray);
437+
438+
if(json_last_error() !== JSON_ERROR_NONE)
439+
{
440+
throw CastException::forInvalidJsonFormatException(json_last_error());
441+
}
442+
}
443+
}
444+
return $tmp;
445+
}
403446
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php namespace CodeIgniter\Exceptions;
2+
3+
/**
4+
* Cast Exceptions.
5+
*/
6+
class CastException extends CriticalError
7+
{
8+
9+
/**
10+
* Error code
11+
* @var int
12+
*/
13+
protected $code = 3;
14+
15+
public static function forInvalidJsonFormatException(int $error)
16+
{
17+
switch($error)
18+
{
19+
case JSON_ERROR_DEPTH:
20+
throw new static(lang('Cast.jsonErrorDepth'));
21+
break;
22+
case JSON_ERROR_STATE_MISMATCH:
23+
throw new static(lang('Cast.jsonErrorStateMismatch'));
24+
break;
25+
case JSON_ERROR_CTRL_CHAR:
26+
throw new static(lang('Cast.jsonErrorCtrlChar'));
27+
break;
28+
case JSON_ERROR_SYNTAX:
29+
throw new static(lang('Cast.jsonErrorSyntax'));
30+
break;
31+
case JSON_ERROR_UTF8:
32+
throw new static(lang('Cast.jsonErrorUtf8'));
33+
break;
34+
default:
35+
throw new static(lang('Cast.jsonErrorUnknown'));
36+
}
37+
38+
}
39+
40+
}

system/Language/en/Cast.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
/**
3+
* Cast language strings.
4+
*
5+
* @package CodeIgniter
6+
* @author CodeIgniter Dev Team
7+
* @copyright 2014-2018 British Columbia Institute of Technology (https://bcit.ca/)
8+
* @license https://opensource.org/licenses/MIT MIT License
9+
* @link https://codeigniter.com
10+
* @since Version 3.0.0
11+
* @filesource
12+
*
13+
* @codeCoverageIgnore
14+
*/
15+
16+
return [
17+
'jsonErrorDepth' => 'Maximum stack depth exceeded',
18+
'jsonErrorStateMismatch' => 'Underflow or the modes mismatch',
19+
'jsonErrorCtrlChar' => 'Unexpected control character found',
20+
'jsonErrorSyntax' => 'Syntax error, malformed JSON',
21+
'jsonErrorUtf8' => 'Malformed UTF-8 characters, possibly incorrectly encoded',
22+
'jsonErrorUnknown' => 'Unknown error'
23+
];

user_guide_src/source/models/entities.rst

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,22 @@ For example, if you had a User entity with an **is_banned** property, you can ca
338338
];
339339
}
340340

341-
Array Casting
341+
Array/Json Casting
342342
-------------
343343

344-
Array casting is especially useful with fields that store serialized arrays or json in them. When cast as an array,
345-
they will automatically be unserialized when you read the property's value. Unlike the rest of the data types that
346-
you can cast properties into, the **array** cast type will serialize the value whenever the property is set::
344+
Array/Json casting is especially useful with fields that store serialized arrays or json in them. When cast as:
345+
346+
* an **array**, they will automatically be unserialized,
347+
* a **json**, they will automatically be set as an value of json_decode($value, false),
348+
* a **json-array**, they will automatically be set as an value of json_decode($value, true),
349+
350+
when you read the property's value.
351+
Unlike the rest of the data types that you can cast properties into, the:
352+
353+
* **array** cast type will serialize,
354+
* **json** and **json-array** cast will use json_encode function on
355+
356+
the value whenever the property is set::
347357

348358
<?php namespace App\Entities;
349359

@@ -355,7 +365,9 @@ you can cast properties into, the **array** cast type will serialize the value w
355365

356366
protected $_options = [
357367
'casts' => [
358-
'options' => 'array'
368+
'options' => 'array',
369+
'options_object' => 'json',
370+
'options_array' => 'json-array'
359371
],
360372
'dates' => ['created_at', 'updated_at', 'deleted_at'],
361373
'datamap' => []

0 commit comments

Comments
 (0)