diff --git a/Events/CacheResolveEvent.php b/Events/CacheResolveEvent.php new file mode 100644 index 000000000..325d0ff7e --- /dev/null +++ b/Events/CacheResolveEvent.php @@ -0,0 +1,99 @@ +path = $path; + $this->filter = $filter; + $this->url = $url; + } + + /** + * Sets resource path + * + * @param $path + */ + public function setPath($path) + { + $this->path = $path; + } + + /** + * Returns resource path + * + * @return string + */ + public function getPath() + { + return $this->path; + } + + /** + * Sets filter name + * + * @param $filter + */ + public function setFilter($filter) + { + $this->filter = $filter; + } + + /** + * Returns filter name + * + * @return string + */ + public function getFilter() + { + return $this->filter; + } + + /** + * Sets resource url + * + * @param $url + */ + public function setUrl($url) + { + $this->url = $url; + } + + /** + * Returns resource url + * + * @return null + */ + public function getUrl() + { + return $this->url; + } +} diff --git a/Imagine/Cache/CacheManager.php b/Imagine/Cache/CacheManager.php index e9c6f6810..d0c270b64 100644 --- a/Imagine/Cache/CacheManager.php +++ b/Imagine/Cache/CacheManager.php @@ -8,6 +8,10 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\UriSigner; use Symfony\Component\Routing\RouterInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\Event; +use Liip\ImagineBundle\ImagineEvents; +use Liip\ImagineBundle\Events\CacheResolveEvent; class CacheManager { @@ -31,6 +35,11 @@ class CacheManager */ protected $uriSigner; + /** + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $dispatcher; + /** * @var string */ @@ -44,11 +53,17 @@ class CacheManager * @param UriSigner $uriSigner * @param string $defaultResolver */ - public function __construct(FilterConfiguration $filterConfig, RouterInterface $router, UriSigner $uriSigner, $defaultResolver = null) - { + public function __construct( + FilterConfiguration $filterConfig, + RouterInterface $router, + UriSigner $uriSigner, + EventDispatcherInterface $dispatcher, + $defaultResolver = null + ) { $this->filterConfig = $filterConfig; $this->router = $router; $this->uriSigner = $uriSigner; + $this->dispatcher = $dispatcher; $this->defaultResolver = $defaultResolver ?: 'default'; } @@ -176,7 +191,15 @@ public function resolve($path, $filter) throw new NotFoundHttpException(sprintf("Source image was searched with '%s' outside of the defined root path", $path)); } - return $this->getResolver($filter)->resolve($path, $filter); + $preEvent = new CacheResolveEvent($path, $filter); + $this->dispatcher->dispatch(ImagineEvents::PRE_RESOLVE, $preEvent); + + $url = $this->getResolver($preEvent->getFilter())->resolve($preEvent->getPath(), $preEvent->getFilter()); + + $postEvent = new CacheResolveEvent($preEvent->getPath(), $preEvent->getFilter(), $url); + $this->dispatcher->dispatch(ImagineEvents::POST_RESOLVE, $postEvent); + + return $postEvent->getUrl(); } /** diff --git a/ImagineEvents.php b/ImagineEvents.php new file mode 100644 index 000000000..cce7bb1cf --- /dev/null +++ b/ImagineEvents.php @@ -0,0 +1,14 @@ + + %liip_imagine.cache.resolver.default% diff --git a/Tests/AbstractTest.php b/Tests/AbstractTest.php index 9e5ea46fd..ea355f251 100644 --- a/Tests/AbstractTest.php +++ b/Tests/AbstractTest.php @@ -6,6 +6,7 @@ use Liip\ImagineBundle\Imagine\Filter\FilterConfiguration; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Routing\RouterInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; abstract class AbstractTest extends \PHPUnit_Framework_TestCase { @@ -81,6 +82,11 @@ protected function createResolverMock() return $this->getMock('Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface'); } + protected function createEventDispatcherMock() + { + return $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + } + protected function getMockImage() { return $this->getMock('Imagine\Image\ImageInterface'); diff --git a/Tests/Events/CacheResolveEventTest.php b/Tests/Events/CacheResolveEventTest.php new file mode 100644 index 000000000..41e826345 --- /dev/null +++ b/Tests/Events/CacheResolveEventTest.php @@ -0,0 +1,105 @@ +assertAttributeEquals('default_path', 'path', $event); + } + + public function testShouldAllowSetPathByMethod() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + $event->setPath('new_path'); + + $this->assertAttributeEquals('new_path', 'path', $event); + } + + public function testShouldAllowGetPathWhichWasSetInConstruct() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + + $this->assertEquals('default_path', $event->getPath()); + } + + public function testShouldAllowGetPathWhichWasSetByMethod() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + $event->setPath('new_path'); + + $this->assertEquals('new_path', $event->getPath()); + } + + public function testShouldAllowSetFilterInConstruct() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + + $this->assertAttributeEquals('default_filter', 'filter', $event); + } + + public function testShouldAllowSetFilterByMethod() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + $event->setFilter('new_filter'); + + $this->assertAttributeEquals('new_filter', 'filter', $event); + } + + public function testShouldAllowGetFilterWhichWasSetInConstruct() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + + $this->assertEquals('default_filter', $event->getFilter()); + } + + public function testShouldAllowGetFilterWhichWasSetByMethod() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + $event->setFilter('new_filter'); + + $this->assertEquals('new_filter', $event->getFilter()); + } + + public function testShouldAllowSetUrlInConstruct() + { + $event = new CacheResolveEvent('default_path', 'default_filter', 'default_url'); + + $this->assertAttributeEquals('default_url', 'url', $event); + } + + public function testShouldAllowSetUrlByMethod() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + $event->setUrl('new_url'); + + $this->assertAttributeEquals('new_url', 'url', $event); + } + + public function testShouldAllowGetUrlWhichWasSetInConstruct() + { + $event = new CacheResolveEvent('default_path', 'default_filter', 'default_url'); + + $this->assertEquals('default_url', $event->getUrl()); + } + + public function testShouldAllowGetUrlWhichWasSetByMethod() + { + $event = new CacheResolveEvent('default_path', 'default_filter'); + $event->setUrl('new_url'); + + $this->assertEquals('new_url', $event->getUrl()); + } +} diff --git a/Tests/Imagine/Cache/CacheManagerTest.php b/Tests/Imagine/Cache/CacheManagerTest.php index 31f72debe..1ccbefeee 100644 --- a/Tests/Imagine/Cache/CacheManagerTest.php +++ b/Tests/Imagine/Cache/CacheManagerTest.php @@ -7,6 +7,8 @@ use Liip\ImagineBundle\Tests\AbstractTest; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\UriSigner; +use Liip\ImagineBundle\ImagineEvents; +use Liip\ImagineBundle\Events\CacheResolveEvent; /** * @covers Liip\ImagineBundle\Imagine\Cache\CacheManager @@ -17,7 +19,7 @@ class CacheManagerTest extends AbstractTest public function testAddCacheManagerAwareResolver() { - $cacheManager = new CacheManager($this->createFilterConfigurationMock(), $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($this->createFilterConfigurationMock(), $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $resolver = $this->getMock('Liip\ImagineBundle\Tests\Fixtures\CacheManagerAwareResolver'); $resolver @@ -43,7 +45,7 @@ public function testGetBrowserPathWithoutResolver() ))) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $this->setExpectedException('OutOfBoundsException', 'Could not find resolver "default" for "thumbnail" filter type'); $cacheManager->getBrowserPath('cats.jpeg', 'thumbnail'); @@ -83,7 +85,7 @@ public function testDefaultResolverUsedIfNoneSetOnGetBrowserPath() ->method('generate') ; - $cacheManager = new CacheManager($config, $router, new UriSigner('secret')); + $cacheManager = new CacheManager($config, $router, new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver('default', $resolver); $actualBrowserPath = $cacheManager->getBrowserPath('cats.jpeg', 'thumbnail'); @@ -124,7 +126,7 @@ public function testFilterActionUrlGeneratedAndReturnIfResolverReturnNullOnGetBr ->will($this->returnValue('/media/cache/thumbnail/cats.jpeg')) ; - $cacheManager = new CacheManager($config, $router, new UriSigner('secret')); + $cacheManager = new CacheManager($config, $router, new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver('default', $resolver); $actualBrowserPath = $cacheManager->getBrowserPath('cats.jpeg', 'thumbnail'); @@ -137,7 +139,12 @@ public function testFilterActionUrlGeneratedAndReturnIfResolverReturnNullOnGetBr */ public function testResolveInvalidPath($path) { - $cacheManager = new CacheManager($this->createFilterConfigurationMock(), $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $this->createEventDispatcherMock() + ); $this->setExpectedException('Symfony\Component\HttpKernel\Exception\NotFoundHttpException'); $cacheManager->resolve($path, 'thumbnail'); @@ -145,7 +152,12 @@ public function testResolveInvalidPath($path) public function testThrowsIfConcreteResolverNotExists() { - $cacheManager = new CacheManager($this->createFilterConfigurationMock(), $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $this->createEventDispatcherMock() + ); $this->setExpectedException('OutOfBoundsException', 'Could not find resolver "default" for "thumbnail" filter type'); $this->assertFalse($cacheManager->resolve('cats.jpeg', 'thumbnail')); @@ -189,7 +201,8 @@ public function testFallbackToDefaultResolver() $cacheManager = new CacheManager( $config, $this->createRouterMock(), - new UriSigner('secret') + new UriSigner('secret'), + $this->createEventDispatcherMock() ); $cacheManager->addResolver('default', $resolver); @@ -224,7 +237,8 @@ public function testGenerateUrl() $cacheManager = new CacheManager( $this->createFilterConfigurationMock(), $routerMock, - new UriSigner('secret') + new UriSigner('secret'), + $this->createEventDispatcherMock() ); $this->assertEquals( @@ -256,7 +270,7 @@ public function testRemoveCacheForPathAndFilterOnRemove() })) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver($expectedFilter, $resolver); $cacheManager->remove($expectedPath, $expectedFilter); @@ -293,7 +307,7 @@ public function testRemoveCacheForPathAndSomeFiltersOnRemove() })) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver($expectedFilterOne, $resolverOne); $cacheManager->addResolver($expectedFilterTwo, $resolverTwo); @@ -327,7 +341,7 @@ public function testRemoveCacheForSomePathsAndFilterOnRemove() })) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver($expectedFilter, $resolver); $cacheManager->remove(array($expectedPathOne, $expectedPathTwo), $expectedFilter); @@ -365,7 +379,7 @@ public function testRemoveCacheForSomePathsAndSomeFiltersOnRemove() })) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver($expectedFilterOne, $resolverOne); $cacheManager->addResolver($expectedFilterTwo, $resolverTwo); @@ -413,7 +427,7 @@ public function testRemoveCacheForAllFiltersOnRemove() ))) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver($expectedFilterOne, $resolverOne); $cacheManager->addResolver($expectedFilterTwo, $resolverTwo); @@ -459,7 +473,7 @@ public function testRemoveCacheForPathAndAllFiltersOnRemove() ))) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver($expectedFilterOne, $resolverOne); $cacheManager->addResolver($expectedFilterTwo, $resolverTwo); @@ -489,10 +503,170 @@ public function testAggregateFiltersByResolverOnRemove() })) ; - $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret')); + $cacheManager = new CacheManager($config, $this->createRouterMock(), new UriSigner('secret'), $this->createEventDispatcherMock()); $cacheManager->addResolver($expectedFilterOne, $resolver); $cacheManager->addResolver($expectedFilterTwo, $resolver); $cacheManager->remove(null, array($expectedFilterOne, $expectedFilterTwo)); } + + public function testShouldDispatchCachePreResolveEvent() + { + $dispatcher = $this->createEventDispatcherMock(); + $dispatcher + ->expects($this->at(0)) + ->method('dispatch') + ->with(ImagineEvents::PRE_RESOLVE, new CacheResolveEvent('cats.jpg', 'thumbnail')) + ; + + $cacheManager = new CacheManager( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $dispatcher + ); + $cacheManager->addResolver('default', $this->createResolverMock()); + + $cacheManager->resolve('cats.jpg', 'thumbnail'); + } + + public function testShouldDispatchCachePostResolveEvent() + { + $dispatcher = $this->createEventDispatcherMock(); + $dispatcher + ->expects($this->at(1)) + ->method('dispatch') + ->with(ImagineEvents::POST_RESOLVE, new CacheResolveEvent('cats.jpg', 'thumbnail')) + ; + + $cacheManager = new CacheManager( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $dispatcher + ); + $cacheManager->addResolver('default', $this->createResolverMock()); + + $cacheManager->resolve('cats.jpg', 'thumbnail'); + } + + public function testShouldAllowToPassChangedDataFromPreResolveEventToResolver() + { + $dispatcher = $this->createEventDispatcherMock(); + $dispatcher + ->expects($this->at(0)) + ->method('dispatch') + ->with(ImagineEvents::PRE_RESOLVE, $this->isInstanceOf('Liip\ImagineBundle\Events\CacheResolveEvent')) + ->will($this->returnCallback(function ($name, $event) { + $event->setPath('changed_path'); + $event->setFilter('changed_filter'); + })) + ; + + $resolver = $this->createResolverMock(); + $resolver + ->expects($this->once()) + ->method('resolve') + ->with('changed_path', 'changed_filter') + ; + + $cacheManager = new CacheManager( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $dispatcher + ); + $cacheManager->addResolver('default', $resolver); + + $cacheManager->resolve('cats.jpg', 'thumbnail'); + } + + public function testShouldAllowToGetResolverByFilterChangedInPreResolveEvent() + { + $dispatcher = $this->createEventDispatcherMock(); + $dispatcher + ->expects($this->at(0)) + ->method('dispatch') + ->will($this->returnCallback(function ($name, $event) { + $event->setFilter('thumbnail'); + })) + ; + + $cacheManager = $this->getMock('Liip\ImagineBundle\Imagine\Cache\CacheManager', array('getResolver'), array( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $dispatcher + )); + + $cacheManager + ->expects($this->once()) + ->method('getResolver') + ->with('thumbnail') + ->will($this->returnValue($this->createResolverMock())) + ; + + $cacheManager->resolve('cats.jpg', 'default'); + } + + public function testShouldAllowToPassChangedDataFromPreResolveEventToPostResolveEvent() + { + $dispatcher = $this->createEventDispatcherMock(); + $dispatcher + ->expects($this->at(0)) + ->method('dispatch') + ->with(ImagineEvents::PRE_RESOLVE, $this->isInstanceOf('Liip\ImagineBundle\Events\CacheResolveEvent')) + ->will($this->returnCallback(function ($name, $event) { + $event->setPath('changed_path'); + $event->setFilter('changed_filter'); + })) + ; + + $dispatcher + ->expects($this->at(1)) + ->method('dispatch') + ->with( + ImagineEvents::POST_RESOLVE, + $this->logicalAnd( + $this->isInstanceOf('Liip\ImagineBundle\Events\CacheResolveEvent'), + $this->attributeEqualTo('path', 'changed_path'), + $this->attributeEqualTo('filter', 'changed_filter') + )) + ; + + $cacheManager = new CacheManager( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $dispatcher + ); + $cacheManager->addResolver('default', $this->createResolverMock()); + + $cacheManager->resolve('cats.jpg', 'thumbnail'); + } + + public function testShouldReturnUrlChangedInPostResolveEvent() + { + $dispatcher = $this->createEventDispatcherMock(); + $dispatcher + ->expects($this->at(1)) + ->method('dispatch') + ->with(ImagineEvents::POST_RESOLVE, $this->isInstanceOf('Liip\ImagineBundle\Events\CacheResolveEvent')) + ->will($this->returnCallback(function ($name, $event) { + $event->setUrl('changed_url'); + })) + ; + + $cacheManager = new CacheManager( + $this->createFilterConfigurationMock(), + $this->createRouterMock(), + new UriSigner('secret'), + $dispatcher + ); + $cacheManager->addResolver('default', $this->createResolverMock()); + + $url = $cacheManager->resolve('cats.jpg', 'thumbnail'); + + $this->assertEquals('changed_url', $url); + } }