From f51a263570781c6ee76b1d72f9ae138ee8217c77 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 27 Aug 2014 16:44:00 -0400 Subject: [PATCH] new asset management WIP --- apps/basic/.bowerrc | 3 + apps/basic/bower.json | 8 + docs/guide/output-client-scripts.md | 15 +- docs/guide/structure-assets.md | 13 +- extensions/smarty/Extension.php | 8 +- framework/helpers/BaseUrl.php | 11 + framework/web/AssetBundle.php | 111 ++-------- framework/web/AssetManager.php | 312 ++++------------------------ framework/web/JqueryAsset.php | 3 +- framework/web/View.php | 49 +++-- framework/web/YiiAsset.php | 3 +- 11 files changed, 127 insertions(+), 409 deletions(-) create mode 100644 apps/basic/.bowerrc create mode 100644 apps/basic/bower.json diff --git a/apps/basic/.bowerrc b/apps/basic/.bowerrc new file mode 100644 index 0000000000..16098e93d4 --- /dev/null +++ b/apps/basic/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory" : "web/assets" +} \ No newline at end of file diff --git a/apps/basic/bower.json b/apps/basic/bower.json new file mode 100644 index 0000000000..b3ec7cd2f5 --- /dev/null +++ b/apps/basic/bower.json @@ -0,0 +1,8 @@ +{ + "name": "yii2-basic", + "version": "1.0.0", + "dependencies": { + }, + "devDependencies": { + } +} diff --git a/docs/guide/output-client-scripts.md b/docs/guide/output-client-scripts.md index ec3b6b06cd..05a629aaf2 100644 --- a/docs/guide/output-client-scripts.md +++ b/docs/guide/output-client-scripts.md @@ -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: ```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 @@ -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. ```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 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 - AFTER the CSS files in [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. Without this dependency specification, the relative order - between this CSS file and the [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] CSS files would be undefined. -* The third argument specifies the attributes for the resulting `` tag. +* The second argument specifies the HTML attributes for the resulting `` tag. The option `depends` + is specially handled. It specifies which asset bundles this CSS file depends on. In this case, the dependent + asset bundle is [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. This means the CSS file will be added + *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 used instead. diff --git a/docs/guide/structure-assets.md b/docs/guide/structure-assets.md index 16f1c33cec..a735f37252 100644 --- a/docs/guide/structure-assets.md +++ b/docs/guide/structure-assets.md @@ -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 [[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" @@ -89,16 +89,16 @@ following way: ```php class LanguageAsset extends AssetBundle { - public $language; + public static $language; public $sourcePath = '@app/assets/language'; 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'; - parent::registerAssetFiles($view); } } ``` @@ -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: ```php -LanguageAsset::register($this)->language = $language; +LanguageAsset::$language = $language; +LanguageAsset::register($this); ``` diff --git a/extensions/smarty/Extension.php b/extensions/smarty/Extension.php index b81099f57a..011dbddb68 100644 --- a/extensions/smarty/Extension.php +++ b/extensions/smarty/Extension.php @@ -319,11 +319,10 @@ PHP; $url = ArrayHelper::remove($params, 'url'); $key = ArrayHelper::remove($params, 'key', null); - $depends = ArrayHelper::remove($params, 'depends', null); if (isset($params['position'])) $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; $url = ArrayHelper::remove($params, 'url'); $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; $val = @constant('yii\web\View::' . $string); return isset($val) ? $val : $default; } -} \ No newline at end of file +} diff --git a/framework/helpers/BaseUrl.php b/framework/helpers/BaseUrl.php index ac0d9e07f9..8b9418bb3d 100644 --- a/framework/helpers/BaseUrl.php +++ b/framework/helpers/BaseUrl.php @@ -319,4 +319,15 @@ class BaseUrl 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; + } } diff --git a/framework/web/AssetBundle.php b/framework/web/AssetBundle.php index f6a04d377e..eb2bea9e0e 100644 --- a/framework/web/AssetBundle.php +++ b/framework/web/AssetBundle.php @@ -26,41 +26,21 @@ use yii\base\Object; class AssetBundle extends Object { /** - * @var string the root directory of the source asset files. A source asset file - * is a file that is part of your source code repository of your Web application. + * @var string the directory that contains the asset files in this bundle. * - * You must set this property if the directory containing the source asset files - * is not Web accessible (this is usually the case for extensions). - * - * 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). + * The value of this property can be prefixed to every relative asset file path listed in [[js]] and [[css]] + * to form an absolute file path. If this property is null (meaning not set), the value of + * [[AssetManager::basePath]] will be used instead. * * You can use either a directory or an alias of the directory. */ public $basePath; /** - * @var string the base URL that will be prefixed to the asset files for them to - * be accessed via Web server. + * @var string the base URL for the relative asset files listed in [[js]] and [[css]]. * - * 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 asset manager via - * asset publishing). + * The value of this property will be prefixed to every relative asset file path listed in [[js]] and [[css]] + * 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. * * You can use either a URL or an alias of the URL. */ @@ -80,16 +60,16 @@ class AssetBundle extends Object public $depends = []; /** * @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 - * an external JavaScript file. + * be either a file path (without leading slash) relative to [[basePath]] and [[baseUrl]], + * 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 = []; /** * @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 - * an external CSS file. + * be either a file path (without leading slash) relative to [[basePath]] and [[baseUrl]], + * or a URL representing an external CSS file. * * Note that only forward slash "/" can be used as directory separator. */ @@ -104,15 +84,11 @@ class AssetBundle extends Object * when registering the CSS files in this bundle. */ 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 */ public static function register($view) @@ -126,9 +102,6 @@ class AssetBundle extends Object */ public function init() { - if ($this->sourcePath !== null) { - $this->sourcePath = rtrim(Yii::getAlias($this->sourcePath), '/\\'); - } if ($this->basePath !== null) { $this->basePath = rtrim(Yii::getAlias($this->basePath), '/\\'); } @@ -136,58 +109,4 @@ class AssetBundle extends Object $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; - } - } - } - } } diff --git a/framework/web/AssetManager.php b/framework/web/AssetManager.php index d7144bc117..84b4786863 100644 --- a/framework/web/AssetManager.php +++ b/framework/web/AssetManager.php @@ -12,6 +12,7 @@ use yii\base\Component; use yii\base\InvalidConfigException; use yii\base\InvalidParamException; use yii\helpers\FileHelper; +use yii\helpers\Url; /** * AssetManager manages asset bundles and asset publishing. @@ -63,64 +64,7 @@ class AssetManager extends Component * @return string the base URL through which the published asset files can be accessed. */ public $baseUrl = '@web/assets'; - /** - * @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; - + public $assetMap = []; /** * Initializes the component. @@ -130,12 +74,10 @@ class AssetManager extends Component { parent::init(); $this->basePath = Yii::getAlias($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 { + if (is_dir($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), '/'); } @@ -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. * * @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 * @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[$name] instanceof AssetBundle) { - return $this->bundles[$name]; - } elseif (is_array($this->bundles[$name])) { - $bundle = Yii::createObject(array_merge(['class' => $name], $this->bundles[$name])); - } else { - throw new InvalidConfigException("Invalid asset bundle: $name"); - } + if ($this->bundles === false) { + return null; + } elseif (!isset($this->bundles[$name])) { + return $this->bundles[$name] = $this->loadBundle($name); + } elseif ($this->bundles[$name] instanceof AssetBundle) { + return $this->bundles[$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 { - $bundle = Yii::createObject($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; - } - - /** - * @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($this->_published[$path])) { - return $this->_published[$path]; - } - - if (!is_string($path) || ($src = realpath($path)) === false) { - throw new InvalidParamException("The file or directory to be published does not exist: $path"); - } - - if (is_file($src)) { - $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]; + throw new InvalidConfigException("Invalid asset bundle configuration: $name"); } } - /** - * Returns the published path of a file path. - * This method does not perform any publishing. It merely tells you - * 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) + protected function loadBundle($name, $config = []) { - $path = Yii::getAlias($path); - - if (isset($this->_published[$path])) { - return $this->_published[$path][0]; + if (!isset($config['class'])) { + $config['class'] = $name; } - if (is_string($path) && ($path = realpath($path)) !== false) { - $base = $this->basePath . DIRECTORY_SEPARATOR; - 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; + $bundle = Yii::createObject($config); + if ($bundle->basePath === null) { + $bundle->basePath = $this->basePath; } + if ($bundle->baseUrl === null) { + $bundle->baseUrl = $this->baseUrl; + } + return $bundle; } /** - * 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. + * @param View $view + * @param AssetBundle $bundle */ - public function getPublishedUrl($path) + public function registerAssetFiles($view, $bundle) { - $path = Yii::getAlias($path); - - if (isset($this->_published[$path])) { - return $this->_published[$path][1]; + foreach ($bundle->js as $js) { + $view->registerJsFile($this->getAssetUrl($bundle, $js), $bundle->jsOptions); } - if (is_string($path) && ($path = realpath($path)) !== false) { - if (is_file($path)) { - return $this->baseUrl . '/' . $this->hash(dirname($path) . filemtime($path)) . '/' . basename($path); - } else { - return $this->baseUrl . '/' . $this->hash($path . filemtime($path)); - } - } else { - return false; + foreach ($bundle->css as $css) { + $view->registerCssFile($this->getAssetUrl($bundle, $css), $bundle->cssOptions); } } - /** - * 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) + protected function getAssetUrl($bundle, $file) { - return sprintf('%x', crc32($path . Yii::getVersion())); + if (strncmp($file, '@/', 2) === 0) { + $file = $this->baseUrl . substr($file, 1); + } elseif (Url::isRelative($file)) { + $file = $bundle->baseUrl . '/' . $file; + } + // todo: assetMap + return $file; } } diff --git a/framework/web/JqueryAsset.php b/framework/web/JqueryAsset.php index 96cbf032b4..bc5b896304 100644 --- a/framework/web/JqueryAsset.php +++ b/framework/web/JqueryAsset.php @@ -15,8 +15,7 @@ namespace yii\web; */ class JqueryAsset extends AssetBundle { - public $sourcePath = '@vendor/yiisoft/jquery'; public $js = [ - 'jquery.js', + 'jquery/dist/jquery.js', ]; } diff --git a/framework/web/View.php b/framework/web/View.php index cccfd1d1f1..c1ce75a6d4 100644 --- a/framework/web/View.php +++ b/framework/web/View.php @@ -8,9 +8,9 @@ namespace yii\web; use Yii; +use yii\helpers\ArrayHelper; use yii\helpers\Html; use yii\base\InvalidConfigException; -use yii\helpers\Url; /** * View represents a view object in the MVC pattern. @@ -261,7 +261,7 @@ class View extends \yii\base\View foreach ($bundle->depends as $dep) { $this->registerAssetFiles($dep); } - $bundle->registerAssetFiles($this); + $this->getAssetManager()->registerAssetFiles($this, $bundle); } unset($this->assetBundles[$name]); } @@ -360,23 +360,27 @@ class View extends \yii\base\View /** * Registers a CSS file. * @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 supported options. + * @param array $options the HTML attributes for the link tag. Please refer to [[Html::cssFile()]] for + * the supported options. The following options are specially handled and are not treated as HTML attributes: + * + * - `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 * $url as the key. If two CSS files are registered with the same key, the latter * will overwrite the former. */ - public function registerCssFile($url, $depends = [], $options = [], $key = null) + public function registerCssFile($url, $options = [], $key = null) { $url = Yii::getAlias($url); $key = $key ?: $url; + $depends = ArrayHelper::remove($options, 'depends', []); + if (empty($depends)) { $this->cssFiles[$key] = Html::cssFile($url, $options); } else { - $am = $this->getAssetManager(); - $am->bundles[$key] = new AssetBundle([ - 'css' => [Url::to($url)], + $this->getAssetManager()->bundles[$key] = new AssetBundle([ + 'baseUrl' => '', + 'css' => [$url], 'cssOptions' => $options, 'depends' => (array) $depends, ]); @@ -414,14 +418,14 @@ class View extends \yii\base\View /** * Registers a JS file. * @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. A special option - * named "position" is supported which specifies where the JS script tag should be inserted - * in a page. The possible values of "position" are: + * @param array $options the HTML attributes for the script tag. The following options are specially handled + * and are not treated as HTML attributes: * - * - [[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. + * - `depends`: array, specifies the names of the asset bundles that this JS file depends on. + * - `position`: specifies where the JS script tag should be inserted in a page. The possible values are: + * * [[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. * @@ -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 * will overwrite the former. */ - public function registerJsFile($url, $depends = [], $options = [], $key = null) + public function registerJsFile($url, $options = [], $key = null) { $url = Yii::getAlias($url); $key = $key ?: $url; + $depends = ArrayHelper::remove($options, 'depends', []); + if (empty($depends)) { - $position = isset($options['position']) ? $options['position'] : self::POS_END; - unset($options['position']); + $position = ArrayHelper::remove($options, 'position', self::POS_END); $this->jsFiles[$position][$key] = Html::jsFile($url, $options); } else { - $am = $this->getAssetManager(); - $am->bundles[$key] = new AssetBundle([ - 'js' => [Url::to($url)], + $this->getAssetManager()->bundles[$key] = new AssetBundle([ + 'baseUrl' => '', + 'js' => [$url], 'jsOptions' => $options, 'depends' => (array) $depends, ]); diff --git a/framework/web/YiiAsset.php b/framework/web/YiiAsset.php index db7e85ec20..79fd235151 100644 --- a/framework/web/YiiAsset.php +++ b/framework/web/YiiAsset.php @@ -15,9 +15,8 @@ namespace yii\web; */ class YiiAsset extends AssetBundle { - public $sourcePath = '@yii/assets'; public $js = [ - 'yii.js', + 'yii2/assets/yii.js', ]; public $depends = [ 'yii\web\JqueryAsset',