Commit f51a2635 by Qiang Xue

new asset management WIP

parent 280c2ca0
{
"directory" : "web/assets"
}
\ No newline at end of file
{
"name": "yii2-basic",
"version": "1.0.0",
"dependencies": {
},
"devDependencies": {
}
}
...@@ -30,7 +30,7 @@ instead of adding a new one. If you don't provide it, the JS code itself will be ...@@ -30,7 +30,7 @@ instead of adding a new one. If you don't provide it, the JS code itself will be
An external script can be added like the following: An external script can be added like the following:
```php ```php
$this->registerJsFile('http://example.com/js/main.js', [JqueryAsset::className()]); $this->registerJsFile('http://example.com/js/main.js', ['depends' => [JqueryAsset::className()]]);
``` ```
The arguments for [[yii\web\View::registerJsFile()|registerJsFile()]] are similar to those for The arguments for [[yii\web\View::registerJsFile()|registerJsFile()]] are similar to those for
...@@ -76,16 +76,19 @@ If you want to specify additional properties of the style tag, pass an array of ...@@ -76,16 +76,19 @@ If you want to specify additional properties of the style tag, pass an array of
If you need to make sure there's only a single style tag use fourth argument as was mentioned in meta tags description. If you need to make sure there's only a single style tag use fourth argument as was mentioned in meta tags description.
```php ```php
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [BootstrapAsset::className()], ['media' => 'print'], 'css-print-theme'); $this->registerCssFile("http://example.com/css/themes/black-and-white.css", [
'depends' => [BootstrapAsset::className()],
'media' => 'print',
], 'css-print-theme');
``` ```
The code above will add a link to CSS file to the head section of the page. The code above will add a link to CSS file to the head section of the page.
* The first argument specifies the CSS file to be registered. * The first argument specifies the CSS file to be registered.
* The second argument specifies that this CSS file depends on [[yii\bootstrap\BootstrapAsset|BootstrapAsset]], meaning it will be added * The second argument specifies the HTML attributes for the resulting `<link>` tag. The option `depends`
AFTER the CSS files in [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. Without this dependency specification, the relative order is specially handled. It specifies which asset bundles this CSS file depends on. In this case, the dependent
between this CSS file and the [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] CSS files would be undefined. asset bundle is [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. This means the CSS file will be added
* The third argument specifies the attributes for the resulting `<link>` tag. *after* the CSS files in [[yii\bootstrap\BootstrapAsset|BootstrapAsset]].
* The last argument specifies an ID identifying this CSS file. If it is not provided, the URL of the CSS file will be * The last argument specifies an ID identifying this CSS file. If it is not provided, the URL of the CSS file will be
used instead. used instead.
......
...@@ -76,7 +76,7 @@ class can be placed anywhere but the convention for it is to be under `assets` d ...@@ -76,7 +76,7 @@ class can be placed anywhere but the convention for it is to be under `assets` d
Additionally you may specify `$jsOptions`, `$cssOptions` and `$publishOptions` that will be passed to Additionally you may specify `$jsOptions`, `$cssOptions` and `$publishOptions` that will be passed to
[[yii\web\View::registerJsFile()]], [[yii\web\View::registerCssFile()]] and [[yii\web\AssetManager::publish()]] [[yii\web\View::registerJsFile()]], [[yii\web\View::registerCssFile()]] and [[yii\web\AssetManager::publish()]]
respectively during registering and publising an asset. For more details on this see [Setting special options](#setting-special-options). respectively during registering and publishing an asset. For more details on this see [Setting special options](#setting-special-options).
[alias]: basics.md#path-aliases "Yii Path alias" [alias]: basics.md#path-aliases "Yii Path alias"
...@@ -89,16 +89,16 @@ following way: ...@@ -89,16 +89,16 @@ following way:
```php ```php
class LanguageAsset extends AssetBundle class LanguageAsset extends AssetBundle
{ {
public $language; public static $language;
public $sourcePath = '@app/assets/language'; public $sourcePath = '@app/assets/language';
public $js = [ public $js = [
]; ];
public function registerAssetFiles($view) public function init()
{ {
$language = $this->language ? $this->language : Yii::$app->language; parent::init();
$language = self::$language ? self::$language : Yii::$app->language;
$this->js[] = 'language-' . $language . '.js'; $this->js[] = 'language-' . $language . '.js';
parent::registerAssetFiles($view);
} }
} }
``` ```
...@@ -106,7 +106,8 @@ class LanguageAsset extends AssetBundle ...@@ -106,7 +106,8 @@ class LanguageAsset extends AssetBundle
In order to set language use the following code when registering an asset bundle in a view: In order to set language use the following code when registering an asset bundle in a view:
```php ```php
LanguageAsset::register($this)->language = $language; LanguageAsset::$language = $language;
LanguageAsset::register($this);
``` ```
......
...@@ -319,11 +319,10 @@ PHP; ...@@ -319,11 +319,10 @@ PHP;
$url = ArrayHelper::remove($params, 'url'); $url = ArrayHelper::remove($params, 'url');
$key = ArrayHelper::remove($params, 'key', null); $key = ArrayHelper::remove($params, 'key', null);
$depends = ArrayHelper::remove($params, 'depends', null);
if (isset($params['position'])) if (isset($params['position']))
$params['position'] = $this->getViewConstVal($params['position'], View::POS_END); $params['position'] = $this->getViewConstVal($params['position'], View::POS_END);
Yii::$app->getView()->registerJsFile($url, $depends, $params, $key); Yii::$app->getView()->registerJsFile($url, $params, $key);
} }
/** /**
...@@ -379,9 +378,8 @@ PHP; ...@@ -379,9 +378,8 @@ PHP;
$url = ArrayHelper::remove($params, 'url'); $url = ArrayHelper::remove($params, 'url');
$key = ArrayHelper::remove($params, 'key', null); $key = ArrayHelper::remove($params, 'key', null);
$depends = ArrayHelper::remove($params, 'depends', null);
Yii::$app->getView()->registerCssFile($url, $depends, $params, $key); Yii::$app->getView()->registerCssFile($url, $params, $key);
} }
/** /**
...@@ -427,4 +425,4 @@ PHP; ...@@ -427,4 +425,4 @@ PHP;
$val = @constant('yii\web\View::' . $string); $val = @constant('yii\web\View::' . $string);
return isset($val) ? $val : $default; return isset($val) ? $val : $default;
} }
} }
\ No newline at end of file
...@@ -319,4 +319,15 @@ class BaseUrl ...@@ -319,4 +319,15 @@ class BaseUrl
return $url; return $url;
} }
/**
* Returns a value indicating whether a URL is relative.
* A relative URL does not have host info part.
* @param string $url the URL to be checked
* @return boolean whether the URL is relative
*/
public static function isRelative($url)
{
return strncmp($url, '//', 2) && strpos($url, '://') === false;
}
} }
...@@ -26,41 +26,21 @@ use yii\base\Object; ...@@ -26,41 +26,21 @@ use yii\base\Object;
class AssetBundle extends Object class AssetBundle extends Object
{ {
/** /**
* @var string the root directory of the source asset files. A source asset file * @var string the directory that contains the asset files in this bundle.
* is a file that is part of your source code repository of your Web application.
* *
* You must set this property if the directory containing the source asset files * The value of this property can be prefixed to every relative asset file path listed in [[js]] and [[css]]
* is not Web accessible (this is usually the case for extensions). * to form an absolute file path. If this property is null (meaning not set), the value of
* * [[AssetManager::basePath]] will be used instead.
* By setting this property, the asset manager will publish the source asset files
* to a Web-accessible directory [[basePath]].
*
* You can use either a directory or an alias of the directory.
*/
public $sourcePath;
/**
* @var string the Web-accessible directory that contains the asset files in this bundle.
*
* If [[sourcePath]] is set, this property will be *overwritten* by [[AssetManager]]
* when it publishes the asset files from [[sourcePath]].
*
* If the bundle contains any assets that are specified in terms of relative file path,
* then this property must be set either manually or automatically (by [[AssetManager]] via
* asset publishing).
* *
* You can use either a directory or an alias of the directory. * You can use either a directory or an alias of the directory.
*/ */
public $basePath; public $basePath;
/** /**
* @var string the base URL that will be prefixed to the asset files for them to * @var string the base URL for the relative asset files listed in [[js]] and [[css]].
* be accessed via Web server.
* *
* If [[sourcePath]] is set, this property will be *overwritten* by [[AssetManager]] * The value of this property will be prefixed to every relative asset file path listed in [[js]] and [[css]]
* when it publishes the asset files from [[sourcePath]]. * when they are being registered in a view so that they can be Web accessible.
* * If this property is null (meaning not set), the value of [[AssetManager::baseUrl]] will be used instead.
* If the bundle contains any assets that are specified in terms of relative file path,
* then this property must be set either manually or automatically (by asset manager via
* asset publishing).
* *
* You can use either a URL or an alias of the URL. * You can use either a URL or an alias of the URL.
*/ */
...@@ -80,16 +60,16 @@ class AssetBundle extends Object ...@@ -80,16 +60,16 @@ class AssetBundle extends Object
public $depends = []; public $depends = [];
/** /**
* @var array list of JavaScript files that this bundle contains. Each JavaScript file can * @var array list of JavaScript files that this bundle contains. Each JavaScript file can
* be either a file path (without leading slash) relative to [[basePath]] or a URL representing * be either a file path (without leading slash) relative to [[basePath]] and [[baseUrl]],
* an external JavaScript file. * or a URL representing an external JavaScript file.
* *
* Note that only forward slash "/" can be used as directory separator. * Note that only forward slash "/" can be used as directory separators.
*/ */
public $js = []; public $js = [];
/** /**
* @var array list of CSS files that this bundle contains. Each CSS file can * @var array list of CSS files that this bundle contains. Each CSS file can
* be either a file path (without leading slash) relative to [[basePath]] or a URL representing * be either a file path (without leading slash) relative to [[basePath]] and [[baseUrl]],
* an external CSS file. * or a URL representing an external CSS file.
* *
* Note that only forward slash "/" can be used as directory separator. * Note that only forward slash "/" can be used as directory separator.
*/ */
...@@ -104,15 +84,11 @@ class AssetBundle extends Object ...@@ -104,15 +84,11 @@ class AssetBundle extends Object
* when registering the CSS files in this bundle. * when registering the CSS files in this bundle.
*/ */
public $cssOptions = []; public $cssOptions = [];
/**
* @var array the options to be passed to [[AssetManager::publish()]] when the asset bundle
* is being published.
*/
public $publishOptions = [];
/** /**
* @param View $view * Registers this asset bundle with a view.
* @param View $view the view to be registered with
* @return static the registered asset bundle instance * @return static the registered asset bundle instance
*/ */
public static function register($view) public static function register($view)
...@@ -126,9 +102,6 @@ class AssetBundle extends Object ...@@ -126,9 +102,6 @@ class AssetBundle extends Object
*/ */
public function init() public function init()
{ {
if ($this->sourcePath !== null) {
$this->sourcePath = rtrim(Yii::getAlias($this->sourcePath), '/\\');
}
if ($this->basePath !== null) { if ($this->basePath !== null) {
$this->basePath = rtrim(Yii::getAlias($this->basePath), '/\\'); $this->basePath = rtrim(Yii::getAlias($this->basePath), '/\\');
} }
...@@ -136,58 +109,4 @@ class AssetBundle extends Object ...@@ -136,58 +109,4 @@ class AssetBundle extends Object
$this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/'); $this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/');
} }
} }
/**
* Registers the CSS and JS files with the given view.
* @param \yii\web\View $view the view that the asset files are to be registered with.
*/
public function registerAssetFiles($view)
{
foreach ($this->js as $js) {
if ($js[0] !== '/' && $js[0] !== '.' && strpos($js, '://') === false) {
$view->registerJsFile($this->baseUrl . '/' . $js, [], $this->jsOptions);
} else {
$view->registerJsFile($js, [], $this->jsOptions);
}
}
foreach ($this->css as $css) {
if ($css[0] !== '/' && $css[0] !== '.' && strpos($css, '://') === false) {
$view->registerCssFile($this->baseUrl . '/' . $css, [], $this->cssOptions);
} else {
$view->registerCssFile($css, [], $this->cssOptions);
}
}
}
/**
* Publishes the asset bundle if its source code is not under Web-accessible directory.
* It will also try to convert non-CSS or JS files (e.g. LESS, Sass) into the corresponding
* CSS or JS files using [[AssetManager::converter|asset converter]].
* @param AssetManager $am the asset manager to perform the asset publishing
*/
public function publish($am)
{
if ($this->sourcePath !== null && !isset($this->basePath, $this->baseUrl)) {
list ($this->basePath, $this->baseUrl) = $am->publish($this->sourcePath, $this->publishOptions);
}
$converter = $am->getConverter();
foreach ($this->js as $i => $js) {
if (strpos($js, '/') !== 0 && strpos($js, '://') === false) {
if (isset($this->basePath, $this->baseUrl)) {
$this->js[$i] = $converter->convert($js, $this->basePath);
} else {
$this->js[$i] = '/' . $js;
}
}
}
foreach ($this->css as $i => $css) {
if (strpos($css, '/') !== 0 && strpos($css, '://') === false) {
if (isset($this->basePath, $this->baseUrl)) {
$this->css[$i] = $converter->convert($css, $this->basePath);
} else {
$this->css[$i] = '/' . $css;
}
}
}
}
} }
...@@ -12,6 +12,7 @@ use yii\base\Component; ...@@ -12,6 +12,7 @@ use yii\base\Component;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\helpers\FileHelper; use yii\helpers\FileHelper;
use yii\helpers\Url;
/** /**
* AssetManager manages asset bundles and asset publishing. * AssetManager manages asset bundles and asset publishing.
...@@ -63,64 +64,7 @@ class AssetManager extends Component ...@@ -63,64 +64,7 @@ class AssetManager extends Component
* @return string the base URL through which the published asset files can be accessed. * @return string the base URL through which the published asset files can be accessed.
*/ */
public $baseUrl = '@web/assets'; public $baseUrl = '@web/assets';
/** public $assetMap = [];
* @var boolean whether to use symbolic link to publish asset files. Defaults to false, meaning
* asset files are copied to [[basePath]]. Using symbolic links has the benefit that the published
* assets will always be consistent with the source assets and there is no copy operation required.
* This is especially useful during development.
*
* However, there are special requirements for hosting environments in order to use symbolic links.
* In particular, symbolic links are supported only on Linux/Unix, and Windows Vista/2008 or greater.
*
* Moreover, some Web servers need to be properly configured so that the linked assets are accessible
* to Web users. For example, for Apache Web server, the following configuration directive should be added
* for the Web folder:
*
* ~~~
* Options FollowSymLinks
* ~~~
*/
public $linkAssets = false;
/**
* @var integer the permission to be set for newly published asset files.
* This value will be used by PHP chmod() function. No umask will be applied.
* If not set, the permission will be determined by the current environment.
*/
public $fileMode;
/**
* @var integer the permission to be set for newly generated asset directories.
* This value will be used by PHP chmod() function. No umask will be applied.
* Defaults to 0775, meaning the directory is read-writable by owner and group,
* but read-only for other users.
*/
public $dirMode = 0775;
/**
* @var callback a PHP callback that is called before copying each sub-directory or file.
* This option is used only when publishing a directory. If the callback returns false, the copy
* operation for the sub-directory or file will be cancelled.
*
* The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
* file to be copied from, while `$to` is the copy target.
*
* This is passed as a parameter `beforeCopy` to [[\yii\helpers\FileHelper::copyDirectory()]].
*/
public $beforeCopy;
/**
* @var callback a PHP callback that is called after a sub-directory or file is successfully copied.
* This option is used only when publishing a directory. The signature of the callback is the same as
* for [[beforeCopy]].
* This is passed as a parameter `afterCopy` to [[\yii\helpers\FileHelper::copyDirectory()]].
*/
public $afterCopy;
/**
* @var boolean whether the directory being published should be copied even if
* it is found in the target directory. This option is used only when publishing a directory.
* You may want to set this to be `true` during the development stage to make sure the published
* directory is always up-to-date. Do not set this to true on production servers as it will
* significantly degrade the performance.
*/
public $forceCopy = false;
/** /**
* Initializes the component. * Initializes the component.
...@@ -130,12 +74,10 @@ class AssetManager extends Component ...@@ -130,12 +74,10 @@ class AssetManager extends Component
{ {
parent::init(); parent::init();
$this->basePath = Yii::getAlias($this->basePath); $this->basePath = Yii::getAlias($this->basePath);
if (!is_dir($this->basePath)) { if (is_dir($this->basePath)) {
throw new InvalidConfigException("The directory does not exist: {$this->basePath}");
} elseif (!is_writable($this->basePath)) {
throw new InvalidConfigException("The directory is not writable by the Web process: {$this->basePath}");
} else {
$this->basePath = realpath($this->basePath); $this->basePath = realpath($this->basePath);
} else {
throw new InvalidConfigException("The directory does not exist: {$this->basePath}");
} }
$this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/'); $this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/');
} }
...@@ -147,233 +89,63 @@ class AssetManager extends Component ...@@ -147,233 +89,63 @@ class AssetManager extends Component
* it will treat `$name` as the class of the asset bundle and create a new instance of it. * it will treat `$name` as the class of the asset bundle and create a new instance of it.
* *
* @param string $name the class name of the asset bundle * @param string $name the class name of the asset bundle
* @param boolean $publish whether to publish the asset files in the asset bundle before it is returned.
* If you set this false, you must manually call `AssetBundle::publish()` to publish the asset files.
* @return AssetBundle the asset bundle instance * @return AssetBundle the asset bundle instance
* @throws InvalidConfigException if $name does not refer to a valid asset bundle * @throws InvalidConfigException if $name does not refer to a valid asset bundle
*/ */
public function getBundle($name, $publish = true) public function getBundle($name)
{ {
if (isset($this->bundles[$name])) { if ($this->bundles === false) {
if ($this->bundles[$name] instanceof AssetBundle) { return null;
return $this->bundles[$name]; } elseif (!isset($this->bundles[$name])) {
} elseif (is_array($this->bundles[$name])) { return $this->bundles[$name] = $this->loadBundle($name);
$bundle = Yii::createObject(array_merge(['class' => $name], $this->bundles[$name])); } elseif ($this->bundles[$name] instanceof AssetBundle) {
} else { return $this->bundles[$name];
throw new InvalidConfigException("Invalid asset bundle: $name"); } elseif (is_array($this->bundles[$name])) {
} return $this->bundles[$name] = $this->loadBundle($name, $this->bundles[$name]);
} elseif ($this->bundles[$name] === false) {
return null;
} else { } else {
$bundle = Yii::createObject($name); throw new InvalidConfigException("Invalid asset bundle configuration: $name");
}
if ($publish) {
/* @var $bundle AssetBundle */
$bundle->publish($this);
}
return $this->bundles[$name] = $bundle;
}
private $_converter;
/**
* Returns the asset converter.
* @return AssetConverterInterface the asset converter.
*/
public function getConverter()
{
if ($this->_converter === null) {
$this->_converter = Yii::createObject(AssetConverter::className());
} elseif (is_array($this->_converter) || is_string($this->_converter)) {
if (is_array($this->_converter) && !isset($this->_converter['class'])) {
$this->_converter['class'] = AssetConverter::className();
}
$this->_converter = Yii::createObject($this->_converter);
} }
return $this->_converter;
}
/**
* Sets the asset converter.
* @param array|AssetConverterInterface $value the asset converter. This can be either
* an object implementing the [[AssetConverterInterface]], or a configuration
* array that can be used to create the asset converter object.
*/
public function setConverter($value)
{
$this->_converter = $value;
} }
/** protected function loadBundle($name, $config = [])
* @var array published assets
*/
private $_published = [];
/**
* Publishes a file or a directory.
*
* This method will copy the specified file or directory to [[basePath]] so that
* it can be accessed via the Web server.
*
* If the asset is a file, its file modification time will be checked to avoid
* unnecessary file copying.
*
* If the asset is a directory, all files and subdirectories under it will be published recursively.
* Note, in case $forceCopy is false the method only checks the existence of the target
* directory to avoid repetitive copying (which is very expensive).
*
* By default, when publishing a directory, subdirectories and files whose name starts with a dot "."
* will NOT be published. If you want to change this behavior, you may specify the "beforeCopy" option
* as explained in the `$options` parameter.
*
* Note: On rare scenario, a race condition can develop that will lead to a
* one-time-manifestation of a non-critical problem in the creation of the directory
* that holds the published assets. This problem can be avoided altogether by 'requesting'
* in advance all the resources that are supposed to trigger a 'publish()' call, and doing
* that in the application deployment phase, before system goes live. See more in the following
* discussion: http://code.google.com/p/yii/issues/detail?id=2579
*
* @param string $path the asset (file or directory) to be published
* @param array $options the options to be applied when publishing a directory.
* The following options are supported:
*
* - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
* This overrides [[beforeCopy]] if set.
* - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied.
* This overrides [[afterCopy]] if set.
* - forceCopy: boolean, whether the directory being published should be copied even if
* it is found in the target directory. This option is used only when publishing a directory.
* This overrides [[forceCopy]] if set.
*
* @return array the path (directory or file path) and the URL that the asset is published as.
* @throws InvalidParamException if the asset to be published does not exist.
*/
public function publish($path, $options = [])
{ {
$path = Yii::getAlias($path); if (!isset($config['class'])) {
$config['class'] = $name;
if (isset($this->_published[$path])) {
return $this->_published[$path];
} }
$bundle = Yii::createObject($config);
if (!is_string($path) || ($src = realpath($path)) === false) { if ($bundle->basePath === null) {
throw new InvalidParamException("The file or directory to be published does not exist: $path"); $bundle->basePath = $this->basePath;
} }
if ($bundle->baseUrl === null) {
if (is_file($src)) { $bundle->baseUrl = $this->baseUrl;
$dir = $this->hash(dirname($src) . filemtime($src));
$fileName = basename($src);
$dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir;
$dstFile = $dstDir . DIRECTORY_SEPARATOR . $fileName;
if (!is_dir($dstDir)) {
FileHelper::createDirectory($dstDir, $this->dirMode, true);
}
if ($this->linkAssets) {
if (!is_file($dstFile)) {
symlink($src, $dstFile);
}
} elseif (@filemtime($dstFile) < @filemtime($src)) {
copy($src, $dstFile);
if ($this->fileMode !== null) {
@chmod($dstFile, $this->fileMode);
}
}
return $this->_published[$path] = [$dstFile, $this->baseUrl . "/$dir/$fileName"];
} else {
$dir = $this->hash($src . filemtime($src));
$dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir;
if ($this->linkAssets) {
if (!is_dir($dstDir)) {
symlink($src, $dstDir);
}
} elseif (!is_dir($dstDir) || !empty($options['forceCopy']) || (!isset($options['forceCopy']) && $this->forceCopy)) {
$opts = [
'dirMode' => $this->dirMode,
'fileMode' => $this->fileMode,
];
if (isset($options['beforeCopy'])) {
$opts['beforeCopy'] = $options['beforeCopy'];
} elseif ($this->beforeCopy !== null) {
$opts['beforeCopy'] = $this->beforeCopy;
} else {
$opts['beforeCopy'] = function ($from, $to) {
return strncmp(basename($from), '.', 1) !== 0;
};
}
if (isset($options['afterCopy'])) {
$opts['afterCopy'] = $options['afterCopy'];
} elseif ($this->afterCopy !== null) {
$opts['afterCopy'] = $this->afterCopy;
}
FileHelper::copyDirectory($src, $dstDir, $opts);
}
return $this->_published[$path] = [$dstDir, $this->baseUrl . '/' . $dir];
} }
return $bundle;
} }
/** /**
* Returns the published path of a file path. * @param View $view
* This method does not perform any publishing. It merely tells you * @param AssetBundle $bundle
* if the file or directory is published, where it will go.
* @param string $path directory or file path being published
* @return string the published file path. False if the file or directory does not exist
*/ */
public function getPublishedPath($path) public function registerAssetFiles($view, $bundle)
{ {
$path = Yii::getAlias($path); foreach ($bundle->js as $js) {
$view->registerJsFile($this->getAssetUrl($bundle, $js), $bundle->jsOptions);
if (isset($this->_published[$path])) {
return $this->_published[$path][0];
} }
if (is_string($path) && ($path = realpath($path)) !== false) { foreach ($bundle->css as $css) {
$base = $this->basePath . DIRECTORY_SEPARATOR; $view->registerCssFile($this->getAssetUrl($bundle, $css), $bundle->cssOptions);
if (is_file($path)) {
return $base . $this->hash(dirname($path) . filemtime($path)) . DIRECTORY_SEPARATOR . basename($path);
} else {
return $base . $this->hash($path . filemtime($path));
}
} else {
return false;
} }
} }
/** protected function getAssetUrl($bundle, $file)
* Returns the URL of a published file path.
* This method does not perform any publishing. It merely tells you
* if the file path is published, what the URL will be to access it.
* @param string $path directory or file path being published
* @return string the published URL for the file or directory. False if the file or directory does not exist.
*/
public function getPublishedUrl($path)
{ {
$path = Yii::getAlias($path); if (strncmp($file, '@/', 2) === 0) {
$file = $this->baseUrl . substr($file, 1);
if (isset($this->_published[$path])) { } elseif (Url::isRelative($file)) {
return $this->_published[$path][1]; $file = $bundle->baseUrl . '/' . $file;
} }
if (is_string($path) && ($path = realpath($path)) !== false) { // todo: assetMap
if (is_file($path)) { return $file;
return $this->baseUrl . '/' . $this->hash(dirname($path) . filemtime($path)) . '/' . basename($path);
} else {
return $this->baseUrl . '/' . $this->hash($path . filemtime($path));
}
} else {
return false;
}
}
/**
* Generate a CRC32 hash for the directory path. Collisions are higher
* than MD5 but generates a much smaller hash string.
* @param string $path string to be hashed.
* @return string hashed string.
*/
protected function hash($path)
{
return sprintf('%x', crc32($path . Yii::getVersion()));
} }
} }
...@@ -15,8 +15,7 @@ namespace yii\web; ...@@ -15,8 +15,7 @@ namespace yii\web;
*/ */
class JqueryAsset extends AssetBundle class JqueryAsset extends AssetBundle
{ {
public $sourcePath = '@vendor/yiisoft/jquery';
public $js = [ public $js = [
'jquery.js', 'jquery/dist/jquery.js',
]; ];
} }
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
namespace yii\web; namespace yii\web;
use Yii; use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Html; use yii\helpers\Html;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\helpers\Url;
/** /**
* View represents a view object in the MVC pattern. * View represents a view object in the MVC pattern.
...@@ -261,7 +261,7 @@ class View extends \yii\base\View ...@@ -261,7 +261,7 @@ class View extends \yii\base\View
foreach ($bundle->depends as $dep) { foreach ($bundle->depends as $dep) {
$this->registerAssetFiles($dep); $this->registerAssetFiles($dep);
} }
$bundle->registerAssetFiles($this); $this->getAssetManager()->registerAssetFiles($this, $bundle);
} }
unset($this->assetBundles[$name]); unset($this->assetBundles[$name]);
} }
...@@ -360,23 +360,27 @@ class View extends \yii\base\View ...@@ -360,23 +360,27 @@ class View extends \yii\base\View
/** /**
* Registers a CSS file. * Registers a CSS file.
* @param string $url the CSS file to be registered. * @param string $url the CSS file to be registered.
* @param array $depends the names of the asset bundles that this CSS file depends on * @param array $options the HTML attributes for the link tag. Please refer to [[Html::cssFile()]] for
* @param array $options the HTML attributes for the link tag. * the supported options. The following options are specially handled and are not treated as HTML attributes:
* Please refer to [[Html::cssFile()]] for supported options. *
* - `depends`: array, specifies the names of the asset bundles that this CSS file depends on.
*
* @param string $key the key that identifies the CSS script file. If null, it will use * @param string $key the key that identifies the CSS script file. If null, it will use
* $url as the key. If two CSS files are registered with the same key, the latter * $url as the key. If two CSS files are registered with the same key, the latter
* will overwrite the former. * will overwrite the former.
*/ */
public function registerCssFile($url, $depends = [], $options = [], $key = null) public function registerCssFile($url, $options = [], $key = null)
{ {
$url = Yii::getAlias($url); $url = Yii::getAlias($url);
$key = $key ?: $url; $key = $key ?: $url;
$depends = ArrayHelper::remove($options, 'depends', []);
if (empty($depends)) { if (empty($depends)) {
$this->cssFiles[$key] = Html::cssFile($url, $options); $this->cssFiles[$key] = Html::cssFile($url, $options);
} else { } else {
$am = $this->getAssetManager(); $this->getAssetManager()->bundles[$key] = new AssetBundle([
$am->bundles[$key] = new AssetBundle([ 'baseUrl' => '',
'css' => [Url::to($url)], 'css' => [$url],
'cssOptions' => $options, 'cssOptions' => $options,
'depends' => (array) $depends, 'depends' => (array) $depends,
]); ]);
...@@ -414,14 +418,14 @@ class View extends \yii\base\View ...@@ -414,14 +418,14 @@ class View extends \yii\base\View
/** /**
* Registers a JS file. * Registers a JS file.
* @param string $url the JS file to be registered. * @param string $url the JS file to be registered.
* @param array $depends the names of the asset bundles that this JS file depends on * @param array $options the HTML attributes for the script tag. The following options are specially handled
* @param array $options the HTML attributes for the script tag. A special option * and are not treated as HTML attributes:
* named "position" is supported which specifies where the JS script tag should be inserted
* in a page. The possible values of "position" are:
* *
* - [[POS_HEAD]]: in the head section * - `depends`: array, specifies the names of the asset bundles that this JS file depends on.
* - [[POS_BEGIN]]: at the beginning of the body section * - `position`: specifies where the JS script tag should be inserted in a page. The possible values are:
* - [[POS_END]]: at the end of the body section. This is the default value. * * [[POS_HEAD]]: in the head section
* * [[POS_BEGIN]]: at the beginning of the body section
* * [[POS_END]]: at the end of the body section. This is the default value.
* *
* Please refer to [[Html::jsFile()]] for other supported options. * Please refer to [[Html::jsFile()]] for other supported options.
* *
...@@ -429,18 +433,19 @@ class View extends \yii\base\View ...@@ -429,18 +433,19 @@ class View extends \yii\base\View
* $url as the key. If two JS files are registered with the same key, the latter * $url as the key. If two JS files are registered with the same key, the latter
* will overwrite the former. * will overwrite the former.
*/ */
public function registerJsFile($url, $depends = [], $options = [], $key = null) public function registerJsFile($url, $options = [], $key = null)
{ {
$url = Yii::getAlias($url); $url = Yii::getAlias($url);
$key = $key ?: $url; $key = $key ?: $url;
$depends = ArrayHelper::remove($options, 'depends', []);
if (empty($depends)) { if (empty($depends)) {
$position = isset($options['position']) ? $options['position'] : self::POS_END; $position = ArrayHelper::remove($options, 'position', self::POS_END);
unset($options['position']);
$this->jsFiles[$position][$key] = Html::jsFile($url, $options); $this->jsFiles[$position][$key] = Html::jsFile($url, $options);
} else { } else {
$am = $this->getAssetManager(); $this->getAssetManager()->bundles[$key] = new AssetBundle([
$am->bundles[$key] = new AssetBundle([ 'baseUrl' => '',
'js' => [Url::to($url)], 'js' => [$url],
'jsOptions' => $options, 'jsOptions' => $options,
'depends' => (array) $depends, 'depends' => (array) $depends,
]); ]);
......
...@@ -15,9 +15,8 @@ namespace yii\web; ...@@ -15,9 +15,8 @@ namespace yii\web;
*/ */
class YiiAsset extends AssetBundle class YiiAsset extends AssetBundle
{ {
public $sourcePath = '@yii/assets';
public $js = [ public $js = [
'yii.js', 'yii2/assets/yii.js',
]; ];
public $depends = [ public $depends = [
'yii\web\JqueryAsset', 'yii\web\JqueryAsset',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment