(The $datamap functionality would also be very useful at the entity level so that it can be used standalone from model.)
EDIT: ugh while playing further I set up the entity in error as:
Code:
use CodeIgniter\Entity;
Instead of:
Code:
use CodeIgniter\Entity\Entity;
hence the brain fart.
I get that model functionality will need to work whether or not an entity is used ie. Model needs to retain functionality to define and transform output.
However where an entity is defined then shouldn't this be where "row" definitions are provided???
When an entity is present then: Model is used for transformation / Entity is used for definition?
Entities being reusable across models.
---ok enough whining to myself... this is how I extended the entity class to have similar functionality to allowedFields in Models...
To utilise this in the Entity setup:
PHP Code:
<?php
namespace App\Entities;
class JSOutput extends EntityExt
{
protected $attributes = [ ... as you will ...]
protected $expectedFields = [ 'Originated', 'Tab', 'Price', 'MapLongitude', 'MapLatitude', 'Zoom',];
protected $datamap = [ ... as you will ...]
}
From a controller output will be constrained to expectedFields:
PHP Code:
$jsinput = new \App\Entities\JSOutput();
$jsinput->fill($currentRequest);
print_r($jsinput->toArray());
Added a class EntityExt as an extension of Entity as follows:
Code:
<?php
namespace App\Entities;
use CodeIgniter\Entity\Entity;
class EntityExt extends Entity
{
/*
* Adds "allowedField" functionality as available in a Model to an Entity
*
* There is already allowedField functionality already in Model
* -this acts to filter output from the model (resulting in interaction with db) to be only of previously allowed fields
*
* This is similar functionality in Entity
* - Uses "expectedField" in the entity to differentiate from "allowedField" functionality in the model
* - extra fields can be added to the entity (eg with the bulk fill) however only previously defined expected fields will be present in array generated output
* - all expectedFields will be present in array generated output - if the entity has not been filled with a corresponding value a NULL will be populated
* - be aware that expectedFields use the name of the field prior to it being involved in a Datamap (if applicable)
// Present in BaseModel
/**
* Whether we should limit fields in inserts
* and updates to those available in $expectedFields or not.
*
* @var boolean
*/
protected $protectFields = true;
// Renamed from setAllowedFields in BaseModel
/**
* It could be used when you have to change default or override current expected fields.
*
* @param array $expectedFields Array with names of fields
*
* @return $this
*/
public function setExpectedFields(array $expectedFields)
{
$this->expectedFields = $expectedFields;
return $this;
}
// This is a modified doProtectFields function from the BaseModel renamed to deExpectedFields
/**
* Ensures that only the fields that are expected to be updated
* are in the data array.
*
* Used by toArray() to protect against mass assignment
* vulnerabilities.
*
* @param array $data Data
*
* @return array
*
*/
protected function doExpectedFields(array $data): array
{
if (! $this->protectFields)
{
return $data;
}
if (!empty($this->expectedFields))
{
foreach ($this->expectedFields as $key)
{
(array_key_exists($key, $data)) ? $return[$key]=$data[$key] : $return[$key]=NULL;
}
return $return;
}
return $data;
}
/*
* The entity toArray function needs a single line added to call the doExpectedField check above
* ie ADD $this->attributes = $this->doExpectedFields($this->attributes);
/**
* General method that will return all public and protected 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 boolean $onlyChanged If true, only return values that have changed since object creation
* @param boolean $cast If true, properties will be casted.
* @param boolean $recursive If true, inner entities will be casted as array as well.
*
* @return array
*/
public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recursive = false): array
{
$this->_cast = $cast;
//ADDED Line BELOW
$this->attributes = $this->doExpectedFields($this->attributes);
//ADDED Line ABOVE
$keys = array_filter(array_keys($this->attributes), function ($key) {
return strpos($key, '_') !== 0;
});
if (is_array($this->datamap))
{
$keys = array_unique(
array_merge(array_diff($keys, $this->datamap), array_keys($this->datamap))
);
}
$return = [];
// Loop over the properties, to allow magic methods to do their thing.
foreach ($keys as $key)
{
if ($onlyChanged && ! $this->hasChanged($key))
{
continue;
}
$return[$key] = $this->__get($key);
if ($recursive)
{
if ($return[$key] instanceof Entity)
{
$return[$key] = $return[$key]->toArray($onlyChanged, $cast, $recursive);
}
elseif (is_callable([$return[$key], 'toArray']))
{
$return[$key] = $return[$key]->toArray();
}
}
}
$this->_cast = true;
return $return;
}
}
Hope that helps someone else.