Skip to content

Commit 01d79d6

Browse files
committed
Add parameter completion and navigation support for PHP array service configurations
1 parent 386e03c commit 01d79d6

2 files changed

Lines changed: 126 additions & 3 deletions

File tree

src/main/java/fr/adrienbrault/idea/symfony2plugin/config/php/PhpArrayGotoCompletionRegistrar.java

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
package fr.adrienbrault.idea.symfony2plugin.config.php;
22

3+
import com.intellij.codeInsight.lookup.LookupElement;
34
import com.intellij.patterns.PlatformPatterns;
45
import com.intellij.psi.PsiElement;
56
import com.jetbrains.php.lang.PhpLanguage;
67
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
78
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider;
89
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar;
910
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter;
11+
import fr.adrienbrault.idea.symfony2plugin.codeInsight.utils.GotoCompletionUtil;
1012
import fr.adrienbrault.idea.symfony2plugin.completion.DecoratedServiceCompletionProvider;
13+
import fr.adrienbrault.idea.symfony2plugin.config.component.parser.ParameterLookupPercentElement;
14+
import fr.adrienbrault.idea.symfony2plugin.dic.ContainerParameter;
15+
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
16+
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
17+
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
1118
import org.jetbrains.annotations.NotNull;
1219
import org.jetbrains.annotations.Nullable;
1320

21+
import java.util.ArrayList;
22+
import java.util.Collection;
23+
import java.util.Collections;
24+
import java.util.List;
25+
1426
/**
15-
* Registers service-id completion for PHP array `decorates` and `parent` values, eg:
16-
* `'decorates' => 'mailer'`
17-
* `'parent' => 'app.abstract_mailer'`
27+
* Registers completion/navigation for PHP array service config values.
1828
*/
1929
public class PhpArrayGotoCompletionRegistrar implements GotoCompletionRegistrar {
2030
@Override
@@ -34,6 +44,27 @@ public void register(@NotNull GotoCompletionRegistrarParameter registrar) {
3444
return new DecoratesParentContributor(stringLiteralExpression);
3545
}
3646
);
47+
48+
registrar.register(
49+
PlatformPatterns.psiElement().withParent(StringLiteralExpression.class).withLanguage(PhpLanguage.INSTANCE),
50+
psiElement -> {
51+
if (!(psiElement.getParent() instanceof StringLiteralExpression stringLiteralExpression)) {
52+
return null;
53+
}
54+
55+
PhpArrayServiceUtil.ServiceConfigPath keyPath = PhpArrayServiceUtil.getKeyPath(stringLiteralExpression);
56+
if (keyPath == null || !keyPath.isArgument()) {
57+
return null;
58+
}
59+
60+
String contents = stringLiteralExpression.getContents();
61+
if (!contents.isBlank() && !contents.startsWith("%")) {
62+
return null;
63+
}
64+
65+
return new ParameterArgumentContributor(stringLiteralExpression);
66+
}
67+
);
3768
}
3869

