This commit is contained in:
Dennis Eichhorn 2021-11-29 20:04:41 +01:00
parent e740bfbe3e
commit be1cdcf1ec
7 changed files with 322 additions and 322 deletions

View File

@ -35,78 +35,78 @@ abstract class DataMapperAbstract
protected array $with = []; protected array $with = [];
protected array $sort = []; protected array $sort = [];
protected array $limit = []; protected array $limit = [];
protected array $where = []; protected array $where = [];
/** /**
* Database connection. * Database connection.
* *
* @var ConnectionAbstract * @var ConnectionAbstract
* @since 1.0.0 * @since 1.0.0
*/ */
protected ConnectionAbstract $db; protected ConnectionAbstract $db;
public function __construct(DataMapperFactory $mapper, ConnectionAbstract $db) public function __construct(DataMapperFactory $mapper, ConnectionAbstract $db)
{ {
$this->mapper = $mapper; $this->mapper = $mapper;
$this->db = $db; $this->db = $db;
} }
// Only for relations, no impact on anything else // Only for relations, no impact on anything else
public function with(string $member) : self public function with(string $member) : self
{ {
$split = \explode('/', $member); $split = \explode('/', $member);
$memberSplit = \array_shift($split); $memberSplit = \array_shift($split);
$this->with[$memberSplit ?? ''][] = [ $this->with[$memberSplit ?? ''][] = [
'child' => \implode('/', $split), 'child' => \implode('/', $split),
]; ];
return $this; return $this;
} }
public function sort(string $member, string $order = OrderType::DESC) : self public function sort(string $member, string $order = OrderType::DESC) : self
{ {
$split = \explode('/', $member); $split = \explode('/', $member);
$memberSplit = \array_shift($split); $memberSplit = \array_shift($split);
$this->sort[$memberSplit ?? ''][] = [ $this->sort[$memberSplit ?? ''][] = [
'child' => \implode('/', $split), 'child' => \implode('/', $split),
'order' => $order, 'order' => $order,
]; ];
return $this; return $this;
} }
public function limit(int $limit = 0, string $member = '') : self public function limit(int $limit = 0, string $member = '') : self
{ {
$split = \explode('/', $member); $split = \explode('/', $member);
$memberSplit = \array_shift($split); $memberSplit = \array_shift($split);
$this->limit[$memberSplit ?? ''][] = [ $this->limit[$memberSplit ?? ''][] = [
'child' => \implode('/', $split), 'child' => \implode('/', $split),
'limit' => $limit, 'limit' => $limit,
]; ];
return $this; return $this;
} }
public function where(string $member, mixed $value, string $logic = '=', string $comparison = 'AND') : self public function where(string $member, mixed $value, string $logic = '=', string $comparison = 'AND') : self
{ {
$split = \explode('/', $member); $split = \explode('/', $member);
$memberSplit = \array_shift($split); $memberSplit = \array_shift($split);
$this->where[$memberSplit ?? ''][] = [ $this->where[$memberSplit ?? ''][] = [
'child' => \implode('/', $split), 'child' => \implode('/', $split),
'value' => $value, 'value' => $value,
'logic' => $logic, 'logic' => $logic,
'comparison' => $comparison, 'comparison' => $comparison,
]; ];
return $this; return $this;
} }
public function createRelationMapper(self $mapper, string $member) : self public function createRelationMapper(self $mapper, string $member) : self
@ -153,7 +153,7 @@ abstract class DataMapperAbstract
} }
} }
return $relMapper; return $relMapper;
} }
/** /**
@ -191,5 +191,5 @@ abstract class DataMapperAbstract
return $value; return $value;
} }
abstract public function execute(...$options); abstract public function execute(...$options);
} }

View File

@ -27,7 +27,7 @@ use phpOMS\DataStorage\Database\Query\Builder;
*/ */
class DataMapperFactory class DataMapperFactory
{ {
/** /**
* Datetime format of the database datetime * Datetime format of the database datetime
* *
* This is only for the datetime stored in the database not the generated query. * This is only for the datetime stored in the database not the generated query.
@ -38,7 +38,7 @@ class DataMapperFactory
*/ */
public static string $datetimeFormat = 'Y-m-d H:i:s'; public static string $datetimeFormat = 'Y-m-d H:i:s';
/** /**
* Primary field name. * Primary field name.
* *
* @var string * @var string
@ -120,15 +120,15 @@ class DataMapperFactory
*/ */
public const MODEL = ''; public const MODEL = '';
/** /**
* Database connection. * Database connection.
* *
* @var ConnectionAbstract * @var ConnectionAbstract
* @since 1.0.0 * @since 1.0.0
*/ */
public static ConnectionAbstract $db; public static ConnectionAbstract $db;
/** /**
* Initialized objects for cross reference to reduce initialization costs * Initialized objects for cross reference to reduce initialization costs
* *
* @var array[] * @var array[]
@ -136,7 +136,7 @@ class DataMapperFactory
*/ */
protected static array $initObjects = []; protected static array $initObjects = [];
/** /**
* Constructor. * Constructor.
* *
* @since 1.0.0 * @since 1.0.0
@ -146,7 +146,7 @@ class DataMapperFactory
{ {
} }
/** /**
* Clone. * Clone.
* *
* @return void * @return void
@ -166,71 +166,71 @@ class DataMapperFactory
} }
public static function reader(ConnectionAbstract $db = null) : ReadMapper public static function reader(ConnectionAbstract $db = null) : ReadMapper
{ {
return new ReadMapper(new static(), $db ?? self::$db); return new ReadMapper(new static(), $db ?? self::$db);
} }
public static function get(ConnectionAbstract $db = null) : ReadMapper public static function get(ConnectionAbstract $db = null) : ReadMapper
{ {
return (new ReadMapper(new static(), $db ?? self::$db))->get(); return (new ReadMapper(new static(), $db ?? self::$db))->get();
} }
public static function getRaw(ConnectionAbstract $db = null) : ReadMapper public static function getRaw(ConnectionAbstract $db = null) : ReadMapper
{ {
return (new ReadMapper(new static(), $db ?? self::$db))->getRaw(); return (new ReadMapper(new static(), $db ?? self::$db))->getRaw();
} }
public static function getRandom(ConnectionAbstract $db = null) : ReadMapper public static function getRandom(ConnectionAbstract $db = null) : ReadMapper
{ {
return (new ReadMapper(new static(), $db ?? self::$db))->getRandom(); return (new ReadMapper(new static(), $db ?? self::$db))->getRandom();
} }
public static function count(ConnectionAbstract $db = null) : ReadMapper public static function count(ConnectionAbstract $db = null) : ReadMapper
{ {
return (new ReadMapper(new static(), $db ?? self::$db))->count(); return (new ReadMapper(new static(), $db ?? self::$db))->count();
} }
public static function getQuery(ConnectionAbstract $db = null) : Builder public static function getQuery(ConnectionAbstract $db = null) : Builder
{ {
return (new ReadMapper(new static(), $db ?? self::$db))->getQuery(); return (new ReadMapper(new static(), $db ?? self::$db))->getQuery();
} }
public static function getAll(ConnectionAbstract $db = null) : ReadMapper public static function getAll(ConnectionAbstract $db = null) : ReadMapper
{ {
return (new ReadMapper(new static(), $db ?? self::$db))->getAll(); return (new ReadMapper(new static(), $db ?? self::$db))->getAll();
} }
public static function writer(ConnectionAbstract $db = null) : WriteMapper public static function writer(ConnectionAbstract $db = null) : WriteMapper
{ {
return new WriteMapper(new static(), $db ?? self::$db); return new WriteMapper(new static(), $db ?? self::$db);
} }
public static function create(ConnectionAbstract $db = null) : WriteMapper public static function create(ConnectionAbstract $db = null) : WriteMapper
{ {
return (new WriteMapper(new static(), $db ?? self::$db))->create(); return (new WriteMapper(new static(), $db ?? self::$db))->create();
} }
public static function updater(ConnectionAbstract $db = null) : UpdateMapper public static function updater(ConnectionAbstract $db = null) : UpdateMapper
{ {
return new UpdateMapper(new static(), $db ?? self::$db); return new UpdateMapper(new static(), $db ?? self::$db);
} }
public static function update(ConnectionAbstract $db = null) : UpdateMapper public static function update(ConnectionAbstract $db = null) : UpdateMapper
{ {
return (new UpdateMapper(new static(), $db ?? self::$db))->update(); return (new UpdateMapper(new static(), $db ?? self::$db))->update();
} }
public static function remover(ConnectionAbstract $db = null) : DeleteMapper public static function remover(ConnectionAbstract $db = null) : DeleteMapper
{ {
return new DeleteMapper(new static(), $db ?? self::$db); return new DeleteMapper(new static(), $db ?? self::$db);
} }
public static function delete(ConnectionAbstract $db = null) : DeleteMapper public static function delete(ConnectionAbstract $db = null) : DeleteMapper
{ {
return (new DeleteMapper(new static(), $db ?? self::$db))->delete(); return (new DeleteMapper(new static(), $db ?? self::$db))->delete();
} }
/** /**
* Add initialized object to local cache * Add initialized object to local cache
* *
* @param string $mapper Mapper name * @param string $mapper Mapper name
@ -317,7 +317,7 @@ class DataMapperFactory
} }
} }
/** /**
* Test if object is null object * Test if object is null object
* *
* @param mixed $obj Object to check * @param mixed $obj Object to check
@ -382,7 +382,7 @@ class DataMapperFactory
return empty(static::MODEL) ? \substr(static::class, 0, -6) : static::MODEL; return empty(static::MODEL) ? \substr(static::class, 0, -6) : static::MODEL;
} }
/** /**
* Get id of object * Get id of object
* *
* @param object $obj Model to create * @param object $obj Model to create

View File

@ -30,20 +30,20 @@ use phpOMS\DataStorage\Database\Query\Builder;
class DeleteMapper extends DataMapperAbstract class DeleteMapper extends DataMapperAbstract
{ {
public function delete() : self public function delete() : self
{ {
$this->type = MapperType::DELETE; $this->type = MapperType::DELETE;
return $this; return $this;
} }
public function execute(...$options) : mixed public function execute(...$options) : mixed
{ {
switch($this->type) { switch($this->type) {
case MapperType::DELETE: case MapperType::DELETE:
return $this->executeDelete(...$options); return $this->executeDelete(...$options);
default: default:
return null; return null;
} }
} }
public function executeDelete(mixed $obj) : mixed public function executeDelete(mixed $obj) : mixed
@ -168,7 +168,7 @@ class DeleteMapper extends DataMapperAbstract
} }
if (isset($rel['column']) || !isset($this->with[$propertyName])) { if (isset($rel['column']) || !isset($this->with[$propertyName])) {
continue; continue;
} }
$property = $refClass->getProperty($propertyName); $property = $refClass->getProperty($propertyName);

View File

@ -29,43 +29,43 @@ class ReadMapper extends DataMapperAbstract
{ {
private $columns = []; private $columns = [];
public function get() : self public function get() : self
{ {
$this->type = MapperType::GET; $this->type = MapperType::GET;
return $this; return $this;
} }
public function getRaw() : self public function getRaw() : self
{ {
$this->type = MapperType::GET_RAW; $this->type = MapperType::GET_RAW;
return $this; return $this;
} }
public function getAll() : self public function getAll() : self
{ {
$this->type = MapperType::GET_ALL; $this->type = MapperType::GET_ALL;
return $this; return $this;
} }
public function count() : self public function count() : self
{ {
$this->type = MapperType::COUNT_MODELS; $this->type = MapperType::COUNT_MODELS;
return $this; return $this;
} }
public function getRandom() : self public function getRandom() : self
{ {
$this->type = MapperType::GET_RANDOM; $this->type = MapperType::GET_RANDOM;
return $this; return $this;
} }
public function find() : self public function find() : self
{ {
$this->type = MapperType::FIND; $this->type = MapperType::FIND;
return $this; return $this;
@ -78,46 +78,46 @@ class ReadMapper extends DataMapperAbstract
return $this; return $this;
} }
public function execute(...$options) : mixed public function execute(...$options) : mixed
{ {
switch($this->type) { switch($this->type) {
case MapperType::GET: case MapperType::GET:
return $options !== null return $options !== null
? $this->executeGet(...$options) ? $this->executeGet(...$options)
: $this->executeGet(); : $this->executeGet();
case MapperType::GET_RAW: case MapperType::GET_RAW:
return $options !== null return $options !== null
? $this->executeGetRaw(...$options) ? $this->executeGetRaw(...$options)
: $this->executeGetRaw(); : $this->executeGetRaw();
case MapperType::GET_ALL: case MapperType::GET_ALL:
return $options !== null return $options !== null
? $this->executeGetAll(...$options) ? $this->executeGetAll(...$options)
: $this->executeGetAll(); : $this->executeGetAll();
case MapperType::GET_RANDOM: case MapperType::GET_RANDOM:
return $this->executeGetRaw(); return $this->executeGetRaw();
case MapperType::COUNT_MODELS: case MapperType::COUNT_MODELS:
return $this->executeCount(); return $this->executeCount();
default: default:
return null; return null;
} }
} }
// @todo: consider to always return an array, this way we could remove executeGetAll // @todo: consider to always return an array, this way we could remove executeGetAll
public function executeGet(Builder $query = null) : mixed public function executeGet(Builder $query = null) : mixed
{ {
$primaryKeys = []; $primaryKeys = [];
$memberOfPrimaryField = $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['internal']; $memberOfPrimaryField = $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['internal'];
$emptyWhere = empty($this->where); $emptyWhere = empty($this->where);
if (isset($this->where[$memberOfPrimaryField])) { if (isset($this->where[$memberOfPrimaryField])) {
$keys = $this->where[$memberOfPrimaryField][0]['value']; $keys = $this->where[$memberOfPrimaryField][0]['value'];
$primaryKeys = \array_merge(\is_array($keys) ? $keys : [$keys], $primaryKeys); $primaryKeys = \array_merge(\is_array($keys) ? $keys : [$keys], $primaryKeys);
} }
// Get initialized objects from memory cache. // Get initialized objects from memory cache.
$obj = []; $obj = [];
foreach ($primaryKeys as $index => $value) { foreach ($primaryKeys as $index => $value) {
if (!$this->mapper::isInitialized($this->mapper::class, $value)) { if (!$this->mapper::isInitialized($this->mapper::class, $value)) {
continue; continue;
} }
@ -126,32 +126,32 @@ class ReadMapper extends DataMapperAbstract
unset($primaryKeys[$index]); unset($primaryKeys[$index]);
} }
// Get remaining objects (not available in memory cache) or remaining where clauses. // Get remaining objects (not available in memory cache) or remaining where clauses.
if (!empty($primaryKeys) || (!empty($this->where) || $emptyWhere)) { if (!empty($primaryKeys) || (!empty($this->where) || $emptyWhere)) {
$dbData = $this->executeGetRaw($query); $dbData = $this->executeGetRaw($query);
foreach ($dbData as $row) { foreach ($dbData as $row) {
$value = $row[$this->mapper::PRIMARYFIELD . '_d' . $this->depth]; $value = $row[$this->mapper::PRIMARYFIELD . '_d' . $this->depth];
$obj[$value] = $this->mapper::createBaseModel(); $obj[$value] = $this->mapper::createBaseModel();
$this->mapper::addInitialized($this->mapper::class, $value, $obj[$value]); $this->mapper::addInitialized($this->mapper::class, $value, $obj[$value]);
$obj[$value] = $this->populateAbstract($row, $obj[$value]); $obj[$value] = $this->populateAbstract($row, $obj[$value]);
$this->loadHasManyRelations($obj[$value]); $this->loadHasManyRelations($obj[$value]);
} }
} }
$countResulsts = \count($obj); $countResulsts = \count($obj);
if ($countResulsts === 0) { if ($countResulsts === 0) {
return $this->mapper::createNullModel(); return $this->mapper::createNullModel();
} elseif ($countResulsts === 1) { } elseif ($countResulsts === 1) {
return \reset($obj); return \reset($obj);
} }
return $obj; return $obj;
} }
public function executeGetRaw(Builder $query = null) : array public function executeGetRaw(Builder $query = null) : array
{ {
$query ??= $this->getQuery($query); $query ??= $this->getQuery($query);
@ -173,15 +173,15 @@ class ReadMapper extends DataMapperAbstract
} }
public function executeGetAll(Builder $query = null) : array public function executeGetAll(Builder $query = null) : array
{ {
$result = $this->executeGet($query); $result = $this->executeGet($query);
if (\is_object($result) && \stripos(\get_class($result), '\Null') !== false) { if (\is_object($result) && \stripos(\get_class($result), '\Null') !== false) {
return []; return [];
} }
return !\is_array($result) ? [$result] : $result; return !\is_array($result) ? [$result] : $result;
} }
/** /**
* Count the number of elements * Count the number of elements
@ -242,146 +242,146 @@ class ReadMapper extends DataMapperAbstract
// where // where
foreach ($this->where as $member => $values) { foreach ($this->where as $member => $values) {
if(($col = $this->mapper::getColumnByMember($member)) !== null) { if(($col = $this->mapper::getColumnByMember($member)) !== null) {
/* variable in model */ /* variable in model */
foreach ($values as $index => $where) { foreach ($values as $index => $where) {
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails // @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
if ($where['child'] !== '') { if ($where['child'] !== '') {
continue; continue;
} }
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic']; $comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], $where['comparison']); $query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], $where['comparison']);
} }
} elseif (isset($this->mapper::HAS_MANY[$member])) { } elseif (isset($this->mapper::HAS_MANY[$member])) {
/* variable in has many */ /* variable in has many */
foreach ($values as $index => $where) { foreach ($values as $index => $where) {
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails // @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
if ($where['child'] !== '') { if ($where['child'] !== '') {
continue; continue;
} }
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic']; $comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
$query->where($this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['external'], $comparison, $where['value'], $where['comparison']); $query->where($this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['external'], $comparison, $where['value'], $where['comparison']);
$query->leftJoin($this->mapper::HAS_MANY[$member]['table'], $this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth); $query->leftJoin($this->mapper::HAS_MANY[$member]['table'], $this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth);
if ($this->mapper::HAS_MANY[$member]['external'] !== null) { if ($this->mapper::HAS_MANY[$member]['external'] !== null) {
$query->on( $query->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member][$this->mapper::PRIMARYFIELD], '=', $this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member][$this->mapper::PRIMARYFIELD], '=',
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['self'], 'AND', $this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['self'], 'AND',
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth $this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth
); );
} else { } else {
$query->on( $query->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::PRIMARYFIELD, '=', $this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::PRIMARYFIELD, '=',
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['self'], 'AND', $this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['self'], 'AND',
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth $this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth
); );
} }
} }
} elseif (isset($this->mapper::BELONGS_TO[$member])) { } elseif (isset($this->mapper::BELONGS_TO[$member])) {
/* variable in belogns to */ /* variable in belogns to */
foreach ($values as $index => $where) { foreach ($values as $index => $where) {
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails // @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
if ($where['child'] !== '') { if ($where['child'] !== '') {
continue; continue;
} }
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic']; $comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $member, $comparison, $where['value'], $where['comparison']); $query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $member, $comparison, $where['value'], $where['comparison']);
$query->leftJoin($this->mapper::BELONGS_TO[$member]['mapper']::TABLE, $this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth) $query->leftJoin($this->mapper::BELONGS_TO[$member]['mapper']::TABLE, $this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth)
->on( ->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::BELONGS_TO[$member]['external'], '=', $this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::BELONGS_TO[$member]['external'], '=',
$this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth . '.' . $this->mapper::BELONGS_TO[$member]['mapper']::PRIMARYFIELD , 'AND', $this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth . '.' . $this->mapper::BELONGS_TO[$member]['mapper']::PRIMARYFIELD , 'AND',
$this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth $this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth
); );
} }
} elseif (isset($this->mapper::OWNS_ONE[$member])) { } elseif (isset($this->mapper::OWNS_ONE[$member])) {
/* variable in owns one */ /* variable in owns one */
foreach ($values as $index => $where) { foreach ($values as $index => $where) {
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails // @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
if ($where['child'] !== '') { if ($where['child'] !== '') {
continue; continue;
} }
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic']; $comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $member, $comparison, $where['value'], $where['comparison']); $query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $member, $comparison, $where['value'], $where['comparison']);
$query->leftJoin($this->mapper::OWNS_ONE[$member]['mapper']::TABLE, $this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth) $query->leftJoin($this->mapper::OWNS_ONE[$member]['mapper']::TABLE, $this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth)
->on( ->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::OWNS_ONE[$member]['external'], '=', $this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::OWNS_ONE[$member]['external'], '=',
$this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth . '.' . $this->mapper::OWNS_ONE[$member]['mapper']::PRIMARYFIELD , 'AND', $this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth . '.' . $this->mapper::OWNS_ONE[$member]['mapper']::PRIMARYFIELD , 'AND',
$this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth $this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth
); );
} }
} }
} }
// load relations // load relations
foreach ($this->with as $member => $data) { foreach ($this->with as $member => $data) {
$rel = null; $rel = null;
if ((isset($this->mapper::OWNS_ONE[$member]) || isset($this->mapper::BELONGS_TO[$member])) if ((isset($this->mapper::OWNS_ONE[$member]) || isset($this->mapper::BELONGS_TO[$member]))
|| (!isset($this->mapper::HAS_MANY[$member]['external']) && isset($this->mapper::HAS_MANY[$member]['column'])) || (!isset($this->mapper::HAS_MANY[$member]['external']) && isset($this->mapper::HAS_MANY[$member]['column']))
) { ) {
$rel = $this->mapper::OWNS_ONE[$member] ?? ($this->mapper::BELONGS_TO[$member] ?? ($this->mapper::HAS_MANY[$member] ?? null)); $rel = $this->mapper::OWNS_ONE[$member] ?? ($this->mapper::BELONGS_TO[$member] ?? ($this->mapper::HAS_MANY[$member] ?? null));
} else { } else {
break; break;
} }
foreach ($data as $index => $with) { foreach ($data as $index => $with) {
if ($with['child'] !== '') { if ($with['child'] !== '') {
continue; continue;
} }
if (isset($this->mapper::OWNS_ONE[$member]) || isset($this->mapper::BELONGS_TO[$member])) { if (isset($this->mapper::OWNS_ONE[$member]) || isset($this->mapper::BELONGS_TO[$member])) {
$query->leftJoin($rel['mapper']::TABLE, $rel['mapper']::TABLE . '_d' . ($this->depth + 1)) $query->leftJoin($rel['mapper']::TABLE, $rel['mapper']::TABLE . '_d' . ($this->depth + 1))
->on( ->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $rel['external'], '=', $this->mapper::TABLE . '_d' . $this->depth . '.' . $rel['external'], '=',
$rel['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . ( $rel['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . (
isset($rel['by']) ? $rel['mapper']::getColumnByMember($rel['by']) : $rel['mapper']::PRIMARYFIELD isset($rel['by']) ? $rel['mapper']::getColumnByMember($rel['by']) : $rel['mapper']::PRIMARYFIELD
), 'and', ), 'and',
$rel['mapper']::TABLE . '_d' . ($this->depth + 1) $rel['mapper']::TABLE . '_d' . ($this->depth + 1)
); );
} elseif (!isset($this->mapper::HAS_MANY[$member]['external']) && isset($this->mapper::HAS_MANY[$member]['column'])) { } elseif (!isset($this->mapper::HAS_MANY[$member]['external']) && isset($this->mapper::HAS_MANY[$member]['column'])) {
// get HasManyQuery (but only for elements which have a 'column' defined) // get HasManyQuery (but only for elements which have a 'column' defined)
// todo: handle self and self === null // todo: handle self and self === null
$query->leftJoin($rel['mapper']::TABLE, $rel['mapper']::TABLE . '_d' . ($this->depth + 1)) $query->leftJoin($rel['mapper']::TABLE, $rel['mapper']::TABLE . '_d' . ($this->depth + 1))
->on( ->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . ($rel['external'] ?? $this->mapper::PRIMARYFIELD), '=', $this->mapper::TABLE . '_d' . $this->depth . '.' . ($rel['external'] ?? $this->mapper::PRIMARYFIELD), '=',
$rel['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . ( $rel['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . (
isset($rel['by']) ? $rel['mapper']::getColumnByMember($rel['by']) : $rel['self'] isset($rel['by']) ? $rel['mapper']::getColumnByMember($rel['by']) : $rel['self']
), 'and', ), 'and',
$rel['mapper']::TABLE . '_d' . ($this->depth + 1) $rel['mapper']::TABLE . '_d' . ($this->depth + 1)
); );
} }
/** @var self $relMapper */ /** @var self $relMapper */
$relMapper = $this->createRelationMapper($rel['mapper']::reader(db: $this->db), $member); $relMapper = $this->createRelationMapper($rel['mapper']::reader(db: $this->db), $member);
$relMapper->depth = $this->depth + 1; $relMapper->depth = $this->depth + 1;
$query = $relMapper->getQuery( $query = $relMapper->getQuery(
$query, $query,
isset($rel['column']) ? [$rel['mapper']::getColumnByMember($rel['column']) => []] : [] isset($rel['column']) ? [$rel['mapper']::getColumnByMember($rel['column']) => []] : []
); );
break; // there is only one root element (one element with child === '') break; // there is only one root element (one element with child === '')
} }
} }
// handle sort, the column name order is very important. Therefore it cannot be done in the foreach loop above! // handle sort, the column name order is very important. Therefore it cannot be done in the foreach loop above!
foreach ($this->sort as $member => $data) { foreach ($this->sort as $member => $data) {
foreach ($data as $index => $sort) { foreach ($data as $index => $sort) {
if (($column = $this->mapper::getColumnByMember($member)) === null if (($column = $this->mapper::getColumnByMember($member)) === null
|| ($sort['child'] !== '') || ($sort['child'] !== '')
) { ) {
continue; continue;
} }
$query->orderBy($this->mapper::TABLE . '_d' . $this->depth . '.' . $column, $sort['order']); $query->orderBy($this->mapper::TABLE . '_d' . $this->depth . '.' . $column, $sort['order']);
break; // there is only one root element (one element with child === '') break; // there is only one root element (one element with child === '')
} }
} }
// handle limit // handle limit
@ -390,13 +390,13 @@ class ReadMapper extends DataMapperAbstract
continue; continue;
} }
foreach ($data as $index => $limit) { foreach ($data as $index => $limit) {
if ($limit['child'] === '') { if ($limit['child'] === '') {
$query->limit($limit['limit']); $query->limit($limit['limit']);
break 2; // there is only one root element (one element with child === '') break 2; // there is only one root element (one element with child === '')
} }
} }
} }
return $query; return $query;
@ -703,7 +703,7 @@ class ReadMapper extends DataMapperAbstract
/** @var class-string<DataMapperFactory> $belongsToMapper */ /** @var class-string<DataMapperFactory> $belongsToMapper */
$belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member); $belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member);
$belongsToMapper->depth = $this->depth + 1; $belongsToMapper->depth = $this->depth + 1;
$belongsToMapper->where($this->mapper::BELONGS_TO[$member]['by'], $result[$mapper::getColumnByMember($this->mapper::BELONGS_TO[$member]['by']) . '_d' . $this->depth], '='); $belongsToMapper->where($this->mapper::BELONGS_TO[$member]['by'], $result[$mapper::getColumnByMember($this->mapper::BELONGS_TO[$member]['by']) . '_d' . $this->depth], '=');
return $belongsToMapper->execute(); return $belongsToMapper->execute();
} }
@ -746,7 +746,7 @@ class ReadMapper extends DataMapperAbstract
// there can be pseudo has many elements like localizations. They are has manies but these are already loaded with joins! // there can be pseudo has many elements like localizations. They are has manies but these are already loaded with joins!
foreach ($this->mapper::HAS_MANY as $member => $many) { foreach ($this->mapper::HAS_MANY as $member => $many) {
if (isset($many['column']) || !isset($this->with[$member])) { if (isset($many['column']) || !isset($this->with[$member])) {
continue; continue;
} }
$query = new Builder($this->db); $query = new Builder($this->db);
@ -771,22 +771,22 @@ class ReadMapper extends DataMapperAbstract
$result = $sth->fetchAll(\PDO::FETCH_COLUMN); $result = $sth->fetchAll(\PDO::FETCH_COLUMN);
$objects = $this->createRelationMapper($many['mapper']::get(db: $this->db), $member) $objects = $this->createRelationMapper($many['mapper']::get(db: $this->db), $member)
->where($many['mapper']::COLUMNS[$many['mapper']::PRIMARYFIELD]['internal'], $result, 'in') ->where($many['mapper']::COLUMNS[$many['mapper']::PRIMARYFIELD]['internal'], $result, 'in')
->execute(); ->execute();
$refProp = $refClass->getProperty($member); $refProp = $refClass->getProperty($member);
if (!$refProp->isPublic()) { if (!$refProp->isPublic()) {
$refProp->setAccessible(true); $refProp->setAccessible(true);
$refProp->setValue($obj, !\is_array($objects) && !isset($this->mapper::HAS_MANY[$member]['conditional']) $refProp->setValue($obj, !\is_array($objects) && !isset($this->mapper::HAS_MANY[$member]['conditional'])
? [$many['mapper']::getObjectId($objects) => $objects] ? [$many['mapper']::getObjectId($objects) => $objects]
: $objects : $objects
); );
$refProp->setAccessible(false); $refProp->setAccessible(false);
} else { } else {
$obj->{$member} = !\is_array($objects) && !isset($this->mapper::HAS_MANY[$member]['conditional']) $obj->{$member} = !\is_array($objects) && !isset($this->mapper::HAS_MANY[$member]['conditional'])
? [$many['mapper']::getObjectId($objects) => $objects] ? [$many['mapper']::getObjectId($objects) => $objects]
: $objects; : $objects;
} }
} }
} }
} }

