Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ parameters:
- tests/
ignoreErrors:
- message: '/Call to an undefined (static )?method Respect\\Relational\\(Sql|Db|Mapper)::\w+\(\)\./'
- message: '/Call to an undefined (static )?method Respect\\Data\\Collections\\(Collection|Filtered|Composite|Typed)::\w+\(\)\./'
- message: '/Access to an undefined property Respect\\Relational\\Mapper::\$\w+\./'
- message: '/Call to an undefined (static )?method Respect\\Data\\Collections\\(Collection|Composite|Typed)::\w+\(\)\./'
- message: '/Unsafe usage of new static\(\)\./'
- message: '/Cannot unset property .+ because it might have hooks in a subclass\./'
-
message: '/(Access to an undefined property object|Cannot access property .+ on mixed)/'
path: tests/
-
message: '/Parameter #1 .+ of class Respect\\Relational\\Mapper constructor expects .+, string given\./'
path: tests/MapperTest.php
79 changes: 25 additions & 54 deletions src/Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use Respect\Data\CollectionIterator;
use Respect\Data\Collections\Collection;
use Respect\Data\Collections\Composite;
use Respect\Data\Collections\Filtered;
use Respect\Data\Hydrator;
use Respect\Data\Hydrators\PrestyledAssoc;
use SplObjectStorage;
Expand Down Expand Up @@ -70,28 +69,18 @@ public function fetchAll(Collection $collection, mixed $extra = null): array

public function persist(object $object, Collection $onCollection): object
{
if ($onCollection instanceof Filtered) {
return parent::persist($object, $onCollection);
}

if ($this->persisting->offsetExists($object)) {
return parent::persist($object, $onCollection);
}

$this->persisting[$object] = true;

try {
$connectsTo = $onCollection->connectsTo;

if ($connectsTo) {
$remote = $this->style->remoteIdentifier($connectsTo->name);
$related = $this->getRelatedEntity($object, $remote);
if ($related !== null) {
$this->persist($related, $connectsTo);
foreach ($onCollection->with as $child) {
if ($child->name === null) {
continue;
}
}

foreach ($onCollection->children as $child) {
$remote = $this->style->remoteIdentifier($child->name);
$related = $this->getRelatedEntity($object, $remote);
if ($related === null) {
Expand Down Expand Up @@ -347,13 +336,8 @@ private function generateQuery(Collection $collection): Sql
/** @return array<string, mixed> */
private function extractColumns(object $entity, Collection $collection): array
{
$cols = $this->filterColumns(
$this->entityFactory->extractColumns($entity),
$collection,
);

$dbCols = [];
foreach ($cols as $key => $value) {
foreach ($this->entityFactory->extractColumns($entity) as $key => $value) {
$dbCols[$this->style->realProperty($key)] = $value;
}

Expand All @@ -365,29 +349,8 @@ private function buildSelectStatement(Sql $sql, array $collections): Sql
{
$selectTable = [];
foreach ($collections as $tableSpecifier => $c) {
if ($c instanceof Filtered) {
$filters = $c->filters;
if ($filters) {
$fields = $this->entityFactory->enumerateFields($c->name);
$pk = $this->style->identifier($c->name);
$selectTable[] = self::aliasedColumn($tableSpecifier, $pk, $fields[$pk] ?? $pk);

if (!$c->identifierOnly) {
foreach ($filters as $f) {
$selectTable[] = self::aliasedColumn($tableSpecifier, $f, $fields[$f] ?? $f);
}
}

$connectedName = $c->connectsTo?->name;
if ($connectedName !== null) {
$fk = $this->style->remoteIdentifier($connectedName);
$selectTable[] = self::aliasedColumn($tableSpecifier, $fk, $fields[$fk] ?? $fk);
}
}
} else {
foreach ($this->entityFactory->enumerateFields($c->name) as $dbCol => $styledProp) {
$selectTable[] = self::aliasedColumn($tableSpecifier, $dbCol, $styledProp);
}
foreach ($this->entityFactory->enumerateFields($c->name) as $dbCol => $styledProp) {
$selectTable[] = self::aliasedColumn($tableSpecifier, $dbCol, $styledProp);
}

// Composition columns come after entity columns so they override on collision
Expand Down Expand Up @@ -440,10 +403,10 @@ private function parseConditions(array &$conditions, Collection $collection, str
$parsedConditions = [];
$aliasedPk = $alias . '.' . $this->style->identifier($collection->name);

if (is_scalar($collection->condition)) {
$parsedConditions[] = [$aliasedPk, '=', $collection->condition];
} elseif (is_array($collection->condition)) {
foreach ($collection->condition as $column => $value) {
if (is_scalar($collection->filter)) {
$parsedConditions[] = [$aliasedPk, '=', $collection->filter];
} elseif (is_array($collection->filter)) {
foreach ($collection->filter as $column => $value) {
if (!empty($parsedConditions)) {
$parsedConditions[] = 'AND';
}
Expand Down Expand Up @@ -486,7 +449,6 @@ private function parseCollection(
$s = $this->style;
$entity = $collection->name;
$parent = $collection->parent?->name;
$connected = $collection->connectsTo?->name;

$parentAlias = $parent ? $aliases[$parent] : null;
$aliases[$entity] = $alias;
Expand Down Expand Up @@ -526,7 +488,7 @@ private function parseCollection(
$aliasedPk = $alias . '.' . $s->identifier($entity);
$aliasedParentPk = $parentAlias . '.' . $s->identifier($parent);

if ($this->hasComposition($entity, $connected, $parent)) {
if ($this->isCompositionJoin($collection, $entity, $parent)) {
$onName = $alias . '.' . $s->remoteIdentifier($parent);
$onAlias = $aliasedParentPk;
} else {
Expand All @@ -537,14 +499,23 @@ private function parseCollection(
$sql->on([$onName => $onAlias]);
}

private function hasComposition(string $entity, string|null $connected, string|null $parent): bool
private function isCompositionJoin(Collection $collection, string $entity, string $parent): bool
{
if ($connected === null || $parent === null) {
return false;
foreach ($collection->with as $child) {
$connected = $child->name;
if ($connected === null) {
continue;
}

if (
$entity === $this->style->composed($parent, $connected)
|| $entity === $this->style->composed($connected, $parent)
) {
return true;
}
}

return $entity === $this->style->composed($parent, $connected)
|| $entity === $this->style->composed($connected, $parent);
return false;
}

/** @param SplObjectStorage<object, Collection> $hydrated */
Expand Down
Loading
Loading