Skip to content

Commit

Permalink
Oh yeah
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Nov 8, 2021
1 parent 972e12d commit c2347ec
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 153 deletions.
1 change: 1 addition & 0 deletions features/main/subresource.feature
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ Feature: Subresource support
}
"""

@createSchema
Scenario: Get offers subresource from aggregate offers subresource
Given I have a product with offers
When I send a "GET" request to "/dummy_products/2/offers/1/offers"
Expand Down
1 change: 0 additions & 1 deletion src/Bridge/Doctrine/Orm/State/ItemProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ public function provide(string $resourceClass, array $identifiers = [], ?string

$this->handleLinks($queryBuilder, $identifiers, $queryNameGenerator, $context, $resourceClass, $operationName);

dd($queryBuilder->getDQL());
foreach ($this->itemExtensions as $extension) {
$extension->applyToItem($queryBuilder, $queryNameGenerator, $resourceClass, $identifiers, $operationName, $context);

Expand Down
183 changes: 91 additions & 92 deletions src/Bridge/Doctrine/Orm/State/LinksHandlerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\DummyProduct;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\Mapping\ClassMetadata;

Expand All @@ -30,113 +32,110 @@ private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, Que

$links = $operation instanceof GraphQlOperation ? $operation->getLinks() : $operation->getUriVariables();

if ($linkClass = $context['linkClass'] ?? false) {
foreach ($links as $link) {
if ($linkClass === $link->getTargetClass()) {
foreach ($identifiers as $identifier => $value) {
$this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifier, $value);
}

return;
}
}
}

if (null === $links) {
// if ($linkClass = $context['linkClass'] ?? false) {
// foreach ($links as $link) {
// if ($linkClass === $link->getTargetClass()) {
// foreach ($identifiers as $identifier => $value) {
// $this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifier, $value);
// }
//
// return;
// }
// }
// }

if (!$links) {
return;
}

dd($links)
dump($operation->getUriTemplate());
$aliases = [];
$previousContext = [];
$conditions = [];
foreach ($links as $parameterName => $link) {
$identifier = $link->getIdentifiers()[0];
if (!isset($aliases[$link->getTargetClass()])) {
$aliases[$link->getTargetClass()] = $link->getTargetClass() === $operation->getClass() ? $alias : $queryNameGenerator->generateJoinAlias($alias);
}
$previousAlias = $alias;
$previousIdentifier = end($links)->getIdentifiers()[0] ?? 'id';
$expressions = [];
$i = 0;

$currentAlias = $aliases[$link->getTargetClass()];
$placeholder = $queryNameGenerator->generateParameterName($parameterName);
// inverse == prop de la targetClass
if (!$link->getInverseProperty() && !$link->getProperty() && !$link->getExpandedValue()) {
$conditions[] = $aliases[$link->getTargetClass()] . ".$identifier = :$placeholder";
$previousContext = ['alias' => $currentAlias, 'identifier' => $identifier];
foreach (array_reverse($links) as $parameterName => $link) {
if ($link->getExpandedValue() || !$link->getFromClass()) {
++$i;
continue;
}

$identifierProperty = $link->getIdentifiers()[0] ?? 'id';
$currentAlias = $i === 0 ? $alias : $queryNameGenerator->generateJoinAlias($alias);
$placeholder = $queryNameGenerator->generateParameterName($parameterName);

if (!$link->getFromProperty() && !$link->getToProperty()) {
$doctrineClassMetadata = $manager->getClassMetadata($link->getFromClass());

if ($inverseProperty = $link->getInverseProperty()) {
$joinAlias = $queryNameGenerator->generateJoinAlias($alias);
$inverseAlias = $queryNameGenerator->generateJoinAlias($alias);
$conditions[] = "{$previousContext['alias']}.{$previousContext['identifier']} IN (SELECT $inverseAlias.$identifier FROM {$link->getTargetClass()} $joinAlias JOIN $joinAlias.$inverseProperty $inverseAlias WHERE $joinAlias.$identifier = $placeholder)";
$previousContext = ['alias' => $currentAlias, 'identifier' => $identifier];
$queryBuilder->andWhere("{$currentAlias}.$identifierProperty = :$placeholder");
$queryBuilder->setParameter($placeholder, $identifiers[$parameterName], $doctrineClassMetadata->getTypeOfField($identifierProperty));
$previousAlias = $currentAlias;
$previousIdentifier = $identifierProperty;
++$i;
continue;
}

dump($conditions);
dd($link);
// dd($link);
// if ($link->getExpandedValue()) {
// dd($queryBuilder->getDQL());
// dd('test');
// continue;
// }
if ($link->getFromProperty()) {
$doctrineClassMetadata = $manager->getClassMetadata($link->getFromClass());
$joinAlias = $queryNameGenerator->generateJoinAlias('m');
$assocationMapping = $doctrineClassMetadata->getAssociationMappings()[$link->getFromProperty()];
$relationType = $assocationMapping['type'];

// $this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifiers[$parameterName] ?? null);
}
}
if ($relationType & ClassMetadataInfo::TO_MANY) {
$nextAlias = $queryNameGenerator->generateJoinAlias($alias);

$expressions["$previousAlias.$previousIdentifier"] = "SELECT $joinAlias.{$previousIdentifier} FROM {$link->getFromClass()} $nextAlias INNER JOIN $nextAlias.{$link->getFromProperty()} $joinAlias WHERE $nextAlias.{$identifierProperty} = :$placeholder";

$queryBuilder->setParameter($placeholder, $identifiers[$parameterName], $doctrineClassMetadata->getTypeOfField($identifierProperty));
$previousAlias = $nextAlias;
++$i;
continue;
}


// A single-valued association path expression to an inverse side is not supported in DQL queries.
if ($relationType & ClassMetadataInfo::TO_ONE && !$assocationMapping['isOwningSide']) {
$queryBuilder->innerJoin("$previousAlias.".$assocationMapping['mappedBy'], $joinAlias);
} else {
$queryBuilder->join(
$link->getFromClass(),
$joinAlias,
'with',
"{$previousAlias}.{$previousIdentifier} = $joinAlias.{$link->getFromProperty()}"
);
}

$queryBuilder->andWhere("$joinAlias.$identifierProperty = :$placeholder");
$queryBuilder->setParameter($placeholder, $identifiers[$parameterName], $doctrineClassMetadata->getTypeOfField($identifierProperty));
$previousAlias = $joinAlias;
$previousIdentifier = $identifierProperty;
++$i;
continue;
}

private function applyLink(QueryBuilder $queryBuilder, QueryNameGenerator $queryNameGenerator, ClassMetadata $doctrineClassMetadata, string $alias, Link $link, $value = null)
{
$propertyIdentifier = $link->getIdentifiers()[0];
$placeholder = ':' . $queryNameGenerator->generateParameterName($propertyIdentifier);
if ($inverseProperty = $link->getInverseProperty()) {
$joinAlias = $queryNameGenerator->generateJoinAlias($alias);
$inverseAlias = $queryNameGenerator->generateJoinAlias($alias);

// SELECT o FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\ThirdLevel o
// WHERE o.id IN (
// SELECT o_a3.id FROM
// ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy o_a1
// JOIN o_a1.relatedDummies o_a2
// JOIN o_a2.thirdLevel o_a3
// WHERE o_a1.id = :id_id
// ) AND o.id = :id_id

// $queryBuilder->join(
// $link->getTargetClass(),
// $joinAlias,
// 'with',
// "$alias.$propertyIdentifier = $joinAlias.$inverseProperty"
// );

$expression = "$alias.$propertyIdentifier IN (SELECT $inverseAlias.$propertyIdentifier FROM {$link->getTargetClass()} $joinAlias JOIN $joinAlias.$inverseProperty $inverseAlias WHERE $joinAlias.$propertyIdentifier = $placeholder)";

// $expression = $queryBuilder->expr()->eq(
// "{$joinAlias}.{$propertyIdentifier}",
// $placeholder
// );
} elseif ($property = $link->getProperty()) {
$joinAlias = $queryNameGenerator->generateJoinAlias($property);

$queryBuilder->join(
"$alias.$property",
$joinAlias,
);

$expression = $queryBuilder->expr()->eq(
"{$joinAlias}.{$propertyIdentifier}",
$placeholder
);
} else {
$expression = $queryBuilder->expr()->eq(
"{$alias}.{$propertyIdentifier}", $placeholder
);
$queryBuilder->join("{$previousAlias}.{$link->getToProperty()}", $joinAlias);
$queryBuilder->andWhere("$joinAlias.$identifierProperty = :$placeholder");
$queryBuilder->setParameter($placeholder, $identifiers[$parameterName], $doctrineClassMetadata->getTypeOfField($identifierProperty));
$previousAlias = $joinAlias;
$previousIdentifier = $identifierProperty;
++$i;
}

$queryBuilder->andWhere($expression);
$queryBuilder->setParameter($placeholder, $value, $doctrineClassMetadata->getTypeOfField($propertyIdentifier));
if ($expressions) {
$i = 0;
$clause = '';
foreach ($expressions as $alias => $expression) {
if ($i === 0) {
$clause .= "$alias IN (" . $expression;
$i++;
continue;
}

$clause .= " AND $alias IN (" . $expression;
$i++;
}

$queryBuilder->andWhere($clause . str_repeat(')', $i));
}
}
}
10 changes: 5 additions & 5 deletions src/Core/Bridge/Rector/Parser/TransformApiSubresourceVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ public function enterNode(Node $node)
new Node\Expr\ArrayItem(
new Node\Expr\ClassConstFetch(
new Node\Name(
($resource['target_class'] === $this->subresourceMetadata['resource_class']) ? 'self' : '\\'.$resource['target_class']
($resource['from_class'] === $this->subresourceMetadata['resource_class']) ? 'self' : '\\'.$resource['from_class']
),
'class'
),
new Node\Scalar\String_('target_class')
new Node\Scalar\String_('from_class')
),
new Node\Expr\ArrayItem(
new Node\Expr\Array_(
Expand All @@ -93,10 +93,10 @@ public function enterNode(Node $node)
);
}

if (isset($resource['property']) || isset($resource['inverse_property'])) {
if (isset($resource['from_property']) || isset($resource['to_property'])) {
$identifierNodes[] = new Node\Expr\ArrayItem(
new Node\Scalar\String_($resource['property'] ?? $resource['inverse_property']),
new Node\Scalar\String_(isset($resource['property']) ? 'property' : 'inverse_property')
new Node\Scalar\String_($resource['to_property'] ?? $resource['from_property']),
new Node\Scalar\String_(isset($resource['to_property']) ? 'to_property' : 'from_property')
);
}

Expand Down
1 change: 0 additions & 1 deletion src/Core/Bridge/Rector/Service/SubresourceTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ public function toUriVariables(array $subresourceMetadata): array
$fromClassMetadataAssociationMappings = $fromClassMetadata->getAssociationMappings();

$uriVariables[$identifier] = [
'target_class' => $fromClass,
'from_class' => $fromClass,
'inverse_property' => null,
'from_property' => null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,13 @@ private function normalizeUriVariables($operation)
$normalizedUriVariable = (new Link())->withIdentifiers([$normalizedUriVariable])->withFromClass($resourceClass);
}
if (\is_array($normalizedUriVariable)) {
if (!isset($normalizedUriVariable['target_class'])) {
if (!isset($normalizedUriVariable['from_class']) && !isset($normalizedUriVariable['expanded_value'])) {
if (2 !== \count($normalizedUriVariable)) {
throw new \LogicException("The uriVariables shortcut syntax needs to be the tuple: 'uriVariable' => [fromClass, fromProperty]");
}
$normalizedUriVariable = (new Link())->withIdentifiers([$normalizedUriVariable[1]])->withFromClass($normalizedUriVariable[0]);
} else {
$normalizedUriVariable = new Link(null, $normalizedUriVariable['from_property'] ?? null, $normalizedUriVariable['to_property'] ?? null, $normalizedUriVariable['class'], $normalizedUriVariable['to_class'] ?? null, $normalizedUriVariable['identifiers'] ?? null, $normalizedUriVariable['composite_identifier'] ?? null, $normalizedUriVariable['expanded_value'] ?? null);
$normalizedUriVariable = new Link($normalizedParameterName, $normalizedUriVariable['from_property'] ?? null, $normalizedUriVariable['to_property'] ?? null, $normalizedUriVariable['from_class'] ?? null, $normalizedUriVariable['to_class'] ?? null, $normalizedUriVariable['identifiers'] ?? null, $normalizedUriVariable['composite_identifier'] ?? null, $normalizedUriVariable['expanded_value'] ?? null);
}
}
if (null !== ($hasCompositeIdentifier = $operation->getCompositeIdentifier())) {
Expand Down

0 comments on commit c2347ec

Please sign in to comment.