From 11e943765dd913dd3b0ad13624c45963ec9774af Mon Sep 17 00:00:00 2001 From: webimpress Date: Wed, 15 Jun 2016 23:54:55 +0100 Subject: [PATCH] added new View Helper - Asset helper --- doc/book/helpers/asset.md | 74 +++++++++++++++++++ doc/book/helpers/intro.md | 1 + mkdocs.yml | 1 + src/Helper/Asset.php | 48 +++++++++++++ src/Helper/Service/AssetFactory.php | 61 ++++++++++++++++ src/HelperPluginManager.php | 4 ++ test/Helper/AssetTest.php | 89 +++++++++++++++++++++++ test/Helper/Service/AssetFactoryTest.php | 91 ++++++++++++++++++++++++ 8 files changed, 369 insertions(+) create mode 100644 doc/book/helpers/asset.md create mode 100644 src/Helper/Asset.php create mode 100644 src/Helper/Service/AssetFactory.php create mode 100644 test/Helper/AssetTest.php create mode 100644 test/Helper/Service/AssetFactoryTest.php diff --git a/doc/book/helpers/asset.md b/doc/book/helpers/asset.md new file mode 100644 index 00000000..2271580a --- /dev/null +++ b/doc/book/helpers/asset.md @@ -0,0 +1,74 @@ +# Asset + +The `Asset` helper is used to translate asset names. +It could be used to prevent browser caching for assets. + +## Configuration and Basic Usage + +`Zend\View\Helper\Service\AssetFactory` checks the application +configuration, making it possible to set up the resource map through +your `module.config.php`. The next example will set up `Asset` helper: + +```php +'view_helper_config' => [ + 'asset' => [ + 'resource_map' => [ + 'css/style.css' => 'css/style-3a97ff4ee3.css', + 'js/vendor.js' => 'js/vendor-a507086eba.js', + ], + ], +], +``` + +Then in your view you can use: + +```php +// Usable in any of your .phtml files: +echo $this->asset('css/style.css'); +``` + +and you would receive following output: + +```html +css/style-3a97ff4ee3.css +``` + +The first argument of the `asset` helper is the regular asset name, +which will be replaced by versioned asset name defined in `resource_map` +of the configuration. + +### Note + +When `asset` key is defined but `resource_map` is not provided or is not +an array exception `Zend\View\Exception\RuntimeException` will be +thrown. + +When you call `asset` helper with parameter which is not defined on your +`resource_map` exception `Zend\View\Exception\InvalidArgumentException` +will be thrown. + +## Resource map in JSON file + +If you have JSON file with resource map, for example +`rev-manifest.json`: + +```javascript +{ + "css/style.css": "css/style-3a97ff4ee3.css", + "js/vendor.js": "js/vendor-a507086eba.js" +} +``` + +then you can have in your configuration: + +```php +'view_helper_config' => [ + 'asset' => [ + 'resource_map' => json_decode(file_get_contents('/path/to/rev-manifest.json'), true), + ], +], +``` + +and when you have enabled cache config this file will be also cached in +compiled configuration cache, so it prevents reading the file on each +page load. diff --git a/doc/book/helpers/intro.md b/doc/book/helpers/intro.md index 34f10de8..35ef7228 100644 --- a/doc/book/helpers/intro.md +++ b/doc/book/helpers/intro.md @@ -55,6 +55,7 @@ variables. Additionally, there are a rich set of helpers for providing values for, and rendering, the various HTML `` tags, such as `HeadTitle`, `HeadLink`, and `HeadScript`. The currently shipped helpers include: +- [Asset](asset.md) - [BasePath](base-path.md) - [Cycle](cycle.md) - [Doctype](doctype.md) diff --git a/mkdocs.yml b/mkdocs.yml index 0163b550..ad6ac9c5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,6 +9,7 @@ pages: - "The ViewEvent": view-event.md - Helpers: - Intro: helpers/intro.md + - Asset: helpers/asset.md - BasePath: helpers/base-path.md - Cycle: helpers/cycle.md - Doctype: helpers/doctype.md diff --git a/src/Helper/Asset.php b/src/Helper/Asset.php new file mode 100644 index 00000000..d24ec0e7 --- /dev/null +++ b/src/Helper/Asset.php @@ -0,0 +1,48 @@ +resourceMap)) { + throw new Exception\InvalidArgumentException('Asset is not defined.'); + } + + return $this->resourceMap[$asset]; + } + + public function setResourceMap($resourceMap) + { + $this->resourceMap = $resourceMap; + + return $this; + } + + public function getResourceMap() + { + return $this->resourceMap; + } +} diff --git a/src/Helper/Service/AssetFactory.php b/src/Helper/Service/AssetFactory.php new file mode 100644 index 00000000..cad7f086 --- /dev/null +++ b/src/Helper/Service/AssetFactory.php @@ -0,0 +1,61 @@ +getServiceLocator(); + } + $helper = new Asset(); + + $config = $container->get('config'); + if (isset($config['view_helper_config']['asset'])) { + $configHelper = $config['view_helper_config']['asset']; + if (isset($configHelper['resource_map']) && is_array($configHelper['resource_map'])) { + $helper->setResourceMap($configHelper['resource_map']); + } else { + throw new Exception\RuntimeException('Invalid resource map configuration.'); + } + } + + return $helper; + } + + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @param string|null $rName + * @param string|null $cName + * @return Asset + */ + public function createService(ServiceLocatorInterface $serviceLocator, $rName = null, $cName = null) + { + return $this($serviceLocator, $cName); + } +} diff --git a/src/HelperPluginManager.php b/src/HelperPluginManager.php index 652980be..6a07792b 100644 --- a/src/HelperPluginManager.php +++ b/src/HelperPluginManager.php @@ -37,6 +37,8 @@ class HelperPluginManager extends AbstractPluginManager * @var string[] */ protected $aliases = [ + 'asset' => Helper\Asset::class, + 'Asset' => Helper\Asset::class, 'basePath' => Helper\BasePath::class, 'BasePath' => Helper\BasePath::class, 'basepath' => Helper\BasePath::class, @@ -148,6 +150,7 @@ class HelperPluginManager extends AbstractPluginManager * @var array */ protected $factories = [ + Helper\Asset::class => Helper\Service\AssetFactory::class, Helper\FlashMessenger::class => Helper\Service\FlashMessengerFactory::class, Helper\Identity::class => Helper\Service\IdentityFactory::class, Helper\BasePath::class => InvokableFactory::class, @@ -186,6 +189,7 @@ class HelperPluginManager extends AbstractPluginManager // v2 canonical FQCNs + 'zendviewhelperasset' => Helper\Service\AssetFactory::class, 'zendviewhelperflashmessenger' => Helper\Service\FlashMessengerFactory::class, 'zendviewhelperidentity' => Helper\Service\IdentityFactory::class, 'zendviewhelperbasepath' => InvokableFactory::class, diff --git a/test/Helper/AssetTest.php b/test/Helper/AssetTest.php new file mode 100644 index 00000000..6f2aeae9 --- /dev/null +++ b/test/Helper/AssetTest.php @@ -0,0 +1,89 @@ + 'css/style-3a97ff4ee3.css', + 'js/vendor.js' => 'js/vendor-a507086eba.js', + ]; + + /** @var Asset */ + protected $asset; + + protected function setUp() + { + parent::setUp(); + + $this->asset = new Asset(); + $this->asset->setResourceMap($this->resourceMap); + } + + public function testHelperPluginManagerReturnsAssetHelper() + { + $helpers = $this->getHelperPluginManager(); + $asset = $helpers->get('asset'); + + $this->assertInstanceOf(Asset::class, $asset); + } + + public function testHelperPluginManagerReturnsAssetHelperByClassName() + { + $helpers = $this->getHelperPluginManager(); + $asset = $helpers->get(Asset::class); + + $this->assertInstanceOf(Asset::class, $asset); + } + + public function testInvalidAssetName() + { + $this->setExpectedException(Exception\InvalidArgumentException::class, 'Asset is not defined.'); + + $this->asset->__invoke('unknown'); + } + + /** + * @dataProvider assets + * + * @param string $name + * @param string $expected + */ + public function testInvokeResult($name, $expected) + { + $result = $this->asset->__invoke($name); + + $this->assertEquals($expected, $result); + } + + public function assets() + { + $data = []; + foreach ($this->resourceMap as $key => $value) { + $data[] = [$key, $value]; + } + return $data; + } + + protected function getHelperPluginManager(array $config = []) + { + $services = $this->prophesize(ServiceManager::class); + $services->get('config')->willReturn($config); + + return new HelperPluginManager($services->reveal()); + } +} diff --git a/test/Helper/Service/AssetFactoryTest.php b/test/Helper/Service/AssetFactoryTest.php new file mode 100644 index 00000000..b139a7ce --- /dev/null +++ b/test/Helper/Service/AssetFactoryTest.php @@ -0,0 +1,91 @@ +getServices(); + + $assetFactory = new AssetFactory(); + $asset = $assetFactory->createService($services); + + $this->assertInstanceOf(Asset::class, $asset); + } + + public function testAssetFactoryInvokableCreatesAssetInstance() + { + $services = $this->getServices(); + + $assetFactory = new AssetFactory(); + $asset = $assetFactory($services, ''); + + $this->assertInstanceOf(Asset::class, $asset); + } + + public function testValidConfiguration() + { + $config = [ + 'view_helper_config' => [ + 'asset' => [ + 'resource_map' => [ + 'css/style.css' => 'css/style-3a97ff4ee3.css', + 'js/vendor.js' => 'js/vendor-a507086eba.js', + ], + ], + ], + ]; + + $services = $this->getServices($config); + $assetFactory = new AssetFactory(); + + $asset = $assetFactory($services, ''); + + $this->assertEquals($config['view_helper_config']['asset']['resource_map'], $asset->getResourceMap()); + } + + public function testInvalidConfiguration() + { + $config = [ + 'view_helper_config' => [ + 'asset' => [], + ], + ]; + $services = $this->getServices($config); + + $assetFactory = new AssetFactory(); + + $this->setExpectedException(Exception\RuntimeException::class, 'Invalid resource map configuration.'); + $assetFactory($services, ''); + } + + protected function getServices(array $config = []) + { + $services = $this->prophesize(ServiceManager::class); + $services->get('config')->willReturn($config); + + $helpers = new HelperPluginManager($services->reveal()); + + // test if we are using Zend\ServiceManager v3 + if (method_exists($helpers, 'configure')) { + return $services->reveal(); + } + + return $helpers; + } +}