From 9f66abc984d6f002f156a81f4456c471356ab5c5 Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Sat, 18 May 2013 21:33:06 +0300 Subject: [PATCH 1/5] "yii\console\controllers\AssetController" has been updated: - assetManager has been converted into virtual property - bundle dependency load has been fixed --- .../console/controllers/AssetControllerTest.php | 6 +- yii/console/controllers/AssetController.php | 115 ++++++++++++++++----- 2 files changed, 93 insertions(+), 28 deletions(-) diff --git a/tests/unit/framework/console/controllers/AssetControllerTest.php b/tests/unit/framework/console/controllers/AssetControllerTest.php index 9dc7c11..e0d7d26 100644 --- a/tests/unit/framework/console/controllers/AssetControllerTest.php +++ b/tests/unit/framework/console/controllers/AssetControllerTest.php @@ -92,7 +92,8 @@ class AssetControllerTest extends TestCase */ protected function createCompressConfig(array $bundles) { - $baseUrl = '/test'; + //$baseUrl = '/test'; + $baseUrl = ''; $config = array( 'bundles' => $this->createBundleConfig($bundles), 'targets' => array( @@ -207,6 +208,9 @@ class AssetControllerTest extends TestCase 'app' => array( 'css' => array_keys($cssFiles), 'js' => array_keys($jsFiles), + 'depends' => array( + 'yii', + ), ), );; $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; diff --git a/yii/console/controllers/AssetController.php b/yii/console/controllers/AssetController.php index 4cc2ffe..1f2be91 100644 --- a/yii/console/controllers/AssetController.php +++ b/yii/console/controllers/AssetController.php @@ -14,6 +14,8 @@ use yii\console\Controller; /** * This command allows you to combine and compress your JavaScript and CSS files. * + * @property array|\yii\web\AssetManager $assetManager asset manager, which will be used for assets processing. + * * @author Qiang Xue * @since 2.0 */ @@ -50,10 +52,10 @@ class AssetController extends Controller */ public $targets = array(); /** - * @var array configuration for [[yii\web\AssetManager]] instance, which will be used - * for assets publishing. + * @var array|\yii\web\AssetManager [[yii\web\AssetManager]] instance or its array configuration, which will be used + * for assets processing. */ - public $assetManager = array(); + private $_assetManager = array(); /** * @var string|callback Java Script file compressor. * If a string, it is treated as shell command template, which should contain @@ -76,6 +78,33 @@ class AssetController extends Controller public $cssCompressor = 'java -jar yuicompressor.jar {from} -o {to}'; /** + * @return \yii\web\AssetManager asset manager instance. + */ + public function getAssetManager() + { + if (!is_object($this->_assetManager)) { + $options = $this->_assetManager; + if (!isset($options['class'])) { + $options['class'] = 'yii\\web\\AssetManager'; + } + $this->_assetManager = Yii::createObject($options); + } + return $this->_assetManager; + } + + /** + * @param \yii\web\AssetManager|array $assetManager asset manager instance or its array configuration. + * @throws \yii\console\Exception on invalid argument type. + */ + public function setAssetManager($assetManager) + { + if (is_scalar($assetManager)) { + throw new Exception('"' . get_class($this) . '::assetManager" should be either object or array - "' . gettype($assetManager) . '" given.'); + } + $this->_assetManager = $assetManager; + } + + /** * Combines and compresses the asset files according to the given configuration. * During the process new asset bundle configuration file will be created. * You should replace your original asset bundle configuration with this file in order to use compressed files. @@ -114,19 +143,14 @@ class AssetController extends Controller echo "Loading configuration from '{$configFile}'...\n"; foreach (require($configFile) as $name => $value) { - if (property_exists($this, $name)) { + if (property_exists($this, $name) || $this->canSetProperty($name)) { $this->$name = $value; } else { throw new Exception("Unknown configuration option: $name"); } } - if (!isset($this->assetManager['basePath'])) { - throw new Exception("Please specify 'basePath' for the 'assetManager' option."); - } - if (!isset($this->assetManager['baseUrl'])) { - throw new Exception("Please specify 'baseUrl' for the 'assetManager' option."); - } + $this->getAssetManager(); // check asset manager configuration } /** @@ -138,27 +162,60 @@ class AssetController extends Controller protected function loadBundles($bundles, $extensions) { echo "Collecting source bundles information...\n"; + + $assetManager = $this->getAssetManager(); $result = array(); - foreach ($bundles as $name => $bundle) { - $bundle['class'] = 'yii\\web\\AssetBundle'; - $result[$name] = Yii::createObject($bundle); + + $assetManager->bundles = $bundles; + foreach ($assetManager->bundles as $name => $bundle) { + $result[$name] = $assetManager->getBundle($name); } + foreach ($extensions as $path) { $manifest = $path . '/assets.php'; if (!is_file($manifest)) { continue; } - foreach (require($manifest) as $name => $bundle) { + $assetManager->bundles = require($manifest); + foreach ($assetManager->bundles as $name => $bundle) { if (!isset($result[$name])) { - $bundle['class'] = 'yii\\web\\AssetBundle'; - $result[$name] = Yii::createObject($bundle); + $result[$name] = $assetManager->getBundle($name); } } } + + foreach ($result as $name => $bundle) { + $this->loadBundleDependency($name, $bundle, $result); + } + return $result; } /** + * Loads asset bundle dependencies recursively. + * @param string $name bundle name + * @param \yii\web\AssetBundle $bundle bundle instance + * @param array $result already loaded bundles list. + * @throws \yii\console\Exception on failure. + */ + protected function loadBundleDependency($name, $bundle, &$result) { + if (!empty($bundle->depends)) { + $assetManager = $this->getAssetManager(); + foreach ($bundle->depends as $dependencyName) { + if (!array_key_exists($dependencyName, $result)) { + $dependencyBundle = $assetManager->getBundle($dependencyName); + if ($dependencyBundle === null) { + throw new Exception("Unable to load dependency bundle '{$dependencyName}' for bundle '{$name}'."); + } else { + $result[$dependencyName] = $dependencyBundle; + $this->loadBundleDependency($dependencyName, $dependencyBundle, $result); + } + } + } + } + } + + /** * Creates full list of output asset bundles. * @param array $targets output asset bundles configuration. * @param \yii\web\AssetBundle[] $bundles list of source asset bundles. @@ -222,17 +279,13 @@ class AssetController extends Controller /** * Publishes given asset bundles. * @param \yii\web\AssetBundle[] $bundles asset bundles to be published. - * @param array $options assert manager instance configuration. */ - protected function publishBundles($bundles, $options) + protected function publishBundles($bundles) { echo "\nPublishing bundles:\n"; - if (!isset($options['class'])) { - $options['class'] = 'yii\\web\\AssetManager'; - } - $am = Yii::createObject($options); + $assetManager = $this->getAssetManager(); foreach ($bundles as $name => $bundle) { - $bundle->publish($am); + $bundle->publish($assetManager); echo " '".$name."' published.\n"; } echo "\n"; @@ -252,14 +305,20 @@ class AssetController extends Controller '{ts}' => $timestamp, )); $inputFiles = array(); - foreach ($target->depends as $name) { if (isset($bundles[$name])) { - foreach ($bundles[$name]->$type as $file) { - $inputFiles[] = $bundles[$name]->basePath . $file; + $bundle = $bundles[$name]; + foreach ($bundle->$type as $file) { + if ($bundle->sourcePath === null) { + // native : + $inputFiles[] = $bundle->basePath . $file; + } else { + // published : + $inputFiles[] = $this->getAssetManager()->basePath . $file; + } } } else { - throw new Exception("Unknown bundle: $name"); + throw new Exception("Unknown bundle: '{$name}'"); } } if ($type === 'js') { @@ -339,6 +398,8 @@ class AssetController extends Controller * Saves new asset bundles configuration. * @param \yii\web\AssetBundle[] $targets list of asset bundles to be saved. * @param string $bundleFile output file name. + * @throws \yii\console\Exception on failure. + * @return void */ protected function saveTargets($targets, $bundleFile) { From 4695362ae22783e7d70f401d80f19900cafc2be1 Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Sat, 18 May 2013 21:40:39 +0300 Subject: [PATCH 2/5] Unit test for "yii\console\controllers\AssetController" has been adjusted. --- tests/unit/framework/console/controllers/AssetControllerTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/framework/console/controllers/AssetControllerTest.php b/tests/unit/framework/console/controllers/AssetControllerTest.php index e0d7d26..d792c9e 100644 --- a/tests/unit/framework/console/controllers/AssetControllerTest.php +++ b/tests/unit/framework/console/controllers/AssetControllerTest.php @@ -92,8 +92,7 @@ class AssetControllerTest extends TestCase */ protected function createCompressConfig(array $bundles) { - //$baseUrl = '/test'; - $baseUrl = ''; + $baseUrl = '/test'; $config = array( 'bundles' => $this->createBundleConfig($bundles), 'targets' => array( @@ -106,7 +105,7 @@ class AssetControllerTest extends TestCase ), 'assetManager' => array( 'basePath' => $this->testAssetsBasePath, - 'baseUrl' => $baseUrl, + 'baseUrl' => '', ), ); return $config; From 57e5474143d02e77b0c8279d755c58e0c8b7d91e Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Sun, 19 May 2013 15:46:24 +0300 Subject: [PATCH 3/5] Method "yii\console\controllers\AssetController::loadBundleDependency()" has been improved allowing dection of the circular dependency. --- yii/console/controllers/AssetController.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/yii/console/controllers/AssetController.php b/yii/console/controllers/AssetController.php index 1f2be91..fcf8846 100644 --- a/yii/console/controllers/AssetController.php +++ b/yii/console/controllers/AssetController.php @@ -203,12 +203,16 @@ class AssetController extends Controller $assetManager = $this->getAssetManager(); foreach ($bundle->depends as $dependencyName) { if (!array_key_exists($dependencyName, $result)) { + if ($result[$dependencyName] === false) { + throw new Exception("A circular dependency is detected for target '{$dependencyName}'."); + } $dependencyBundle = $assetManager->getBundle($dependencyName); if ($dependencyBundle === null) { throw new Exception("Unable to load dependency bundle '{$dependencyName}' for bundle '{$name}'."); } else { - $result[$dependencyName] = $dependencyBundle; + $result[$dependencyName] = false; $this->loadBundleDependency($dependencyName, $dependencyBundle, $result); + $result[$dependencyName] = $dependencyBundle; } } } From 84237dd8285dbbbfb1abda4bbbbdfcba8715812f Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Sun, 19 May 2013 15:57:49 +0300 Subject: [PATCH 4/5] E_NOTICE at "yii\console\controllers\AssetController::loadBundleDependency()" has been fixed. --- yii/console/controllers/AssetController.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/yii/console/controllers/AssetController.php b/yii/console/controllers/AssetController.php index fcf8846..fd75096 100644 --- a/yii/console/controllers/AssetController.php +++ b/yii/console/controllers/AssetController.php @@ -203,9 +203,6 @@ class AssetController extends Controller $assetManager = $this->getAssetManager(); foreach ($bundle->depends as $dependencyName) { if (!array_key_exists($dependencyName, $result)) { - if ($result[$dependencyName] === false) { - throw new Exception("A circular dependency is detected for target '{$dependencyName}'."); - } $dependencyBundle = $assetManager->getBundle($dependencyName); if ($dependencyBundle === null) { throw new Exception("Unable to load dependency bundle '{$dependencyName}' for bundle '{$name}'."); @@ -214,6 +211,10 @@ class AssetController extends Controller $this->loadBundleDependency($dependencyName, $dependencyBundle, $result); $result[$dependencyName] = $dependencyBundle; } + } else { + if ($result[$dependencyName] === false) { + throw new Exception("A circular dependency is detected for target '{$dependencyName}'."); + } } } } From 9a472c8323667f264ee4946a81c1e43eb4ff93bf Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Sun, 19 May 2013 16:17:02 +0300 Subject: [PATCH 5/5] "yii\console\controllers\AssetController::getAssetManager()" has been updated enforcing 'basePath' and 'baseUrl' config parameters. --- yii/console/controllers/AssetController.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/yii/console/controllers/AssetController.php b/yii/console/controllers/AssetController.php index fd75096..59cf1f5 100644 --- a/yii/console/controllers/AssetController.php +++ b/yii/console/controllers/AssetController.php @@ -60,7 +60,7 @@ class AssetController extends Controller * @var string|callback Java Script file compressor. * If a string, it is treated as shell command template, which should contain * placeholders {from} - source file name - and {to} - output file name. - * If an array, it is treated as PHP callback, which should perform the compression. + * Otherwise, it is treated as PHP callback, which should perform the compression. * * Default value relies on usage of "Closure Compiler" * @see https://developers.google.com/closure/compiler/ @@ -70,7 +70,7 @@ class AssetController extends Controller * @var string|callback CSS file compressor. * If a string, it is treated as shell command template, which should contain * placeholders {from} - source file name - and {to} - output file name. - * If an array, it is treated as PHP callback, which should perform the compression. + * Otherwise, it is treated as PHP callback, which should perform the compression. * * Default value relies on usage of "YUI Compressor" * @see https://github.com/yui/yuicompressor/ @@ -78,6 +78,8 @@ class AssetController extends Controller public $cssCompressor = 'java -jar yuicompressor.jar {from} -o {to}'; /** + * Returns the asset manager instance. + * @throws \yii\console\Exception on invalid configuration. * @return \yii\web\AssetManager asset manager instance. */ public function getAssetManager() @@ -87,12 +89,19 @@ class AssetController extends Controller if (!isset($options['class'])) { $options['class'] = 'yii\\web\\AssetManager'; } + if (!isset($options['basePath'])) { + throw new Exception("Please specify 'basePath' for the 'assetManager' option."); + } + if (!isset($options['baseUrl'])) { + throw new Exception("Please specify 'baseUrl' for the 'assetManager' option."); + } $this->_assetManager = Yii::createObject($options); } return $this->_assetManager; } /** + * Sets asset manager instance or configuration. * @param \yii\web\AssetManager|array $assetManager asset manager instance or its array configuration. * @throws \yii\console\Exception on invalid argument type. */