Add new ModuleResourceLoader helper

This commit is contained in:
Damian Mooyman 2017-10-03 12:20:49 +13:00
parent e1b98d154e
commit f64c95b33c
No known key found for this signature in database
GPG Key ID: 78B823A10DE27D1A
6 changed files with 118 additions and 39 deletions

View File

@ -369,6 +369,26 @@ If the Javascript files are preferred to be placed in the `<head>` tag rather th
Requirements::set_write_js_to_body(false);
```
## Direct resource urls
In templates you can use the `$resourcePath()` or `$resourceURL()` helper methods to inject links to
resources directly. If you want to link to resources within a specific module you can use
the `vendor/module:some/path/to/file.jpg` syntax.
E.g.
```ss
<div class="loading">
<img src="$resourceURL('silverstripe/admin:client/dist/images/spinner.gif')" />
</div>
```
In PHP you can directly resolve these urls using the `ModuleResourceLoader` helper.
```php
$file = ModuleResourceLoader::singleton()
->resolveURL('silverstripe/admin:client/dist/images/spinner.gif');
```
## API Documentation

View File

@ -0,0 +1,85 @@
<?php
namespace SilverStripe\Core\Manifest;
use InvalidArgumentException;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\View\TemplateGlobalProvider;
/**
* Helper for mapping module resources to paths / urls
*/
class ModuleResourceLoader implements TemplateGlobalProvider
{
use Injectable;
/**
* Convert a file of the form "vendor/package:resource" into a BASE_PATH-relative file
* For other files, return original value
*
* @param string $resource
* @return string
*/
public function resolvePath($resource)
{
// String of the form vendor/package:resource. Excludes "http://bla" as that's an absolute URL
if (!preg_match('#(?<module>[^/: ]*/[^/: ]*) *: *(?<resource>[^ ]*)#', $resource, $matches)) {
return $resource;
}
$module = $matches['module'];
$resource = $matches['resource'];
$moduleObj = ModuleLoader::getModule($module);
if (!$moduleObj) {
throw new InvalidArgumentException("Can't find module '$module'");
}
$resourceObj = $moduleObj->getResource($resource);
if (!$resourceObj->exists()) {
throw new InvalidArgumentException("Module '$module' does not have specified resource '$resource'");
}
return $resourceObj->getRelativePath();
}
/**
* Resolves resource specifier to the given url.
*
* @param string $resource
* @return string
*/
public function resolveURL($resource)
{
/** @var ResourceURLGenerator $generator */
$generator = Injector::inst()->get(ResourceURLGenerator::class);
return $generator->urlForResource($this->resolvePath($resource));
}
/**
* Template wrapper for resolvePath
*
* @param string $resource
* @return string
*/
public static function resourcePath($resource)
{
return static::singleton()->resolvePath($resource);
}
/**
* Template wrapper for resolveURL
*
* @param string $resource
* @return string
*/
public static function resourceURL($resource)
{
return static::singleton()->resolveURL($resource);
}
public static function get_template_global_variables()
{
return [
'resourcePath',
'resourceURL'
];
}
}

View File

@ -9,6 +9,8 @@ use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Manifest\ModuleLoader;
use SilverStripe\Core\Manifest\ModuleResourceLoader;
/**
* A basic HTML wrapper for stylish rendering of a developement info view.
@ -217,12 +219,8 @@ class DebugView
'UTF-8'
);
$debugCSS = Controller::join_links(
Director::absoluteBaseURL(),
FRAMEWORK_DIR,
'client/styles/debug.css'
);
$debugCSS = ModuleResourceLoader::singleton()
->resolveURL('silverstripe/framework:client/styles/debug.css');
$output = '<!DOCTYPE html><html><head><title>' . $url . '</title>';
$output .= '<link rel="stylesheet" type="text/css" href="'. $debugCSS .'" />';
$output .= '</head>';

View File

@ -417,7 +417,7 @@ YML
</Files>
# Deny access to YAML configuration files which might include sensitive information
<Files *.yml>
<Files ~ "\.ya?ml$">
Order allow,deny
Deny from all
</Files>
@ -431,6 +431,7 @@ ErrorDocument 500 /assets/error-500.html
# Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
<IfModule mod_dir.c>
DirectoryIndex disabled
DirectorySlash Off
</IfModule>
SetEnv HTTP_MOD_REWRITE On
@ -440,7 +441,7 @@ ErrorDocument 500 /assets/error-500.html
# Deny access to vendor, unless you're requesting main.php
# Not restricting to the start of the path to support RewriteBase
RewriteCond %{REQUEST_URI} !/vendor/silverstripe/framework/main\.php
RewriteCond %{REQUEST_URI} !^/vendor/silverstripe/framework/main\.php
RewriteRule ^vendor(/|$) - [F,L,NC]
# Deny access to potentially sensitive files and folders
@ -449,10 +450,6 @@ ErrorDocument 500 /assets/error-500.html
RewriteRule composer\.(json|lock) - [F,L,NC]
RewriteRule (error|silverstripe|debug)\.log - [F,L,NC]
# Deny access to potentially sensitive files and folders
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
RewriteRule composer\.(json|lock) - [F,L,NC]
# Process through SilverStripe if no file with the requested name exists.
# Pass through the original path as a query parameter, and retain the existing parameters.
# Try finding framework in the vendor folder first

View File

@ -12,8 +12,8 @@ use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Manifest\ModuleResourceLoader;
use SilverStripe\Core\Manifest\ResourceURLGenerator;
use SilverStripe\Core\Manifest\ModuleLoader;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\Deprecation;
use SilverStripe\i18n\i18n;
@ -401,7 +401,7 @@ class Requirements_Backend
*/
public function javascript($file, $options = array())
{
$file = $this->parseModuleResourceReference($file);
$file = ModuleResourceLoader::singleton()->resolvePath($file);
// Get type
$type = null;
@ -626,34 +626,13 @@ class Requirements_Backend
*/
public function css($file, $media = null)
{
$file = $this->parseModuleResourceReference($file);
$file = ModuleResourceLoader::singleton()->resolvePath($file);
$this->css[$file] = array(
"media" => $media
);
}
/**
* Convert a file of the form "vendor/package:resource" into a BASE_PATH-relative file
* For other files, reutrn original value
*
* @param string $file
* @return string
*/
protected function parseModuleResourceReference($file)
{
// String of the form vendor/package:resource. Excludes "http://bla" as that's an absolute URL
if (preg_match('#([^\/\/][^ /]*\/[^ /]*) *: *([^ ]*)#', $file, $matches)) {
list(, $module, $resource) = $matches;
$moduleObj = ModuleLoader::getModule($module);
if (!$moduleObj) {
throw new \InvalidArgumentException("Can't find module '$module'");
}
return $moduleObj->getRelativeResourcePath($resource);
}
return $file;
}
/**
* Remove a css requirement
*
@ -1462,7 +1441,7 @@ MESSAGE
if ($path) {
$this->css($path, $media);
} else {
throw new \InvalidArgumentException(
throw new InvalidArgumentException(
"The css file doesn't exist. Please check if the file $name.css exists in any context or search for "
. "themedCSS references calling this file in your templates."
);
@ -1490,7 +1469,7 @@ MESSAGE
}
$this->javascript($path, $opts);
} else {
throw new \InvalidArgumentException(
throw new InvalidArgumentException(
"The javascript file doesn't exist. Please check if the file $name.js exists in any "
. "context or search for themedJavascript references calling this file in your templates."
);

View File

@ -3,7 +3,6 @@
namespace SilverStripe\View;
use InvalidArgumentException;
use RuntimeException;
use SilverStripe\Core\Manifest\ModuleLoader;
/**
@ -279,6 +278,7 @@ class ThemeResourceLoader
*
* @param string $resource A file path relative to the root folder of a theme
* @param array $themes An order listed of themes to search
* @return string
*/
public function findThemedResource($resource, $themes)
{