add trashes
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\DataConverter;
|
||||
|
||||
use Closure;
|
||||
use CodeIgniter\DataCaster\DataCaster;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* PHP data <==> DataSource data converter
|
||||
*
|
||||
* @see \CodeIgniter\DataConverter\DataConverterTest
|
||||
*
|
||||
* @template TEntity of object
|
||||
*/
|
||||
final class DataConverter
|
||||
{
|
||||
/**
|
||||
* The data caster.
|
||||
*/
|
||||
private readonly DataCaster $dataCaster;
|
||||
|
||||
/**
|
||||
* @param array<string, class-string> $castHandlers Custom convert handlers
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(
|
||||
/**
|
||||
* Type definitions.
|
||||
*
|
||||
* @var array<string, string> [column => type]
|
||||
*/
|
||||
private readonly array $types,
|
||||
array $castHandlers = [],
|
||||
/**
|
||||
* Helper object.
|
||||
*/
|
||||
private readonly ?object $helper = null,
|
||||
/**
|
||||
* Static reconstruct method name or closure to reconstruct an object.
|
||||
* Used by reconstruct().
|
||||
*
|
||||
* @phpstan-var (Closure(array<string, mixed>): TEntity)|string|null
|
||||
*/
|
||||
private readonly Closure|string|null $reconstructor = 'reconstruct',
|
||||
/**
|
||||
* Extract method name or closure to extract data from an object.
|
||||
* Used by extract().
|
||||
*
|
||||
* @phpstan-var (Closure(TEntity, bool, bool): array<string, mixed>)|string|null
|
||||
*/
|
||||
private readonly Closure|string|null $extractor = null,
|
||||
) {
|
||||
$this->dataCaster = new DataCaster($castHandlers, $types, $this->helper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts data from DataSource to PHP array with specified type values.
|
||||
*
|
||||
* @param array<string, mixed> $data DataSource data
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function fromDataSource(array $data): array
|
||||
{
|
||||
foreach (array_keys($this->types) as $field) {
|
||||
if (array_key_exists($field, $data)) {
|
||||
$data[$field] = $this->dataCaster->castAs($data[$field], $field, 'get');
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts PHP array to data for DataSource field types.
|
||||
*
|
||||
* @param array<string, mixed> $phpData PHP data
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function toDataSource(array $phpData): array
|
||||
{
|
||||
foreach (array_keys($this->types) as $field) {
|
||||
if (array_key_exists($field, $phpData)) {
|
||||
$phpData[$field] = $this->dataCaster->castAs($phpData[$field], $field, 'set');
|
||||
}
|
||||
}
|
||||
|
||||
return $phpData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes database data array and creates a specified type object.
|
||||
*
|
||||
* @param class-string $classname
|
||||
* @phpstan-param class-string<TEntity> $classname
|
||||
* @param array<string, mixed> $row Raw data from database
|
||||
*
|
||||
* @phpstan-return TEntity
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function reconstruct(string $classname, array $row): object
|
||||
{
|
||||
$phpData = $this->fromDataSource($row);
|
||||
|
||||
// Use static reconstruct method.
|
||||
if (is_string($this->reconstructor) && method_exists($classname, $this->reconstructor)) {
|
||||
$method = $this->reconstructor;
|
||||
|
||||
return $classname::$method($phpData);
|
||||
}
|
||||
|
||||
// Use closure to reconstruct.
|
||||
if ($this->reconstructor instanceof Closure) {
|
||||
$closure = $this->reconstructor;
|
||||
|
||||
return $closure($phpData);
|
||||
}
|
||||
|
||||
$classObj = new $classname();
|
||||
|
||||
if ($classObj instanceof Entity) {
|
||||
$classObj->injectRawData($phpData);
|
||||
$classObj->syncOriginal();
|
||||
|
||||
return $classObj;
|
||||
}
|
||||
|
||||
$classSet = Closure::bind(function ($key, $value): void {
|
||||
$this->{$key} = $value;
|
||||
}, $classObj, $classname);
|
||||
|
||||
foreach ($phpData as $key => $value) {
|
||||
$classSet($key, $value);
|
||||
}
|
||||
|
||||
return $classObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an object and extract properties as an array.
|
||||
*
|
||||
* @param bool $onlyChanged Only for CodeIgniter's Entity. If true, only returns
|
||||
* values that have changed since object creation.
|
||||
* @param bool $recursive Only for CodeIgniter's Entity. If true, inner
|
||||
* entities will be cast as array as well.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function extract(object $object, bool $onlyChanged = false, bool $recursive = false): array
|
||||
{
|
||||
// Use extractor method.
|
||||
if (is_string($this->extractor) && method_exists($object, $this->extractor)) {
|
||||
$method = $this->extractor;
|
||||
$row = $object->{$method}($onlyChanged, $recursive);
|
||||
|
||||
return $this->toDataSource($row);
|
||||
}
|
||||
|
||||
// Use closure to extract.
|
||||
if ($this->extractor instanceof Closure) {
|
||||
$closure = $this->extractor;
|
||||
$row = $closure($object, $onlyChanged, $recursive);
|
||||
|
||||
return $this->toDataSource($row);
|
||||
}
|
||||
|
||||
if ($object instanceof Entity) {
|
||||
$row = $object->toRawArray($onlyChanged, $recursive);
|
||||
|
||||
return $this->toDataSource($row);
|
||||
}
|
||||
|
||||
$array = (array) $object;
|
||||
|
||||
$row = [];
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
$key = preg_replace('/\000.*\000/', '', $key);
|
||||
|
||||
$row[$key] = $value;
|
||||
}
|
||||
|
||||
return $this->toDataSource($row);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user