Skip to content

Commit 5ebb467

Browse files
author
Vitaliy Boyko
committed
247: Implemented ACL resource title inspection
1 parent 3bf5106 commit 5ebb467

File tree

11 files changed

+345
-8
lines changed

11 files changed

+345
-8
lines changed

resources/META-INF/plugin.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.TestNameIndex" />
114114
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.RequireJsIndex" />
115115
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex" />
116+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.xml.AclResourceIndex" />
116117

117118
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.linemarker.php.PluginLineMarkerProvider"/>
118119
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.linemarker.php.PluginTargetLineMarkerProvider"/>
@@ -166,6 +167,13 @@
166167
enabledByDefault="true" level="ERROR"
167168
implementationClass="com.magento.idea.magento2plugin.inspections.xml.ModuleDeclarationInModuleXmlInspection"/>
168169

170+
<localInspection language="XML" groupPath="XML"
171+
shortName="AclResourceXmlInspection"
172+
displayName="Inspection for the Title XML required attribute in the `etc/acl.xml` file"
173+
groupName="Magento 2"
174+
enabledByDefault="true" level="ERROR"
175+
implementationClass="com.magento.idea.magento2plugin.inspections.xml.AclResourceXmlInspection"/>
176+
169177
<libraryRoot id=".phpstorm.meta.php" path=".phpstorm.meta.php/" runtime="false"/>
170178

171179
<internalFileTemplate name="Magento Module Composer"/>

resources/magento2/inspection.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ inspection.observer.duplicateInOtherPlaces=The observer name "{0}" for event "{1
1616
inspection.cache.disabledCache=Cacheable false attribute on the default layout will disable cache site-wide
1717
inspection.moduleDeclaration.warning.wrongModuleName=Provided module name "{0}" does not match expected "{1}"
1818
inspection.moduleDeclaration.fix=Fix module name
19+
inspection.aclResource.error.missingAttribute=Attribute "{0}" is required
20+
inspection.aclResource.error.idAttributeCanNotBeEmpty=Attribute value "{0}" can not be empty

src/com/magento/idea/magento2plugin/indexes/IndexManager.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,39 @@
22
* Copyright © Magento, Inc. All rights reserved.
33
* See COPYING.txt for license details.
44
*/
5+
56
package com.magento.idea.magento2plugin.indexes;
67

78
import com.intellij.util.indexing.FileBasedIndexImpl;
89
import com.intellij.util.indexing.ID;
9-
import com.magento.idea.magento2plugin.stubs.indexes.*;
10+
import com.magento.idea.magento2plugin.stubs.indexes.BlockNameIndex;
11+
import com.magento.idea.magento2plugin.stubs.indexes.ContainerNameIndex;
12+
import com.magento.idea.magento2plugin.stubs.indexes.EventNameIndex;
13+
import com.magento.idea.magento2plugin.stubs.indexes.EventObserverIndex;
14+
import com.magento.idea.magento2plugin.stubs.indexes.ModuleNameIndex;
15+
import com.magento.idea.magento2plugin.stubs.indexes.ModulePackageIndex;
1016
import com.magento.idea.magento2plugin.stubs.indexes.PluginIndex;
17+
import com.magento.idea.magento2plugin.stubs.indexes.VirtualTypeIndex;
18+
import com.magento.idea.magento2plugin.stubs.indexes.WebApiTypeIndex;
19+
import com.magento.idea.magento2plugin.stubs.indexes.graphql.GraphQlResolverIndex;
1120
import com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex;
1221
import com.magento.idea.magento2plugin.stubs.indexes.js.RequireJsIndex;
13-
import com.magento.idea.magento2plugin.stubs.indexes.graphql.GraphQlResolverIndex;
14-
import com.magento.idea.magento2plugin.stubs.indexes.mftf.*;
22+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.ActionGroupIndex;
23+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.DataIndex;
24+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.PageIndex;
25+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.SectionIndex;
26+
import com.magento.idea.magento2plugin.stubs.indexes.mftf.TestNameIndex;
27+
import com.magento.idea.magento2plugin.stubs.indexes.xml.AclResourceIndex;
1528
import com.magento.idea.magento2plugin.stubs.indexes.xml.PhpClassNameIndex;
1629

