Last active
December 19, 2015 03:48
-
-
Save sdboyer/5892709 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * @file | |
| * Contains Drupal\Core\Asset\AssetCollector. | |
| */ | |
| namespace Drupal\Core\Asset; | |
| /** | |
| * A class that helps to create and collect assets. | |
| * | |
| * This class should be set with appropriate defaults, injected with an AssetBag | |
| * for collection, then injected into an asset-producing segment of code in | |
| * order to ease the creation and collection of asset information. | |
| */ | |
| class AssetCollector { | |
| /** | |
| * The bag used to store any assets that are added. | |
| * | |
| * @var \Drupal\Core\Asset\AssetBagInterface | |
| */ | |
| protected $bag; | |
| /** | |
| * Flag indicating whether or not the object is locked. | |
| * | |
| * Locking prevents modifying the underlying defaults or the current bag. | |
| * | |
| * @var bool | |
| */ | |
| protected $locked = FALSE; | |
| /** | |
| * The key with which the lock was set. | |
| * | |
| * This exact value (===) must be provided in order to unlock the instance. | |
| * | |
| * There are no type restrictions. | |
| * | |
| * @var mixed | |
| */ | |
| protected $lockKey; | |
| protected $defaultAssetDefaults = array( | |
| 'css' => array( | |
| 'group' => CSS_AGGREGATE_DEFAULT, | |
| 'weight' => 0, | |
| 'every_page' => FALSE, | |
| 'media' => 'all', | |
| 'preprocess' => TRUE, | |
| 'browsers' => array( | |
| 'IE' => TRUE, | |
| '!IE' => TRUE, | |
| ), | |
| ), | |
| 'js' => array( | |
| 'group' => JS_DEFAULT, | |
| 'every_page' => FALSE, | |
| 'weight' => 0, | |
| 'scope' => 'header', | |
| 'cache' => TRUE, | |
| 'preprocess' => TRUE, | |
| 'attributes' => array(), | |
| 'version' => NULL, | |
| 'browsers' => array(), | |
| ), | |
| ); | |
| protected $assetDefaults = array(); | |
| protected $methodMap = array( | |
| 'css' => array( | |
| 'file' => 'createCssFileAsset', | |
| 'external' => 'createCssExternalAsset', | |
| 'string' => 'createCssStringAsset', | |
| ), | |
| 'js' => array( | |
| 'file' => 'createJsFileAsset', | |
| 'external' => 'createJsExternalAsset', | |
| 'string' => 'createJsStringAsset', | |
| ), | |
| ); | |
| public function __construct() { | |
| $this->restoreDefaults(); | |
| } | |
| /** | |
| * Adds an asset to the injected AM | |
| */ | |
| public function add($name, AssetInterface $asset) { | |
| } | |
| /** | |
| * Creates an asset and returns it. | |
| */ | |
| public function create($asset_type, $source_type, $data, $options = array()) { | |
| } | |
| public function setBag(AssetBagInterface $bag) { | |
| if ($this->isLocked()) { | |
| throw new \Exception('The collector instance is locked. A new bag cannot assigned on a locked collector.'); | |
| } | |
| $this->bag = $bag; | |
| } | |
| public function clearBag() { | |
| if ($this->isLocked()) { | |
| throw new \Exception('The collector instance is locked. Bags cannot be cleared on a locked collector.'); | |
| } | |
| $this->bag = NULL; | |
| } | |
| public function createCssFileAsset() { | |
| } | |
| public function createCssStringAsset() { | |
| } | |
| public function createCssExternalAsset() { | |
| } | |
| public function createJsFileAsset() { | |
| } | |
| public function createJsStringAsset() { | |
| } | |
| public function createJsExternalAsset() { | |
| } | |
| public function createJsSetting() { | |
| } | |
| public function lock($key) { | |
| if ($this->isLocked()) { | |
| throw new \Exception('Collector is already locked.', E_WARNING); | |
| } | |
| $this->locked = TRUE; | |
| $this->lockKey = $key; | |
| return TRUE; | |
| } | |
| public function unlock($key) { | |
| if (!$this->isLocked()) { | |
| throw new \Exception('Collector is not locked', E_WARNING); | |
| } | |
| if ($this->lockKey !== $key) { | |
| throw new \Exception('Attempted to unlock Collector with incorrect key.', E_WARNING); | |
| } | |
| $this->locked = FALSE; | |
| $this->lockKey = NULL; | |
| return TRUE; | |
| } | |
| public function isLocked() { | |
| return $this->locked; | |
| } | |
| public function setDefaults($type, array $defaults) { | |
| if ($this->isLocked()) { | |
| throw new \Exception('The collector instance is locked. Asset defaults cannot be modified on a locked collector.'); | |
| } | |
| $this->assetDefaults[$type] = array_merge($this->assetDefaults[$type], $defaults); | |
| } | |
| public function getDefaults($type = NULL) { | |
| if (!isset($type)) { | |
| return $this->assetDefaults; | |
| } | |
| if (!isset($this->assetDefaults[$type])) { | |
| throw new \InvalidArgumentException(sprintf('The type provided, "%s", is not known.', $type)); | |
| } | |
| return $this->assetDefaults[$type]; | |
| } | |
| public function restoreDefaults() { | |
| if ($this->isLocked()) { | |
| throw new \Exception('The collector instance is locked. Asset defaults cannot be modified on a locked collector.'); | |
| } | |
| $this->assetDefaults = $this->defaultAssetDefaults; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * @file | |
| * Contains Drupal\Tests\Core\Asset\AssetCollectorTest. | |
| */ | |
| namespace Drupal\Tests\Core\Asset; | |
| if (!defined('CSS_AGGREGATE_THEME')) { | |
| define('CSS_AGGREGATE_THEME', 100); | |
| } | |
| if (!defined('CSS_AGGREGATE_DEFAULT')) { | |
| define('CSS_AGGREGATE_DEFAULT', 0); | |
| } | |
| if (!defined('JS_DEFAULT')) { | |
| define('JS_DEFAULT', 0); | |
| } | |
| use Drupal\Core\Asset\AssetBag; | |
| use Drupal\Core\Asset\AssetCollector; | |
| use Drupal\Tests\UnitTestCase; | |
| /** | |
| * Tests for the asset collector. | |
| * | |
| * TODO DOCS, DOCS, DOCS DOCS DOCS | |
| * | |
| * @group Asset | |
| */ | |
| class AssetCollectorTest extends UnitTestCase { | |
| /** | |
| * @var \Drupal\Core\Asset\AssetCollector | |
| */ | |
| protected $collector; | |
| public static function getInfo() { | |
| return array( | |
| 'name' => 'Asset Collector tests', | |
| 'description' => 'Tests that the AssetCollector system works correctly.', | |
| 'group' => 'Asset', | |
| ); | |
| } | |
| public function setUp() { | |
| parent::setUp(); | |
| $this->collector = new AssetCollector(); | |
| } | |
| /** | |
| * Tests that the collector creates the right types of assets. | |
| */ | |
| public function testAssetCreation() { | |
| // First, ensure that each type of asset can be created correctly, both | |
| // through the generic and specific methods. | |
| $css_file1 = $this->collector->create('css', 'file', 'foo'); | |
| $css_file2 = $this->collector->createCssFileAsset('foo'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\CssFileAsset', $css_file1, 'Collector correctly created a CssFileAsset instance through the generic method.'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\CssFileAsset', $css_file2, 'Collector correctly created a CssFileAsset instance through the specific method.'); | |
| $css_external1 = $this->collector->create('css', 'external', 'foo'); | |
| $css_external2 = $this->collector->createCssExternalAsset('foo'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\CssExternalAsset', $css_external1, 'Collector correctly created a CssExternalAsset instance through the generic method.'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\CssExternalAsset', $css_external2, 'Collector correctly created a CssExternalAsset instance through the specific method.'); | |
| $css_string1 = $this->collector->create('css', 'string', 'foo'); | |
| $css_string2 = $this->collector->createCssStringAsset('foo'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\CssStringAsset', $css_string1, 'Collector correctly created a CssStringAsset instance through the generic method.'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\CssStringAsset', $css_string2, 'Collector correctly created a CssStringAsset instance through the specific method.'); | |
| $js_file1 = $this->collector->create('js', 'file', 'foo'); | |
| $js_file2 = $this->collector->createJsFileAsset('foo'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\JsFileAsset', $js_file1, 'Collector correctly created a JsFileAsset instance through the generic method.'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\JsFileAsset', $js_file2, 'Collector correctly created a JsFileAsset instance through the specific method.'); | |
| $js_external1 = $this->collector->create('js', 'external', 'foo'); | |
| $js_external2 = $this->collector->createJsExternalAsset('foo'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\JsExternalAsset', $js_external1, 'Collector correctly created a JsExternalAsset instance through the generic method.'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\JsExternalAsset', $js_external2, 'Collector correctly created a JsExternalAsset instance through the specific method.'); | |
| $js_string1 = $this->collector->create('js', 'string', 'foo'); | |
| $js_string2 = $this->collector->createJsStringAsset('foo'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\JsStringAsset', $js_string1, 'Collector correctly created a JsStringAsset instance through the generic method.'); | |
| $this->assertInstanceOf('\Drupal\Core\Asset\JsStringAsset', $js_string2, 'Collector correctly created a JsStringAsset instance through the specific method.'); | |
| // Now ensure that an exception is thrown | |
| } | |
| /** | |
| * Tests that the collector injects provided metadata to created assets. | |
| */ | |
| public function testMetadataInjection() { | |
| // Test a single value first | |
| $asset = $this->collector->createCssFileAsset('foo', array('group' => CSS_AGGREGATE_THEME)); | |
| $this->assertEquals(CSS_AGGREGATE_THEME, $asset['group'], 'Collector injected user-passed parameters into the created asset.'); | |
| // TODO is it worth testing multiple params? what about weird ones, like weight? | |
| } | |
| public function testStorage() { | |
| // First, try to add an asset when no bag is present in the collector. | |
| $asset = $this->collector->create('css', 'string', 'foo'); | |
| try { | |
| $this->collector->add('foo', $asset); | |
| $this->fail('Collector failed to throw an appropriate exception when an asset was added without a bag being present.'); | |
| } | |
| catch (\Exception $e) { | |
| $this->assertTrue(TRUE, 'Collector threw expected exception when attempting to add an asset without an underlying bag present.'); | |
| } | |
| // Now add a bag to the collector, add the asset, and ensure we can get it | |
| // back out of the bag. | |
| $bag = new AssetBag(); | |
| $this->collector->setBag($bag); | |
| $this->collector->add('foo', $asset); | |
| $this->assertContains($asset, $bag->getCss(), 'Asset added to collector is available to the code that injected the bag.'); | |
| // Ensure that implicit adding also works: when a bag is present in a | |
| // collector, it should automatically add created assets to it. | |
| $asset2 = $this->collector->create('css', 'file', 'bar'); | |
| $this->assertContains($asset2, $bag->getCss(), 'Asset created via generic method was implicitly added to bag.'); | |
| $asset3 = $this->collector->createCssFileAsset('baz'); | |
| $this->assertContains($asset3, $bag->getCss(), 'Asset created via specific method was implicitly added to bag.'); | |
| // Now remove the bag, and make sure the adding exception is thrown again. | |
| $this->collector->clearBag(); | |
| try { | |
| $this->collector->add('foo', $asset); | |
| $this->fail('Collector failed to throw an appropriate exception when an asset was added after the containing bag should have been cleared.'); | |
| } | |
| catch (\Exception $e) { | |
| $this->assertTrue(TRUE, 'Collector threw expected exception when attempting to add an asset after the containing bag was removed.'); | |
| } | |
| } | |
| /** | |
| * Tests that locking works, and the correct methods are disabled when locked. | |
| */ | |
| public function testLocking() { | |
| $this->assertTrue($this->collector->lock($this), 'Collector locked succesfully.'); | |
| $this->assertTrue($this->collector->isLocked(), 'Collector accurately reports that it is locked via isLocked() method.'); | |
| try { | |
| $this->collector->setDefaults('css', array('foo' => 'bar')); | |
| $this->fail('No exception thrown when an attempt was made to change protected values while the collector was locked.'); | |
| } | |
| catch (\Exception $e) { | |
| $this->assertTrue(TRUE, 'Collector threw appropriate exception on lock violation.'); | |
| } | |
| try { | |
| $this->collector->restoreDefaults(); | |
| $this->fail('No exception thrown when an attempt was made to change protected values while the collector was locked.'); | |
| } | |
| catch (\Exception $e) { | |
| $this->assertTrue(TRUE, 'Collector threw appropriate exception on lock violation.'); | |
| } | |
| try { | |
| $this->collector->clearBag(); | |
| $this->fail('No exception thrown when an attempt was made to clear the current bag while the collector was locked.'); | |
| } | |
| catch (\Exception $e) { | |
| $this->assertTrue(TRUE, 'Collector threw appropriate exception on lock violation.'); | |
| } | |
| try { | |
| $this->collector->setBag(new AssetBag()); | |
| $this->fail('No exception thrown when an attempt was made to clear the current bag while the collector was locked.'); | |
| } | |
| catch (\Exception $e) { | |
| $this->assertTrue(TRUE, 'Collector threw appropriate exception on lock violation.'); | |
| } | |
| try { | |
| $this->collector->unlock('foo'); | |
| $this->fail('Collector failed to throw an appropriate exception when an attempt to unlock was made without the correct key.'); | |
| } | |
| catch (\Exception $e) { | |
| $this->assertTrue(TRUE, 'Collector threw appropriate exception on unauthorized attempt to unlock.'); | |
| } | |
| $this->assertTrue($this->collector->unlock($this), 'Collector unlocked successfully when appropriate key was provided.'); | |
| $this->assertFalse($this->collector->isLocked(), 'Collector correctly reported unlocked state via isLocked() method after unlocking.'); | |
| } | |
| public function testDefaults() { | |
| $builtin_defaults = array( | |
| 'css' => array( | |
| 'group' => CSS_AGGREGATE_DEFAULT, | |
| 'weight' => 0, | |
| 'every_page' => FALSE, | |
| 'media' => 'all', | |
| 'preprocess' => TRUE, | |
| 'browsers' => array( | |
| 'IE' => TRUE, | |
| '!IE' => TRUE, | |
| ), | |
| ), | |
| 'js' => array( | |
| 'group' => JS_DEFAULT, | |
| 'every_page' => FALSE, | |
| 'weight' => 0, | |
| 'scope' => 'header', | |
| 'cache' => TRUE, | |
| 'preprocess' => TRUE, | |
| 'attributes' => array(), | |
| 'version' => NULL, | |
| 'browsers' => array(), | |
| ), | |
| ); | |
| // First, test that manipulating the assets works as expected. | |
| $this->assertEquals($builtin_defaults['css'], $this->collector->getDefaults('css'), 'Expected set of built-in defaults reside in the collector.'); | |
| $changed_defaults = array('every_page' => TRUE, 'group' => CSS_AGGREGATE_THEME); | |
| $this->collector->setDefaults('css', $changed_defaults); | |
| $this->assertEquals($changed_defaults + $builtin_defaults['css'], $this->collector->getDefaults('css'), 'Expected combination of built-in and injected defaults reside in the collector.'); | |
| $this->collector->restoreDefaults(); | |
| $this->assertEquals($builtin_defaults, $this->collector->getDefaults(), 'Built-in defaults were correctly restored.'); | |
| // Test that an exception is thrown when an invalid type is requested. | |
| try { | |
| $this->collector->getDefaults('foo'); | |
| $this->fail('No exception thrown when an invalid key was requested.'); | |
| } | |
| catch (\InvalidArgumentException $e) {} | |
| // Test that defaults are correctly applied when passing through both | |
| // the generic and specific factory methods. | |
| $css1 = $this->collector->create('css', 'file', 'foo'); | |
| $this->assertTrue($css1['every_page'], 'Correct default propagated for "every_page" property.'); | |
| $this->assertEquals(CSS_AGGREGATE_THEME, $css1['group'], 'Correct default propagated for "group" property.'); | |
| $css2 = $this->collector->createCssFileAsset('foo'); | |
| $this->assertTrue($css2['every_page'], 'Correct default propagated for "every_page" property.'); | |
| $this->assertEquals(CSS_AGGREGATE_THEME, $css2['group'], 'Correct default propagated for "group" property.'); | |
| // TODO bother testing js? it seems logically redundant | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment