Package org.nbphpcouncil.modules.php.yii.util

Source Code of org.nbphpcouncil.modules.php.yii.util.YiiUtils$MainVisitor

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2013 Oracle and/or its affiliates. All rights reserved.
*
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License.  When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
* Contributor(s):
*
* Portions Copyrighted 2013 Sun Microsystems, Inc.
*/
package org.nbphpcouncil.modules.php.yii.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.nbphpcouncil.modules.php.yii.Yii;
import org.nbphpcouncil.modules.php.yii.YiiModule;
import org.nbphpcouncil.modules.php.yii.YiiModuleFactory;
import org.nbphpcouncil.modules.php.yii.YiiPhpFrameworkProvider;
import org.netbeans.modules.csl.spi.ParserResult;
import org.netbeans.modules.parsing.api.ParserManager;
import org.netbeans.modules.parsing.api.ResultIterator;
import org.netbeans.modules.parsing.api.Source;
import org.netbeans.modules.parsing.api.UserTask;
import org.netbeans.modules.parsing.spi.ParseException;
import org.netbeans.modules.php.api.editor.PhpClass;
import org.netbeans.modules.php.api.phpmodule.PhpModule;
import org.netbeans.modules.php.api.util.FileUtils;
import org.netbeans.modules.php.api.util.StringUtils;
import org.netbeans.modules.php.editor.parser.api.Utils;
import org.netbeans.modules.php.editor.parser.astnodes.ArrayElement;
import org.netbeans.modules.php.editor.parser.astnodes.Expression;
import org.netbeans.modules.php.editor.parser.astnodes.visitors.DefaultVisitor;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;

/**
*
* @author junichi11
*/
public class YiiUtils {

    private static final String YII_INCLUDE_PATH_REGEX = "^\\$yii *=.+'(.+/framework)/yii\\.php';$"; // NOI18N
    private static final String CONTROLLER_SUFFIX = "Controller"; // NOI18N
    private static final String ACTION_METHOD_PREFIX = "action"; // NOI18N
    private static final String VIEW_RELATIVE_PATH_FORMAT = "../..%s%s/views/%s%s/%s.php"; // NOI18N
    private static final String CONTROLLER_RELATIVE_PATH_FORMAT = "../../..%s%s/controllers/%s%s.php"; // NOI18N
    private static final String THEME_PATH = "/../themes/%s"; // NOI18N
    private static final String NBPROJECT = "nbproject"; // NOI18N
    private static final String MODELS_PATH = "models"; // NOI18N
    private static final String TESTS_PATH = "tests"; // NOI18N
    private static final Logger LOGGER = Logger.getLogger(YiiUtils.class.getName());

    /**
     * Check whether php module is yii
     *
     * @param phpModule
     * @return true if php module is yii, otherwiser false
     */
    public static boolean isYii(PhpModule phpModule) {
        if (phpModule == null) {
            return false;
        }
        return YiiPhpFrameworkProvider.getInstance().isInPhpModule(phpModule);
    }

    private static PhpModule getPhpModule(FileObject fileObject) {
        return PhpModule.Factory.forFileObject(fileObject);
    }

