public function resolveAssetSourcePathAndTemplate(
        $source,
        $templateName,
        $fileName,
        ParserInterface $parserInterface,
        TemplateDefinition &$templateDefinition
    ) {
        // A simple cache for the path list, to gain some performances
        static $cache = [];

        // The path are categorized, and will be checked in the following order. (see getPossibleAssetSources)
        // - template : the template directory
        // - module_override : the module override directory (template/modules/module_name/...)
        // - module_directory : the current template in the module directory
        // - the default template in the module directory.
        static $pathOrigin = ['template', 'module_override', 'module_directory', 'default_fallback'];

        $templateName = $templateName ?: $templateDefinition->getName();

        $templateDirectories = $parserInterface->getTemplateDirectories($templateDefinition->getType());

        $hash = "$source|$templateName";

        if (! isset($cache[$hash])) {
            // Build a list of all template names, starting with current template
            $templateList = [$templateName => $templateDefinition];

            /** @var TemplateDefinition $tplDef */
            foreach ($templateDefinition->getParentList() as $tplDef) {
                $templateList[$tplDef->getName()] = $tplDef;
            }

            $pathList = [];

            // Get all possible directories to search, including the parent templates ones.
            // The current template is checked firts, then the parent ones.

            /** @var TemplateDefinition $templateDef */
            foreach ($templateList as $tplName => $dummy) {
                $this->getPossibleAssetSources(
                    $templateDirectories,
                    $tplName,
                    $source,
                    $pathList
                );
            }

            $cache[$hash] = [ $pathList, $templateList ];
        } else {
            list($pathList, $templateList) = $cache[$hash];
        }

        // Normalize path separator if required (e.g., / becomes \ on windows)
        $fileName = $this->fixPathSeparator($fileName);

        /* Absolute paths are not allowed. This may be a mistake, such as '/assets/...' instead of 'assets/...'. Forgive it.  */
        $fileName = ltrim($fileName, DS);

        /* Navigating in the server's directory tree is not allowed :) */
        if (preg_match('!\.\.\\'.DS.'!', $fileName)) {
            // This time, we will not forgive.
            throw new \InvalidArgumentException("Relative paths are not allowed in assets names.");
        }

        // Find the first occurrence of the file in the directory list.
        foreach ($pathOrigin as $origin) {
            if (isset($pathList[$origin])) {
                foreach ($pathList[$origin] as $pathInfo) {
                    list($tplName, $path) = $pathInfo;

                    if ($this->filesExist($path, $fileName)) {
                        // Got it ! Save the template where the asset was found and return !
                        $templateDefinition = $templateList[$tplName];

                        return $path;
                    }
                }
            }
        }

        // Not found !
        return null;
    }
public function resolveAssetSourcePathAndTemplate(
        $source,
        $templateName,
        $fileName,
        ParserInterface $parserInterface,
        TemplateDefinition &$templateDefinition
    ) {
        // A simple cache for the path list, to gain some performances
        static $cache = [];

        // The path are categorized, and will be checked in the following order. (see getPossibleAssetSources)
        // - template : the template directory
        // - module_override : the module override directory (template/modules/module_name/...)
        // - module_directory : the current template in the module directory
        // - the default template in the module directory.
        static $pathOrigin = ['template', 'module_override', 'module_directory', 'default_fallback'];

        $templateName = $templateName ?: $templateDefinition->getName();

        $templateDirectories = $parserInterface->getTemplateDirectories($templateDefinition->getType());

        $hash = "$source|$templateName";

        if (! isset($cache[$hash])) {
            // Build a list of all template names, starting with current template
            $templateList = [$templateName => $templateDefinition];

            /** @var TemplateDefinition $tplDef */
            foreach ($templateDefinition->getParentList() as $tplDef) {
                $templateList[$tplDef->getName()] = $tplDef;
            }

            $pathList = [];

            // Get all possible directories to search, including the parent templates ones.
            // The current template is checked firts, then the parent ones.

            /** @var TemplateDefinition $templateDef */
            foreach ($templateList as $tplName => $dummy) {
                $this->getPossibleAssetSources(
                    $templateDirectories,
                    $tplName,
                    $source,
                    $pathList
                );
            }

            $cache[$hash] = [ $pathList, $templateList ];
        } else {
            list($pathList, $templateList) = $cache[$hash];
        }

        // Normalize path separator if required (e.g., / becomes \ on windows)
        $fileName = $this->fixPathSeparator($fileName);

        /* Absolute paths are not allowed. This may be a mistake, such as '/assets/...' instead of 'assets/...'. Forgive it.  */
        $fileName = ltrim($fileName, DS);

        /* Navigating in the server's directory tree is not allowed :) */
        if (preg_match('!\.\.\\'.DS.'!', $fileName)) {
            // This time, we will not forgive.
            throw new \InvalidArgumentException("Relative paths are not allowed in assets names.");
        }

        // Find the first occurrence of the file in the directory list.
        foreach ($pathOrigin as $origin) {
            if (isset($pathList[$origin])) {
                foreach ($pathList[$origin] as $pathInfo) {
                    list($tplName, $path) = $pathInfo;

                    if ($this->filesExist($path, $fileName)) {
                        // Got it ! Save the template where the asset was found and return !
                        $templateDefinition = $templateList[$tplName];

                        return $path;
                    }
                }
            }
        }

        // Not found !
        return null;
    }
