public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            bool isLess;
            bool isBundle;

            if (!ThemeHelper.IsStyleSheet(virtualPath, out isLess, out isBundle))
            {
                return(GetCacheDependencyInternal(virtualPath, virtualPathDependencies, utcStart));
            }
            else
            {
                if (!isLess && !isBundle)
                {
                    // it's a static css file (no bundle, no less)
                    return(GetCacheDependencyInternal(virtualPath, virtualPathDependencies, utcStart));
                }

                var arrPathDependencies = virtualPathDependencies.Cast <string>().ToArray();

                // determine the virtual themevars.less import reference
                var themeVarsFile = arrPathDependencies.Where(x => ThemeHelper.PathIsThemeVars(x)).FirstOrDefault();

                if (themeVarsFile.IsEmpty())
                {
                    // no themevars import... so no special considerations here
                    return(GetCacheDependencyInternal(virtualPath, virtualPathDependencies, utcStart));
                }

                // exclude the themevars import from the file dependencies list,
                // 'cause this one cannot be monitored by the physical file system
                var fileDependencies = arrPathDependencies.Except(new string[] { themeVarsFile });

                if (arrPathDependencies.Any())
                {
                    int storeId = ThemeHelper.ResolveCurrentSiteId();
                    var theme   = ThemeHelper.ResolveCurrentTheme();
                    // invalidate the cache when variables change
                    string cacheKey        = AspNetCache.BuildKey(ModelCacheEventConsumer.BuildThemeVarsCacheKey(theme.ThemeName, storeId));
                    var    cacheDependency = new CacheDependency(MapDependencyPaths(fileDependencies), new string[] { cacheKey }, utcStart);
                    return(cacheDependency);
                }

                return(null);
            }
        }
예제 #2
0
        /// <summary>
        /// Tries to resolve a file up in the current theme's hierarchy chain.
        /// </summary>
        /// <param name="virtualPath">The original virtual path of the theme file</param>
        /// <returns>
        /// If the current working themme is based on another theme AND the requested file
        /// was physically found in the theme's hierarchy chain, an instance of <see cref="InheritedThemeFileResult" /> will be returned.
        /// In any other case the return value is <c>null</c>.
        /// </returns>
        public InheritedThemeFileResult Resolve(string virtualPath)
        {
            Guard.ArgumentNotEmpty(() => virtualPath);

            virtualPath = VirtualPathUtility.ToAppRelative(virtualPath);

            if (!ThemeHelper.PathIsInheritableThemeFile(virtualPath))
            {
                return(null);
            }

            bool isExplicit = false;

            string requestedThemeName;
            string relativePath;
            string query;

            virtualPath = TokenizePath(virtualPath, out requestedThemeName, out relativePath, out query);

            Func <InheritedThemeFileResult> nullOrFile = () =>
            {
                if (isExplicit)
                {
                    return(new InheritedThemeFileResult {
                        IsExplicit = true, OriginalVirtualPath = virtualPath
                    });
                }
                return(null);
            };

            ThemeManifest currentTheme;
            var           isAdmin = EngineContext.Current.Resolve <IWorkContext>().IsAdmin;  // ThemeHelper.IsAdminArea()

            if (isAdmin)
            {
                currentTheme = _themeRegistry.GetThemeManifest(requestedThemeName);
            }
            else
            {
                bool isLess;
                bool isBundle;
                if (ThemeHelper.IsStyleSheet(relativePath, out isLess, out isBundle) && isLess)
                {
                    // special consideration for LESS files: they can be validated
                    // in the backend. For validation, a "theme" query is appended
                    // to the url. During validation we must work with the actual
                    // requested theme instead dynamically resolving the working theme.
                    var httpContext = HttpContext.Current;
                    if (httpContext != null && httpContext.Request != null)
                    {
                        var qs = httpContext.Request.QueryString;
                        if (qs["theme"].HasValue())
                        {
                            EngineContext.Current.Resolve <IThemeContext>().SetRequestTheme(qs["theme"]);
                        }
                    }
                }

                if (isLess && query != null && query.StartsWith("explicit", StringComparison.OrdinalIgnoreCase))
                {
                    // special case to support LESS @import declarations
                    // within inherited LESS files. Snenario: an inheritor wishes to
                    // include the same file from it's base theme (e.g. custom.less) just to tweak it
                    // a bit for his child theme. Without the 'explicit' query the resolution starting point
                    // for custom.less would be the CURRENT theme's folder, and NOT the requested one's,
                    // which inevitably would result in a cyclic dependency.
                    currentTheme = _themeRegistry.GetThemeManifest(requestedThemeName);
                    isExplicit   = true;
                }
                else
                {
                    currentTheme = ThemeHelper.ResolveCurrentTheme();
                }

                if (currentTheme.BaseTheme == null)
                {
                    // dont't bother resolving files: the current theme is not inherited.
                    // Let the current VPP do the work.
                    return(nullOrFile());
                }
            }

            if (!currentTheme.ThemeName.Equals(requestedThemeName, StringComparison.OrdinalIgnoreCase))
            {
                if (!_themeRegistry.IsChildThemeOf(currentTheme.ThemeName, requestedThemeName))
                {
                    return(nullOrFile());
                }
            }

            var fileKey = new FileKey(currentTheme.ThemeName, relativePath);

            var result = _files.GetOrAdd(fileKey, (k) =>
            {
                // ALWAYS begin the search with the current working theme's location!
                string resultVirtualPath;
                string resultPhysicalPath;
                string actualLocation = LocateFile(currentTheme.ThemeName, relativePath, out resultVirtualPath, out resultPhysicalPath);

                if (actualLocation != null)
                {
                    return(new InheritedThemeFileResult
                    {
                        RelativePath = relativePath,
                        OriginalVirtualPath = virtualPath,
                        ResultVirtualPath = resultVirtualPath,
                        ResultPhysicalPath = resultPhysicalPath,
                        OriginalThemeName = requestedThemeName,
                        ResultThemeName = actualLocation
                    });
                }

                return(null);
            });

            if (result == null)
            {
                return(nullOrFile());
            }

            return(result);
        }