Package com.dubture.symfony.core.model

Source Code of com.dubture.symfony.core.model.SymfonyModelAccess$ReturnTypeVisitor

/*******************************************************************************
* 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.internal.core.compiler.ast.nodes.NamespaceDeclaration;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocBlock;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocTag;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocTagKinds;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPMethodDeclaration;
import org.eclipse.php.internal.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(PHPDocTagKinds.RETURN);
                if (returnTags.length == 1) {
                    PHPDocTag tag = returnTags[0];

                    if (tag.getReferences().length == 1) {
                        SimpleReference ref = tag.getReferences()[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);

    }


    public Map<String, String> findAnnotationClasses(IScriptProject project) {
        IDLTKSearchScope scope = SearchEngine.createSearchScope(project.getScriptProject());
        ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit.getDefault());

        final Map<String, String> annotations = new HashMap<String, String>();
        if (scope == null || engine == null) {
            return annotations;
        }

        engine.search(ISymfonyModelElement.ANNOTATION, 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) {
                annotations.put(elementName, qualifier);
            }
        }, null);

        return annotations;
    }

    /**
    *
    * 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) {

        IDLTKSearchScope scope = SearchEngine.createSearchScope(project);

        IType[] types = findTypes(bundle, MatchRule.EXACT, 0, 0, scope, null);

        if (types.length != 1)
            return null;

        IType bundleType = types[0];
        return  (ScriptFolder) bundleType.getSourceModule().getParent();

    }

    /**
    *
    * 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);
        }

        ScriptFolder bundleFolder = findBundleFolder(bundle, scriptProject);
        if(bundleFolder == null)
            return null;

        ISourceModule controllerSource = bundleFolder.getSourceModule("Controller");

        if (controllerSource == null)
            return null;

        IDLTKSearchScope controllerScope = SearchEngine.createSearchScope(controllerSource);

        IType[] controllers = findTypes(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;
    }

}
TOP

Related Classes of com.dubture.symfony.core.model.SymfonyModelAccess$ReturnTypeVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.