Browse Source

fix issue #700

adjust depended asset position or throw exception on conflict
tags/2.0.0-beta
Carsten Brandt 11 years ago
parent
commit
abc1e0c2bb
  1. 45
      framework/yii/base/View.php
  2. 5
      framework/yii/web/AssetBundle.php
  3. 22
      tests/unit/data/views/layout.php
  4. 5
      tests/unit/data/views/rawlayout.php
  5. 1
      tests/unit/data/views/simple.php
  6. 126
      tests/unit/framework/web/AssetBundleTest.php

45
framework/yii/base/View.php

@ -146,7 +146,7 @@ class View extends Component
* are the registered [[AssetBundle]] objects. * are the registered [[AssetBundle]] objects.
* @see registerAssetBundle * @see registerAssetBundle
*/ */
public $assetBundles; public $assetBundles = array();
/** /**
* @var string the page title * @var string the page title
*/ */
@ -523,6 +523,9 @@ class View extends Component
$this->trigger(self::EVENT_END_PAGE); $this->trigger(self::EVENT_END_PAGE);
$content = ob_get_clean(); $content = ob_get_clean();
foreach(array_keys($this->assetBundles) as $bundle) {
$this->registerAssetFiles($bundle);
}
echo strtr($content, array( echo strtr($content, array(
self::PH_HEAD => $this->renderHeadHtml(), self::PH_HEAD => $this->renderHeadHtml(),
self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(), self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
@ -530,7 +533,6 @@ class View extends Component
)); ));
unset( unset(
$this->assetBundles,
$this->metaTags, $this->metaTags,
$this->linkTags, $this->linkTags,
$this->css, $this->css,
@ -566,25 +568,58 @@ class View extends Component
echo self::PH_HEAD; echo self::PH_HEAD;
} }
protected function registerAssetFiles($name)
{
if (!isset($this->assetBundles[$name])) {
return;
}
$bundle = $this->assetBundles[$name];
foreach($bundle->depends as $depName) {
$this->registerAssetFiles($depName);
}
$bundle->registerAssets($this);
unset($this->assetBundles[$name]);
}
/** /**
* Registers the named asset bundle. * Registers the named asset bundle.
* All dependent asset bundles will be registered. * All dependent asset bundles will be registered.
* @param string $name the name of the asset bundle. * @param string $name the name of the asset bundle.
* @param integer|null $position optional parameter to force a minimum Javascript position TODO link to relevant method
* Null means to register on default position.
* @return AssetBundle the registered asset bundle instance * @return AssetBundle the registered asset bundle instance
* @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected * @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected
*/ */
public function registerAssetBundle($name) public function registerAssetBundle($name, $position = null)
{ {
if (!isset($this->assetBundles[$name])) { if (!isset($this->assetBundles[$name])) {
$am = $this->getAssetManager(); $am = $this->getAssetManager();
$bundle = $am->getBundle($name); $bundle = $am->getBundle($name);
$this->assetBundles[$name] = false; $this->assetBundles[$name] = false;
$bundle->registerAssets($this); // register dependencies
$pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
foreach ($bundle->depends as $dep) {
$this->registerAssetBundle($dep, $pos);
}
$this->assetBundles[$name] = $bundle; $this->assetBundles[$name] = $bundle;
} elseif ($this->assetBundles[$name] === false) { } elseif ($this->assetBundles[$name] === false) {
throw new InvalidConfigException("A circular dependency is detected for bundle '$name'."); throw new InvalidConfigException("A circular dependency is detected for bundle '$name'.");
} else {
$bundle = $this->assetBundles[$name];
}
if ($position !== null) {
$pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
if ($pos === null) {
$bundle->jsOptions['position'] = $pos = $position;
} elseif ($pos > $position) {
throw new InvalidConfigException("A dependend AssetBundle of '$name' requires a higher position but it conflicts with the position set for '$name'!");
}
foreach ($bundle->depends as $dep) {
$this->registerAssetBundle($dep, $pos);
}
} }
return $this->assetBundles[$name]; return $bundle;
} }
/** /**

5
framework/yii/web/AssetBundle.php

@ -130,7 +130,6 @@ class AssetBundle extends Object
/** /**
* Registers the CSS and JS files with the given view. * Registers the CSS and JS files with the given view.
* This method will first register all dependent asset bundles.
* It will then try to convert non-CSS or JS files (e.g. LESS, Sass) into the corresponding * It will then try to convert non-CSS or JS files (e.g. LESS, Sass) into the corresponding
* CSS or JS files using [[AssetManager::converter|asset converter]]. * CSS or JS files using [[AssetManager::converter|asset converter]].
* @param \yii\base\View $view the view that the asset files to be registered with. * @param \yii\base\View $view the view that the asset files to be registered with.
@ -139,10 +138,6 @@ class AssetBundle extends Object
*/ */
public function registerAssets($view) public function registerAssets($view)
{ {
foreach ($this->depends as $name) {
$view->registerAssetBundle($name);
}
$this->publish($view->getAssetManager()); $this->publish($view->getAssetManager());
foreach ($this->js as $js) { foreach ($this->js as $js) {

22
tests/unit/data/views/layout.php

@ -0,0 +1,22 @@
<?php
/**
* @var $this \yii\base\View
* @var $content string
*/
?>
<?php $this->beginPage(); ?>
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<?php $this->head(); ?>
</head>
<body>
<?php $this->beginBody(); ?>
<?php echo $content; ?>
<?php $this->endBody(); ?>
</body>
</html>
<?php $this->endPage(); ?>

5
tests/unit/data/views/rawlayout.php

@ -0,0 +1,5 @@
<?php
/**
* @var $this \yii\base\View
*/
?><?php $this->beginPage(); ?>1<?php $this->head(); ?>2<?php $this->beginBody(); ?>3<?php $this->endBody(); ?>4<?php $this->endPage(); ?>

1
tests/unit/data/views/simple.php

@ -0,0 +1 @@
This is a damn simple view file.

126
tests/unit/framework/web/AssetBundleTest.php

@ -45,6 +45,13 @@ class AssetBundleTest extends \yiiunit\TestCase
TestJqueryAsset::register($view); TestJqueryAsset::register($view);
$this->assertEquals(1, count($view->assetBundles)); $this->assertEquals(1, count($view->assetBundles));
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
$expected = <<<EOF
123<script src="/js/jquery.js"></script>
4
EOF;
$this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php'));
} }
public function testSimpleDependency() public function testSimpleDependency()
@ -56,6 +63,125 @@ class AssetBundleTest extends \yiiunit\TestCase
$this->assertEquals(2, count($view->assetBundles)); $this->assertEquals(2, count($view->assetBundles));
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles); $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles);
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
$expected = <<<EOF
1<link href="/files/cssFile.css" rel="stylesheet">
23<script src="/js/jquery.js"></script>
<script src="/files/jsFile.js"></script>
4
EOF;
$this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php'));
}
public function positionProvider()
{
return array(
array(View::POS_HEAD, true),
array(View::POS_HEAD, false),
array(View::POS_BEGIN, true),
array(View::POS_BEGIN, false),
array(View::POS_END, true),
array(View::POS_END, false),
);
}
/**
* @dataProvider positionProvider
*/
public function testPositionDependency($pos, $jqAlreadyRegistered)
{
$view = $this->getView();
$view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = array(
'jsOptions' => array(
'position' => $pos,
),
);
$this->assertEmpty($view->assetBundles);
if ($jqAlreadyRegistered) {
TestJqueryAsset::register($view);
}
TestAssetBundle::register($view);
$this->assertEquals(2, count($view->assetBundles));
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles);
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
$this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions);
$this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions['position']);
$this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions);
$this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions['position']);
switch($pos)
{
case View::POS_HEAD:
$expected = <<<EOF
1<link href="/files/cssFile.css" rel="stylesheet">
<script src="/js/jquery.js"></script>
<script src="/files/jsFile.js"></script>
234
EOF;
break;
case View::POS_BEGIN:
$expected = <<<EOF
1<link href="/files/cssFile.css" rel="stylesheet">
2<script src="/js/jquery.js"></script>
<script src="/files/jsFile.js"></script>
34
EOF;
break;
default:
case View::POS_END:
$expected = <<<EOF
1<link href="/files/cssFile.css" rel="stylesheet">
23<script src="/js/jquery.js"></script>
<script src="/files/jsFile.js"></script>
4
EOF;
break;
}
$this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php'));
}
public function positionProvider2()
{
return array(
array(View::POS_BEGIN, true),
array(View::POS_BEGIN, false),
array(View::POS_END, true),
array(View::POS_END, false),
);
}
/**
* @dataProvider positionProvider
*/
public function testPositionDependencyConflict($pos, $jqAlreadyRegistered)
{
$view = $this->getView();
$view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = array(
'jsOptions' => array(
'position' => $pos - 1,
),
);
$view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestJqueryAsset'] = array(
'jsOptions' => array(
'position' => $pos,
),
);
$this->assertEmpty($view->assetBundles);
if ($jqAlreadyRegistered) {
TestJqueryAsset::register($view);
}
$this->setExpectedException('yii\\base\\InvalidConfigException');
TestAssetBundle::register($view);
} }
} }

Loading…
Cancel
Save