30+
@SuppressWarnings({"PMD.ClassNamingConventions", "PMD.UseUtilityClass"})
1731
public class IndexManager {
32+
33+
/**
34+
* Refresh Magento 2 indexes.
35+
*/
1836
public static void manualReindex() {
19-
ID<?, ?>[] indexIds = new ID<?, ?>[] {
37+
final ID<?, ?>[] indexIds = new ID<?, ?>[] {//NOPMD
2038
// php
2139
ModulePackageIndex.KEY,
2240
// xml|di configuration
@@ -32,6 +50,8 @@ public static void manualReindex() {
3250
WebApiTypeIndex.KEY,
3351
ModuleNameIndex.KEY,
3452
PhpClassNameIndex.KEY,
53+
//acl
54+
AclResourceIndex.KEY,
3555
//require_js
3656
RequireJsIndex.KEY,
3757
MagentoLibJsIndex.KEY,
@@ -41,15 +61,15 @@ public static void manualReindex() {
4161
PageIndex.KEY,
4262
SectionIndex.KEY,
4363
TestNameIndex.KEY,
44-
//graphql
64+
//graphql
4565
GraphQlResolverIndex.KEY
4666
};
4767

48-
for (ID<?, ?> id: indexIds) {
68+
for (final ID<?, ?> id: indexIds) {
4969
try {
5070
FileBasedIndexImpl.getInstance().requestRebuild(id);
51-
FileBasedIndexImpl.getInstance().scheduleRebuild(id, new Throwable());
52-
} catch (NullPointerException exception) {
71+
FileBasedIndexImpl.getInstance().scheduleRebuild(id, new Throwable());//NOPMD
72+
} catch (NullPointerException exception) { //NOPMD
5373
//that's fine, indexer is not present in map java.util.Map.get
5474
}
5575
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.inspections.xml;
7+
8+
import com.intellij.codeInspection.ProblemHighlightType;
9+
import com.intellij.codeInspection.ProblemsHolder;
10+
import com.intellij.codeInspection.XmlSuppressableInspectionTool;
11+
import com.intellij.psi.PsiElementVisitor;
12+
import com.intellij.psi.PsiFile;
13+
import com.intellij.psi.XmlElementVisitor;
14+
import com.intellij.psi.search.GlobalSearchScope;
15+
import com.intellij.psi.xml.XmlAttribute;
16+
import com.intellij.psi.xml.XmlTag;
17+
import com.intellij.util.indexing.FileBasedIndex;
18+
import com.magento.idea.magento2plugin.bundles.InspectionBundle;
19+
import com.magento.idea.magento2plugin.magento.files.ModuleAclXml;
20+
import com.magento.idea.magento2plugin.stubs.indexes.xml.AclResourceIndex;
21+
import java.util.List;
22+
import org.jetbrains.annotations.NotNull;
23+
24+
public class AclResourceXmlInspection extends XmlSuppressableInspectionTool {
25+
26+
@NotNull
27+
@Override
28+
public PsiElementVisitor buildVisitor(
29+
final @NotNull ProblemsHolder problemsHolder,
30+
final boolean isOnTheFly
31+
) {
32+
return new XmlElementVisitor() {
33+
private final InspectionBundle inspectionBundle = new InspectionBundle();
34+
35+
@Override
36+
public void visitXmlTag(final XmlTag xmlTag) {
37+
final PsiFile file = xmlTag.getContainingFile();
38+
final String filename = file.getName();
39+
if (!filename.equals(ModuleAclXml.FILE_NAME)) {
40+
return;
41+
}
42+
43+
if (!xmlTag.getName().equals(ModuleAclXml.XML_TAG_RESOURCE)) {
44+
return;
45+
}
46+
47+
final XmlAttribute identifier = xmlTag.getAttribute(ModuleAclXml.XML_ATTR_ID);
48+
if (identifier == null) {
49+
//should be handled by schema
50+
return;
51+
}
52+
53+
final String idValue = identifier.getValue();
54+
if (idValue == null || idValue.isEmpty()) {
55+
problemsHolder.registerProblem(
56+
identifier,
57+
inspectionBundle.message(
58+
"inspection.aclResource.error.idAttributeCanNotBeEmpty",
59+
"id"
60+
),
61+
ProblemHighlightType.WARNING
62+
);
63+
return;
64+
}
65+
66+
final XmlAttribute title = xmlTag.getAttribute(ModuleAclXml.XML_ATTR_TITLE);
67+
if (title != null && title.getValue() != null) {
68+
return;
69+
}
70+
71+
final List<String> titles =
72+
FileBasedIndex.getInstance().getValues(
73+
AclResourceIndex.KEY,
74+
idValue,
75+
GlobalSearchScope.allScope(file.getProject()
76+
)
77+
);
78+
79+
if (titles.isEmpty()) {
80+
problemsHolder.registerProblem(
81+
identifier,
82+
inspectionBundle.message(
83+
"inspection.aclResource.error.missingAttribute",
84+
"title"
85+
),
86+
ProblemHighlightType.WARNING
87+
);
88+
}
89+
}
90+
};
91+
}
92+
}

src/com/magento/idea/magento2plugin/magento/files/ModuleAclXml.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
* Copyright © Magento, Inc. All rights reserved.
33
* See COPYING.txt for license details.
44
*/
5+
56
package com.magento.idea.magento2plugin.magento.files;
67

78
public class ModuleAclXml {
89
public static String XML_ATTR_ID = "id";
10+
public static String XML_ATTR_TITLE = "title";
11+
public static String XML_TAG_RESOURCE = "resource";
12+
public static String XML_TAG_RESOURCES = "resources";
13+
public static String XML_TAG_ACL = "acl";
914
public static String FILE_NAME = "acl.xml";
1015
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.stubs.indexes.xml;
7+
8+
import com.intellij.ide.highlighter.XmlFileType;
9+
import com.intellij.psi.PsiFile;
10+
import com.intellij.psi.xml.XmlDocument;
11+
import com.intellij.psi.xml.XmlFile;
12+
import com.intellij.psi.xml.XmlTag;
13+
import com.intellij.util.indexing.DataIndexer;
14+
import com.intellij.util.indexing.FileBasedIndex;
15+
import com.intellij.util.indexing.FileBasedIndexExtension;
16+
import com.intellij.util.indexing.FileContent;
17+
import com.intellij.util.indexing.ID;
18+
import com.intellij.util.io.DataExternalizer;
19+
import com.intellij.util.io.EnumeratorStringDescriptor;
20+
import com.intellij.util.io.KeyDescriptor;
21+
import com.intellij.util.xml.impl.DomApplicationComponent;
22+
import com.magento.idea.magento2plugin.magento.files.ModuleAclXml;
23+
import com.magento.idea.magento2plugin.project.Settings;
24+
import gnu.trove.THashMap;
25+
import java.util.Map;
26+
import org.jetbrains.annotations.NotNull;
27+
28+
public class AclResourceIndex extends FileBasedIndexExtension<String, String> {
29+
public static final ID<String, String> KEY = ID.create(
30+
"com.magento.idea.magento2plugin.stubs.indexes.acl_resources");
31+
private final KeyDescriptor<String> myKeyDescriptor = new EnumeratorStringDescriptor();
32+
33+
@NotNull
34+
@Override
35+
public DataIndexer<String, String, FileContent> getIndexer() {
36+
return inputData -> {
37+
final Map<String, String> map = new THashMap<>();//NOPMD
38+
final PsiFile psiFile = inputData.getPsiFile();
39+
if (!Settings.isEnabled(psiFile.getProject())) {
40+
return map;
41+
}
42+
43+
if (psiFile instanceof XmlFile) {
44+
final XmlDocument xmlDocument = ((XmlFile) psiFile).getDocument();
45+
if (xmlDocument != null) {
46+
final XmlTag xmlRootTag = xmlDocument.getRootTag();
47+
if (xmlRootTag != null) { //NOPMD
48+
parseRootTag(map, xmlRootTag);
49+
}
50+
}
51+
}
52+
return map;
53+
};
54+
}
55+
56+
protected void parseRootTag(final Map<String, String> map, final XmlTag xmlRootTag) {
57+
for (final XmlTag aclTag : xmlRootTag.findSubTags(ModuleAclXml.XML_TAG_ACL)) {
58+
for (final XmlTag resourcesTag : aclTag.findSubTags(ModuleAclXml.XML_TAG_RESOURCES)) {
59+
parseResourceTag(map, resourcesTag);
60+
}
61+
}
62+
}
63+
64+
private void parseResourceTag(final Map<String, String> map, final XmlTag resourcesTag) {
65+
for (final XmlTag resourceTag : resourcesTag.findSubTags(ModuleAclXml.XML_TAG_RESOURCE)) {
66+
final String identifier = resourceTag.getAttributeValue(ModuleAclXml.XML_ATTR_ID);
67+
final String title = resourceTag.getAttributeValue(ModuleAclXml.XML_ATTR_TITLE);
68+
69+
if (identifier != null && title != null && !identifier.isEmpty()
70+
&& !title.isEmpty()) {
71+
map.put(identifier, title);
72+
}
73+
74+
parseResourceTag(map, resourceTag);
75+
}
76+
}
77+
78+
@NotNull
79+
@Override
80+
public ID<String, String> getName() {
81+
return KEY;
82+
}
83+
84+
@NotNull
85+
@Override
86+
public KeyDescriptor<String> getKeyDescriptor() {
87+
return this.myKeyDescriptor;
88+
}
89+
90+
@NotNull
91+
@Override
92+
public DataExternalizer<String> getValueExternalizer() {
93+
return EnumeratorStringDescriptor.INSTANCE;
94+
}
95+
96+
@NotNull
97+
@Override
98+
public FileBasedIndex.InputFilter getInputFilter() {
99+
return file ->
100+
file.getFileType() == XmlFileType.INSTANCE
101+
&& file.getName().equalsIgnoreCase(ModuleAclXml.FILE_NAME);
102+
}
103+
104+
@Override
105+
public boolean dependsOnFileContent() {
106+
return true;
107+
}
108+
109+
@Override
110+
public int getVersion() {
111+
return DomApplicationComponent.getInstance().getCumulativeVersion(false);
112+
}
113+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0"?>
2+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
3+
<acl>
4+
<resources>
5+
<resource id="" />
6+
</resources>
7+
</acl>
8+
</config>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0"?>
2+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
3+
<acl>
4+
<resources>
5+
<resource id="Unique_Acl::resource" />
6+
</resources>
7+
</acl>
8+
</config>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0"?>
2+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
3+
<acl>
4+
<resources>
5+
<!-- Override existing resource in the project -->
6+
<resource id="Magento_Catalog::test" />
7+
</resources>
8+
</acl>
9+
</config>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0"?>
2+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
3+
<acl>
4+
<resources>
5+
<resource id="Magento_Catalog::test" title="Test Resource"/>
6+
</resources>
7+
</acl>
8+
</config>

0 commit comments

Comments
 (0)