View File

@ -32,20 +32,20 @@ use phpOMS\Utils\ArrayUtils;
class UpdateMapper extends DataMapperAbstract class UpdateMapper extends DataMapperAbstract
{ {
public function update() : self public function update() : self
{ {
$this->type = MapperType::UPDATE; $this->type = MapperType::UPDATE;
return $this; return $this;
} }
public function execute(...$options) : mixed public function execute(...$options) : mixed
{ {
switch($this->type) { switch($this->type) {
case MapperType::UPDATE: case MapperType::UPDATE:
return $this->executeUpdate(...$options); return $this->executeUpdate(...$options);
default: default:
return null; return null;
} }
} }
public function executeUpdate(mixed $obj) : mixed public function executeUpdate(mixed $obj) : mixed
@ -267,7 +267,7 @@ class UpdateMapper extends DataMapperAbstract
{ {
foreach ($this->mapper::HAS_MANY as $member => $many) { foreach ($this->mapper::HAS_MANY as $member => $many) {
if (isset($many['column']) || !isset($this->with[$member])) { if (isset($many['column']) || !isset($this->with[$member])) {
continue; continue;
} }
$query = new Builder($this->db); $query = new Builder($this->db);

View File

@ -30,20 +30,20 @@ use phpOMS\Utils\ArrayUtils;
class WriteMapper extends DataMapperAbstract class WriteMapper extends DataMapperAbstract
{ {
public function create() : self public function create() : self
{ {
$this->type = MapperType::CREATE; $this->type = MapperType::CREATE;
return $this; return $this;
} }
public function execute(...$options) : mixed public function execute(...$options) : mixed
{ {
switch($this->type) { switch($this->type) {
case MapperType::CREATE: case MapperType::CREATE:
return $this->executeCreate(...$options); return $this->executeCreate(...$options);
default: default:
return null; return null;
} }
} }
public function executeCreate(mixed $obj) : mixed public function executeCreate(mixed $obj) : mixed

View File

@ -16,8 +16,8 @@ namespace phpOMS\tests\DataStorage\Database\TestModel;
final class NullBaseModel extends BaseModel final class NullBaseModel extends BaseModel
{ {
public function __construct(int $id = 0) public function __construct(int $id = 0)
{ {
$this->id = $id; $this->id = $id;
} }
} }