Browse Source

new asset WIP: renabled asset publishing

tags/2.0.0-rc
Qiang Xue 10 years ago
parent
commit
60e07e0d2a
  1. 2
      apps/advanced/.bowerrc
  2. 1
      apps/advanced/assets/.gitkeep
  3. 2
      apps/advanced/backend/web/assets/.gitignore
  4. 8
      apps/advanced/environments/index.php
  5. 2
      apps/advanced/frontend/web/assets/.gitignore
  6. 2
      apps/basic/.bowerrc
  7. 2
      apps/basic/web/assets/.gitignore
  8. 1
      apps/basic/web/assets/.gitkeep
  9. 11
      docs/guide/concept-aliases.md
  10. 5
      extensions/authclient/widgets/AuthChoiceAsset.php
  11. 3
      extensions/bootstrap/BootstrapAsset.php
  12. 3
      extensions/bootstrap/BootstrapPluginAsset.php
  13. 3
      extensions/bootstrap/BootstrapThemeAsset.php
  14. 5
      extensions/debug/DebugAsset.php
  15. 9
      extensions/gii/GiiAsset.php
  16. 11
      extensions/gii/TypeAheadAsset.php
  17. 2
      extensions/gii/views/layouts/main.php
  18. 27
      extensions/jui/CoreAsset.php
  19. 3
      extensions/jui/DatePicker.php
  20. 1
      extensions/jui/DatePickerLanguageAsset.php
  21. 5
      extensions/jui/JuiAsset.php
  22. 2
      framework/base/Application.php
  23. 3
      framework/captcha/CaptchaAsset.php
  24. 3
      framework/grid/GridViewAsset.php
  25. 3
      framework/validators/PunycodeAsset.php
  26. 3
      framework/validators/ValidationAsset.php
  27. 100
      framework/web/AssetBundle.php
  28. 375
      framework/web/AssetManager.php
  29. 3
      framework/web/JqueryAsset.php
  30. 3
      framework/web/YiiAsset.php
  31. 3
      framework/widgets/ActiveFormAsset.php
  32. 3
      framework/widgets/MaskedInputAsset.php
  33. 3
      framework/widgets/PjaxAsset.php

2
apps/advanced/.bowerrc

@ -1,3 +1,3 @@
{
"directory" : "assets"
"directory" : "vendor/bower"
}

1
apps/advanced/assets/.gitkeep

@ -1 +0,0 @@
*

2
apps/advanced/backend/web/assets/.gitignore vendored

@ -0,0 +1,2 @@
*
!.gitignore

8
apps/advanced/environments/index.php

@ -41,10 +41,6 @@ return [
'backend/config/main-local.php',
'frontend/config/main-local.php',
],
'createSymlink' => [
'frontend/web/assets' => 'assets',
'backend/web/assets' => 'assets',
],
],
'Production' => [
'path' => 'prod',
@ -61,9 +57,5 @@ return [
'backend/config/main-local.php',
'frontend/config/main-local.php',
],
'createSymlink' => [
'frontend/web/assets' => 'assets',
'backend/web/assets' => 'assets',
],
],
];

2
apps/advanced/frontend/web/assets/.gitignore vendored

@ -0,0 +1,2 @@
*
!.gitignore

2
apps/basic/.bowerrc

@ -1,3 +1,3 @@
{
"directory" : "web/assets"
"directory" : "vendor/bower"
}

2
apps/basic/web/assets/.gitignore vendored

@ -0,0 +1,2 @@
*
!.gitignore

1
apps/basic/web/assets/.gitkeep

@ -1 +0,0 @@
*

11
docs/guide/concept-aliases.md

