Skip to content

Commit

Permalink
Merge bd8b3f2 into 53a0579
Browse files Browse the repository at this point in the history
  • Loading branch information
lonnieezell committed Oct 14, 2018
2 parents 53a0579 + bd8b3f2 commit 5c99d68
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 36 deletions.
40 changes: 36 additions & 4 deletions system/Entity.php
Expand Up @@ -64,13 +64,36 @@ class Entity
'casts' => []
];

/**
* Holds original copies of all class vars so
* we can determine what's actually been changed
* and not accidentally write nulls where we shouldn't.
*
* @var array
*/
protected $_original = [];

/**
* Allows filling in Entity parameters during construction.
*
* @param array|null $data
*/
public function __construct(array $data = null)
{
// Collect any original values of things
// so we can compare later to see what's changed
$properties = get_object_vars($this);

foreach ($properties as $key => $value)
{
if (substr($key, 0, 1) == '_')
{
unset($properties[$key]);
}
}

$this->_original = $properties;

if (is_array($data))
{
$this->fill($data);
Expand Down Expand Up @@ -108,8 +131,12 @@ public function fill(array $data)
* values of this entity as an array. All values are accessed
* through the __get() magic method so will have any casts, etc
* applied to them.
*
* @param bool $onlyChanged If true, only return values that have changed since object creation
*
* @return array
*/
public function toArray(): array
public function toArray(bool $onlyChanged = false): array
{
$return = [];

Expand All @@ -119,7 +146,12 @@ public function toArray(): array

foreach ($properties as $key => $value)
{
if ($key == '_options') continue;
if (substr($key, 0, 1) == '_') continue;

if ($onlyChanged && $this->_original[$key] === null && $value === null)
{
continue;
}

$return[$key] = $this->__get($key);
}
Expand Down Expand Up @@ -368,7 +400,7 @@ protected function mutateDate($value)
*
* @return mixed
*/

protected function castAs($value, string $type)
{
switch($type)
Expand Down Expand Up @@ -422,7 +454,7 @@ protected function castAs($value, string $type)
* Cast as JSON
*
* @param mixed $value
* @param bool $asArray
* @param bool $asArray
*
* @return mixed
*/
Expand Down
79 changes: 48 additions & 31 deletions system/Model.php
Expand Up @@ -479,45 +479,59 @@ public function save($data)
* properties as an array suitable for use in creates and updates.
*
* @param string|object $data
* @param string $dateFormat
* @param string $dateFormat
*
* @return array
* @throws \ReflectionException
*/
public static function classToArray($data, string $dateFormat = 'datetime'): array
{
$mirror = new \ReflectionClass($data);
$props = $mirror->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED);

$properties = [];

// Loop over each property,
// saving the name/value in a new array we can return.
foreach ($props as $prop)
if (method_exists($data, 'toArray'))
{
$properties = $data->toArray(true);
}
else
{
// Must make protected values accessible.
$prop->setAccessible(true);
$propName = $prop->getName();
$properties[$propName] = $prop->getValue($data);
$mirror = new \ReflectionClass($data);
$props = $mirror->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED);

$properties = [];

// Convert any Time instances to appropriate $dateFormat
if ($properties[$propName] instanceof Time)
// Loop over each property,
// saving the name/value in a new array we can return.
foreach ($props as $prop)
{
$converted = (string)$properties[$propName];
// Must make protected values accessible.
$prop->setAccessible(true);
$propName = $prop->getName();
$properties[$propName] = $prop->getValue($data);
}
}

switch($dateFormat)
// Convert any Time instances to appropriate $dateFormat
if (count($properties))
{
foreach ($properties as $key => $value)
{
if ($value instanceof Time)
{
case 'datetime':
$converted = $properties[$propName]->format('Y-m-d H:i:s');
break;
case 'date':
$converted = $properties[$propName]->format('Y-m-d');
break;
case 'int':
$converted = $properties[$propName]->getTimestamp();
break;
}
switch ($dateFormat)
{
case 'datetime':
$converted = $value->format('Y-m-d H:i:s');
break;
case 'date':
$converted = $value->format('Y-m-d');
break;
case 'int':
$converted = $value->getTimestamp();
break;
default:
$converted = (string)$value;
}

$properties[$prop->getName()] = $converted;
$properties[$key] = $converted;
}
}
}

Expand Down Expand Up @@ -1077,11 +1091,14 @@ protected function doProtectFields($data)
throw DataException::forInvalidAllowedFields(get_class($this));
}

foreach ($data as $key => $val)
if (is_array($data) && count($data))
{
if ( ! in_array($key, $this->allowedFields))
foreach ($data as $key => $val)
{
unset($data[$key]);
if (! in_array($key, $this->allowedFields))
{
unset($data[$key]);
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions tests/_support/Models/SimpleEntity.php
Expand Up @@ -17,4 +17,9 @@ class SimpleEntity extends Entity
protected $description;
protected $created_at;

protected $_options = [
'datamap' => [],
'dates' => ['created_at', 'updated_at', 'deleted_at'],
'casts' => []
];
}
24 changes: 24 additions & 0 deletions tests/system/Database/Live/ModelTest.php
Expand Up @@ -712,4 +712,28 @@ public function testUpdateBatchValidationFail()
}

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

public function testSelectAndEntitiesSaveOnlyChangedValues()
{
$this->hasInDatabase('job', [
'name' => 'Rocket Scientist',
'description' => 'Plays guitar for Queen',
'created_at' => date('Y-m-d H:i:s')
]);

$model = new EntityModel();

$job = $model->select('id, name')->where('name', 'Rocket Scientist')->first();

$this->assertNull($job->description);
$this->assertEquals('Rocket Scientist', $job->name);

$model->save($job);

$this->seeInDatabase('job', [
'id' => $job->id,
'name' => 'Rocket Scientist',
'description' => 'Plays guitar for Queen',
]);
}
}
2 changes: 1 addition & 1 deletion tests/system/View/ParserTest.php
Expand Up @@ -213,7 +213,7 @@ public function testParseLoopEntityProperties()
$power = new class extends \CodeIgniter\Entity {
public $foo = 'bar';
protected $bar = 'baz';
public function toArray(): array
public function toArray(bool $onlyChanged = false): array
{
return [
'foo' => $this->foo,
Expand Down

0 comments on commit 5c99d68

Please sign in to comment.