public function resolveAssetSourcePathAndTemplate ( $ source , $ templateName , $ fileName , ParserInterface $ parserInterface , TemplateDefinition & $ templateDefinition ) { // A simple cache for the path list, to gain some performances static $ cache = [ ] ; // The path are categorized, and will be checked in the following order. (see getPossibleAssetSources) // - template : the template directory // - module_override : the module override directory (template/modules/module_name/...) // - module_directory : the current template in the module directory // - the default template in the module directory. static $ pathOrigin = [ 'template' , 'module_override' , 'module_directory' , 'default_fallback' ] ; $ templateName = $ templateName ? : $ templateDefinition -> getName ( ) ; $ templateDirectories = $ parserInterface -> getTemplateDirectories ( $ templateDefinition -> getType ( ) ) ; $ hash = "$source|$templateName" ; if ( ! isset ( $ cache [ $ hash ] ) ) { // Build a list of all template names, starting with current template $ templateList = [ $ templateName => $ templateDefinition ] ; /** @var TemplateDefinition $tplDef */ foreach ( $ templateDefinition -> getParentList ( ) as $ tplDef ) { $ templateList [ $ tplDef -> getName ( ) ] = $ tplDef ; } $ pathList = [ ] ; // Get all possible directories to search, including the parent templates ones. // The current template is checked firts, then the parent ones. /** @var TemplateDefinition $templateDef */ foreach ( $ templateList as $ tplName => $ dummy ) { $ this -> getPossibleAssetSources ( $ templateDirectories , $ tplName , $ source , $ pathList ) ; } $ cache [ $ hash ] = [ $ pathList , $ templateList ] ; } else { list ( $ pathList , $ templateList ) = $ cache [ $ hash ] ; } // Normalize path separator if required (e.g., / becomes \ on windows) $ fileName = $ this -> fixPathSeparator ( $ fileName ) ; /* Absolute paths are not allowed. This may be a mistake, such as '/assets/...' instead of 'assets/...'. Forgive it.  */ $ fileName = ltrim ( $ fileName , DS ) ; /* Navigating in the server's directory tree is not allowed :) */ if ( preg_match ( '!\.\.\\' . DS . '!' , $ fileName ) ) { // This time, we will not forgive. throw new \ InvalidArgumentException ( "Relative paths are not allowed in assets names." ) ; } // Find the first occurrence of the file in the directory list. foreach ( $ pathOrigin as $ origin ) { if ( isset ( $ pathList [ $ origin ] ) ) { foreach ( $ pathList [ $ origin ] as $ pathInfo ) { list ( $ tplName , $ path ) = $ pathInfo ; if ( $ this -> filesExist ( $ path , $ fileName ) ) { // Got it ! Save the template where the asset was found and return ! $ templateDefinition = $ templateList [ $ tplName ] ; return $ path ; } } } } // Not found ! return null ; }
Return an asset source file path, and get the original template where it was found

A system of fallback enables file overriding. It will look for the template :
- in the current template in directory /modules/{module code}/
- in the parent templates (if any) in directory /modules/{module code}/
- in the module in the current template if it exists
- in the module in the default template

@param  string $source a module code, or or ParserInterface::TEMPLATE_ASSETS_KEY
@param  string $templateName a template name, or false to use the current template
@param  string $fileName the filename
@param  ParserInterface $parserInterface the current template parser
@param  TemplateDefinition &$templateDefinition the template where to start search.
This parameter will contain the template where the asset was found.

@return mixed the path to directory containing the file, or null if the file doesn't exists.
Return an asset source file path and get the original template where it was found