From 6082f78425e7ac7e63913996f8b782a822d245b8 Mon Sep 17 00:00:00 2001 From: Tycho Kamphuios Date: Fri, 30 Aug 2024 13:50:16 +0200 Subject: [PATCH 1/4] Fixed Lambda HasManyThrough --- src/Drivers/EloquentEntitySet.php | 24 ++++++++++++-------- src/Drivers/SQL/SQLExpression.php | 37 ++++++++++++++++++++++--------- src/ReferentialConstraint.php | 16 ++++++++++++- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/Drivers/EloquentEntitySet.php b/src/Drivers/EloquentEntitySet.php index 122adfb58..27b618cdb 100644 --- a/src/Drivers/EloquentEntitySet.php +++ b/src/Drivers/EloquentEntitySet.php @@ -56,6 +56,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOneOrMany; @@ -151,7 +152,9 @@ public function getModelByKey(PropertyValue $key): ?Model */ public function getTable(): string { - return $this->getModel()->getTable(); + $model = $this->getModel(); + + return $model->getTable(); } /** @@ -166,7 +169,7 @@ public function getConnection(): ConnectionInterface /** * Read an Eloquent model * @param PropertyValue $key Model key - * @return Entity Entity + * @return Entity|null Entity */ public function read(PropertyValue $key): Entity { @@ -256,10 +259,6 @@ public function delete(PropertyValue $key): void { $model = $this->getModelByKey($key); - if (null === $model) { - throw new NotFoundException('entity_not_found', 'Entity not found'); - } - try { $model->delete(); } catch (Exception $e) { @@ -395,6 +394,7 @@ protected function getRelationships(): array $expansionSet->configureBuilder($builder); }; + $relations = array_merge( $relations, Collection::make($expansionSet->getRelationships()) @@ -543,10 +543,11 @@ public function discoverRelationship( $navigationProperty->setNullable($nullable); - if ($relation instanceof HasOneOrMany || $relation instanceof BelongsTo) { + if ($relation instanceof HasOneOrMany || $relation instanceof BelongsTo || $relation instanceof HasManyThrough) { $localProperty = null; $foreignProperty = null; + switch (true) { case $relation instanceof HasOneOrMany: $localProperty = $this->getPropertyBySourceName($relation->getLocalKeyName()); @@ -557,10 +558,15 @@ public function discoverRelationship( $localProperty = $this->getPropertyBySourceName($relation->getForeignKeyName()); $foreignProperty = $right->getPropertyBySourceName($relation->getOwnerKeyName()); break; + + case $relation instanceof HasManyThrough: + $localProperty = $this->getPropertyBySourceName($relation->getLocalKeyName()); + $foreignProperty = $right->getPropertyBySourceName($relation->getForeignKeyName()); + break; } if ($localProperty && $foreignProperty) { - $referentialConstraint = new ReferentialConstraint($localProperty, $foreignProperty); + $referentialConstraint = new ReferentialConstraint($localProperty, $foreignProperty, $relation); $navigationProperty->addConstraint($referentialConstraint); } } @@ -815,4 +821,4 @@ public function discover(): self return $this; } -} +} \ No newline at end of file diff --git a/src/Drivers/SQL/SQLExpression.php b/src/Drivers/SQL/SQLExpression.php index d8d9b9bfd..463bea1e8 100644 --- a/src/Drivers/SQL/SQLExpression.php +++ b/src/Drivers/SQL/SQLExpression.php @@ -66,6 +66,7 @@ use Flat3\Lodata\NavigationProperty; use Flat3\Lodata\ReferentialConstraint; use Flat3\Lodata\Type; +use Illuminate\Database\Eloquent\Relations\HasManyThrough; /** * SQL Expression, with its associated parameters @@ -1317,16 +1318,29 @@ protected function lambdaExpression(Lambda $node): void $constraint = array_shift($constraints); $field = $this->entitySet->propertyToExpression($constraint->getProperty()); - $this->pushParameters($field->getParameters()); - - $this->pushStatement( - sprintf('( %s = %s ( SELECT %s from %s WHERE', - $field->getStatement(), - $node instanceof Lambda\Any ? 'ANY' : 'ALL', - $targetSet->propertyToExpression($constraint->getReferencedProperty())->getStatement(), - $targetSet->quoteSingleIdentifier($targetSet->getTable()), - ) - ); + + $relation = $constraint?->relation; + if (isset($relation) && $relation instanceof HasManyThrough) { + $constraint->relation->select($relation->getQualifiedFirstKeyName()); + $where = preg_replace('/\s+where\s+.*$/i', '', $constraint->relation->toSql()); + $this->pushStatement( + sprintf('( %s = %s ( %s WHERE', + $field->getStatement(), + $node instanceof Lambda\Any ? 'ANY' : 'ALL', + $where, + ) + ); + } else { + $this->pushParameters($field->getParameters()); + $this->pushStatement( + sprintf('( %s = %s ( SELECT %s from %s WHERE', + $field->getStatement(), + $node instanceof Lambda\Any ? 'ANY' : 'ALL', + $targetSet->propertyToExpression($constraint->getReferencedProperty())->getStatement(), + $targetSet->quoteSingleIdentifier($targetSet->getTable()), + ) + ); + } $operatingTargetSet = clone $targetSet; @@ -1335,6 +1349,7 @@ protected function lambdaExpression(Lambda $node): void $targetExpression->evaluate($lambdaExpression); $parser->popEntitySet(); + $this->pushStatement($targetExpression->getStatement()); $this->parameters = array_merge($this->parameters, $targetExpression->getParameters()); @@ -1345,4 +1360,4 @@ protected function lambdaExpression(Lambda $node): void } } } -} \ No newline at end of file +} diff --git a/src/ReferentialConstraint.php b/src/ReferentialConstraint.php index caf4cfcc6..88791c0d7 100644 --- a/src/ReferentialConstraint.php +++ b/src/ReferentialConstraint.php @@ -4,6 +4,8 @@ namespace Flat3\Lodata; +use Illuminate\Database\Eloquent\Relations\Relation; + /** * Referential Constraint * @link https://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#_Toc38530370 @@ -23,10 +25,13 @@ class ReferentialConstraint */ protected $referencedProperty; - public function __construct(Property $property, Property $referenced_property) + private $relation; + + public function __construct(Property $property, Property $referenced_property, Relation $relation = null) { $this->property = $property; $this->referencedProperty = $referenced_property; + $this->relation = $relation; } /** @@ -47,6 +52,15 @@ public function getReferencedProperty(): Property return $this->referencedProperty; } + /** + * Get the referenced relation + * @return Relation|null + */ + public function getRelation(): ?Relation + { + return $this->relation; + } + /** * @return string */ From 72095dfd045fa7f528492424be1b160877eb40b9 Mon Sep 17 00:00:00 2001 From: Tycho Kamphuios Date: Fri, 30 Aug 2024 14:09:09 +0200 Subject: [PATCH 2/4] Removed redundant change --- src/Drivers/EloquentEntitySet.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Drivers/EloquentEntitySet.php b/src/Drivers/EloquentEntitySet.php index 27b618cdb..8f3357dc9 100644 --- a/src/Drivers/EloquentEntitySet.php +++ b/src/Drivers/EloquentEntitySet.php @@ -152,9 +152,7 @@ public function getModelByKey(PropertyValue $key): ?Model */ public function getTable(): string { - $model = $this->getModel(); - - return $model->getTable(); + return $this->getModel()->getTable(); } /** @@ -169,7 +167,7 @@ public function getConnection(): ConnectionInterface /** * Read an Eloquent model * @param PropertyValue $key Model key - * @return Entity|null Entity + * @return Entity Entity */ public function read(PropertyValue $key): Entity { @@ -259,6 +257,10 @@ public function delete(PropertyValue $key): void { $model = $this->getModelByKey($key); + if (null === $model) { + throw new NotFoundException('entity_not_found', 'Entity not found'); + } + try { $model->delete(); } catch (Exception $e) { From 9d92e69d1a9aa14d7556624bce72edce3f7e5338 Mon Sep 17 00:00:00 2001 From: Tycho Kamphuios Date: Fri, 30 Aug 2024 14:10:55 +0200 Subject: [PATCH 3/4] Improvements for php7 --- src/Drivers/SQL/SQLExpression.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Drivers/SQL/SQLExpression.php b/src/Drivers/SQL/SQLExpression.php index 463bea1e8..3adeb812f 100644 --- a/src/Drivers/SQL/SQLExpression.php +++ b/src/Drivers/SQL/SQLExpression.php @@ -1319,10 +1319,10 @@ protected function lambdaExpression(Lambda $node): void $field = $this->entitySet->propertyToExpression($constraint->getProperty()); - $relation = $constraint?->relation; + $relation = $constraint->getRelation(); if (isset($relation) && $relation instanceof HasManyThrough) { - $constraint->relation->select($relation->getQualifiedFirstKeyName()); - $where = preg_replace('/\s+where\s+.*$/i', '', $constraint->relation->toSql()); + $constraint->getRelation()->select($relation->getQualifiedFirstKeyName()); + $where = preg_replace('/\s+where\s+.*$/i', '', $constraint->getRelation()->toSql()); $this->pushStatement( sprintf('( %s = %s ( %s WHERE', $field->getStatement(), From 5912cede1db3a9576d24baba36bda6a03cda4a4d Mon Sep 17 00:00:00 2001 From: Tycho Kamphuios Date: Thu, 26 Sep 2024 10:47:48 +0200 Subject: [PATCH 4/4] Added support for array if using other packages --- src/Drivers/EloquentEntitySet.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Drivers/EloquentEntitySet.php b/src/Drivers/EloquentEntitySet.php index 3036742ba..6b41ade48 100644 --- a/src/Drivers/EloquentEntitySet.php +++ b/src/Drivers/EloquentEntitySet.php @@ -550,18 +550,18 @@ public function discoverRelationship( switch (true) { case $relation instanceof HasOneOrMany: - $localProperty = $this->getPropertyBySourceName($relation->getLocalKeyName()); - $foreignProperty = $right->getPropertyBySourceName($relation->getForeignKeyName()); + $localProperty = $this->getPropertyBySourceName(is_array($relation->getLocalKeyName()) ? $relation->getLocalKeyName()[0] : $relation->getLocalKeyName()); + $foreignProperty = $right->getPropertyBySourceName(is_array($relation->getForeignKeyName()) ? $relation->getForeignKeyName()[0] : $relation->getForeignKeyName()); break; case $relation instanceof BelongsTo: - $localProperty = $this->getPropertyBySourceName($relation->getForeignKeyName()); - $foreignProperty = $right->getPropertyBySourceName($relation->getOwnerKeyName()); + $localProperty = $this->getPropertyBySourceName(is_array($relation->getForeignKeyName()) ? $relation->getForeignKeyName()[0] : $relation->getForeignKeyName()); + $foreignProperty = $right->getPropertyBySourceName(is_array($relation->getOwnerKeyName()) ? $relation->getOwnerKeyName()[0] : $relation->getOwnerKeyName()); break; case $relation instanceof HasManyThrough: - $localProperty = $this->getPropertyBySourceName($relation->getLocalKeyName()); - $foreignProperty = $right->getPropertyBySourceName($relation->getForeignKeyName()); + $localProperty = $this->getPropertyBySourceName(is_array($relation->getLocalKeyName()) ? $relation->getLocalKeyName()[0] : $relation->getLocalKeyName()); + $foreignProperty = $right->getPropertyBySourceName(is_array($relation->getForeignKeyName()) ? $relation->getForeignKeyName()[0] : $relation->getForeignKeyName()); break; }