    /**
     * Get include path.
     *
     * @param index index.php file
     * @return if exists include path, string. otherwise null.
     */
    public static List<String> getIncludePath(FileObject index) {
        List<String> lines;
        List<String> includePath = new ArrayList<String>();
        try {
            lines = index.asLines("UTF-8"); // NOI18N
            Pattern pattern = Pattern.compile(YII_INCLUDE_PATH_REGEX);
            for (String line : lines) {
                Matcher matcher = pattern.matcher(line);
                if (matcher.find()) {
                    String path = matcher.group(1);
                    if (path.startsWith("/")) { // NOI18N
                        path = path.replaceFirst("/", ""); // NOI18N
                    }
                    includePath.add(path);
                    break;
                }
            }
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
        return includePath;
    }

    /**
     * Check view file
     *
     * @param fo
     * @return true if file is view file, otherwise false.
     */
    public static boolean isView(FileObject fo) {
        if (fo == null
                || !fo.isData()
                || !FileUtils.isPhpFile(fo)) {
            return false;
        }

        String subpath = getPathFromWebroot(fo);
        if (StringUtils.isEmpty(subpath)) {
            return false;
        }
        return subpath.contains("/views/");
    }

    /**
     * Get path from webroot directory.
     *
     * @param fo
     * @return
     */
    private static String getPathFromWebroot(FileObject fo) {
        PhpModule phpModule = getPhpModule(fo);
        // return null if use external files #11
        if (phpModule == null) {
            return null;
        }
        String path = fo.getPath();
        YiiModule yiiModule = YiiModuleFactory.create(phpModule);
        FileObject webroot = yiiModule.getWebroot();
        String webrootPath = webroot.getPath();
        return path.replace(webrootPath, ""); // NOI18N
    }

    /**
     * Create view file for target path.
     *
     * @param baseDirectory
     * @param targetPath
     * @return file if file was created, otherwise null.
     */
    public static FileObject createFile(FileObject baseDirectory, String targetPath) {
        File file = new File(FileUtil.toFile(baseDirectory), targetPath);
        createParents(file);
        try {
            if (file.createNewFile()) {
                return baseDirectory.getFileObject(targetPath);
            }
        } catch (IOException ex) {
            LOGGER.log(Level.WARNING, "Fail: can't create file {0}", targetPath);
        }

        return null;
    }

    /**
     * Create parent directories if it doesn't exist.
     *
     * @param file
     * @return true if create parents, otherwise false.
     */
    private static boolean createParents(File file) {
        File parentFile = file.getParentFile();
        return parentFile.mkdirs();
    }

    /**
     * Get relative path to view file from controller.
     *
     * @param controller
     * @param actionId action name(view file name). e.g actionIndex -> index
     * @param themeName theme name
     * @return view file object
     */
    public static String getRelativePathToView(FileObject controller, String actionId, String themeName) {
        String controllerId = getViewFolderName(controller.getName());
        String subPath = getSubDirectoryPathForController(controller);
        if (subPath == null) {
            return null;
        }
        return getRelativePathToView(controller, subPath, controllerId, actionId, themeName);
    }

    /**
     * Get sub directory path for controller file. If file doesn't exist within
     * protected/controllers, return null. Otherwise return empty string "" or
     * path. For example : protected/controllers/subdir/SiteController.php ->
     * subdir/
     *
     * @param controller
     * @return sub directory path from controllers dir to file.
     */
    public static String getSubDirectoryPathForController(FileObject controller) {
        String filePath = controller.getPath();
        if (!filePath.contains("/controllers/")) { // NOI18N
            return null;
        }
        String subPath = filePath.replaceAll(".+/controllers/", ""); // NOI18N
        return subPath.replace(controller.getNameExt(), ""); // NOI18N
    }

    /**
     * Get relative path to view file from controller.
     *
     * @param controller
     * @param controllerId
     * @param actionId
     * @param themeName
     * @return
     */
    public static String getRelativePathToView(FileObject controller, String subPath, String controllerId, String actionId, String themeName) {
        if (controller == null) {
            return null;
        }
        String themePath = ""; // NOI18N
        if (!StringUtils.isEmpty(themeName)) {
            themePath = String.format(THEME_PATH, themeName);
        }

        // add depth for sub path
        String subpathDepth = toSubpathDepth(subPath);

        // create relative path from controller to view file
        return String.format(VIEW_RELATIVE_PATH_FORMAT, subpathDepth, themePath, subPath, controllerId, actionId);
    }

    /**
     * Get theme name from main.php file.
     *
     * @param main
     * @return theme name if find the theme, otherwise empty string.
     */
    public static String getThemeName(FileObject main) {
        final Set<String> themes = new HashSet<String>();
        try {
            ParserManager.parse(Collections.singleton(Source.create(main)), new UserTask() {
                @Override
                public void run(ResultIterator resultIterator) throws Exception {
                    if (resultIterator == null) {
                        return;
                    }
                    ParserResult parserResult = (ParserResult) resultIterator.getParserResult();
                    final MainVisitor mainVisitor = new MainVisitor();
                    mainVisitor.scan(Utils.getRoot(parserResult));
                    themes.addAll(mainVisitor.getThemeName());
                }
            });
        } catch (ParseException ex) {
            Exceptions.printStackTrace(ex);
        }
        String themeName = ""; // NOI18N
        for (String theme : themes) {
            themeName = theme;
            break;
        }
        return themeName;
    }

    /**
     * For auto create option.
     *
     * @param controller
     * @param pathToView
     * @return
     */
    public static FileObject createViewFileAuto(FileObject controller, String pathToView) {
        String viewPath = FileUtil.normalizePath(controller.getParent().getPath() + pathToView);
        File file = new File(viewPath);
        FileObject view = null;
        try {
            // create sub directories
            File parentFile = file.getParentFile();
            if (!parentFile.exists()) {
                parentFile.mkdirs();
            }
            // create file
            if (file.createNewFile()) {
                view = FileUtil.toFileObject(file);
            }
        } catch (IOException ex) {
            LOGGER.log(Level.WARNING, "Can't create view file : {0}", viewPath);
        }
        return view;
    }

    /**
     * Check controller file
     *
     * @param fo
     * @return true if file is controller file, otherwise false.
     */
    public static boolean isController(FileObject fo) {
        String subPath = getSubDirectoryPathForController(fo);
        if (subPath == null) {
            return false;
        }
        return fo.isData() && FileUtils.isPhpFile(fo) && fo.getName().endsWith(CONTROLLER_SUFFIX);
    }

    /**
     * Get controller file object
     *
     * @param view
     * @return controller file object
     */
    public static FileObject getController(FileObject view) {
        if (!isView(view)) {
            return null;
        }

        // views
        String subpath = getSubpathToView(view);
        String controllerId = ""; // NOI18N
        String nestedPath = ""; // NOI18N
        if (!subpath.isEmpty()) {
            int lastSlash = subpath.lastIndexOf("/"); // NOI18N
            if (lastSlash == -1) {
                controllerId = subpath;
                nestedPath = ""; // NOI18N
            } else {
                controllerId = subpath.substring(lastSlash + 1);
                nestedPath = subpath.substring(0, lastSlash + 1);
            }
        }

        // add depth for sub path
        FileObject controller = null;
        String controllerName = getControllerFileName(controllerId);
        if (isInModules(view)) {
            String nestedPathDepth = toSubpathDepth(nestedPath);
            String format = String.format(CONTROLLER_RELATIVE_PATH_FORMAT, nestedPathDepth, "", nestedPath, controllerName);
            controller = view.getFileObject(format);
        } else {
            PhpModule phpModule = PhpModule.Factory.forFileObject(view);
            YiiModule yiiModule = YiiModuleFactory.create(phpModule);
            if (yiiModule != null) {
                FileObject controllersDirectory = yiiModule.getControllers();
                if (controllersDirectory == null) {
                    return null;
                }

                // nested directory
                String path = String.format("%s%s.php", nestedPath, controllerName); // NOI18N
                controller = controllersDirectory.getFileObject(path);

                // has sub directory
                if (controller == null) {
                    if (!subpath.isEmpty()) {
                        int firstSlash = subpath.indexOf("/"); // NOI18N
                        if (firstSlash == -1) {
                            controllerId = subpath;
                        } else {
                            controllerId = subpath.substring(0, firstSlash);
                        }
                    }
                    controllerName = getControllerFileName(controllerId);
                    path = String.format("%s.php", controllerName); // NOI18N
                    controller = controllersDirectory.getFileObject(path);
                }
            }

        }
        return controller;
    }

    private static String getSubpathToView(FileObject view) {
        String subpathFromWebroot = getPathFromWebroot(view);
        String subpath = ""; // NOI18N
        if (subpathFromWebroot.contains("/views/")) { // NOI18N
            subpath = subpathFromWebroot.replaceAll(".+/views/", ""); // NOI18N
            subpath = subpath.replace("/" + view.getNameExt(), ""); // NOI18N
        }
        return subpath;
    }

    /**
     * Get subpath depth.
     *
     * @param path
     * @return
     */
    private static String toSubpathDepth(String path) {
        StringBuilder sb = new StringBuilder();
        int startIndex = 0;
        while (startIndex != -1) {
            startIndex++;
            startIndex = path.indexOf("/", startIndex); // NOI18N
            if (startIndex > 0) {
                sb.append("/.."); // NOI18N
            }
        }
        return sb.toString();
    }

    /**
     * Get controller file name. e.g. SiteController,DemoController
     *
     * @param viewFolderName each views directory name
     * @return controller file name. ControllerName + Controller
     */
    public static String getControllerFileName(String viewFolderName) {
        viewFolderName = toFirstUpperCase(viewFolderName);
        if (viewFolderName == null) {
            return null;
        }
        return viewFolderName + CONTROLLER_SUFFIX;
    }

    /**
     * Check controller class name
     *
     * @param controller
     * @return true if controller class, otherwise false
     */
    public static boolean isControllerName(String controller) {
        if (controller == null) {
            return false;
        }
        return controller.endsWith(CONTROLLER_SUFFIX);
    }

    /**
     * Get controller action method name
     *
     * @param view file name
     * @return action method name
     */
    public static String getActionMethodName(String view) {
        if (view == null || view.isEmpty()) {
            return null;
        }
        return ACTION_METHOD_PREFIX + toFirstUpperCase(view);
    }

    /**
     * Get view folder name
     *
     * @param controllerName
     * @return
     */
    public static String getViewFolderName(String controllerName) {
        if (!isControllerName(controllerName)) {
            return null;
        }
        String name = controllerName.replace(CONTROLLER_SUFFIX, ""); // NOI18N
        // #44 e.g. AbcDefController -> abcDef
        return toFirstLowerCase(name);
    }

    /**
     * Get view name
     *
     * @param method
     * @return
     */
    public static String getViewName(PhpClass.Method method) {
        String name = method.getName();
        if (!isActionMethodName(name)) {
            return null;
        }
        name = name.replace(ACTION_METHOD_PREFIX, ""); // NOI18N
        return name.toLowerCase();
    }

    /**
     * Check action method name
     *
     * @param name
     * @return
     */
    public static boolean isActionMethodName(String name) {
        if (name == null || !name.startsWith(ACTION_METHOD_PREFIX) || name.isEmpty()) {
            return false;
        }
        name = name.replace(ACTION_METHOD_PREFIX, ""); // NOI18N
        String first = name.substring(0, 1);
        return first.equals(first.toUpperCase());
    }

    /**
     * Converts the first of characters to upper case.
     *
     * Examples: "apple" -> "Apple", "minBanana" -> "MiniBanana", "ORANGE" ->
     * "ORANGE"
     *
     * @param string
     * @return the converted string
     */
    public static String toFirstUpperCase(String string) {
        if (string == null || string.isEmpty()) {
            return null;
        }
        return string.substring(0, 1).toUpperCase() + string.substring(1);
    }

    /**
     * Converts the first of characters to lower case.
     *
     * Examples: "Apple" -> "apple", "MiniBanana" -> "miniBanana", "ORANGE" ->
     * "oRANGE"
     *
     * @param string
     * @return the converted string
     */
    public static String toFirstLowerCase(String string) {
        if (string == null || string.isEmpty()) {
            return string;
        }

        if (string.length() == 1) {
            return string.toLowerCase();
        }
        return string.substring(0, 1).toLowerCase() + string.substring(1);
    }

    /**
     * Create code completion file
     *
     * @param phpModule
     * @throws IOException
     */
    public static void createCodeCompletionFile(PhpModule phpModule) throws IOException {
        if (!isYii(phpModule)) {
            return;
        }
        FileObject codeCompletion = FileUtil.getConfigFile(Yii.YII_CODE_COMPLETION_CONFIG_PATH);
        FileObject nbproject = getNbproject(phpModule);
        if (nbproject != null && codeCompletion != null) {
            codeCompletion.copy(nbproject, codeCompletion.getName(), codeCompletion.getExt());
        }
    }

    /**
     * Get nbproject directory
     *
     * @param phpModule
     * @return
     */
    public static FileObject getNbproject(PhpModule phpModule) {
        FileObject projectDirectory = phpModule.getProjectDirectory();
        FileObject nbproject = null;
        return projectDirectory.getFileObject(NBPROJECT);
    }

    /**
     * Get views directory (protected/views)
     *
     * @param phpModule
     * @return
     */
    public static FileObject getViewsDirectory(PhpModule phpModule) {
        YiiModule yiiModule = YiiModuleFactory.create(phpModule);
        if (yiiModule != null) {
            return yiiModule.getViews();
        }
        return null;
    }

    /**
     * Get controllers directory (protected/controllers)
     *
     * @param phpModule
     * @return
     */
    public static FileObject getControllersDirectory(PhpModule phpModule) {
        YiiModule yiiModule = YiiModuleFactory.create(phpModule);
        if (yiiModule != null) {
            return yiiModule.getControllers();
        }
        return null;
    }

    /**
     * Get models directory (protected/models)
     *
     * @param phpModule
     * @return
     */
    public static FileObject getModelsDirectory(PhpModule phpModule) {
        return getDirectory(phpModule, MODELS_PATH);
    }

    /**
     * Get tests directory (protected/tests)
     *
     * @param phpModule
     * @return
     */
    public static FileObject getTestsDirectory(PhpModule phpModule) {
        YiiModule yiiModule = YiiModuleFactory.create(phpModule);
        if (yiiModule != null) {
            FileObject application = yiiModule.getApplication();
            if (application != null) {
                return application.getFileObject(TESTS_PATH);
            }
        }
        return null;
    }

    /**
     * Get themes directory (protected/themes).
     *
     * @param phpModule
     * @return
     */
    public static FileObject getThemesDirectory(PhpModule phpModule) {
        YiiModule yiiModule = YiiModuleFactory.create(phpModule);
        if (yiiModule != null) {
            return yiiModule.getThemes();
        }
        return null;
    }

    /**
     * Get directory
     *
     * @param phpModule
     * @param path relative path from source directory
     * @return
     */
    public static FileObject getDirectory(PhpModule phpModule, String path) {
        YiiModule yiiModule = YiiModuleFactory.create(phpModule);
        FileObject sourceDirectory = yiiModule.getWebroot();
        if (sourceDirectory == null) {
            return null;
        }
        return sourceDirectory.getFileObject(path);
    }

    private static class MainVisitor extends DefaultVisitor {

        private static final String THEME = "theme"; // NOI18N
        private final Set<String> themeName = new HashSet<String>();

        @Override
        public void visit(ArrayElement node) {
            super.visit(node);
            Expression key = node.getKey();
            String keyName = YiiCodeUtils.getStringValue(key);
            if (keyName.equals(THEME)) {
                String value = YiiCodeUtils.getStringValue(node.getValue());
                if (!value.isEmpty()) {
                    themeName.add(value);
                }
            }
        }

        public synchronized Set<String> getThemeName() {
            return themeName;
        }
    }

    /**
     * Check whether file is within modules directory.
     *
     * @param fileObject current file
     * @return true if file exists within modules directory, otherwise false.
     */
    public static boolean isInModules(FileObject fileObject) {
        String pathFromWebroot = getPathFromWebroot(fileObject);
        if (pathFromWebroot != null) {
            return pathFromWebroot.contains("/modules/"); // NOI18N
        }
        return false;
    }

    /**
     * Get module name.
     *
     * @param fileObject
     * @return module name in current file. if file doesn't exist in modules,
     * null.
     */
    public static String getModuleName(FileObject fileObject) {
        if (fileObject == null || !isInModules(fileObject)) {
            return null;
        }
        String path = getPathFromWebroot(fileObject);
        if (path == null) {
            return null;
        }

        path = path.replaceAll(".+/modules/", path); // NOI18N
        return path.substring(0, path.indexOf("/")); // NOI18N
    }

    /**
     * Get current module directory.
     *
     * @param fileObject current file
     * @return current module directory.
     */
    public static FileObject getCurrentModuleDirectory(FileObject fileObject) {
        if (fileObject == null || !isInModules(fileObject)) {
            return null;
        }
        String path = getPathFromWebroot(fileObject);
        if (path == null) {
            return null;
        }
        String modules = "/modules/"; // NOI18N
        int modulesIndex = path.lastIndexOf(modules);

        // contains module name
        int moduleIndex = path.indexOf("/", modulesIndex + modules.length()); // NOI18N
        String modulePath = path.substring(0, moduleIndex);
        YiiModule yiiModule = YiiModuleFactory.create(PhpModule.Factory.forFileObject(fileObject));
        FileObject webroot = yiiModule.getWebroot();
        if (webroot == null) {
            return null;
        }
        return webroot.getFileObject(modulePath);
    }

    /**
     * Sort files.
     *
     * @param files
     * @param desc true if order by desc, false if asc.
     */
    public static void sort(FileObject[] files, final boolean desc) {
        Arrays.sort(files, new ComparatorImpl(desc));
    }

    /**
     * Sort files order by asc.
     *
     * @param files
     */
    public static void sort(FileObject[] files) {
        sort(files, false);
    }

    /**
     * Sort files.
     *
     * @param files
     * @param desc
     */
    public static void sort(List<FileObject> files, final boolean desc) {
        Collections.sort(files, new ComparatorImpl(desc));
    }

    /**
     * Sort files order by asc.
     *
     * @param files
     */
    public static void sort(List<FileObject> files) {
        sort(files, false);
    }

    private static class ComparatorImpl implements Comparator<FileObject> {

        private final boolean desc;

        public ComparatorImpl(boolean desc) {
            this.desc = desc;
        }

        @Override
        public int compare(FileObject o1, FileObject o2) {
            if (desc) {
                return o2.getName().compareToIgnoreCase(o1.getName());
            }
            return o1.getName().compareToIgnoreCase(o2.getName());
        }
    }
}
TOP

Related Classes of org.nbphpcouncil.modules.php.yii.util.YiiUtils$MainVisitor

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.