@ -106,10 +106,13 @@ Yii predefines a set of aliases to easily reference commonly used file paths and
- `@yii`, the directory where the `BaseYii.php` file is located (also called the framework directory)
- `@app`, the [[yii\base\Application::basePath|base path]] of the currently running application
- `@runtime`, the [[yii\base\Application::runtimePath|runtime path]] of the currently running application
- `@vendor`, the [[yii\base\Application::vendorPath|Composer vendor directory]]
- `@webroot`, the Web root directory of the currently running Web application
- `@web`, the base URL of the currently running Web application
- `@runtime`, the [[yii\base\Application::runtimePath|runtime path]] of the currently running application. Defaults to `@app/runtime`.
- `@webroot`, the Web root directory of the currently running Web application. It is determined based on the directory
containing the entry script.
- `@web`, the base URL of the currently running Web application. It has the same value as [[yii\web\Request::baseUrl]].
- `@vendor`, the [[yii\base\Application::vendorPath|Composer vendor directory]]. Defaults to `@app/vendor`.
- `@bower`, the root directory that contains [bower packages](http://bower.io/). Defaults to `@vendor/bower`.
- `@npm`, the root directory that contains [npm packages](https://www.npmjs.org/). Defaults to `@vendor/npm`.
The `@yii` alias is defined when you include the `Yii.php` file in your [entry script](structure-entry-scripts.md). The rest of the aliases are defined in the application constructor when applying the application
[configuration](concept-configurations.md).

5
extensions/authclient/widgets/AuthChoiceAsset.php

@ -17,11 +17,12 @@ use yii\web\AssetBundle;
*/
class AuthChoiceAsset extends AssetBundle
{
public $sourcePath = '@vendor/yii2-authclient/assets';
public $js = [
'yii2-authclient/assets/authchoice.js',
'authchoice.js',
];
public $css = [
'yii2-authclient/assets/authchoice.css',
'authchoice.css',
];
public $depends = [
'yii\web\YiiAsset',

3
extensions/bootstrap/BootstrapAsset.php

@ -17,7 +17,8 @@ use yii\web\AssetBundle;
*/
class BootstrapAsset extends AssetBundle
{
public $sourcePath = '@bower/bootstrap';
public $css = [
'bootstrap/dist/css/bootstrap.css',
'dist/css/bootstrap.css',
];
}

3
extensions/bootstrap/BootstrapPluginAsset.php

@ -17,8 +17,9 @@ use yii\web\AssetBundle;
*/
class BootstrapPluginAsset extends AssetBundle
{
public $sourcePath = '@bower/bootstrap';
public $js = [
'bootstrap/dist/js/bootstrap.js',
'dist/js/bootstrap.js',
];
public $depends = [
'yii\web\JqueryAsset',

3
extensions/bootstrap/BootstrapThemeAsset.php

@ -17,8 +17,9 @@ use yii\web\AssetBundle;
*/
class BootstrapThemeAsset extends AssetBundle
{
public $sourcePath = '@bower/bootstrap';
public $css = [
'bootstrap/dist/css/bootstrap-theme.css',
'dist/css/bootstrap-theme.css',
];
public $depends = [
'yii\bootstrap\BootstrapAsset',

5
extensions/debug/DebugAsset.php

@ -17,9 +17,10 @@ use yii\web\AssetBundle;
*/
class DebugAsset extends AssetBundle
{
public $sourcePath = '@yii/debug/assets';
public $css = [
'yii2-debug/assets/main.css',
'yii2-debug/assets/toolbar.css',
'main.css',
'toolbar.css',
];
public $depends = [
'yii\web\YiiAsset',

9
extensions/gii/GiiAsset.php

@ -17,18 +17,17 @@ use yii\web\AssetBundle;
*/
class GiiAsset extends AssetBundle
{
public $sourcePath = '@yii/gii/assets';
public $css = [
'yii2-gii/assets/main.css',
'main.css',
];
public $js = [
'yii2-gii/assets/gii.js',
'typeahead.js/dist/typeahead.bundle.js',
'gii.js',
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
'yii\bootstrap\BootstrapPluginAsset',
'yii\gii\TypeAheadAsset',
];
}

11
extensions/jui/ButtonAsset.php → extensions/gii/TypeAheadAsset.php

@ -5,20 +5,23 @@
* @license http://www.yiiframework.com/license/
*/
namespace yii\jui;
namespace yii\gii;
use yii\web\AssetBundle;
/**
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ButtonAsset extends AssetBundle
class TypeAheadAsset extends AssetBundle
{
public $sourcePath = '@bower/typeahead.js';
public $js = [
'jquery.ui/ui/button.js',
'dist/typeahead.bundle.js',
];
public $depends = [
'yii\jui\CoreAsset',
'yii\bootstrap\BootstrapAsset',
'yii\bootstrap\BootstrapPluginAsset',
];
}

2
extensions/gii/views/layouts/main.php

@ -22,7 +22,7 @@ $asset = yii\gii\GiiAsset::register($this);
<?php $this->beginBody() ?>
<?php
NavBar::begin([
'brandLabel' => Html::img('@web/assets/yii2-gii/assets/logo.png'),
'brandLabel' => Html::img($asset->baseUrl . '/logo.png'),
'brandUrl' => ['default/index'],
'options' => ['class' => 'navbar-inverse navbar-fixed-top'],
]);

27
extensions/jui/CoreAsset.php

@ -1,27 +0,0 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\jui;
use yii\web\AssetBundle;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class CoreAsset extends AssetBundle
{
public $js = [
'jquery.ui/ui/core.js',
'jquery.ui/ui/widget.js',
'jquery.ui/ui/position.js',
'jquery.ui/ui/mouse.js',
];
public $depends = [
'yii\web\JqueryAsset',
];
}

3
extensions/jui/DatePicker.php

@ -86,8 +86,7 @@ class DatePicker extends InputWidget
$view = $this->getView();
$bundle = DatePickerLanguageAsset::register($view);
if ($bundle->autoGenerate) {
$am = $view->getAssetManager();
$view->registerJsFile($am->getAssetUrl("jquery-ui/ui/i18n/datepicker-$language.js"), [
$view->registerJsFile($bundle->baseUrl . "/ui/i18n/datepicker-$language.js", [
'depends' => [JuiAsset::className()],
]);
}

1
extensions/jui/DatePickerLanguageAsset.php

@ -15,6 +15,7 @@ use yii\web\AssetBundle;
*/
class DatePickerLanguageAsset extends AssetBundle
{
public $sourcePath = '@bower/jquery-ui';
/**
* @var boolean whether to automatically generate the needed language js files.
* If this is true, the language js files will be determined based on the actual usage of [[DatePicker]]

5
extensions/jui/JuiAsset.php

@ -15,11 +15,12 @@ use yii\web\AssetBundle;
*/
class JuiAsset extends AssetBundle
{
public $sourcePath = '@bower/jquery-ui';
public $js = [
'jquery-ui/jquery-ui.js',
'jquery-ui.js',
];
public $css = [
'jquery-ui/themes/smoothness/jquery-ui.css',
'themes/smoothness/jquery-ui.css',
];
public $depends = [
'yii\web\JqueryAsset',

2
framework/base/Application.php

@ -449,6 +449,8 @@ abstract class Application extends Module
{
$this->_vendorPath = Yii::getAlias($path);
Yii::setAlias('@vendor', $this->_vendorPath);
Yii::setAlias('@bower', $this->_vendorPath . DIRECTORY_SEPARATOR . 'bower');
Yii::setAlias('@npm', $this->_vendorPath . DIRECTORY_SEPARATOR . 'npm');
}
/**

3
framework/captcha/CaptchaAsset.php

@ -17,8 +17,9 @@ use yii\web\AssetBundle;
*/
class CaptchaAsset extends AssetBundle
{
public $sourcePath = '@yii/assets';
public $js = [
'yii2/assets/yii.captcha.js',
'yii.captcha.js',
];
public $depends = [
'yii\web\YiiAsset',

3
framework/grid/GridViewAsset.php

@ -17,8 +17,9 @@ use yii\web\AssetBundle;
*/
class GridViewAsset extends AssetBundle
{
public $sourcePath = '@yii/assets';
public $js = [
'yii2/assets/yii.gridView.js',
'yii.gridView.js',
];
public $depends = [
'yii\web\YiiAsset',

3
framework/validators/PunycodeAsset.php

@ -17,7 +17,8 @@ use yii\web\AssetBundle;
*/
class PunycodeAsset extends AssetBundle
{
public $sourcePath = '@bower/punycode';
public $js = [
'punycode/punycode.js',
'punycode.js',
];
}

3
framework/validators/ValidationAsset.php

@ -17,8 +17,9 @@ use yii\web\AssetBundle;
*/
class ValidationAsset extends AssetBundle
{
public $sourcePath = '@yii/assets';
public $js = [
'yii2/assets/yii.validation.js',
'yii.validation.js',
];
public $depends = [
'yii\web\YiiAsset',

100
framework/web/AssetBundle.php

@ -7,9 +7,9 @@
namespace yii\web;
use Yii;
use yii\base\Object;
use yii\helpers\Url;
use Yii;
/**
* AssetBundle represents a collection of asset files, such as CSS, JS, images.
@ -27,11 +27,23 @@ use yii\helpers\Url;
class AssetBundle extends Object
{
/**
* @var string the directory that contains the asset files in this bundle.
* @var string the directory that contains the source asset files for this asset bundle.
* A source asset file 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 is not Web accessible.
* By setting this property, [[AssetManager]] will publish the source asset files
* to a Web-accessible directory automatically when the asset bundle is registered on a page.
*
* 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), it will be filled with the value of
* [[AssetManager::basePath]] when the bundle is being loaded by [[AssetManager::getBundle()]].
* If you do not set this property, it means the source asset files are located under [[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]].
*
* You can use either a directory or an alias of the directory.
*/
@ -39,10 +51,8 @@ class AssetBundle extends Object
/**
* @var string the base URL for the relative asset files listed in [[js]] and [[css]].
*
* 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), it will be filled with the value of
* [[AssetManager::baseUrl]] when the bundle is being loaded by [[AssetManager::getBundle()]].
* If [[sourcePath]] is set, this property will be *overwritten* by [[AssetManager]]
* when it publishes the asset files from [[sourcePath]].
*
* You can use either a URL or an alias of the URL.
*/
@ -65,11 +75,11 @@ class AssetBundle extends Object
* specified in one of the following formats:
*
* - an absolute URL representing an external asset. For example,
* `//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js` or
* `http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
* - a path relative to [[basePath]] and [[baseUrl]]: for example, `js/main.js`. There should be no leading slash.
* - a path relative to [[AssetManager::basePath]] and [[AssetManager::baseUrl]]: for example,
* `@/jquery/dist/jquery.js`. The path must begin with `@/`.
* `http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js` or
* `//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
* - a relative path representing a local asset (e.g. `js/main.js`). The actual file path of a local
* asset can be determined by prefixing [[basePath]] to the relative path, and the actual URL
* of the asset can be determined by prefixing [[baseUrl]] to the relative path.
*
* Note that only forward slash "/" should be used as directory separators.
*/
@ -91,6 +101,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. This property is used only when [[sourcePath]] is set.
*/
public $publishOptions = [];
/**
@ -109,6 +124,9 @@ 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), '/\\');
}
@ -118,59 +136,43 @@ class AssetBundle extends Object
}
/**
* @param View $view
* 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)
{
$manager = $view->getAssetManager();
foreach ($this->js as $js) {
$view->registerJsFile($this->getAssetUrl($js, $manager), $this->jsOptions);
$view->registerJsFile($manager->getAssetUrl($this, $js), $this->jsOptions);
}
foreach ($this->css as $css) {
$view->registerCssFile($this->getAssetUrl($css, $manager), $this->cssOptions);
$view->registerCssFile($manager->getAssetUrl($this, $css), $this->cssOptions);
}
}
/**
* Returns the actual URL for the specified asset.
* The actual URL is obtained by prepending either [[baseUrl]] or [[AssetManager::baseUrl]] to the given asset path.
* @param string $asset the asset path. This should be one of the assets listed in [[js]] or [[css]].
* @param AssetManager $manager the asset manager
* @return string the actual URL for the specified asset.
* 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
*/
protected function getAssetUrl($asset, $manager)
public function publish($am)
{
if (($actualAsset = $manager->resolveAsset($asset)) !== false) {
return Url::isRelative($actualAsset) ? $manager->baseUrl . '/' . $actualAsset : $actualAsset;
if ($this->sourcePath !== null && !isset($this->basePath, $this->baseUrl)) {
list ($this->basePath, $this->baseUrl) = $am->publish($this->sourcePath, $this->publishOptions);
}
if (strncmp($asset, '@/', 2) === 0) {
return $manager->baseUrl . substr($asset, 1);
} elseif (Url::isRelative($asset)) {
return $this->baseUrl . '/' . $asset;
} else {
return $asset;
if (isset($this->basePath, $this->baseUrl) && ($converter = $am->getConverter()) !== null) {
foreach ($this->js as $i => $js) {
if (Url::isRelative($js)) {
$this->js[$i] = $converter->convert($js, $this->basePath);
}
}
/**
* Returns the actual file path for the specified asset.
* @param string $asset the asset path. This should be one of the assets listed in [[js]] or [[css]].
* @param AssetManager $manager the asset manager
* @return string|boolean the actual file path, or false if the asset is specified as an absolute URL
*/
public function getAssetPath($asset, $manager)
{
if (($actualAsset = $manager->resolveAsset($asset)) !== false) {
return Url::isRelative($actualAsset) ? $manager->basePath . '/' . $actualAsset : false;
foreach ($this->css as $i => $css) {
if (Url::isRelative($css)) {
$this->css[$i] = $converter->convert($css, $this->basePath);
}
}
if (strncmp($asset, '@/', 2) === 0) {
return $manager->basePath . substr($asset, 1);
} elseif (Url::isRelative($asset)) {
return $this->basePath . '/' . $asset;
} else {
return false;
}
}
}

375
framework/web/AssetManager.php

@ -10,6 +10,9 @@ namespace yii\web;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\helpers\FileHelper;
use yii\helpers\Url;
/**
* AssetManager manages asset bundle configuration and loading.
@ -67,13 +70,18 @@ class AssetManager extends Component
public $baseUrl = '@web/assets';
/**
* @var array mapping from source asset files (keys) to target asset files (values).
* When an asset bundle is being loaded by [[getBundle()]], each of its asset files (listed in either
* [[AssetBundle::css]] or [[AssetBundle::js]] will be examined to see if it matches any key
* in this map. If so, the corresponding value will be used to replace the asset file.
*
* This property is provided to support fixing incorrect asset file paths in some asset bundles.
* When an asset bundle is registered with a view, each relative asset file in its [[AssetBundle::css|css]]
* and [[AssetBundle::js|js]] arrays will be examined against this map. If any of the keys is found
* to be the last part of an asset file (which is prefixed with [[AssetBundle::sourcePath]] if available),
* the corresponding value will replace the asset and be registered with the view.
* For example, an asset file `my/path/to/jquery.js` matches a key `jquery.js`.
*
* Note that the target asset files should be either absolute URLs or paths relative to [[baseUrl]] and [[basePath]].
*
* In the following example, any occurrence of `jquery.min.js` will be replaced with `jquery/dist/jquery.js`.
* In the following example, any assets ending with `jquery.min.js` will be replaced with `jquery/dist/jquery.js`
* which is relative to [[baseUrl]] and [[basePath]].
*
* ```php
* [
@ -82,6 +90,63 @@ class AssetManager extends Component
* ```
*/
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;
private $_dummyBundles = [];
@ -94,10 +159,12 @@ class AssetManager extends Component
{
parent::init();
$this->basePath = Yii::getAlias($this->basePath);
if (is_dir($this->basePath)) {
$this->basePath = realpath($this->basePath);
} else {
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->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/');
}
@ -109,19 +176,21 @@ 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)
public function getBundle($name, $publish = true)
{
if ($this->bundles === false) {
return $this->loadDummyBundle($name);
} elseif (!isset($this->bundles[$name])) {
return $this->bundles[$name] = $this->loadBundle($name);
return $this->bundles[$name] = $this->loadBundle($name, [], $publish);
} 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]);
return $this->bundles[$name] = $this->loadBundle($name, $this->bundles[$name], $publish);
} elseif ($this->bundles[$name] === false) {
return $this->loadDummyBundle($name);
} else {
@ -129,17 +198,15 @@ class AssetManager extends Component
}
}
protected function loadBundle($name, $config = [])
protected function loadBundle($name, $config = [], $publish = true)
{
if (!isset($config['class'])) {
$config['class'] = $name;
}
/* @var $bundle AssetBundle */
$bundle = Yii::createObject($config);
if ($bundle->basePath === null) {
$bundle->basePath = $this->basePath;
}
if ($bundle->baseUrl === null) {
$bundle->baseUrl = $this->baseUrl;
if ($publish) {
$bundle->publish($this);
}
return $bundle;
}
@ -156,11 +223,50 @@ class AssetManager extends Component
return $this->_dummyBundles[$name];
}
public function resolveAsset($asset)
/**
* Returns the actual URL for the specified asset.
* The actual URL is obtained by prepending either [[baseUrl]] or [[AssetManager::baseUrl]] to the given asset path.
* @param AssetBundle $bundle the asset bundle which the asset file belongs to
* @param string $asset the asset path. This should be one of the assets listed in [[js]] or [[css]].
* @return string the actual URL for the specified asset.
*/
public function getAssetUrl($bundle, $asset)
{
if (($actualAsset = $this->resolveAsset($bundle, $asset)) !== false) {
return Url::isRelative($actualAsset) ? $this->baseUrl . '/' . $actualAsset : $actualAsset;
} else {
return Url::isRelative($asset) ? $bundle->baseUrl . '/' . $asset : $asset;
}
}
/**
* Returns the actual file path for the specified asset.
* @param AssetBundle $bundle the asset bundle which the asset file belongs to
* @param string $asset the asset path. This should be one of the assets listed in [[js]] or [[css]].
* @return string|boolean the actual file path, or false if the asset is specified as an absolute URL
*/
public function getAssetPath($bundle, $asset)
{
if (($actualAsset = $this->resolveAsset($bundle, $asset)) !== false) {
return Url::isRelative($actualAsset) ? $this->basePath . '/' . $actualAsset : false;
} else {
return Url::isRelative($asset) ? $bundle->basePath . '/' . $asset : false;
}
}
/**
* @param AssetBundle $bundle
* @param string $asset
* @return string|boolean
*/
protected function resolveAsset($bundle, $asset)
{
if (isset($this->assetMap[$asset])) {
return $this->assetMap[$asset];
}
if ($bundle->sourcePath !== null && Url::isRelative($asset)) {
$asset = $bundle->sourcePath . '/' . $asset;
}
$n = strlen($asset);
foreach ($this->assetMap as $from => $to) {
@ -173,13 +279,240 @@ class AssetManager extends Component
return false;
}
public function getAssetUrl($asset)
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)
{
return $this->baseUrl . '/' . ltrim($asset, '/');
$this->_converter = $value;
}
public function getAssetPath($asset)
/**
* @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)) {
return $this->_published[$path] = $this->publishFile($src);
} else {
return $this->_published[$path] = $this->publishDirectory($src, $options);
}
}
/**
* Publishes a file.
* @param string $src the asset file to be published
* @return array the path and the URL that the asset is published as.
* @throws InvalidParamException if the asset to be published does not exist.
*/
protected function publishFile($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 [$dstFile, $this->baseUrl . "/$dir/$fileName"];
}
/**
* Publishes a directory.
* @param string $src the asset 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 and the URL that the asset is published as.
* @throws InvalidParamException if the asset to be published does not exist.
*/
protected function publishDirectory($src, $options)
{
$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 [$dstDir, $this->baseUrl . '/' . $dir];
}
/**
* 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)
{
$path = Yii::getAlias($path);
if (isset($this->_published[$path])) {
return $this->_published[$path][0];
}
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;
}
}
/**
* 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 (isset($this->_published[$path])) {
return $this->_published[$path][1];
}
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;
}
}
/**
* 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 $this->basePath . '/' . ltrim($asset, '/');
return sprintf('%x', crc32($path . Yii::getVersion()));
}
}

3
framework/web/JqueryAsset.php

@ -15,7 +15,8 @@ namespace yii\web;
*/
class JqueryAsset extends AssetBundle
{
public $sourcePath = '@bower/jquery';
public $js = [
'jquery/dist/jquery.js',
'dist/jquery.js',
];
}

3
framework/web/YiiAsset.php

@ -15,8 +15,9 @@ namespace yii\web;
*/
class YiiAsset extends AssetBundle
{
public $sourcePath = '@yii/assets';
public $js = [
'yii2/assets/yii.js',
'yii.js',
];
public $depends = [
'yii\web\JqueryAsset',

3
framework/widgets/ActiveFormAsset.php

@ -15,8 +15,9 @@ use yii\web\AssetBundle;
*/
class ActiveFormAsset extends AssetBundle
{
public $sourcePath = '@yii/assets';
public $js = [
'yii2/assets/yii.activeForm.js',
'yii.activeForm.js',
];
public $depends = [
'yii\web\YiiAsset',

3
framework/widgets/MaskedInputAsset.php

@ -19,8 +19,9 @@ use yii\web\AssetBundle;
*/
class MaskedInputAsset extends AssetBundle
{
public $sourcePath = '@bower/jquery.inputmask';
public $js = [
'jquery.inputmask/dist/jquery.inputmask.bundle.js'
'dist/jquery.inputmask.bundle.js'
];
public $depends = [
'yii\web\YiiAsset'

3
framework/widgets/PjaxAsset.php

@ -17,8 +17,9 @@ use yii\web\AssetBundle;
*/
class PjaxAsset extends AssetBundle
{
public $sourcePath = '@bower/yii2-pjax';
public $js = [
'yii2-pjax/jquery.pjax.js',
'jquery.pjax.js',
];
public $depends = [
'yii\web\YiiAsset',

Loading…
Cancel
Save