1515import com .intellij .psi .search .GlobalSearchScope ;
1616import com .intellij .psi .util .PsiTreeUtil ;
1717import com .intellij .util .indexing .FileBasedIndex ;
18- import com .jetbrains .php .PhpIndex ;
1918import com .jetbrains .php .lang .psi .elements .Method ;
2019import com .jetbrains .php .lang .psi .elements .PhpClass ;
2120import com .magento .idea .magento2plugin .linemarker .SearchGutterIconNavigationHandler ;
21+ import com .magento .idea .magento2plugin .linemarker .php .data .PluginMethodData ;
2222import com .magento .idea .magento2plugin .project .Settings ;
2323import com .magento .idea .magento2plugin .stubs .indexes .PluginIndex ;
24+ import com .magento .idea .magento2plugin .stubs .indexes .data .PluginData ;
2425import java .util .ArrayList ;
2526import java .util .Collection ;
2627import java .util .HashMap ;
@@ -94,12 +95,13 @@ public void collectSlowLineMarkers(
9495 }
9596 }
9697
98+ @ SuppressWarnings ("checkstyle:LineLength" )
9799 private static class PluginClassCache {
98100
99- private final Map <String , List <PhpClass >> classPluginsMap = new HashMap <>();
101+ private final Map <String , List <PluginData >> classPluginsMap = new HashMap <>();
100102
101- public List <PhpClass > getPluginsForClass (final @ NotNull PhpClass phpClass ) {
102- final List <PhpClass > pluginsForClass = getPluginsForClass (
103+ public List <PluginData > getPluginsForClass (final @ NotNull PhpClass phpClass ) {
104+ final List <PluginData > pluginsForClass = getPluginsForClass (
103105 phpClass ,
104106 phpClass .getPresentableFQN ()
105107 );
@@ -114,64 +116,73 @@ public List<PhpClass> getPluginsForClass(final @NotNull PhpClass phpClass) {
114116 return pluginsForClass ;
115117 }
116118
117- public List <PhpClass > getPluginsForClass (
119+ public List <PluginData > getPluginsForClass (
118120 final @ NotNull PhpClass phpClass ,
119121 final @ NotNull String classFQN
120122 ) {
121123 if (classPluginsMap .containsKey (classFQN )) {
122124 return classPluginsMap .get (classFQN );
123125 }
124126
125- final List <Set <String >> plugins = FileBasedIndex .getInstance ()
127+ final List <Set <PluginData >> plugins = FileBasedIndex .getInstance ()
126128 .getValues (
127129 PluginIndex .KEY ,
128130 classFQN ,
129131 GlobalSearchScope .allScope (phpClass .getProject ())
130132 );
131- final List <PhpClass > results = new ArrayList <>();
133+ final List <PluginData > results = new ArrayList <>();
132134
133135 if (plugins .isEmpty ()) {
134136 classPluginsMap .put (classFQN , results );
135137
136138 return results ;
137139 }
138- final PhpIndex phpIndex = PhpIndex .getInstance (phpClass .getProject ());
139140
140- for (final Set <String > pluginClassNames : plugins ) {
141- for (final String pluginClassName : pluginClassNames ) {
142- results .addAll (phpIndex .getClassesByFQN (pluginClassName ));
141+ for (final Set <PluginData > pluginDataList : plugins ) {
142+ for (final PluginData pluginData : pluginDataList ) {
143+ pluginData .setPhpClass (phpClass );
144+ results .add (pluginData );
143145 }
144146 }
145147 classPluginsMap .put (classFQN , results );
146148
147149 return results ;
148150 }
149151
150- public List <Method > getPluginMethods (final List <PhpClass > plugins ) {
151- final List <Method > methodList = new ArrayList <>();
152+ public List <PluginMethodData > getPluginMethods (final List <PluginData > pluginDataList ) {
153+ final List <PluginMethodData > result = new ArrayList <>();
152154
153- for (final PhpClass plugin : plugins ) {
154- methodList .addAll (getPluginMethods (plugin ));
155+ for (final PluginData pluginData : pluginDataList ) {
156+ for (final PhpClass plugin : pluginData .getPhpClassCollection ()) {
157+ //@todo add module sequence ID if sortOrder equal zero. It should be negative value.
158+ result .addAll (getPluginMethods (plugin , pluginData .getSortOrder ()));
159+ }
155160 }
156161
157- return methodList ;
162+ return result ;
158163 }
159164
160- public List <Method > getPluginMethods (final @ NotNull PhpClass pluginClass ) {
161- final List <Method > methodList = new ArrayList <>();
165+ public List <PluginMethodData > getPluginMethods (final @ NotNull PhpClass pluginClass , final int sortOrder ) {
166+ final List <PluginMethodData > methodList = new ArrayList <>();
162167
163168 for (final Method method : pluginClass .getMethods ()) {
164169 if (method .getAccess ().isPublic ()) {
165170 final String pluginMethodName = method .getName ();
166171
167172 if (pluginMethodName .length () > MIN_PLUGIN_METHOD_NAME_LENGTH ) {
168- methodList .add (method );
173+ //@todo module sequence value should be set here instead of zero.
174+ methodList .add (getPluginMethodDataObject (method , sortOrder , 0 ));
169175 }
170176 }
171177 }
172178
173179 return methodList ;
174180 }
181+
182+ @ NotNull
183+ private PluginMethodData getPluginMethodDataObject (final Method method , final int sortOrder , final int moduleSequence ) {
184+ return new PluginMethodData (method , sortOrder , moduleSequence );
185+ }
175186 }
176187
177188 private static class ClassPluginCollector implements Collector <PhpClass , PhpClass > {
@@ -186,41 +197,134 @@ public ClassPluginCollector(
186197
187198 @ Override
188199 public List <PhpClass > collect (final @ NotNull PhpClass psiElement ) {
189- return pluginClassCache .getPluginsForClass (psiElement );
200+ final List <PluginData > pluginDataList = pluginClassCache .getPluginsForClass (psiElement );
201+ final List <PhpClass > phpClassList = new ArrayList <>();
202+
203+ for (final PluginData pluginData : pluginDataList ) {
204+ phpClassList .addAll (pluginData .getPhpClassCollection ());
205+ }
206+
207+ return phpClassList ;
190208 }
191209 }
192210
193211 private static class MethodPluginCollector implements Collector <Method , Method > {
194212
195213 private final PluginLineMarkerProvider .PluginClassCache pluginClassCache ;
214+ private final Map <String , Integer > pluginMethodsSortOrder ;
215+ private static final String AFTER_PLUGIN_PREFIX = "after" ;
196216
197217 public MethodPluginCollector (
198218 final PluginLineMarkerProvider .PluginClassCache pluginClassCache
199219 ) {
200220 this .pluginClassCache = pluginClassCache ;
221+ pluginMethodsSortOrder = new HashMap <>();
222+ pluginMethodsSortOrder .put ("before" , 1 );
223+ pluginMethodsSortOrder .put ("around" , 2 );
224+ pluginMethodsSortOrder .put (AFTER_PLUGIN_PREFIX , 3 );
201225 }
202226
227+ @ SuppressWarnings ("checkstyle:LineLength" )
203228 @ Override
204229 public List <Method > collect (final @ NotNull Method psiElement ) {
205230 final List <Method > results = new ArrayList <>();
206-
207231 final PhpClass methodClass = psiElement .getContainingClass ();
208232
209233 if (methodClass == null ) {
210234 return results ;
211235 }
212- final List <PhpClass > pluginsList = pluginClassCache .getPluginsForClass (methodClass );
213- final List <Method > pluginMethods = pluginClassCache .getPluginMethods (pluginsList );
214236
237+ final List <PluginData > pluginDataList = pluginClassCache .getPluginsForClass (methodClass );
238+ final List <PluginMethodData > pluginMethods = pluginClassCache .getPluginMethods (pluginDataList );
215239 final String classMethodName = WordUtils .capitalize (psiElement .getName ());
216240
217- for (final Method pluginMethod : pluginMethods ) {
218- if (isPluginMethodName (pluginMethod .getName (), classMethodName )) {
219- results .add (pluginMethod );
241+ pluginMethods .removeIf (pluginMethod -> !isPluginMethodName (pluginMethod .getMethodName (), classMethodName ));
242+ sortMethods (pluginMethods , results );
243+
244+ return results ;
245+ }
246+
247+ @ SuppressWarnings ({"checkstyle:Indentation" , "checkstyle:OperatorWrap" , "checkstyle:LineLength" , "PMD.NPathComplexity" })
248+ private void sortMethods (final @ NotNull List <PluginMethodData > methodDataList , final List <Method > results ) {
249+ final List <Integer > bufferSortOrderList = new ArrayList <>();
250+ int biggestSortOrder = 0 ;
251+
252+ for (final PluginMethodData pluginMethodData : methodDataList ) {
253+ final String methodName = pluginMethodData .getMethodName ();
254+
255+ if (methodName .startsWith ("around" )) {
256+ bufferSortOrderList .add (pluginMethodData .getSortOrder ());
257+ }
258+
259+ if (pluginMethodData .getSortOrder () > biggestSortOrder ) {
260+ biggestSortOrder = pluginMethodData .getSortOrder ();
220261 }
221262 }
222263
223- return results ;
264+ final int biggestSortOrderValue = biggestSortOrder ;
265+
266+ methodDataList .sort (
267+ (PluginMethodData method1 , PluginMethodData method2 ) -> {
268+ final String firstMethodName = method1 .getMethodName ();
269+ final String secondMethodName = method2 .getMethodName ();
270+ final int firstIndexEnd = firstMethodName .startsWith (AFTER_PLUGIN_PREFIX ) ? 5 : 6 ;
271+ final int secondIndexEnd = secondMethodName .startsWith (AFTER_PLUGIN_PREFIX ) ? 5 : 6 ;
272+ final String firstMethodPrefix = firstMethodName .substring (0 ,firstIndexEnd );
273+ final String secondMethodPrefix = secondMethodName .substring (0 ,secondIndexEnd );
274+
275+ if (!pluginMethodsSortOrder .containsKey (firstMethodPrefix )
276+ || !pluginMethodsSortOrder .containsKey (secondMethodPrefix )) {
277+ return firstMethodName .compareTo (secondMethodName );
278+ }
279+
280+ final Integer firstNameSortOrder = pluginMethodsSortOrder .get (firstMethodPrefix );
281+ final Integer secondNameSortOrder = pluginMethodsSortOrder .get (secondMethodPrefix );
282+
283+ if (firstNameSortOrder .compareTo (secondNameSortOrder ) != 0 ) {
284+ return firstNameSortOrder .compareTo (secondNameSortOrder );
285+ }
286+
287+ Integer firstBuffer = 0 ;
288+ Integer secondBuffer = 0 ;
289+ final Integer firstModuleSequence = (method1 .getModuleSequence () + biggestSortOrderValue ) * -1 ;
290+ final Integer secondModuleSequence = (method2 .getModuleSequence () + biggestSortOrderValue ) * -1 ;
291+ final Integer firstSortOrder = method1 .getSortOrder () == 0 ?
292+ firstModuleSequence :
293+ method1 .getSortOrder ();
294+ final Integer secondSortOrder = method2 .getSortOrder () == 0 ?
295+ secondModuleSequence :
296+ method2 .getSortOrder ();
297+
298+ if (!bufferSortOrderList .isEmpty () && firstMethodPrefix .equals (AFTER_PLUGIN_PREFIX )) {
299+ for (final Integer bufferSortOrder : bufferSortOrderList ) {
300+ if (bufferSortOrder < firstSortOrder && firstBuffer < bufferSortOrder + 1 ) {
301+ firstBuffer = bufferSortOrder + 1 ;
302+ }
303+
304+ if (bufferSortOrder < secondSortOrder && secondBuffer < bufferSortOrder + 1 ) {
305+ secondBuffer = bufferSortOrder + 1 ;
306+ }
307+ }
308+ }
309+
310+ firstBuffer = firstBuffer .equals (0 ) ? firstSortOrder : firstBuffer * -1 ;
311+ secondBuffer = secondBuffer .equals (0 ) ? secondSortOrder : secondBuffer * -1 ;
312+
313+ if (firstBuffer .compareTo (secondBuffer ) == 0 && firstSortOrder .compareTo (secondSortOrder ) != 0 ) {
314+ return firstSortOrder .compareTo (secondSortOrder );
315+ }
316+
317+ if (firstBuffer .compareTo (secondBuffer ) == 0 && firstSortOrder .compareTo (secondSortOrder ) == 0 ) {
318+ return firstModuleSequence .compareTo (secondModuleSequence );
319+ }
320+
321+ return firstBuffer .compareTo (secondBuffer );
322+ }
323+ );
324+
325+ for (final PluginMethodData pluginMethodData : methodDataList ) {
326+ results .add (pluginMethodData .getMethod ());
327+ }
224328 }
225329
226330 private boolean isPluginMethodName (
0 commit comments