YetiForceCompany/YetiForceCRM

View on GitHub
include/Loader.php

Summary

Maintainability
B
5 hrs
Test Coverage
B
87%
<?php
/* +**********************************************************************************
 * The contents of this file are subject to the vtiger CRM Public License Version 1.1
 * ("License"); You may not use this file except in compliance with the License
 * The Original Code is:  vtiger CRM Open Source
 * The Initial Developer of the Original Code is vtiger.
 * Portions created by vtiger are Copyright (C) vtiger.
 * All Rights Reserved.
 * Contributor(s): YetiForce S.A.
 * ********************************************************************************** */

class Vtiger_Loader
{
    protected static $includeCache = [];
    protected static $includePathCache = [];
    protected static $componentClassCache = [];
    protected static $loaderDirs = [
        'custom.modules.',
        'modules.',
    ];

    /**
     * Static function to resolve the qualified php filename to absolute path.
     *
     * @param string $qualifiedName
     * @param mixed  $fileExtension
     *
     * @return string Absolute File Name
     */
    public static function resolveNameToPath($qualifiedName, $fileExtension = 'php')
    {
        if ($file = self::resolveRelativePath($qualifiedName, $fileExtension)) {
            $file = ROOT_DIRECTORY . DIRECTORY_SEPARATOR . ('php' !== $fileExtension ? 'public_html' . DIRECTORY_SEPARATOR : '') . $file;
        }
        return $file;
    }

    /**
     * Static function to resolve the qualified php filename to relative path.
     *
     * @param string $qualifiedName
     * @param string $fileExtension
     *
     * @return string
     */
    public static function resolveRelativePath(string $qualifiedName, string $fileExtension = 'php'): string
    {
        $allowedExtensions = ['php', 'js', 'css', 'less'];
        $file = '';
        if (\in_array($fileExtension, $allowedExtensions)) {
            if (0 === strpos($qualifiedName, '~')) {
                $file = str_replace('~', '', $qualifiedName);
            } else {
                $file = str_replace('.', DIRECTORY_SEPARATOR, $qualifiedName) . '.' . $fileExtension;
            }
        }
        return $file;
    }

    /**
     * Returns canonicalized absolute pathname for css/js files.
     *
     * @param string $filePath
     * @param string $fileExtension
     * @param array  $layoutPaths
     *
     * @return string
     */
    public static function getRealPathFile(string $filePath, string $fileExtension, array $layoutPaths): string
    {
        $realPath = '';
        $checkMin = \vtlib\Functions::getMinimizationOptions($fileExtension);
        foreach ($layoutPaths as $layoutPath) {
            $realPaths = [];
            $completeFilePath = ROOT_DIRECTORY . DIRECTORY_SEPARATOR . 'public_html' . DIRECTORY_SEPARATOR . $layoutPath . self::resolveRelativePath($filePath, $fileExtension);
            if ($checkMin && false === strpos($completeFilePath, '.min.')) {
                $realPaths[] = substr($completeFilePath, 0, -(\strlen($fileExtension) + 1)) . ".min.{$fileExtension}";
            }
            $realPaths[] = $completeFilePath;
            foreach ($realPaths as $path) {
                if ($path && is_file($path)) {
                    $realPath = $path;
                    break 2;
                }
            }
        }
        return $realPath;
    }

    /**
     * Function to include a given php file through qualified file name.
     *
     * @param string $qualifiedName
     *
     * @return bool
     */
    public static function includeOnce($qualifiedName)
    {
        if (isset(self::$includeCache[$qualifiedName])) {
            return true;
        }

        $file = self::resolveNameToPath($qualifiedName);

        if (!file_exists($file)) {
            return false;
        }

        // Check file inclusion before including it
        \vtlib\Deprecated::checkFileAccessForInclusion($file);

        $status = include_once $file;

        $success = (0 !== $status);

        if ($success) {
            self::$includeCache[$qualifiedName] = $file;
        }
        return $success;
    }

    public static function includePath($qualifiedName)
    {
        // Already included?
        if (isset(self::$includePathCache[$qualifiedName])) {
            return true;
        }

        $path = realpath(self::resolveNameToPath($qualifiedName));
        self::$includePathCache[$qualifiedName] = $path;

        set_include_path($path . PATH_SEPARATOR . get_include_path());

        return true;
    }

    /**
     * Function to get the class name of a given Component, of given Type, for a given Module.
     *
     * @param string $componentType
     * @param string $componentName
     * @param string $moduleName
     * @param mixed  $throwException
     *
     * @throws \App\Exceptions\AppException
     *
     * @return string Required Class Name
     */
    public static function getComponentClassName($componentType, $componentName, $moduleName = 'Vtiger', $throwException = true)
    {
        $cacheKey = "$componentType|$componentName|$moduleName";
        if (isset(self::$componentClassCache[$cacheKey])) {
            return self::$componentClassCache[$cacheKey];
        }
        // Change component type from view to views, action to actions to navigate to the right path.
        $componentTypeDirectory = strtolower($componentType) . 's';
        // Change the Module directory & class, along with intermediate fall back directory and class, if module names has submodule as well
        if (false !== strpos($moduleName, ':')) {
            $load = [
                str_replace(':', '_', $moduleName) => str_replace(':', '.', $moduleName),
            ];
            $moduleHierarchyParts = explode(':', $moduleName);
            $actualModule = $moduleHierarchyParts[\count($moduleHierarchyParts) - 1];
            if ('Users' !== $actualModule) {
                $baseModule = $moduleHierarchyParts[0];
                if ('Settings' === $baseModule) {
                    $baseModule = 'Settings:Vtiger';
                }
                $load[str_replace(':', '_', $baseModule)] = str_replace(':', '.', $baseModule);
            }
            $load[$actualModule] = $actualModule;
            $load['Vtiger'] = 'Vtiger';
        } else {
            $load = [
                $moduleName => $moduleName,
                'Vtiger' => 'Vtiger',
            ];
        }
        foreach ($load as $classPath => $classDir) {
            foreach (self::$loaderDirs as $dir) {
                if (file_exists(self::resolveNameToPath("$dir$classDir.$componentTypeDirectory.$componentName"))) {
                    return self::$componentClassCache[$cacheKey] = "{$classPath}_{$componentName}_{$componentType}";
                }
            }
        }
        if ($throwException) {
            \App\Log::error("Error Vtiger_Loader::getComponentClassName($componentType, $componentName, $moduleName): Handler not found");
            throw new \App\Exceptions\AppException('LBL_HANDLER_NOT_FOUND');
        }
        return false;
    }

    /**
     * Function to auto load the required class files matching the directory pattern modules/xyz/types/Abc.php for class xyz_Abc_Type.
     *
     * @param string $className
     *
     * @return bool
     */
    public static function autoLoad($className)
    {
        $parts = explode('_', $className);
        $noOfParts = \count($parts);
        if ($noOfParts > 2) {
            foreach (self::$loaderDirs as $filePath) {
                // Append modules and sub modules names to the path
                for ($i = 0; $i < ($noOfParts - 2); ++$i) {
                    $filePath .= $parts[$i] . '.';
                }

                $fileName = $parts[$noOfParts - 2];
                $fileComponentName = strtolower($parts[$noOfParts - 1]) . 's';
                $filePath .= $fileComponentName . '.' . $fileName;
                if (file_exists(self::resolveNameToPath($filePath))) {
                    return self::includeOnce($filePath);
                }
            }
        }
        return false;
    }
}

spl_autoload_register('Vtiger_Loader::autoLoad');