From 11e943765dd913dd3b0ad13624c45963ec9774af Mon Sep 17 00:00:00 2001 From: webimpress Date: Wed, 15 Jun 2016 23:54:55 +0100 Subject: [PATCH 1/8] 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; + } +} From dd23c07fc4894405cbeec8c7be1458a96ea40dc0 Mon Sep 17 00:00:00 2001 From: webimpress Date: Mon, 6 Feb 2017 22:08:19 +0000 Subject: [PATCH 2/8] Updated docs - per @froschdesign --- doc/book/helpers/asset.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/book/helpers/asset.md b/doc/book/helpers/asset.md index 2271580a..7a7dc8e4 100644 --- a/doc/book/helpers/asset.md +++ b/doc/book/helpers/asset.md @@ -37,15 +37,15 @@ 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 +> ### 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. +> +> 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 From 3e08baf38f7a9a077501027629642ee73b416cae Mon Sep 17 00:00:00 2001 From: webimpress Date: Mon, 6 Feb 2017 22:09:13 +0000 Subject: [PATCH 3/8] Added helper in PHPDocs for code completion in IDEs - per @froschdesign --- src/Renderer/PhpRenderer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Renderer/PhpRenderer.php b/src/Renderer/PhpRenderer.php index aac1fcd9..fd6a76c3 100644 --- a/src/Renderer/PhpRenderer.php +++ b/src/Renderer/PhpRenderer.php @@ -31,6 +31,7 @@ * * Convenience methods for build in helpers (@see __call): * + * @method string asset($asset) * @method string|null basePath($file = null) * @method \Zend\View\Helper\Cycle cycle(array $data = array(), $name = \Zend\View\Helper\Cycle::DEFAULT_NAME) * @method \Zend\View\Helper\DeclareVars declareVars() From e0ea1ab8ece768ccc1b9e4bae4dec62b303a0385 Mon Sep 17 00:00:00 2001 From: webimpress Date: Mon, 6 Feb 2017 22:10:00 +0000 Subject: [PATCH 4/8] Added missing throws tags in PHPDocs --- src/Helper/Asset.php | 1 + src/Helper/Service/AssetFactory.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Helper/Asset.php b/src/Helper/Asset.php index d24ec0e7..05966309 100644 --- a/src/Helper/Asset.php +++ b/src/Helper/Asset.php @@ -24,6 +24,7 @@ class Asset extends AbstractHelper /** * @param string $asset * @return string + * @throws Exception\InvalidArgumentException */ public function __invoke($asset) { diff --git a/src/Helper/Service/AssetFactory.php b/src/Helper/Service/AssetFactory.php index cad7f086..382f199c 100644 --- a/src/Helper/Service/AssetFactory.php +++ b/src/Helper/Service/AssetFactory.php @@ -24,6 +24,7 @@ class AssetFactory implements FactoryInterface * @param string $name * @param null|array $options * @return Asset + * @throws Exception\RuntimeException */ public function __invoke(ContainerInterface $container, $name, array $options = null) { From edf868646b610ddc477c6244bb06ee4093046011 Mon Sep 17 00:00:00 2001 From: webimpress Date: Mon, 6 Feb 2017 22:10:23 +0000 Subject: [PATCH 5/8] CS fix - single space after `!` --- src/Helper/Asset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Helper/Asset.php b/src/Helper/Asset.php index 05966309..f7ec6525 100644 --- a/src/Helper/Asset.php +++ b/src/Helper/Asset.php @@ -28,7 +28,7 @@ class Asset extends AbstractHelper */ public function __invoke($asset) { - if (!array_key_exists($asset, $this->resourceMap)) { + if (! array_key_exists($asset, $this->resourceMap)) { throw new Exception\InvalidArgumentException('Asset is not defined.'); } From 4630c412829be83c2ccf2075ebd131c1442ec411 Mon Sep 17 00:00:00 2001 From: webimpress Date: Mon, 6 Feb 2017 22:10:50 +0000 Subject: [PATCH 6/8] Added missing PHPDocs - per @froschdesign --- src/Helper/Asset.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Helper/Asset.php b/src/Helper/Asset.php index f7ec6525..65bf5ffe 100644 --- a/src/Helper/Asset.php +++ b/src/Helper/Asset.php @@ -35,6 +35,10 @@ public function __invoke($asset) return $this->resourceMap[$asset]; } + /** + * @param array $resourceMap + * @return $this + */ public function setResourceMap($resourceMap) { $this->resourceMap = $resourceMap; @@ -42,6 +46,9 @@ public function setResourceMap($resourceMap) return $this; } + /** + * @return array + */ public function getResourceMap() { return $this->resourceMap; From 363bbf95169de6323ec91a315b50ab2e19e1f83b Mon Sep 17 00:00:00 2001 From: webimpress Date: Mon, 6 Feb 2017 22:11:09 +0000 Subject: [PATCH 7/8] Added typehint for parameter --- src/Helper/Asset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Helper/Asset.php b/src/Helper/Asset.php index 65bf5ffe..6793a95e 100644 --- a/src/Helper/Asset.php +++ b/src/Helper/Asset.php @@ -39,7 +39,7 @@ public function __invoke($asset) * @param array $resourceMap * @return $this */ - public function setResourceMap($resourceMap) + public function setResourceMap(array $resourceMap) { $this->resourceMap = $resourceMap; From bddbc6bf7fa541ee239b8f8fdac912d8e4edbec3 Mon Sep 17 00:00:00 2001 From: webimpress Date: Mon, 6 Feb 2017 22:19:42 +0000 Subject: [PATCH 8/8] Updated license headers - First publication in a release is gonna be this year (I hope so...) --- src/Helper/Asset.php | 8 +++----- src/Helper/Service/AssetFactory.php | 8 +++----- test/Helper/AssetTest.php | 8 +++----- test/Helper/Service/AssetFactoryTest.php | 8 +++----- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/Helper/Asset.php b/src/Helper/Asset.php index 6793a95e..d7342822 100644 --- a/src/Helper/Asset.php +++ b/src/Helper/Asset.php @@ -1,10 +1,8 @@