3970
private static class DecoratesParentContributor extends DecoratedServiceCompletionProvider {
@@ -53,4 +84,33 @@ public String findIdForElement(@NotNull PsiElement psiElement) {
5384
return PhpArrayServiceUtil.getServiceId(psiElement);
5485
}
5586
}
87+
88+
private static class ParameterArgumentContributor extends GotoCompletionProvider {
89+
private ParameterArgumentContributor(@NotNull StringLiteralExpression element) {
90+
super(element);
91+
}
92+
93+
@NotNull
94+
@Override
95+
public Collection<LookupElement> getLookupElements() {
96+
List<LookupElement> results = new ArrayList<>();
97+
98+
for (ContainerParameter containerParameter : ContainerCollectionResolver.getParameters(getProject()).values()) {
99+
results.add(new ParameterLookupPercentElement(containerParameter));
100+
}
101+
102+
return results;
103+
}
104+
105+
@NotNull
106+
@Override
107+
public Collection<PsiElement> getPsiTargets(PsiElement element) {
108+
String parameterName = GotoCompletionUtil.getStringLiteralValue(element);
109+
if (parameterName == null || !YamlHelper.isValidParameterName(parameterName)) {
110+
return Collections.emptyList();
111+
}
112+
113+
return ServiceUtil.getServiceClassTargets(element.getProject(), parameterName);
114+
}
115+
}
56116
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/php/PhpArrayGotoCompletionRegistrarTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public void setUp() throws Exception {
1212
super.setUp();
1313
myFixture.addFileToProject("src/Service/Mailer.php", "<?php\nnamespace App\\Service;\nclass Mailer {}\n");
1414
myFixture.addFileToProject("src/Service/DecoratingMailer.php", "<?php\nnamespace App\\Service;\nclass DecoratingMailer extends Mailer {}\n");
15+
myFixture.addFileToProject("config/parameters.yaml", "parameters:\n mailer.transport: smtp\n");
1516
myFixture.addFileToProject("config/php_array_targets.php", "<?php\nnamespace Symfony\\Component\\DependencyInjection\\Loader\\Configurator;\nreturn App::config([\n 'services' => [\n 'app.mailer' => ['class' => \\App\\Service\\Mailer::class],\n ],\n]);\n");
1617
}
1718

@@ -65,4 +66,66 @@ public void testDecoratesCompletionPrioritizesMatchingService() {
6566
lookupElement -> "app.mailer".equals(lookupElement.getItemText()) && lookupElement.isItemTextBold()
6667
);
6768
}
69+
70+
public void testArgumentsParameterCompletion() {
71+
assertCompletionContains(
72+
PhpFileType.INSTANCE,
73+
"<?php\n" +
74+
"namespace Symfony\\Component\\DependencyInjection\\Loader\\Configurator;\n" +
75+
"return [\n" +
76+
" 'services' => [\n" +
77+
" 'app.foo' => [\n" +
78+
" 'arguments' => ['%<caret>'],\n" +
79+
" ],\n" +
80+
" ],\n" +
81+
"];",
82+
"%mailer.transport%"
83+
);
84+
}
85+
86+
public void testCallsArgumentParameterCompletion() {
87+
assertCompletionContains(
88+
PhpFileType.INSTANCE,
89+
"<?php\n" +
90+
"namespace Symfony\\Component\\DependencyInjection\\Loader\\Configurator;\n" +
91+
"return [\n" +
92+
" 'services' => [\n" +
93+
" 'app.foo' => [\n" +
94+
" 'calls' => [['setTransport', ['%<caret>']]],\n" +
95+
" ],\n" +
96+
" ],\n" +
97+
"];",
98+
"%mailer.transport%"
99+
);
100+
}
101+
102+
public void testArgumentsParameterNavigation() {
103+
assertNavigationMatch(
104+
PhpFileType.INSTANCE,
105+
"<?php\n" +
106+
"namespace Symfony\\Component\\DependencyInjection\\Loader\\Configurator;\n" +
107+
"return [\n" +
108+
" 'services' => [\n" +
109+
" 'app.foo' => [\n" +
110+
" 'arguments' => ['%mailer.trans<caret>port%'],\n" +
111+
" ],\n" +
112+
" ],\n" +
113+
"];"
114+
);
115+
}
116+
117+
public void testCallsArgumentParameterNavigation() {
118+
assertNavigationMatch(
119+
PhpFileType.INSTANCE,
120+
"<?php\n" +
121+
"namespace Symfony\\Component\\DependencyInjection\\Loader\\Configurator;\n" +
122+
"return [\n" +
123+
" 'services' => [\n" +
124+
" 'app.foo' => [\n" +
125+
" 'calls' => [['setTransport', ['%mailer.trans<caret>port%']]],\n" +
126+
" ],\n" +
127+
" ],\n" +
128+
"];"
129+
);
130+
}
68131
}

0 commit comments

Comments
 (0)