Skip to content

Commit d2fc370

Browse files
committed
support querybuilder model resolving parent constructor call of ServiceEntityRepository
1 parent 8dea435 commit d2fc370

File tree

4 files changed

+129
-15
lines changed

4 files changed

+129
-15
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/querybuilder/QueryBuilderMethodReferenceParser.java

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
import com.intellij.psi.util.PsiTreeUtil;
77
import com.jetbrains.php.PhpIndex;
88
import com.jetbrains.php.lang.parser.PhpElementTypes;
9-
import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression;
10-
import com.jetbrains.php.lang.psi.elements.ClassConstantReference;
11-
import com.jetbrains.php.lang.psi.elements.MethodReference;
12-
import com.jetbrains.php.lang.psi.elements.PhpClass;
9+
import com.jetbrains.php.lang.psi.elements.*;
1310
import fr.adrienbrault.idea.symfony2plugin.doctrine.EntityHelper;
1411
import fr.adrienbrault.idea.symfony2plugin.doctrine.dict.DoctrineModelField;
1512
import fr.adrienbrault.idea.symfony2plugin.doctrine.querybuilder.detector.FormQueryBuilderRepositoryDetector;
@@ -61,15 +58,13 @@ public QueryBuilderScopeContext collect() {
6158
}
6259

6360
for(MethodReference methodReference: methodReferences) {
64-
6561
String name = methodReference.getName();
6662
if(name != null) {
6763
collectParameter(qb, methodReference, name);
6864
collectJoins(qb, methodReference, name);
6965
collectSelects(qb, methodReference, name);
7066
collectSelectInForm(qb, methodReference, name);
7167
}
72-
7368
}
7469

7570
// first tableMap entry is root, we add several initial data
@@ -184,25 +179,30 @@ private void collectParameter(QueryBuilderScopeContext qb, MethodReference metho
184179

185180
}
186181

187-
188182
/**
183+
* Extract model from context
189184
*
190-
* @param methodReferences
191-
* @return
185+
* ```
186+
* getRepository('Foo')->createQueryBuilder('test')
187+
* ```
188+
*
189+
* ```
190+
* public function __construct(RegistryInterface $registry)
191+
* {
192+
* parent::__construct($registry, Entity::class);
193+
* }
194+
* ```
192195
*/
193196
@NotNull
194197
private Map<String, String> findRootDefinition(@NotNull Collection<MethodReference> methodReferences) {
195-
196-
Map<String, String> roots = new HashMap<>();
197-
198198
if(methodReferences.size() == 0) {
199-
return roots;
199+
return Collections.emptyMap();
200200
}
201201

202+
Map<String, String> roots = new HashMap<>();
202203
String rootAlias = null;
203204
String repository = null;
204205

205-
206206
for(MethodReference methodReference: methodReferences) {
207207
String methodReferenceName = methodReference.getName();
208208

@@ -259,11 +259,38 @@ private Map<String, String> findRootDefinition(@NotNull Collection<MethodReferen
259259
roots.put(repository, rootAlias);
260260
}
261261

262+
// public function __construct(RegistryInterface $registry)
263+
// parent::__construct($registry, Entity::class);
264+
if(rootAlias != null && repository == null) {
265+
MethodReference methodReference = methodReferences.iterator().next();
266+
PhpClass phpClass = PsiTreeUtil.getParentOfType(methodReference, PhpClass.class);
267+
268+
if(phpClass != null && PhpElementsUtil.isInstanceOf(phpClass, "\\Doctrine\\Bundle\\DoctrineBundle\\Repository\\ServiceEntityRepository")) {
269+
Method constructor = phpClass.getConstructor();
270+
if (constructor != null) {
271+
for (MethodReference reference : PsiTreeUtil.findChildrenOfType(constructor, MethodReference.class)) {
272+
if ("__construct".equals(reference.getName())) {
273+
PsiElement[] parameters = reference.getParameters();
274+
if (parameters.length > 1) {
275+
PsiElement parameter = parameters[1];
276+
String stringValue = PhpElementsUtil.getStringValue(parameter);
277+
if (stringValue != null) {
278+
roots.put(stringValue, rootAlias);
279+
return roots;
280+
}
281+
}
282+
}
283+
}
284+
}
285+
}
286+
}
287+
262288
// we found a alias but not a repository name, so try a scope search if we are inside repository class
263289
// class implements \Doctrine\Common\Persistence\ObjectRepository, so search for model name of "repositoryClass"
264290
if(rootAlias != null && repository == null) {
265291
MethodReference methodReference = methodReferences.iterator().next();
266292
PhpClass phpClass = PsiTreeUtil.getParentOfType(methodReference, PhpClass.class);
293+
267294
if(
268295
phpClass != null &&
269296
(
@@ -280,7 +307,6 @@ private Map<String, String> findRootDefinition(@NotNull Collection<MethodReferen
280307
}
281308
}
282309
}
283-
284310
}
285311

286312
// search on PhpTypeProvider
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package fr.adrienbrault.idea.symfony2plugin.tests.doctrine.querybuilder;
2+
3+
import fr.adrienbrault.idea.symfony2plugin.doctrine.querybuilder.QueryBuilderCompletionContributor;
4+
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
5+
6+
/**
7+
* @see QueryBuilderCompletionContributor
8+
* @author Daniel Espendiller <daniel@espendiller.net>
9+
*/
10+
public class QueryBuilderCompletionContributorTest extends SymfonyLightCodeInsightFixtureTestCase {
11+
public void setUp() throws Exception {
12+
super.setUp();
13+
myFixture.copyFileToProject("doctrine.orm.yml");
14+
myFixture.copyFileToProject("QueryBuilderCompletionContributor.php");
15+
}
16+
17+
public String getTestDataPath() {
18+
return "src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/querybuilder/fixtures";
19+
}
20+
21+
public void testServiceEntityRepositoryConstructorModelContextOnQueryBuilderJoin() {
22+
assertCompletionContains("test.php", "<?php\n" +
23+
"\n" +
24+
"use Doctrine\\Bundle\\DoctrineBundle\\Repository\\ServiceEntityRepository;\n" +
25+
"\n" +
26+
"class Repository extends ServiceEntityRepository\n" +
27+
"{\n" +
28+
" public function __construct(RegistryInterface $registry)\n" +
29+
" {\n" +
30+
" parent::__construct($registry, \\App\\Entity::class);\n" +
31+
" }\n" +
32+
"\n" +
33+
" public function foobar()\n" +
34+
" {\n" +
35+
" $qb = $this->createQueryBuilder('s');\n" +
36+
" $qb->andWhere('s.<caret>');\n" +
37+
" }\n" +
38+
"}", "s.name", "s.id");
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Doctrine\ORM
4+
{
5+
class QueryBuilder
6+
{
7+
public function andWhere() {}
8+
}
9+
10+
class EntityRepository
11+
{
12+
/**
13+
* @return QueryBuilder
14+
*/
15+
public function createQueryBuilder($alias, $indexBy = null)
16+
{
17+
}
18+
}
19+
}
20+
21+
22+
namespace Doctrine\Bundle\DoctrineBundle\Repository
23+
{
24+
use Doctrine\ORM\EntityRepository;
25+
26+
class ServiceEntityRepository extends EntityRepository
27+
{
28+
}
29+
}
30+
31+
namespace App
32+
{
33+
class Entity
34+
{
35+
}
36+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
App\Entity:
2+
type: entity
3+
table: foo_table
4+
id:
5+
id:
6+
type: integer
7+
generator:
8+
strategy: AUTO
9+
fields:
10+
name:
11+
type: string
12+
length: 50

0 commit comments

Comments
 (0)