/******************************************************************************* * This file is part of the Symfony eclipse plugin. * * (c) Robert Gruendler <r.gruendler@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. ******************************************************************************/ package com.dubture.symfony.core.model; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.core.internal.resources.Project; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.references.SimpleReference; import org.eclipse.dltk.core.IMethod; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.INamespace; import org.eclipse.dltk.core.IScriptFolder; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.core.SourceParserUtil; import org.eclipse.dltk.core.index2.IElementResolver; import org.eclipse.dltk.core.index2.search.ISearchEngine; import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule; import org.eclipse.dltk.core.index2.search.ISearchEngine.SearchFor; import org.eclipse.dltk.core.index2.search.ISearchRequestor; import org.eclipse.dltk.core.index2.search.ModelAccess; import org.eclipse.dltk.core.search.IDLTKSearchScope; import org.eclipse.dltk.core.search.SearchEngine; import org.eclipse.dltk.internal.core.ScriptFolder; import org.eclipse.dltk.internal.core.ScriptProject; import org.eclipse.dltk.internal.core.util.LRUCache; import org.eclipse.php.internal.core.PHPLanguageToolkit; import org.eclipse.php.core.compiler.ast.nodes.NamespaceDeclaration; import org.eclipse.php.core.compiler.ast.nodes.PHPDocBlock; import org.eclipse.php.core.compiler.ast.nodes.PHPDocTag; import org.eclipse.php.core.compiler.ast.nodes.PHPMethodDeclaration; import org.eclipse.php.core.compiler.ast.visitor.PHPASTVisitor; import org.eclipse.php.internal.core.model.PHPModelAccess; import org.eclipse.php.internal.core.typeinference.IModelAccessCache; import com.dubture.symfony.core.SymfonyLanguageToolkit; import com.dubture.symfony.core.index.SymfonyElementResolver.TemplateField; import com.dubture.symfony.core.log.Logger; import com.dubture.symfony.core.preferences.SymfonyCoreConstants; import com.dubture.symfony.core.util.JsonUtils; import com.dubture.symfony.core.util.ModelUtils; import com.dubture.symfony.core.util.PathUtils; import com.dubture.symfony.index.SymfonyIndexer; import com.dubture.symfony.index.handler.IServiceHandler; import com.dubture.symfony.index.handler.ITranslationHandler; import com.dubture.symfony.index.model.Parameter; import com.dubture.symfony.index.model.Route; import com.dubture.symfony.index.model.TransUnit; /** * * The {@link SymfonyModelAccess} is an extension to the * {@link PHPModelAccess} and provides additional helper * methods to find Symfony2 model elements. * * * @author Robert Gruendler <r.gruendler@gmail.com> * */ @SuppressWarnings("restriction") public class SymfonyModelAccess extends PHPModelAccess { private static SymfonyModelAccess modelInstance = null; private SymfonyIndexer index; private Map<Service, IType[]> serviceCache = new HashMap<Service, IType[]>(); private LRUCache controllerCache = new LRUCache(); private LRUCache serviceCache2 = new LRUCache(); private LRUCache entityCache = new LRUCache(); private LRUCache bundleCache = new LRUCache(); private static final String NULL_ENTRY = "$$THIS_IS_NULL_ENTRY$$"; private SymfonyModelAccess() { try { index = SymfonyIndexer.getInstance(); } catch (Exception e) { Logger.logException(e); } } public static SymfonyModelAccess getDefault() { if (modelInstance == null) modelInstance = new SymfonyModelAccess(); return modelInstance; } public TemplateVariable createTemplateVariableByReturnType(ISourceModule sourceModule, PHPMethodDeclaration controllerMethod, SimpleReference callName, String className, String namespace, String variableName) { return createTemplateVariableByReturnType(sourceModule, controllerMethod, callName, className, namespace, variableName, null); } public TemplateVariable createTemplateVariableByReturnType(ISourceModule sourceModule, PHPMethodDeclaration controllerMethod, SimpleReference callName, String className, String namespace, String variableName, IModelAccessCache cache) { IType[] types = null; if (cache != null) { Collection<IType> typesList = cache.getTypes(sourceModule, className, namespace, null); types = typesList.toArray(new IType[typesList.size()]); } else { IDLTKSearchScope scope = createSearchScope(sourceModule); if (scope == null) return null; types = findTypes(namespace, className, MatchRule.EXACT, 0, 0, scope, null); } if (types.length != 1) return null; IType type = types[0]; final IMethod method = type.getMethod(callName.getName()); if (method == null) return null; ModuleDeclaration module = SourceParserUtil.getModuleDeclaration(method.getSourceModule()); ReturnTypeVisitor visitor = new ReturnTypeVisitor(method.getElementName()); try { module.traverse(visitor); } catch (Exception e) { Logger.logException(e); } if (visitor.className == null || visitor.namespace == null) return null; return new TemplateVariable(controllerMethod, variableName, callName.sourceStart(), callName.sourceEnd(), visitor.namespace, visitor.className); } protected IDLTKSearchScope createSearchScope(ISourceModule module) { IScriptProject scriptProject = module.getScriptProject(); if (scriptProject != null) { return SearchEngine.createSearchScope(scriptProject); } return null; } private class ReturnTypeVisitor extends PHPASTVisitor { public String namespace; public String className; private String method; public ReturnTypeVisitor(String method) { this.method = method; } @Override public boolean visit(NamespaceDeclaration s) throws Exception { namespace = s.getName(); return true; } @Override public boolean visit(PHPMethodDeclaration s) throws Exception { if (s.getName().equals(method)) { PHPDocBlock docs = s.getPHPDoc(); PHPDocTag[] returnTags = docs.getTags(PHPDocTag.TagKind.RETURN); if (returnTags.length == 1) { PHPDocTag tag = returnTags[0]; if (tag.getTypeReferences().size() == 1) { SimpleReference ref = tag.getTypeReferences().get(0); className = ref.getName(); return false; } } } return true; } } /** * * Resolve TemplateVariables for a controller. * * * @param controller * @return */ public List<TemplateField> findTemplateVariables(IType controller) { if (controller == null) { return new ArrayList<TemplateField>(); } // create a searchscope for the whole ScriptProject, // as view variables can be declared across controllers IDLTKSearchScope scope = SearchEngine.createSearchScope(controller.getScriptProject()); ISearchEngine engine = ModelAccess.getSearchEngine(SymfonyLanguageToolkit.getDefault()); final List<TemplateField> variables = new ArrayList<TemplateField>(); if (scope == null || engine == null) { return variables; } final IElementResolver resolver = ModelAccess.getElementResolver(SymfonyLanguageToolkit.getDefault()); engine.search(ISymfonyModelElement.TEMPLATE_VARIABLE, null, null, 0, 0, 100, SearchFor.REFERENCES, MatchRule.PREFIX, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { IModelElement element = resolver.resolve(elementType, flags, offset, length, nameOffset, nameLength, elementName, metadata, doc, qualifier, parent, sourceModule); if (element != null) { if (element instanceof TemplateField) variables.add((TemplateField) element); } } }, null); return variables; } /** * Try to find the corresponding controller IType for * a given template. * * @param module * @return */ public IType findControllerByTemplate(ISourceModule module) { // get the name of the Controller to search for String controller = PathUtils.getControllerFromTemplatePath(module.getPath()); if (controller == null) { return null; } // find the type IType types[] = PHPModelAccess.getDefault().findTypes(controller, MatchRule.EXACT, 0, 0, SearchEngine.createSearchScope(module.getScriptProject()), null); // type is ambigous if (types.length != 1) return null; return types[0]; } /** * * * * @param variableName * @param sourceModule * @return */ public TemplateField findTemplateVariableType(String variableName, ISourceModule sourceModule) { // find the corresponding controller for the template IType controller = findControllerByTemplate(sourceModule); if (controller == null) { return null; } // create a searchscope for the Controller class only IDLTKSearchScope scope = SearchEngine.createSearchScope(controller); ISearchEngine engine = ModelAccess.getSearchEngine(SymfonyLanguageToolkit.getDefault()); if (scope == null || engine == null) { return null; } final List<TemplateField> variables = new ArrayList<TemplateField>(); final IElementResolver resolver = ModelAccess.getElementResolver(SymfonyLanguageToolkit.getDefault()); engine.search(ISymfonyModelElement.TEMPLATE_VARIABLE, null, variableName, 0, 0, 100, SearchFor.REFERENCES, MatchRule.EXACT, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { IModelElement element = resolver.resolve(elementType, flags, offset, length, nameOffset, nameLength, elementName, metadata, doc, qualifier, parent, sourceModule); if (element != null && element instanceof TemplateField) { variables.add((TemplateField) element); } } }, null); if (variables.size() > 0) return variables.get(0); return null; } public List<Parameter> findParameters(IScriptProject project) { return index.findParameters(project.getPath()); } /** * * Return a List of all Routes for a given project. * * @param project * @return */ public List<Route> findRoutes(IScriptProject project) { if (index == null) { Logger.log(Logger.ERROR, "The SymfonyIndexer has not been instantiated..."); return new ArrayList<Route>(); } return index.findRoutes(project.getPath()); } /** * Find routes by prefix. * * @param project * @param prefix * @return */ public List<Route> findRoutes(IScriptProject project, String prefix) { if (index == null) { Logger.log(Logger.ERROR, "The SymfonyIndexer has not been instantiated..."); return new ArrayList<Route>(); } return index.findRoutes(project.getPath(), prefix); } /** * * Retrieve all bundles inside a Project. * * @param project * @return */ public List<Bundle> findBundles(IScriptProject project) { IDLTKSearchScope scope = SearchEngine.createSearchScope(project.getScriptProject()); ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit.getDefault()); final List<Bundle> bundles = new ArrayList<Bundle>(); if (scope == null || engine == null) { return bundles; } engine.search(ISymfonyModelElement.BUNDLE, null, null, 0, 0, 100, SearchFor.REFERENCES, MatchRule.PREFIX, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { bundles.add(JsonUtils.unpackBundle(metadata)); } }, null); return bundles; } /** * Finds the {@link ScriptFolder} of corresponding bundle inside the project. * * @param bundle * @param project * @return */ public ScriptFolder findBundleFolder(String bundle, IScriptProject project) { IType bundleType = findBundleType(bundle, project); return (ScriptFolder) bundleType.getSourceModule().getParent(); } public IType findBundleType(String bundle, IScriptProject project) { IDLTKSearchScope scope = SearchEngine.createSearchScope(project); IType[] types = findTypes(bundle, MatchRule.EXACT, 0, 0, scope, null); if (types.length != 1) return null; return types[0]; } /** * * Find all controllers in a given bundle. * * @param bundle * @param project * @return */ public IType[] findBundleControllers(String bundle, IScriptProject project) { ScriptFolder bundleFolder = findBundleFolder(bundle, project); if(bundleFolder == null) return null; ISourceModule controllerSource = bundleFolder.getSourceModule("Controller"); if (controllerSource == null) return null; IDLTKSearchScope controllerScope = SearchEngine.createSearchScope(controllerSource); return findTypes("", MatchRule.PREFIX, 0, 0, controllerScope, null); } public List<IPath> findBundleViewPaths(String bundle, IScriptProject project) { ScriptFolder folder = findBundleFolder(bundle, project); List<IPath> viewPaths = new LinkedList<IPath>(); if (folder == null) { return viewPaths; } try { IResource resource = folder.getUnderlyingResource(); List<IPath> structure = new LinkedList<IPath>(); IPath path = resource.getFullPath(); path = path.removeFirstSegments(1).append("Resources").append("views"); int num = path.segmentCount() + 1; IFolder viewFolder = project.getProject().getFolder(path); getFolderStructure(viewFolder, structure); for (IPath p : structure) { viewPaths.add(p.removeFirstSegments(num)); } } catch (ModelException e) { Logger.logException(e); } catch (CoreException e) { Logger.logException(e); } return viewPaths; } protected List<IPath> getFolderStructure(IFolder folder, List<IPath> structure) throws CoreException { for (IResource child : folder.members()) { if (child instanceof IFolder) { structure.add(child.getFullPath()); getFolderStructure((IFolder) child, structure); } } return structure; } /** * Retrieve templates for a given bundle and controller path inside * the ScriptProject. * * Returns an empty array if nothing found. * * * @param bundle * @param controller * @param project * @return */ public IModelElement[] findTemplates(String bundle, String controller, IScriptProject project) { try { ScriptFolder bundleFolder = findBundleFolder(bundle, project); IPath relative = new Path("Resources/views/" + controller.replace("Controller", "")); IPath path = bundleFolder.getPath().append(relative); IScriptFolder sfolder = project.findScriptFolder(path); if (sfolder != null && sfolder.exists() && sfolder.hasChildren()) { return sfolder.getChildren(); } } catch (Exception e) { Logger.logException(e); } return new IModelElement[] {}; } /** * Check if the {@link ScriptProject} has a PHPMethod * named "method" which accepts viewPaths as parameter. * * @param method * @param project * @return */ public boolean hasViewMethod(final String method, IScriptProject project) { IDLTKSearchScope scope = SearchEngine.createSearchScope(project); ISearchEngine engine = getSearchEngine(PHPLanguageToolkit.getDefault()); if (scope == null || engine == null) { return false; } final List<String> methods = new ArrayList<String>(); engine.search(ISymfonyModelElement.VIEW_METHOD, null, method, 0, 0, 10, SearchFor.REFERENCES, MatchRule.EXACT, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { methods.add(elementName); } }, null); return methods.size() > 0; } /** * Find ITypes of a service * * * @param service * @param project * @return */ public IType[] findServiceTypes(Service service, IScriptProject project) { if (serviceCache.containsKey(service)) return serviceCache.get(service); try { IDLTKSearchScope scope = SearchEngine.createSearchScope(project); String namespace = service.getNamespace() != null ? service.getNamespace().getQualifiedName() : null; IType[] types = findTypes(namespace, service.getClassName(), MatchRule.EXACT, 0, 0, scope, null); serviceCache.put(service, types); return types; } catch (Exception e) { Logger.logException(e); } if (service != null) Logger.debugMSG("No types found for service: " + service.getId()); else Logger.debugMSG("Cannot find service type, service is null"); return new IType[] {}; } public IType findServiceType(Service service, IScriptProject project) { IType[] types = findServiceTypes(service, project); if (types.length > 0) return types[0]; return null; } /** * * @param Retrieve a single service by service id * * * @return */ public Service findService(final String id, IPath path) { if (path == null) { Logger.debugMSG("cannot find service without path: " + id); return null; } String key = id + path.toString(); if (serviceCache2.get(key) != null) { return serviceCache2.get(key) == NULL_ENTRY ? null : (Service) serviceCache2.get(key); } final List<Service> services = new ArrayList<Service>(); if (index == null) { Logger.log(Logger.ERROR, "The SymfonyIndexer has not been instantiated..."); return null; } String pathString = path == null ? "" : path.toString(); index.findService(id, pathString, new IServiceHandler() { @Override public void handle(String id, String phpClass, String path, String _public, String tags) { Service s = new Service(id, phpClass, path, null); s.setTags(tags); s.setPublic(_public); services.add(s); } }); if (services.size() == 1) { Service service = services.get(0); String fqcn = service.getFullyQualifiedName(); if (fqcn.startsWith("alias_")) { String alias = fqcn.substring(fqcn.indexOf("_")+1); Service reference = SymfonyModelAccess.getDefault().findService(alias, service.getPath()); if (reference != null) { serviceCache2.put(key, reference); return reference; } } serviceCache2.put(key, service); return service; } serviceCache2.put(key, NULL_ENTRY); return null; } /** * Return all services of a {@link Project} or null if the * project hasn't been found. * * @param path * @return */ public List<Service> findServices(IPath path) { final List<Service> services = new ArrayList<Service>(); if (index == null) { Logger.log(Logger.ERROR, "The SymfonyIndexer has not been instantiated..."); return null; } index.findServices(path.toString(), new IServiceHandler() { @Override public void handle(String id, String phpClass, String path, String _public, String tags) { Service s = new Service(id, phpClass, path); s.setTags(tags); s.setPublic(_public); if (!services.contains(s)) { services.add(s); } } }); return services; } public List<String> findServiceTags(IPath path) { try { return index.findTags(path); } catch (Exception e) { return null; } } public boolean hasRouteMethod(String method, IScriptProject project) { IDLTKSearchScope scope = SearchEngine.createSearchScope(project); ISearchEngine engine = getSearchEngine(PHPLanguageToolkit.getDefault()); if (scope == null || engine == null) { return false; } final List<String> methods = new ArrayList<String>(); engine.search(ISymfonyModelElement.ROUTE_METHOD, null, method, 0, 0, 10, SearchFor.REFERENCES, MatchRule.EXACT, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { methods.add(elementName); } }, null); return methods.size() > 0; } public Route findRoute(String route, IScriptProject scriptProject) { if (index == null) { Logger.log(Logger.ERROR, "The SymfonyIndexer has not been instantiated..."); return null; } return index.findRoute(route, scriptProject.getPath()); } public IType findController(String bundle, String controller, IScriptProject scriptProject) { String name = scriptProject.getElementName(); String key = bundle + controller + name; if ( (controllerCache.get(key)) != null) { return controllerCache.get(key) == NULL_ENTRY ? null : (IType) controllerCache.get(key); } IType findBundleType = findBundleType(bundle, scriptProject); if (findBundleType == null) { return null; } IModelElement parent = findBundleType.getParent(); StringBuilder ns = new StringBuilder(); if (parent.getElementType() == IModelElement.TYPE) { ns.append(parent.getElementName()); } ScriptFolder bundleFolder = (ScriptFolder) parent.getAncestor(IScriptFolder.class); if(bundleFolder == null) { return null; } ISourceModule controllerSource = bundleFolder.getSourceModule("Controller"); if (controllerSource == null) { return null; } IDLTKSearchScope controllerScope = SearchEngine.createSearchScope(controllerSource); String[] split = controller.split("/"); ns.append("\\Controller"); if (split.length > 1) { for (int i = 0; i + 1 < split.length; i++) { ns.append('\\').append(split[i]); } controller = split[split.length -1]; } IType[] controllers = findTypes(ns.toString(), controller + "Controller", MatchRule.PREFIX, 0, 0, controllerScope, null); if(controllers.length == 1) { controllerCache.put(key, controllers[0]); return controllers[0]; } controllerCache.put(key, NULL_ENTRY); return null; } /** * * Find the templates in the projects' root view path. * * FIXME: find a way to not hardcode the path to app/Resource/views * * @param scriptProject * @return */ public IModelElement[] findRootTemplates(IScriptProject scriptProject) { try { IPath path = scriptProject.getPath().append(new Path("app/Resources/views")); IScriptFolder sfolder = scriptProject.findScriptFolder(path); if (sfolder != null && sfolder.exists() && sfolder.hasChildren()) { return sfolder.getChildren(); } } catch (Exception e) { Logger.logException(e); } return new IModelElement[] {}; } /** * * Return the templates inside the bundles root viewpath: * * Bundle/Resources/views/* * * @param bundle * @param project * @return */ public IModelElement[] findBundleRootTemplates(String bundle, IScriptProject project) { try { ScriptFolder bundleFolder = findBundleFolder(bundle, project); IPath path = new Path("Resources/views/"); IPath viewPath = bundleFolder.getPath().append(path); IScriptFolder sfolder = project.findScriptFolder(viewPath); if (sfolder != null && sfolder.exists() && sfolder.hasChildren()) { return sfolder.getChildren(); } } catch (Exception e) { Logger.logException(e); } return new IModelElement[] {}; } /** * Find the template for the given viewpath. * * * @param viewPath * @param scriptProject * @return */ public IModelElement findTemplate(ViewPath viewPath, IScriptProject project) { try { String bundle = viewPath.getBundle(); String controller = viewPath.getController(); String template = viewPath.getTemplate(); if (viewPath.isRoot()) { IPath path = project.getPath().append(new Path("app/Resources/views")); IScriptFolder sfolder = project.findScriptFolder(path); if (sfolder != null) { return sfolder.getSourceModule(template); } } else if (viewPath.isBundleBasePath()) { ScriptFolder bundleFolder = findBundleFolder(bundle, project); if (bundleFolder == null) return null; IScriptFolder viewFolder = project.findScriptFolder(bundleFolder.getPath().append(new Path("Resources/views"))); if (viewFolder != null) { return viewFolder.getSourceModule(template); } } else { if (bundle == null || controller == null) return null; ScriptFolder bundleFolder = findBundleFolder(bundle, project); IPath path = new Path("Resources/views/" + controller.replace("Controller", "")); IPath iPath = bundleFolder.getPath().append(path); IScriptFolder sfolder = project.findScriptFolder(iPath); if (sfolder != null) { return sfolder.getSourceModule(template); } } } catch (Exception e) { Logger.logException(e); } return null; } /** * Find the corresponding {@link IMethod} to a {@link Route}. * * @param route * @param project * @return */ public IMethod findAction(Route route, IScriptProject project) { ViewPath vPath = new ViewPath(route.getViewPath()); if (!vPath.isValid()) return null; IType type = null; IType[] controllers = findBundleControllers(vPath.getBundle(), project); if (controllers == null) { String msg = "Unable to find bundle controllers "; if (vPath != null) msg += vPath.getBundle(); if (project != null) { msg += " project: " + project.getElementName(); } Logger.debugMSG(msg); return null; } String ctrl = vPath.getController() + "Controller"; for (IType t : controllers) { if (t.getElementName().equals(ctrl)) { type = t; break; } } if (type == null) { return null; } IMethod method = type.getMethod(vPath.getTemplate() + "Action"); if (method != null) return method; return type.getMethod(vPath.getTemplate()); } public String findNameSpace(IScriptProject iScriptProject, final IPath path) { IDLTKSearchScope scope = SearchEngine.createSearchScope(iScriptProject); ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit.getDefault()); if (scope == null || engine == null) { return null; } final List<String> namespaces = new ArrayList<String>(); engine.search(ISymfonyModelElement.NAMESPACE, null, null, 0, 0, 100, SearchFor.REFERENCES, MatchRule.PREFIX, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { if (path != null && path.toString().startsWith(elementName)) { namespaces.add(path.toString().replace(elementName, "")); } } }, null); if (namespaces.size() > 0) { String namespace = namespaces.get(0); if (namespace.startsWith("/")) { namespace = namespace.replaceFirst("/", ""); } return namespace.replace("/", "\\"); } return null; } public List<String> getNameSpaces(IScriptProject project) { IDLTKSearchScope scope = SearchEngine.createSearchScope(project); ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit.getDefault()); final List<String> namespaces = new ArrayList<String>(); if (scope == null || engine == null) { return namespaces; } engine.search(ISymfonyModelElement.NAMESPACE, null, null, 0, 0, 100, SearchFor.REFERENCES, MatchRule.PREFIX, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { namespaces.add(elementName); } }, null); return namespaces; } public IPath resolveBundleShortcut(String string, IScriptProject project) { String bundle = string.replace("@", ""); // split at camelcase // String[] parts = bundle.split("(?<!^)(?=[A-Z])"); IScriptFolder folder = findBundleFolder(bundle, project); if (folder != null) return folder.getPath(); return null; } /** * Search for a specific {@link Bundle} by alias, ie 'AcmeDemoBundle'; * * @param bundleAlias * @param scriptProject * @return {@link Bundle} */ public Bundle findBundle(String bundleAlias, IScriptProject scriptProject) { String key = bundleAlias + scriptProject.getElementName(); if (bundleCache.get(key) != null) { return bundleCache.get(key) == NULL_ENTRY ? null :(Bundle) bundleCache.get(key); } IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject); ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit.getDefault()); if (scope == null || engine == null) { return null; } final List<Bundle> bundles = new ArrayList<Bundle>(); engine.search(ISymfonyModelElement.BUNDLE, null, bundleAlias, 0, 0, 100, SearchFor.REFERENCES, MatchRule.EXACT, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { bundles.add(JsonUtils.unpackBundle(metadata)); } }, null); if (bundles.size() == 1) { Bundle b = bundles.get(0); bundleCache.put(key, b); return b; } bundleCache.put(key, NULL_ENTRY); return null; } /** * Search for a specific {@link IType} by an {@link EntityAlias} like 'AcmeDemoBundle:SomeEntityClass' * * @param alias * @param scriptProject * @return {@link IType} or null */ public IType findEntity(EntityAlias alias, IScriptProject scriptProject) { String key = alias + scriptProject.getElementName(); if (entityCache.get(key) != null) { return entityCache.get(key) == NULL_ENTRY ? null : (IType) entityCache.get(key); } Bundle bundle = findBundle(alias.getBundleAlias(), scriptProject); if (bundle == null) { entityCache.put(key, NULL_ENTRY); return null; } INamespace ns; try { ns = bundle.getNamespace(); } catch (ModelException e) { return null; } if (ns == null) { entityCache.put(key, NULL_ENTRY); return null; } String[] entityNS = new String[ns.getStrings().length + 1]; System.arraycopy(ns.getStrings(), 0, entityNS, 0, ns.getStrings().length); entityNS[ns.getStrings().length] = "Entity"; IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject); StringBuilder sb = new StringBuilder(); sb.append(entityNS[0]); for (int i=1; i<entityNS.length; i++) { sb.append("\\"); sb.append(entityNS[i]); } String entity = alias.getEntity(); if (entity.contains("\\")) { String[] strings = entity.split("\\\\"); for(int i=0; i < strings.length; i++) { if (i < strings.length-1) { sb.append("\\"); sb.append(strings[i]); } else { entity = strings[i]; } } } IType[] types = findTypes(sb.toString(), entity, MatchRule.EXACT, 0, 0, scope, null); if (types.length == 1) { IType t = types[0]; entityCache.put(key, t); return t; } entityCache.put(key, NULL_ENTRY); return null; } public List<TransUnit> findTranslations(IPath path) { final List<TransUnit> translations = new ArrayList<TransUnit>(); if (index == null) { Logger.log(Logger.ERROR, "The SymfonyIndexer has not been instantiated..."); return null; } index.findTranslations(path.toString(), new ITranslationHandler() { @Override public void handle(String name, String value, String language, String path) { TransUnit trans = new TransUnit(name, value, language, path); translations.add(trans); } }); return translations; } public List<TransUnit> findTranslations(Translation translation) { final List<TransUnit> units = new ArrayList<TransUnit>(); index.findTranslations(translation.getElementName(), translation.getPath().toString(), new ITranslationHandler() { @Override public void handle(String name, String value, String language, String path) { TransUnit unit = new TransUnit(name, value, language); units.add(unit); } }); return units; } public Route getRoute(IType type, IMethod method) { IScriptProject project = type.getScriptProject(); String bundleAlias = ModelUtils.extractBundleName(type.getFullyQualifiedName("\\")); String controller = ModelUtils.getControllerName(type); List<Route> routes = index.findRoutesByController(bundleAlias, controller, project.getPath()); String action = method.getElementName().endsWith(SymfonyCoreConstants.ACTION_SUFFIX) ? method.getElementName().replace(SymfonyCoreConstants.ACTION_SUFFIX, "") : method.getElementName(); for (Route route : routes) { if (route.getAction().equals(action)) { return route; } } return null; } /** * Retrieve all templateVariables for the given sourceModule, given the sourceModule is * a template (php or twig). * * @param sourceModule */ public List<TemplateField> findTemplateVariables(ISourceModule sourceModule, String varName) { String viewPath = PathUtils.createViewPathFromTemplate(sourceModule, false); IDLTKSearchScope scope = SearchEngine.createSearchScope(sourceModule.getScriptProject()); ISearchEngine engine = ModelAccess.getSearchEngine(SymfonyLanguageToolkit.getDefault()); if (scope == null || engine == null) { return null; } final List<TemplateField> variables = new ArrayList<TemplateField>(); final IElementResolver resolver = ModelAccess.getElementResolver(SymfonyLanguageToolkit.getDefault()); // handle twig variables if (!varName.startsWith("$")) { varName = "$" + varName; } engine.search(ISymfonyModelElement.TEMPLATE_VARIABLE, viewPath, varName, 0, 0, 100, SearchFor.REFERENCES, MatchRule.EXACT, scope, new ISearchRequestor() { @Override public void match(int elementType, int flags, int offset, int length, int nameOffset, int nameLength, String elementName, String metadata, String doc, String qualifier, String parent, ISourceModule sourceModule, boolean isReference) { IModelElement element = resolver.resolve(elementType, flags, offset, length, nameOffset, nameLength, elementName, metadata, doc, qualifier, parent, sourceModule); if (element != null) { if (element instanceof TemplateField) variables.add((TemplateField) element); } } }, null); return variables; } }