creating join

This commit is contained in:
Dennis Eichhorn 2022-11-25 19:25:41 +01:00
parent 2e442acc3d
commit 9745efa7d5
2 changed files with 119 additions and 9 deletions

View File

@ -95,6 +95,14 @@ abstract class DataMapperAbstract
*/
protected array $where = [];
/**
* Join conditions
*
* @var array
* @since 1.0.0
*/
protected array $join = [];
/**
* Base query which is merged with the query in the mapper
*
@ -307,6 +315,86 @@ abstract class DataMapperAbstract
return $this;
}
/**
* Define the joining data
*
* @param string $member Property name to filter by
* @param string $mapper Mapper
* @param mixed $value Filter value
* @param string $logic Comparison logic (e.g. =, in, ...)
* @param string $type Join type (e.g. left, right, inner)
*
* @return static
*
* @since 1.0.0
*/
public function join(string $member, string $mapper, mixed $value, string $logic = '=', string $type = 'left') : self
{
$split = \explode('/', $member);
$memberSplit = \array_shift($split);
$this->join[$memberSplit][] = [
'child' => \implode('/', $split),
'mapper' => $mapper,
'value' => $value,
'logic' => $logic,
'type' => $type,
];
return $this;
}
/**
* Define the joining data
*
* @param string $member Property name to filter by
* @param string $mapper Mapper
* @param mixed $value Filter value
* @param string $logic Comparison logic (e.g. =, in, ...)
*
* @return static
*
* @since 1.0.0
*/
public function leftJoin(string $member, string $mapper, mixed $value, string $logic = '=') : self
{
return $this->join($member, $mapper, $value, $logic, 'left');
}
/**
* Define the joining data
*
* @param string $member Property name to filter by
* @param string $mapper Mapper
* @param mixed $value Filter value
* @param string $logic Comparison logic (e.g. =, in, ...)
*
* @return static
*
* @since 1.0.0
*/
public function rightJoin(string $member, string $mapper, mixed $value, string $logic = '=') : self
{
return $this->join($member, $mapper, $value, $logic, 'right');
}
/**
* Define the joining data
*
* @param string $member Property name to filter by
* @param string $mapper Mapper
* @param mixed $value Filter value
* @param string $logic Comparison logic (e.g. =, in, ...)
*
* @return static
*
* @since 1.0.0
*/
public function innerJoin(string $member, string $mapper, mixed $value, string $logic = '=') : self
{
return $this->join($member, $mapper, $value, $logic, 'inner');
}
/**
* Populate a mapper (e.g. child mapper, relation mapper) based on the current mapper information.
*

View File

@ -173,7 +173,6 @@ final class ReadMapper extends DataMapperAbstract
{
$primaryKeys = [];
$memberOfPrimaryField = $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['internal'];
$emptyWhere = empty($this->where);
if (isset($this->where[$memberOfPrimaryField])) {
$keys = $this->where[$memberOfPrimaryField][0]['value'];
@ -184,16 +183,14 @@ final class ReadMapper extends DataMapperAbstract
$obj = [];
// Get remaining objects (not available in memory cache) or remaining where clauses.
if (!empty($primaryKeys) || (!empty($this->where) || $emptyWhere)) {
$dbData = $this->executeGetRaw($query);
$dbData = $this->executeGetRaw($query);
foreach ($dbData as $row) {
$value = $row[$this->mapper::PRIMARYFIELD . '_d' . $this->depth];
$obj[$value] = $this->mapper::createBaseModel();
foreach ($dbData as $row) {
$value = $row[$this->mapper::PRIMARYFIELD . '_d' . $this->depth];
$obj[$value] = $this->mapper::createBaseModel();
$obj[$value] = $this->populateAbstract($row, $obj[$value]);
$this->loadHasManyRelations($obj[$value]);
}
$obj[$value] = $this->populateAbstract($row, $obj[$value]);
$this->loadHasManyRelations($obj[$value]);
}
$countResulsts = \count($obj);
@ -322,6 +319,31 @@ final class ReadMapper extends DataMapperAbstract
$query->fromAs($this->mapper::TABLE, $this->mapper::TABLE . '_d' . $this->depth);
}
// Join tables manually without using "with()" (NOT has many/owns one etc.)
// This is necessary for special cases, e.g. when joining in the other direction
// Example: Show all profiles who have written a news article.
// "with()" only allows to go from articles to accounts but we want to go the other way
foreach ($this->join as $member => $values) {
if (($col = $this->mapper::getColumnByMember($member)) !== null) {
/* variable in model */
foreach ($values as $join) {
// @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 ($join['child'] !== '') {
continue;
}
$query->join($join['mapper']::TABLE, $join['type'], $join['mapper']::TABLE . '_d' . ($this->depth + 1))
->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $col,
'=',
$join['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . $join['mapper']::getColumnByMember($join['value']),
'and',
$join['mapper']::TABLE . '_d' . ($this->depth + 1)
);
}
}
}
// where
foreach ($this->where as $member => $values) {
// handle where query