Skip to content

Commit

Permalink
Merge pull request #1283 from bcit-ci/entities
Browse files Browse the repository at this point in the history
Entities
  • Loading branch information
lonnieezell authored Oct 3, 2018
2 parents 979b606 + b840d0a commit ccd9267
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 5 deletions.
43 changes: 43 additions & 0 deletions system/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ public function __set(string $key, $value = null)
$value = serialize($value);
}

// JSON casting requires that we JSONize the value
// when setting it so that it can easily be stored
// back to the database.
if (function_exists('json_encode') && array_key_exists($key, $this->_options['casts']) && ($this->_options['casts'][$key] === 'json' || $this->_options['casts'][$key] === 'json-array'))
{
$value = json_encode($value);
}

// if a set* method exists for this key,

// use that method to insert this value.

$method = 'set' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $key)));
Expand Down Expand Up @@ -360,6 +368,7 @@ protected function mutateDate($value)
*
* @return mixed
*/

protected function castAs($value, string $type)
{
switch($type)
Expand Down Expand Up @@ -390,6 +399,12 @@ protected function castAs($value, string $type)

$value = (array)$value;
break;
case 'json':
$value = $this->castAsJson($value, false);
break;
case 'json-array':
$value = $this->castAsJson($value, true);
break;
case 'datetime':
return new \DateTime($value);
break;
Expand All @@ -400,4 +415,32 @@ protected function castAs($value, string $type)

return $value;
}

//--------------------------------------------------------------------

/**
* Cast as JSON
*
* @param mixed $value
* @param bool $asArray
*
* @return mixed
*/
private function castAsJson($value, bool $asArray = false)
{
$tmp = !is_null($value) ? ($asArray ? [] : new \stdClass) : null;
if(function_exists('json_decode'))
{
if((is_string($value) && (strpos($value, '[') === 0 || strpos($value, '{') === 0 || (strpos($value, '"') === 0 && strrpos($value, '"') === 0 ))) || is_numeric($value))
{
$tmp = json_decode($value, $asArray);

if(json_last_error() !== JSON_ERROR_NONE)
{
throw CastException::forInvalidJsonFormatException(json_last_error());
}
}
}
return $tmp;
}
}
40 changes: 40 additions & 0 deletions system/Exceptions/CastException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php namespace CodeIgniter\Exceptions;

/**
* Cast Exceptions.
*/
class CastException extends CriticalError
{

/**
* Error code
* @var int
*/
protected $code = 3;

public static function forInvalidJsonFormatException(int $error)
{
switch($error)
{
case JSON_ERROR_DEPTH:
throw new static(lang('Cast.jsonErrorDepth'));
break;
case JSON_ERROR_STATE_MISMATCH:
throw new static(lang('Cast.jsonErrorStateMismatch'));
break;
case JSON_ERROR_CTRL_CHAR:
throw new static(lang('Cast.jsonErrorCtrlChar'));
break;
case JSON_ERROR_SYNTAX:
throw new static(lang('Cast.jsonErrorSyntax'));
break;
case JSON_ERROR_UTF8:
throw new static(lang('Cast.jsonErrorUtf8'));
break;
default:
throw new static(lang('Cast.jsonErrorUnknown'));
}

}

}
23 changes: 23 additions & 0 deletions system/Language/en/Cast.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
/**
* Cast language strings.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2014-2018 British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*
* @codeCoverageIgnore
*/

return [
'jsonErrorDepth' => 'Maximum stack depth exceeded',
'jsonErrorStateMismatch' => 'Underflow or the modes mismatch',
'jsonErrorCtrlChar' => 'Unexpected control character found',
'jsonErrorSyntax' => 'Syntax error, malformed JSON',
'jsonErrorUtf8' => 'Malformed UTF-8 characters, possibly incorrectly encoded',
'jsonErrorUnknown' => 'Unknown error'
];
22 changes: 17 additions & 5 deletions user_guide_src/source/models/entities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -338,12 +338,22 @@ For example, if you had a User entity with an **is_banned** property, you can ca
];
}

Array Casting
Array/Json Casting
-------------

Array casting is especially useful with fields that store serialized arrays or json in them. When cast as an array,
they will automatically be unserialized when you read the property's value. Unlike the rest of the data types that
you can cast properties into, the **array** cast type will serialize the value whenever the property is set::
Array/Json casting is especially useful with fields that store serialized arrays or json in them. When cast as:

* an **array**, they will automatically be unserialized,
* a **json**, they will automatically be set as an value of json_decode($value, false),
* a **json-array**, they will automatically be set as an value of json_decode($value, true),

when you read the property's value.
Unlike the rest of the data types that you can cast properties into, the:

* **array** cast type will serialize,
* **json** and **json-array** cast will use json_encode function on

the value whenever the property is set::

<?php namespace App\Entities;

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

protected $_options = [
'casts' => [
'options' => 'array'
'options' => 'array',
'options_object' => 'json',
'options_array' => 'json-array'
],
'dates' => ['created_at', 'updated_at', 'deleted_at'],
'datamap' => []
Expand Down

0 comments on commit ccd9267

Please sign in to comment.