mapper = $mapper; $this->db = $db; } /** * Define a query which is merged with the internal query generation. * * @param Builder $query Query * * @return static * * @since 1.0.0 */ public function query(Builder $query = null) : self { $this->query = $query; return $this; } /** * Define model relations which should be loaded * * @param string $member Property name of the relation (e.g. hasMany, belongsTo, ...) * * @return static * * @since 1.0.0 */ public function with(string $member) : self { $split = \explode('/', $member); $memberSplit = \array_shift($split); $this->with[$memberSplit ?? ''][] = [ 'child' => \implode('/', $split), ]; return $this; } /** * Sort order * * @param string $member Property name to sort by * @param string $order Order type (DESC/ASC) * * @return static * * @since 1.0.0 */ public function sort(string $member, string $order = OrderType::DESC) : self { $split = \explode('/', $member); $memberSplit = \array_shift($split); $this->sort[$memberSplit ?? ''][] = [ 'child' => \implode('/', $split), 'order' => $order, ]; return $this; } /** * Define the result offset * * @param int $offset Offset * @param string $member Property name to offset by ('' = base model, anything else for relations such as hasMany relations) * * @return static * * @since 1.0.0 */ public function offset(int $offset = 0, string $member = '') : self { $split = \explode('/', $member); $memberSplit = \array_shift($split); $this->offset[$memberSplit ?? ''][] = [ 'child' => \implode('/', $split), 'offset' => $offset, ]; return $this; } /** * Define the result limit * * @param int $limit Limit * @param string $member Property name to limit by ('' = base model, anything else for relations such as hasMany relations) * * @return static * * @since 1.0.0 */ public function limit(int $limit = 0, string $member = '') : self { $split = \explode('/', $member); $memberSplit = \array_shift($split); $this->limit[$memberSplit ?? ''][] = [ 'child' => \implode('/', $split), 'limit' => $limit, ]; return $this; } /** * Define the result filtering * * @param string $member Property name to filter by * @param mixed $value Filter value * @param string $logic Comparison logic (e.g. =, in, ...) * @param string $connector Filter connector (e.g. AND, OR, ...) * * @return static * * @since 1.0.0 */ public function where(string $member, mixed $value, string $logic = '=', string $connector = 'AND') : self { $split = \explode('/', $member); $memberSplit = \array_shift($split); $this->where[$memberSplit ?? ''][] = [ 'child' => \implode('/', $split), 'value' => $value, 'logic' => $logic, 'comparison' => $connector, ]; return $this; } /** * Populate a mapper (e.g. child mapper, relation mapper) based on the current mapper information. * * @param DataMapperAbstract $mapper Relation mapper to populate * @param string $member Relation property (e.g. ownsOne, hasMany, ... property name) * * @return self * * @since 1.0.0 */ public function createRelationMapper(self $mapper, string $member) : self { $relMapper = $mapper; if (isset($this->with[$member])) { foreach ($this->with[$member] as $with) { if ($with['child'] === '') { continue; } $relMapper->with($with['child']); } } if (isset($this->sort[$member])) { foreach ($this->sort[$member] as $sort) { // member = child element in this case if ($member === '') { continue; } $relMapper->sort($sort['child'], $sort['order']); } } if (isset($this->offset[$member])) { foreach ($this->offset[$member] as $offset) { if ($offset['child'] === '') { continue; } $relMapper->offset($offset['offset'], $offset['child']); } } if (isset($this->limit[$member])) { foreach ($this->limit[$member] as $limit) { // member = child element in this case if ($member === '') { continue; } $relMapper->limit($limit['limit'], $limit['child']); } } if (isset($this->where[$member])) { foreach ($this->where[$member] as $where) { if ($where['child'] === '') { continue; } $relMapper->where($where['child'], $where['value'], $where['logic'], $where['comparison']); } } return $relMapper; } /** * Parse value * * @param string $type Value type * @param mixed $value Value to parse * * @return mixed * * @since 1.0.0 */ public function parseValue(string $type, mixed $value = null) : mixed { if ($value === null) { return null; } elseif ($type === 'int') { return (int) $value; } elseif ($type === 'string') { return (string) $value; } elseif ($type === 'float') { return (float) $value; } elseif ($type === 'bool') { return (bool) $value; } elseif ($type === 'DateTime' || $type === 'DateTimeImmutable') { return $value === null ? null : $value->format($this->mapper::$datetimeFormat); } elseif ($type === 'Json') { return (string) \json_encode($value); } elseif ($type === 'Serializable') { return $value->serialize(); } elseif (\is_object($value) && \method_exists($value, 'getId')) { return $value->getId(); } return $value; } /** * Execute mapper * * @param mixed ...$options Data for the mapper * * @return mixed * * @since 1.0.0 */ abstract public function execute(...$options) : mixed; }