Skip to content

Commit 972e12d

Browse files
committed
test: fail ci
1 parent 2decc7b commit 972e12d

File tree

17 files changed

+712
-136
lines changed

17 files changed

+712
-136
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,6 @@ jobs:
858858
run: |
859859
mkdir -p build/logs/behat
860860
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=default --no-interaction
861-
continue-on-error: true
862861
- name: Upload test artifacts
863862
if: always()
864863
uses: actions/upload-artifact@v1

docs/adr/0003-uri-variables.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ We will use a POPO to define URI variables, for now these options are available:
3737
uriVariables: [
3838
'companyId' => new UriVariable(
3939
targetClass: Company::class,
40-
inverseProperty: null,
40+
targetProperty: null,
4141
property: 'company'
4242
identifiers: ['id'],
4343
compositeIdentifier: true,
@@ -53,7 +53,7 @@ Where `uriVariables` keys are the URI template's variable names. Its value is a
5353

5454
- `targetClass` is the PHP FQDN of the class this value belongs to
5555
- `property` represents the property, the URI Variable is mapped to in the current class
56-
- `inverseProperty` represents the property, the URI Variable is mapped to in the related class and is not available in the current class
56+
- `targetProperty` represents the property, the URI Variable is mapped to in the related class and is not available in the current class
5757
- `identifiers` are the properties of the targetClass to which we map the URI variable
5858
- `compositeIdentifier` is used to match a single variable to multiple identifiers (`ida=1;idb=2` to `class::ida` and `class::idb`)
5959

@@ -122,7 +122,7 @@ class Company {
122122
}
123123
```
124124

125-
Note that the above is a shortcut for: `new UriVariable(targetClass: Employee::class, inverseProperty: 'company')`
125+
Note that the above is a shortcut for: `new UriVariable(targetClass: Employee::class, targetProperty: 'company')`
126126

127127
Corresponding DQL:
128128

@@ -259,7 +259,7 @@ class Employee {
259259
#[ApiResource("/employees/{employeeId}/company", uriVariables: [
260260
'employeeId' => new UriVariable(
261261
targetClass: Employee::class,
262-
inverseProperty: 'company'
262+
targetProperty: 'company'
263263
property: null,
264264
identifiers: ['id'],
265265
compositeIdentifier: true

features/main/subresource.feature

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ Feature: Subresource support
223223
}
224224
"""
225225

226+
@createSchema
226227
Scenario: Get the subresource relation item
228+
Given there is a dummy object with a fourth level relation
227229
When I send a "GET" request to "/dummies/1/related_dummies/2"
228230
Then the response status code should be 200
229231
And the response should be in JSON

src/Api/IdentifiersExtractor.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,13 @@ private function getIdentifierValue($item, string $class, string $property, stri
9494
continue;
9595
}
9696

97-
if ($type->getClassName() === $class) {
98-
return $this->resolveIdentifierValue($this->propertyAccessor->getValue($item, "$propertyName.$property"), $parameterName);
99-
}
100-
10197
if ($type->isCollection() && ($collectionValueType = $type->getCollectionValueType()) && $collectionValueType->getClassName() === $class) {
10298
return $this->resolveIdentifierValue($this->propertyAccessor->getValue($item, sprintf('%s[0].%s', $propertyName, $property)), $parameterName);
10399
}
100+
101+
if ($type->getClassName() === $class) {
102+
return $this->resolveIdentifierValue($this->propertyAccessor->getValue($item, "$propertyName.$property"), $parameterName);
103+
}
104104
}
105105

106106
throw new RuntimeException('Not able to retrieve identifiers.');

src/Api/UriVariablesConverter.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Api;
1515

1616
use ApiPlatform\Exception\InvalidUriVariableException;
17+
use ApiPlatform\Metadata\Link;
1718
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
1819
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
1920
use Symfony\Component\PropertyInfo\Type;
@@ -46,10 +47,11 @@ public function convert(array $uriVariables, string $class, array $context = [])
4647
{
4748
$operation = $context['operation'] ?? $this->resourceMetadataCollectionFactory->create($class)->getOperation();
4849
$context = $context + ['operation' => $operation];
49-
$uriVariablesDefinition = $operation->getUriVariables() ?? [];
50+
$uriVariablesDefinitions = $operation->getUriVariables() ?? [];
5051

5152
foreach ($uriVariables as $parameterName => $value) {
52-
if ([] === $types = $this->getIdentifierTypes($uriVariablesDefinition[$parameterName]->getFromClass() ?? $class, $uriVariablesDefinition[$parameterName]->getIdentifiers() ?? [$parameterName])) {
53+
$uriVariableDefinition = $uriVariablesDefinitions[$parameterName] ?? $uriVariablesDefinitions['id'] ?? new Link();
54+
if ([] === $types = $this->getIdentifierTypes($uriVariableDefinition->getFromClass() ?? $class, $uriVariableDefinition->getIdentifiers() ?? [$parameterName])) {
5355
continue;
5456
}
5557

src/Bridge/Doctrine/Orm/State/CollectionProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public function provide(string $resourceClass, array $identifiers = [], ?string
6161

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

64+
// dd($queryBuilder->getQuery());
6465
foreach ($this->collectionExtensions as $extension) {
6566
$extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context);
6667

src/Bridge/Doctrine/Orm/State/ItemProvider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2121
use ApiPlatform\State\ProviderInterface;
2222
use Doctrine\ORM\EntityManagerInterface;
23+
use Doctrine\ORM\EntityRepository;
2324
use Doctrine\Persistence\ManagerRegistry;
2425

2526
/**
@@ -56,6 +57,7 @@ public function provide(string $resourceClass, array $identifiers = [], ?string
5657
return $manager->getReference($resourceClass, $identifiers);
5758
}
5859

60+
/** @var EntityRepository $repository */
5961
$repository = $manager->getRepository($resourceClass);
6062
if (!method_exists($repository, 'createQueryBuilder')) {
6163
throw new RuntimeException('The repository class must have a "createQueryBuilder" method.');
@@ -66,6 +68,7 @@ public function provide(string $resourceClass, array $identifiers = [], ?string
6668

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

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

src/Bridge/Doctrine/Orm/State/LinksHandlerTrait.php

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
namespace ApiPlatform\Bridge\Doctrine\Orm\State;
1515

1616
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
17-
use ApiPlatform\Exception\RuntimeException;
1817
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
1918
use ApiPlatform\Metadata\Link;
2019
use Doctrine\ORM\QueryBuilder;
@@ -33,62 +32,93 @@ private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, Que
3332

3433
if ($linkClass = $context['linkClass'] ?? false) {
3534
foreach ($links as $link) {
36-
if ($linkClass === $link->getFromClass()) {
35+
if ($linkClass === $link->getTargetClass()) {
3736
foreach ($identifiers as $identifier => $value) {
3837
$this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifier, $value);
3938
}
4039

4140
return;
4241
}
4342
}
43+
}
4444

45-
$operation = $this->resourceMetadataCollectionFactory->create($linkClass)->getOperation($operationName);
46-
$links = $operation instanceof GraphQlOperation ? $operation->getLinks() : $operation->getUriVariables();
47-
foreach ($links as $link) {
48-
if ($resourceClass === $link->getFromClass()) {
49-
$link = $link->withFromProperty($link->getToProperty())->withFromClass($linkClass);
50-
foreach ($identifiers as $identifier => $value) {
51-
$this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifier, $value);
52-
}
45+
if (null === $links) {
46+
return;
47+
}
5348

54-
return;
55-
}
49+
dd($links)
50+
dump($operation->getUriTemplate());
51+
$aliases = [];
52+
$previousContext = [];
53+
$conditions = [];
54+
foreach ($links as $parameterName => $link) {
55+
$identifier = $link->getIdentifiers()[0];
56+
if (!isset($aliases[$link->getTargetClass()])) {
57+
$aliases[$link->getTargetClass()] = $link->getTargetClass() === $operation->getClass() ? $alias : $queryNameGenerator->generateJoinAlias($alias);
5658
}
5759

58-
throw new RuntimeException(sprintf('The class "%s" cannot be retrieved from "%s".', $resourceClass, $linkClass));
59-
}
60+
$currentAlias = $aliases[$link->getTargetClass()];
61+
$placeholder = $queryNameGenerator->generateParameterName($parameterName);
62+
// inverse == prop de la targetClass
63+
if (!$link->getInverseProperty() && !$link->getProperty() && !$link->getExpandedValue()) {
64+
$conditions[] = $aliases[$link->getTargetClass()] . ".$identifier = :$placeholder";
65+
$previousContext = ['alias' => $currentAlias, 'identifier' => $identifier];
66+
continue;
67+
}
6068

61-
if (!$links) {
62-
return;
63-
}
6469

65-
foreach ($identifiers as $identifier => $value) {
66-
$link = $links[$identifier] ?? $links['id'];
70+
if ($inverseProperty = $link->getInverseProperty()) {
71+
$joinAlias = $queryNameGenerator->generateJoinAlias($alias);
72+
$inverseAlias = $queryNameGenerator->generateJoinAlias($alias);
73+
$conditions[] = "{$previousContext['alias']}.{$previousContext['identifier']} IN (SELECT $inverseAlias.$identifier FROM {$link->getTargetClass()} $joinAlias JOIN $joinAlias.$inverseProperty $inverseAlias WHERE $joinAlias.$identifier = $placeholder)";
74+
$previousContext = ['alias' => $currentAlias, 'identifier' => $identifier];
75+
continue;
76+
}
77+
78+
dump($conditions);
79+
dd($link);
80+
// dd($link);
81+
// if ($link->getExpandedValue()) {
82+
// dd($queryBuilder->getDQL());
83+
// dd('test');
84+
// continue;
85+
// }
6786

68-
$this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifier, $value);
87+
// $this->applyLink($queryBuilder, $queryNameGenerator, $doctrineClassMetadata, $alias, $link, $identifiers[$parameterName] ?? null);
6988
}
7089
}
7190

72-
private function applyLink(QueryBuilder $queryBuilder, QueryNameGenerator $queryNameGenerator, ClassMetadata $doctrineClassMetadata, string $alias, Link $link, string $identifier, $value)
91+
private function applyLink(QueryBuilder $queryBuilder, QueryNameGenerator $queryNameGenerator, ClassMetadata $doctrineClassMetadata, string $alias, Link $link, $value = null)
7392
{
74-
$placeholder = ':id_'.$identifier;
75-
if ($fromProperty = $link->getFromProperty()) {
76-
$propertyIdentifier = $link->getIdentifiers()[0];
77-
$joinAlias = $queryNameGenerator->generateJoinAlias($fromProperty);
78-
79-
$queryBuilder->join(
80-
$link->getFromClass(),
81-
$joinAlias,
82-
'with',
83-
"$alias.$propertyIdentifier = $joinAlias.$fromProperty"
84-
);
85-
86-
$expression = $queryBuilder->expr()->eq(
87-
"{$joinAlias}.{$propertyIdentifier}",
88-
$placeholder
89-
);
90-
} elseif ($property = $link->getToProperty()) {
91-
$propertyIdentifier = $link->getIdentifiers()[0];
93+
$propertyIdentifier = $link->getIdentifiers()[0];
94+
$placeholder = ':' . $queryNameGenerator->generateParameterName($propertyIdentifier);
95+
if ($inverseProperty = $link->getInverseProperty()) {
96+
$joinAlias = $queryNameGenerator->generateJoinAlias($alias);
97+
$inverseAlias = $queryNameGenerator->generateJoinAlias($alias);
98+
99+
// SELECT o FROM ApiPlatform\Tests\Fixtures\TestBundle\Entity\ThirdLevel o
100+
// WHERE o.id IN (
101+
// SELECT o_a3.id FROM
102+
// ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy o_a1
103+
// JOIN o_a1.relatedDummies o_a2
104+
// JOIN o_a2.thirdLevel o_a3
105+
// WHERE o_a1.id = :id_id
106+
// ) AND o.id = :id_id
107+
108+
// $queryBuilder->join(
109+
// $link->getTargetClass(),
110+
// $joinAlias,
111+
// 'with',
112+
// "$alias.$propertyIdentifier = $joinAlias.$inverseProperty"
113+
// );
114+
115+
$expression = "$alias.$propertyIdentifier IN (SELECT $inverseAlias.$propertyIdentifier FROM {$link->getTargetClass()} $joinAlias JOIN $joinAlias.$inverseProperty $inverseAlias WHERE $joinAlias.$propertyIdentifier = $placeholder)";
116+
117+
// $expression = $queryBuilder->expr()->eq(
118+
// "{$joinAlias}.{$propertyIdentifier}",
119+
// $placeholder
120+
// );
121+
} elseif ($property = $link->getProperty()) {
92122
$joinAlias = $queryNameGenerator->generateJoinAlias($property);
93123

94124
$queryBuilder->join(
@@ -102,10 +132,11 @@ private function applyLink(QueryBuilder $queryBuilder, QueryNameGenerator $query
102132
);
103133
} else {
104134
$expression = $queryBuilder->expr()->eq(
105-
"{$alias}.{$identifier}", $placeholder
135+
"{$alias}.{$propertyIdentifier}", $placeholder
106136
);
107137
}
138+
108139
$queryBuilder->andWhere($expression);
109-
$queryBuilder->setParameter($placeholder, $value, $doctrineClassMetadata->getTypeOfField($identifier));
140+
$queryBuilder->setParameter($placeholder, $value, $doctrineClassMetadata->getTypeOfField($propertyIdentifier));
110141
}
111142
}

0 commit comments

Comments
 (0)