From c5a68392301b580c0949f8a65108bb38ccf75b8b Mon Sep 17 00:00:00 2001 From: Johannes Wachter Date: Mon, 23 May 2016 16:20:55 +0200 Subject: [PATCH 1/3] implemented logic for liip-theme bundle --- .styleci.yml | 13 ++ .travis.yml | 25 ++++ CHANGELOG.md | 5 + .../CompilerPass/ImageFormatCompilerPass.php | 104 ++++++++++++++ .../WebspaceStructureProviderCompilerPass.php | 35 +++++ DependencyInjection/SuluThemeExtension.php | 34 +++++ EventListener/SetThemeEventListener.php | 67 +++++++++ README.md | 5 + Resources/config/admin.xml | 15 ++ Resources/config/website.xml | 15 ++ .../WebspaceStructureProvider.php | 83 +++++++++++ SuluThemeBundle.php | 28 ++++ .../SetThemeEventListenerTest.php | 97 +++++++++++++ .../WebspaceStructureProviderTest.php | 130 ++++++++++++++++++ composer.json | 18 ++- phpunit.xml.dist | 19 +++ 16 files changed, 691 insertions(+), 2 deletions(-) create mode 100644 .styleci.yml create mode 100644 .travis.yml create mode 100644 CHANGELOG.md create mode 100644 DependencyInjection/CompilerPass/ImageFormatCompilerPass.php create mode 100644 DependencyInjection/CompilerPass/WebspaceStructureProviderCompilerPass.php create mode 100644 DependencyInjection/SuluThemeExtension.php create mode 100644 EventListener/SetThemeEventListener.php create mode 100644 README.md create mode 100644 Resources/config/admin.xml create mode 100644 Resources/config/website.xml create mode 100644 StructureProvider/WebspaceStructureProvider.php create mode 100644 SuluThemeBundle.php create mode 100644 Tests/Unit/EventListener/SetThemeEventListenerTest.php create mode 100644 Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php create mode 100644 phpunit.xml.dist diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 0000000..b30d120 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,13 @@ +preset: symfony + +enabled: + - concat_with_spaces + - ordered_use + - short_array_syntax + +disabled: + - concat_without_spaces + - phpdoc_align + - phpdoc_indent + - phpdoc_to_comment + - blankline_after_open_tag diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2c814c4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +sudo: false + +language: php + +cache: + directories: + - $HOME/.composer/cache + - downloads + +matrix: + include: + - php: 5.5 + - php: 7.0 + +before_script: + - phpenv config-rm xdebug.ini + - composer self-update + - composer install --prefer-dist --no-interaction + +script: + - vendor/bin/phpunit + +notifications: + slack: + secure: "Gd3/1e0pBKvJv1UhWpBkWijJpmSWlarg6uPBJO0h4z1IpkZjd++jOjhmOQ7n+yMfuapQuJTcVOK0yIWu7orJoGAKFkBlMEIrLk1xMAG9phjjMLUO0FWgcQ3eVW5mTyfMBtClz4OL5wXckw17ohtXHDK8qnI0Hz9Qj8Rqgf2OZhM=" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e53b4d2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG for Sulu +================== + +* dev-develop + * FEATURE #1 Introduced liip/theme-bundle to enable theming diff --git a/DependencyInjection/CompilerPass/ImageFormatCompilerPass.php b/DependencyInjection/CompilerPass/ImageFormatCompilerPass.php new file mode 100644 index 0000000..b4c86f9 --- /dev/null +++ b/DependencyInjection/CompilerPass/ImageFormatCompilerPass.php @@ -0,0 +1,104 @@ +container = $container; + + $formats = $this->loadThemeFormats( + $container->getParameter('sulu_media.format_manager.default_imagine_options') + ); + if ($container->hasParameter('sulu_media.image.formats')) { + $formats = array_merge($container->getParameter('sulu_media.image.formats'), $formats); + } + + $container->setParameter('sulu_media.image.formats', $formats); + } + + /** + * @param array $defaultOptions + * + * @return array + */ + protected function loadThemeFormats($defaultOptions) + { + $activeFormats = []; + $activeTheme = $this->container->get('liip_theme.active_theme'); + $bundles = $this->container->getParameter('kernel.bundles'); + $configPaths = $this->container->getParameter('sulu_media.format_manager.config_paths'); + $defaultConfigPath = 'config/image-formats.xml'; + + foreach ($activeTheme->getThemes() as $theme) { + foreach ($bundles as $bundleName => $bundle) { + $reflector = new \ReflectionClass($bundle); + $configPath = $defaultConfigPath; + if (isset($configPaths[$theme])) { + $configPath = $configPaths[$theme]; + } + $fullPath = sprintf( + '%s/Resources/themes/%s/%s', + dirname($reflector->getFileName()), + $theme, + $configPath + ); + + if (file_exists($fullPath)) { + $this->setFormatsFromFile($fullPath, $activeFormats, $defaultOptions); + } + } + } + + return $activeFormats; + } + + /** + * @param $fullPath + * @param $activeFormats + * @param $defaultOptions + */ + protected function setFormatsFromFile($fullPath, &$activeFormats, $defaultOptions) + { + $folder = dirname($fullPath); + $fileName = basename($fullPath); + + $locator = new FileLocator($folder); + $loader = new XmlFormatLoader($locator); + $loader->setDefaultOptions($defaultOptions); + $themeFormats = $loader->load($fileName); + foreach ($themeFormats as $format) { + if (isset($format['name']) && !array_key_exists($format['name'], $activeFormats)) { + $activeFormats[$format['name']] = $format; + } + } + } +} diff --git a/DependencyInjection/CompilerPass/WebspaceStructureProviderCompilerPass.php b/DependencyInjection/CompilerPass/WebspaceStructureProviderCompilerPass.php new file mode 100644 index 0000000..db35ca0 --- /dev/null +++ b/DependencyInjection/CompilerPass/WebspaceStructureProviderCompilerPass.php @@ -0,0 +1,35 @@ +hasDefinition('sulu.content.webspace_structure_provider')) { + return; + } + + $definition = $container->getDefinition('sulu.content.webspace_structure_provider'); + $definition->setClass(WebspaceStructureProvider::class); + $definition->addArgument(new Reference('sulu_core.webspace.webspace_manager')); + $definition->addArgument(new Reference('liip_theme.active_theme')); + } +} diff --git a/DependencyInjection/SuluThemeExtension.php b/DependencyInjection/SuluThemeExtension.php new file mode 100644 index 0000000..cfa13ae --- /dev/null +++ b/DependencyInjection/SuluThemeExtension.php @@ -0,0 +1,34 @@ +load(sprintf('%s.xml', $container->getParameter('sulu.context'))); + } +} diff --git a/EventListener/SetThemeEventListener.php b/EventListener/SetThemeEventListener.php new file mode 100644 index 0000000..1888761 --- /dev/null +++ b/EventListener/SetThemeEventListener.php @@ -0,0 +1,67 @@ +requestAnalyzer = $requestAnalyzer; + $this->activeTheme = $activeTheme; + } + + /** + * Set the active theme if there is a portal. + */ + public function setActiveThemeOnEngineInitialize() + { + $portal = $this->requestAnalyzer->getPortal(); + + if (null === $portal || null === $portal->getWebspace()->getTheme()) { + return; + } + + $themeKey = $portal->getWebspace()->getTheme()->getKey(); + $this->activeTheme->setName($themeKey); + } + + /** + * Set the active theme for a preview rendering. + * + * @param PreRenderEvent $event + */ + public function setActiveThemeOnPreviewPreRender(PreRenderEvent $event) + { + $this->activeTheme->setName($event->getAttribute('webspace')->getTheme()->getKey()); + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..66d9be8 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# SuluThemeBundle + +[![Build Status](https://travis-ci.org/sulu/SuluThemeBundle.svg?branch=develop)](https://travis-ci.org/sulu/SuluThemeBundle) + +This package enables a basic theming for sulu. It uses liip/theme-bundle to extend the discovery feature of twig. diff --git a/Resources/config/admin.xml b/Resources/config/admin.xml new file mode 100644 index 0000000..5b39adc --- /dev/null +++ b/Resources/config/admin.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/Resources/config/website.xml b/Resources/config/website.xml new file mode 100644 index 0000000..8efa606 --- /dev/null +++ b/Resources/config/website.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/StructureProvider/WebspaceStructureProvider.php b/StructureProvider/WebspaceStructureProvider.php new file mode 100644 index 0000000..fbf58b4 --- /dev/null +++ b/StructureProvider/WebspaceStructureProvider.php @@ -0,0 +1,83 @@ +webspaceManager = $webspaceManager; + $this->activeTheme = $activeTheme; + } + + /** + * {@inheritdoc} + */ + protected function loadStructures($webspaceKey) + { + $before = $this->activeTheme->getName(); + $webspace = $this->webspaceManager->findWebspaceByKey($webspaceKey); + + if (null !== $webspace->getTheme()) { + $this->activeTheme->setName($webspace->getTheme()->getKey()); + } + + $structures = []; + $keys = []; + foreach ($this->structureManager->getStructures() as $page) { + /* @var PageBridge $page */ + $template = sprintf('%s.html.twig', $page->getView()); + if ($this->templateExists($template)) { + $keys[] = $page->getKey(); + $structures[] = $page; + } + } + $this->activeTheme->setName($before); + $this->cache->save($webspaceKey, $keys); + + return $structures; + } +} diff --git a/SuluThemeBundle.php b/SuluThemeBundle.php new file mode 100644 index 0000000..07d582b --- /dev/null +++ b/SuluThemeBundle.php @@ -0,0 +1,28 @@ +addCompilerPass(new WebspaceStructureProviderCompilerPass()); + $container->addCompilerPass(new ImageFormatCompilerPass()); + } +} diff --git a/Tests/Unit/EventListener/SetThemeEventListenerTest.php b/Tests/Unit/EventListener/SetThemeEventListenerTest.php new file mode 100644 index 0000000..f5fc4ba --- /dev/null +++ b/Tests/Unit/EventListener/SetThemeEventListenerTest.php @@ -0,0 +1,97 @@ +requestAnalyzer = $this->getMock('Sulu\Component\Webspace\Analyzer\RequestAnalyzerInterface'); + $this->activeTheme = $this->getMockBuilder('Liip\ThemeBundle\ActiveTheme') + ->disableOriginalConstructor()->getMock(); + + $this->portal = $this->getMock('Sulu\Component\Webspace\Portal'); + $this->webspace = $this->getMock('Sulu\Component\Webspace\Webspace'); + $this->theme = $this->getMock('Sulu\Component\Webspace\Theme'); + $this->event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') + ->disableOriginalConstructor()->getMock(); + + $this->listener = new SetThemeEventListener($this->requestAnalyzer, $this->activeTheme); + } + + public function testEventListener() + { + $this->requestAnalyzer->expects($this->once()) + ->method('getPortal') + ->will($this->returnValue($this->portal)); + $this->portal->expects($this->any()) + ->method('getWebspace') + ->will($this->returnValue($this->webspace)); + $this->webspace->expects($this->any()) + ->method('getTheme') + ->will($this->returnValue($this->theme)); + $this->theme->expects($this->once()) + ->method('getKey') + ->will($this->returnValue('test')); + $this->activeTheme->expects($this->once()) + ->method('setName') + ->with('test'); + + $this->listener->setActiveThemeOnEngineInitialize(); + } + + public function testEventListenerNotMaster() + { + $this->requestAnalyzer->expects($this->once()) + ->method('getPortal') + ->willReturn(null); + $this->webspace->expects($this->never()) + ->method('getTheme'); + + $this->listener->setActiveThemeOnEngineInitialize(); + } + + public function testEventListenerOnPreview() + { + $webspace = new Webspace(); + $theme = new Theme('test'); + $webspace->setTheme($theme); + + $this->activeTheme->expects($this->once())->method('setName')->with('test'); + + $this->listener->setActiveThemeOnPreviewPreRender( + new PreRenderEvent(new RequestAttributes(['webspace' => $webspace])) + ); + } +} diff --git a/Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php b/Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php new file mode 100644 index 0000000..65da2e9 --- /dev/null +++ b/Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php @@ -0,0 +1,130 @@ +generateStructure('t1', 'MyBundle:default:t1'), + $this->generateStructure('t2', 'MyBundle:default:t2'), + $this->generateStructure('t3', 'MyBundle:default:t3'), + ]; + + $theme = $this->prophesize('Sulu\Component\Webspace\Theme'); + $theme->getKey()->willReturn('test'); + + $webspace = $this->prophesize('Sulu\Component\Webspace\Webspace'); + $webspace->getTheme()->willReturn($theme->reveal()); + + $twigLoader = $this->prophesize('\Twig_LoaderInterface'); + $twigLoader->getSource('MyBundle:default:t1.html.twig')->willThrow(new \Twig_Error_Loader('Missing template')); + $twigLoader->getSource('MyBundle:default:t2.html.twig')->shouldBeCalled(); + $twigLoader->getSource('MyBundle:default:t3.html.twig')->willThrow(new \Twig_Error_Loader('Missing template')); + + $twig = $this->prophesize('\Twig_Environment'); + $twig->getLoader()->willReturn($twigLoader->reveal()); + + $structureManager = $this->prophesize('Sulu\Component\Content\Compat\StructureManagerInterface'); + $structureManager->getStructures()->willReturn($structures); + + $webspaceManager = $this->prophesize('Sulu\Component\Webspace\Manager\WebspaceManagerInterface'); + $webspaceManager->findWebspaceByKey('sulu_io')->willReturn($webspace->reveal()); + + $activeTheme = $this->prophesize('Liip\ThemeBundle\ActiveTheme'); + $activeTheme->getName()->willReturn('before'); + $activeTheme->setName('test')->shouldBeCalled(); + $activeTheme->setName('before')->shouldBeCalled(); + + $structureProvider = new WebspaceStructureProvider( + $twig->reveal(), + $structureManager->reveal(), + $cache, + $webspaceManager->reveal(), + $activeTheme->reveal() + ); + + $result = $structureProvider->getStructures('sulu_io'); + + $this->assertCount(1, $result); + $this->assertEquals($structures[1], $result[0]); + + $this->assertTrue($cache->contains('sulu_io')); + $this->assertEquals(['t2'], $cache->fetch('sulu_io')); + } + + public function testGetStructuresCached() + { + $cache = new ArrayCache(); + $cache->save('sulu_io', ['t1', 't3']); + + $structures = [ + $this->generateStructure('t1', 'MyBundle:default:t1'), + $this->generateStructure('t2', 'MyBundle:default:t2'), + $this->generateStructure('t3', 'MyBundle:default:t3'), + ]; + + $twig = $this->prophesize('\Twig_Environment'); + $twig->getLoader()->shouldNotBeCalled(); + + $structureManager = $this->prophesize('Sulu\Component\Content\Compat\StructureManagerInterface'); + $structureManager->getStructures()->shouldNotBeCalled(); + $structureManager->getStructure('t1')->willReturn($structures[0]); + $structureManager->getStructure('t2')->shouldNotBeCalled(); + $structureManager->getStructure('t3')->willReturn($structures[2]); + + $webspaceManager = $this->prophesize('Sulu\Component\Webspace\Manager\WebspaceManagerInterface'); + $webspaceManager->findWebspaceByKey('sulu_io')->shouldNotBeCalled(); + + $activeTheme = $this->prophesize('Liip\ThemeBundle\ActiveTheme'); + $activeTheme->getName()->shouldNotBeCalled(); + $activeTheme->setName('test')->shouldNotBeCalled(); + $activeTheme->setName('before')->shouldNotBeCalled(); + + $structureProvider = new WebspaceStructureProvider( + $twig->reveal(), + $structureManager->reveal(), + $cache, + $webspaceManager->reveal(), + $activeTheme->reveal() + ); + + $result = $structureProvider->getStructures('sulu_io'); + + $this->assertCount(2, $result); + $this->assertEquals($structures[0]->getKey(), $result[0]->getKey()); + $this->assertEquals($structures[2]->getKey(), $result[1]->getKey()); + } + + /** + * @param string $key + * @param string $view + * + * @return StructureInterface + */ + private function generateStructure($key, $view) + { + $mock = $this->prophesize('Sulu\Component\Content\Compat\Structure\PageBridge'); + + $mock->getKey()->willReturn($key); + $mock->getView()->willReturn($view); + + return $mock->reveal(); + } +} diff --git a/composer.json b/composer.json index 844623e..a625423 100644 --- a/composer.json +++ b/composer.json @@ -12,8 +12,23 @@ } ], "require": { - "php": "^5.5 || ^7.0" + "php": "^5.5 || ^7.0", + "liip/theme-bundle": "1.3.*" }, + "require-dev": { + "sulu/sulu": "dev-feature/extract-theme-bundle", + "jackalope/jackalope-jackrabbit": "~1.2.0", + "jackalope/jackalope-doctrine-dbal": "~1.2.0", + "sulu/document-manager": "@dev", + "symfony/symfony": "~2.8", + "phpunit/phpunit": ">=4.8.0" + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/wachterjohannes/sulu" + } + ], "autoload": { "psr-0": { "Sulu\\Bundle\\ThemeBundle": "" @@ -21,4 +36,3 @@ }, "target-dir": "Sulu/Bundle/ThemeBundle" } - diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..8aac5b0 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,19 @@ + + + + + + ./Tests + + + + + + ./ + + ./Tests + ./vendor + + + + From ac9ad02cca13eaaa917118a0eeec9a99831f95ba Mon Sep 17 00:00:00 2001 From: Johannes Wachter Date: Mon, 13 Jun 2016 14:51:30 +0200 Subject: [PATCH 2/3] added eventaware engine --- Resources/config/website.xml | 12 +- Templating/EngineEvents.php | 27 ++++ Templating/EventAwareEngine.php | 98 +++++++++++++ .../Unit/Templating/EventAwareEngineTest.php | 130 ++++++++++++++++++ 4 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 Templating/EngineEvents.php create mode 100644 Templating/EventAwareEngine.php create mode 100644 Tests/Unit/Templating/EventAwareEngineTest.php diff --git a/Resources/config/website.xml b/Resources/config/website.xml index 8efa606..b66760e 100644 --- a/Resources/config/website.xml +++ b/Resources/config/website.xml @@ -2,13 +2,23 @@ + + Sulu\Bundle\WebsiteBundle\Templating\EngineEvents::INITIALIZE + + + + + + + - diff --git a/Templating/EngineEvents.php b/Templating/EngineEvents.php new file mode 100644 index 0000000..00bf3ef --- /dev/null +++ b/Templating/EngineEvents.php @@ -0,0 +1,27 @@ +engine = $engine; + $this->eventDispatcher = $eventDispatcher; + } + + /** + * {@inheritdoc} + */ + public function render($name, array $parameters = []) + { + $this->initialize(); + + return $this->engine->render($name, $parameters); + } + + /** + * {@inheritdoc} + */ + public function renderResponse($view, array $parameters = [], Response $response = null) + { + $this->initialize(); + + return $this->engine->renderResponse($view, $parameters, $response); + } + + /** + * {@inheritdoc} + */ + public function exists($name) + { + $this->initialize(); + + return $this->engine->exists($name); + } + + /** + * {@inheritdoc} + */ + public function supports($name) + { + $this->initialize(); + + return $this->engine->supports($name); + } + + /** + * Throw the event initialize once. + */ + private function initialize() + { + if ($this->initialized) { + return; + } + + $this->eventDispatcher->dispatch(EngineEvents::INITIALIZE); + $this->initialized = true; + } +} diff --git a/Tests/Unit/Templating/EventAwareEngineTest.php b/Tests/Unit/Templating/EventAwareEngineTest.php new file mode 100644 index 0000000..618eff5 --- /dev/null +++ b/Tests/Unit/Templating/EventAwareEngineTest.php @@ -0,0 +1,130 @@ +prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->render('test', ['test' => 1])->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); + + $this->assertTrue($eventableEngine->render('test', ['test' => 1])); + } + + public function testRenderTwice() + { + $engine = $this->prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->render('test', ['test' => 1])->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); + + $this->assertTrue($eventableEngine->render('test', ['test' => 1])); + $this->assertTrue($eventableEngine->render('test', ['test' => 1])); + } + + public function testRenderResponse() + { + $engine = $this->prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->renderResponse('test', ['test' => 1], Argument::type(Response::class)) + ->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1)->shouldBeCalled(); + + $this->assertTrue( + $eventableEngine->renderResponse('test', ['test' => 1], $this->prophesize(Response::class)->reveal()) + ); + } + + public function testRenderResponseTwice() + { + $engine = $this->prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->renderResponse('test', ['test' => 1], Argument::type(Response::class)) + ->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); + + $this->assertTrue( + $eventableEngine->renderResponse('test', ['test' => 1], $this->prophesize(Response::class)->reveal()) + ); + $this->assertTrue( + $eventableEngine->renderResponse('test', ['test' => 1], $this->prophesize(Response::class)->reveal()) + ); + } + + public function testExists() + { + $engine = $this->prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->exists('test')->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); + + $this->assertTrue($eventableEngine->exists('test')); + } + + public function testExistsTwice() + { + $engine = $this->prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->exists('test')->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); + + $this->assertTrue($eventableEngine->exists('test')); + $this->assertTrue($eventableEngine->exists('test')); + } + + public function testSupports() + { + $engine = $this->prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->supports('test')->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); + + $this->assertTrue($eventableEngine->supports('test')); + } + + public function testSupportsTwice() + { + $engine = $this->prophesize(EngineInterface::class); + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); + + $engine->supports('test')->shouldBeCalled()->willReturn(true); + $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); + + $this->assertTrue($eventableEngine->supports('test')); + $this->assertTrue($eventableEngine->supports('test')); + } +} From 4487b92b72b00a6c72b93511eeebf29ba5f14762 Mon Sep 17 00:00:00 2001 From: Johannes Wachter Date: Tue, 14 Jun 2016 10:48:16 +0200 Subject: [PATCH 3/3] fixed comments --- EventListener/SetThemeEventListener.php | 28 ++-- Resources/config/admin.xml | 1 - Resources/config/website.xml | 13 +- .../WebspaceStructureProvider.php | 2 +- Templating/EngineEvents.php | 27 ---- Templating/EventAwareEngine.php | 98 ------------- .../SetThemeEventListenerTest.php | 109 +++++++++------ .../WebspaceStructureProviderTest.php | 5 +- .../Unit/Templating/EventAwareEngineTest.php | 130 ------------------ composer.json | 8 +- 10 files changed, 84 insertions(+), 337 deletions(-) delete mode 100644 Templating/EngineEvents.php delete mode 100644 Templating/EventAwareEngine.php delete mode 100644 Tests/Unit/Templating/EventAwareEngineTest.php diff --git a/EventListener/SetThemeEventListener.php b/EventListener/SetThemeEventListener.php index 1888761..5139373 100644 --- a/EventListener/SetThemeEventListener.php +++ b/EventListener/SetThemeEventListener.php @@ -13,46 +13,42 @@ use Liip\ThemeBundle\ActiveTheme; use Sulu\Bundle\PreviewBundle\Preview\Events\PreRenderEvent; -use Sulu\Component\Webspace\Analyzer\RequestAnalyzerInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; /** * Listener which applies the configured theme. */ class SetThemeEventListener { - /** - * @var RequestAnalyzerInterface - */ - private $requestAnalyzer; - /** * @var ActiveTheme */ private $activeTheme; /** - * @param RequestAnalyzerInterface $requestAnalyzer * @param ActiveTheme $activeTheme */ - public function __construct(RequestAnalyzerInterface $requestAnalyzer, ActiveTheme $activeTheme) + public function __construct(ActiveTheme $activeTheme) { - $this->requestAnalyzer = $requestAnalyzer; $this->activeTheme = $activeTheme; } /** * Set the active theme if there is a portal. + * + * @param GetResponseEvent $event */ - public function setActiveThemeOnEngineInitialize() + public function setActiveThemeOnRequest(GetResponseEvent $event) { - $portal = $this->requestAnalyzer->getPortal(); - - if (null === $portal || null === $portal->getWebspace()->getTheme()) { + if (!$event->isMasterRequest() + || null === ($attributes = $event->getRequest()->get('_sulu')) + || null === ($webspace = $attributes->getAttribute('webspace')) + || null === ($theme = $webspace->getTheme()) + ) { return; } - $themeKey = $portal->getWebspace()->getTheme()->getKey(); - $this->activeTheme->setName($themeKey); + $this->activeTheme->setName($theme); } /** @@ -62,6 +58,6 @@ public function setActiveThemeOnEngineInitialize() */ public function setActiveThemeOnPreviewPreRender(PreRenderEvent $event) { - $this->activeTheme->setName($event->getAttribute('webspace')->getTheme()->getKey()); + $this->activeTheme->setName($event->getAttribute('webspace')->getTheme()); } } diff --git a/Resources/config/admin.xml b/Resources/config/admin.xml index 5b39adc..07e7fef 100644 --- a/Resources/config/admin.xml +++ b/Resources/config/admin.xml @@ -5,7 +5,6 @@ - - - Sulu\Bundle\WebsiteBundle\Templating\EngineEvents::INITIALIZE - - - - - - - - + diff --git a/StructureProvider/WebspaceStructureProvider.php b/StructureProvider/WebspaceStructureProvider.php index fbf58b4..c2ec427 100644 --- a/StructureProvider/WebspaceStructureProvider.php +++ b/StructureProvider/WebspaceStructureProvider.php @@ -62,7 +62,7 @@ protected function loadStructures($webspaceKey) $webspace = $this->webspaceManager->findWebspaceByKey($webspaceKey); if (null !== $webspace->getTheme()) { - $this->activeTheme->setName($webspace->getTheme()->getKey()); + $this->activeTheme->setName($webspace->getTheme()); } $structures = []; diff --git a/Templating/EngineEvents.php b/Templating/EngineEvents.php deleted file mode 100644 index 00bf3ef..0000000 --- a/Templating/EngineEvents.php +++ /dev/null @@ -1,27 +0,0 @@ -engine = $engine; - $this->eventDispatcher = $eventDispatcher; - } - - /** - * {@inheritdoc} - */ - public function render($name, array $parameters = []) - { - $this->initialize(); - - return $this->engine->render($name, $parameters); - } - - /** - * {@inheritdoc} - */ - public function renderResponse($view, array $parameters = [], Response $response = null) - { - $this->initialize(); - - return $this->engine->renderResponse($view, $parameters, $response); - } - - /** - * {@inheritdoc} - */ - public function exists($name) - { - $this->initialize(); - - return $this->engine->exists($name); - } - - /** - * {@inheritdoc} - */ - public function supports($name) - { - $this->initialize(); - - return $this->engine->supports($name); - } - - /** - * Throw the event initialize once. - */ - private function initialize() - { - if ($this->initialized) { - return; - } - - $this->eventDispatcher->dispatch(EngineEvents::INITIALIZE); - $this->initialized = true; - } -} diff --git a/Tests/Unit/EventListener/SetThemeEventListenerTest.php b/Tests/Unit/EventListener/SetThemeEventListenerTest.php index f5fc4ba..062686c 100644 --- a/Tests/Unit/EventListener/SetThemeEventListenerTest.php +++ b/Tests/Unit/EventListener/SetThemeEventListenerTest.php @@ -14,21 +14,27 @@ use Sulu\Bundle\PreviewBundle\Preview\Events\PreRenderEvent; use Sulu\Bundle\ThemeBundle\EventListener\SetThemeEventListener; use Sulu\Component\Webspace\Analyzer\Attributes\RequestAttributes; -use Sulu\Component\Webspace\Analyzer\RequestAnalyzerInterface; use Sulu\Component\Webspace\Theme; use Sulu\Component\Webspace\Webspace; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; class SetThemeEventListenerTest extends \PHPUnit_Framework_TestCase { /** * @var ActiveTheme */ - protected $activeTheme; + private $activeTheme; /** - * @var RequestAnalyzerInterface + * @var string */ - protected $requestAnalyzer; + private $theme = 'test'; + + /** + * @var Webspace + */ + private $webspace; /** * @var SetThemeEventListener @@ -37,61 +43,80 @@ class SetThemeEventListenerTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->requestAnalyzer = $this->getMock('Sulu\Component\Webspace\Analyzer\RequestAnalyzerInterface'); - $this->activeTheme = $this->getMockBuilder('Liip\ThemeBundle\ActiveTheme') - ->disableOriginalConstructor()->getMock(); + $this->activeTheme = $this->prophesize(ActiveTheme::class); + $this->webspace = $this->prophesize(Webspace::class); + $this->webspace->getTheme()->willReturn($this->theme); - $this->portal = $this->getMock('Sulu\Component\Webspace\Portal'); - $this->webspace = $this->getMock('Sulu\Component\Webspace\Webspace'); - $this->theme = $this->getMock('Sulu\Component\Webspace\Theme'); - $this->event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') - ->disableOriginalConstructor()->getMock(); - - $this->listener = new SetThemeEventListener($this->requestAnalyzer, $this->activeTheme); + $this->listener = new SetThemeEventListener($this->activeTheme->reveal()); } public function testEventListener() { - $this->requestAnalyzer->expects($this->once()) - ->method('getPortal') - ->will($this->returnValue($this->portal)); - $this->portal->expects($this->any()) - ->method('getWebspace') - ->will($this->returnValue($this->webspace)); - $this->webspace->expects($this->any()) - ->method('getTheme') - ->will($this->returnValue($this->theme)); - $this->theme->expects($this->once()) - ->method('getKey') - ->will($this->returnValue('test')); - $this->activeTheme->expects($this->once()) - ->method('setName') - ->with('test'); - - $this->listener->setActiveThemeOnEngineInitialize(); + $request = $this->prophesize(Request::class); + $attributes = $this->prophesize(RequestAttributes::class); + $attributes->getAttribute('webspace')->willReturn($this->webspace->reveal()); + $request->get('_sulu')->willReturn($attributes->reveal()); + + $event = $this->prophesize(GetResponseEvent::class); + $event->getRequest()->willReturn($request->reveal()); + $event->isMasterRequest()->willReturn(true); + + $this->activeTheme->setName($this->theme)->shouldBeCalled(); + + $this->listener->setActiveThemeOnRequest($event->reveal()); } public function testEventListenerNotMaster() { - $this->requestAnalyzer->expects($this->once()) - ->method('getPortal') - ->willReturn(null); - $this->webspace->expects($this->never()) - ->method('getTheme'); + $request = $this->prophesize(Request::class); + $event = $this->prophesize(GetResponseEvent::class); + $event->isMasterRequest()->willReturn(false); + $event->getRequest()->willReturn($request->reveal()); + + $this->activeTheme->setName($this->theme)->shouldNotBeCalled(); + + $this->listener->setActiveThemeOnRequest($event->reveal()); + } + + public function testEventListenerNoWebspace() + { + $request = $this->prophesize(Request::class); + $attributes = $this->prophesize(RequestAttributes::class); + $attributes->getAttribute('webspace')->willReturn(null); + $request->get('_sulu')->willReturn($attributes->reveal()); + + $event = $this->prophesize(GetResponseEvent::class); + $event->getRequest()->willReturn($request->reveal()); + $event->isMasterRequest()->willReturn(true); + + $this->activeTheme->setName($this->theme)->shouldNotBeCalled(); + + $this->listener->setActiveThemeOnRequest($event->reveal()); + } + + public function testEventListenerNoAttributes() + { + $request = $this->prophesize(Request::class); + $request->get('_sulu')->willReturn(null); + + $event = $this->prophesize(GetResponseEvent::class); + $event->getRequest()->willReturn($request->reveal()); + $event->isMasterRequest()->willReturn(true); + + $this->activeTheme->setName($this->theme)->shouldNotBeCalled(); - $this->listener->setActiveThemeOnEngineInitialize(); + $this->listener->setActiveThemeOnRequest($event->reveal()); } public function testEventListenerOnPreview() { - $webspace = new Webspace(); - $theme = new Theme('test'); - $webspace->setTheme($theme); + $attributes = $this->prophesize(RequestAttributes::class); + $attributes->getAttribute('webspace', null)->willReturn($this->webspace->reveal()); - $this->activeTheme->expects($this->once())->method('setName')->with('test'); + $this->activeTheme->setName($this->theme)->shouldBeCalled(); $this->listener->setActiveThemeOnPreviewPreRender( - new PreRenderEvent(new RequestAttributes(['webspace' => $webspace])) + new PreRenderEvent($attributes->reveal()) ); } } diff --git a/Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php b/Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php index 65da2e9..71524d3 100644 --- a/Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php +++ b/Tests/Unit/StructureProvider/WebspaceStructureProviderTest.php @@ -27,11 +27,10 @@ public function testGetStructures() $this->generateStructure('t3', 'MyBundle:default:t3'), ]; - $theme = $this->prophesize('Sulu\Component\Webspace\Theme'); - $theme->getKey()->willReturn('test'); + $theme = 'test'; $webspace = $this->prophesize('Sulu\Component\Webspace\Webspace'); - $webspace->getTheme()->willReturn($theme->reveal()); + $webspace->getTheme()->willReturn($theme); $twigLoader = $this->prophesize('\Twig_LoaderInterface'); $twigLoader->getSource('MyBundle:default:t1.html.twig')->willThrow(new \Twig_Error_Loader('Missing template')); diff --git a/Tests/Unit/Templating/EventAwareEngineTest.php b/Tests/Unit/Templating/EventAwareEngineTest.php deleted file mode 100644 index 618eff5..0000000 --- a/Tests/Unit/Templating/EventAwareEngineTest.php +++ /dev/null @@ -1,130 +0,0 @@ -prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->render('test', ['test' => 1])->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); - - $this->assertTrue($eventableEngine->render('test', ['test' => 1])); - } - - public function testRenderTwice() - { - $engine = $this->prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->render('test', ['test' => 1])->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); - - $this->assertTrue($eventableEngine->render('test', ['test' => 1])); - $this->assertTrue($eventableEngine->render('test', ['test' => 1])); - } - - public function testRenderResponse() - { - $engine = $this->prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->renderResponse('test', ['test' => 1], Argument::type(Response::class)) - ->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1)->shouldBeCalled(); - - $this->assertTrue( - $eventableEngine->renderResponse('test', ['test' => 1], $this->prophesize(Response::class)->reveal()) - ); - } - - public function testRenderResponseTwice() - { - $engine = $this->prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->renderResponse('test', ['test' => 1], Argument::type(Response::class)) - ->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); - - $this->assertTrue( - $eventableEngine->renderResponse('test', ['test' => 1], $this->prophesize(Response::class)->reveal()) - ); - $this->assertTrue( - $eventableEngine->renderResponse('test', ['test' => 1], $this->prophesize(Response::class)->reveal()) - ); - } - - public function testExists() - { - $engine = $this->prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->exists('test')->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); - - $this->assertTrue($eventableEngine->exists('test')); - } - - public function testExistsTwice() - { - $engine = $this->prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->exists('test')->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); - - $this->assertTrue($eventableEngine->exists('test')); - $this->assertTrue($eventableEngine->exists('test')); - } - - public function testSupports() - { - $engine = $this->prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->supports('test')->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); - - $this->assertTrue($eventableEngine->supports('test')); - } - - public function testSupportsTwice() - { - $engine = $this->prophesize(EngineInterface::class); - $eventDispatcher = $this->prophesize(EventDispatcherInterface::class); - $eventableEngine = new EventAwareEngine($engine->reveal(), $eventDispatcher->reveal()); - - $engine->supports('test')->shouldBeCalled()->willReturn(true); - $eventDispatcher->dispatch(EngineEvents::INITIALIZE, null)->shouldBeCalledTimes(1); - - $this->assertTrue($eventableEngine->supports('test')); - $this->assertTrue($eventableEngine->supports('test')); - } -} diff --git a/composer.json b/composer.json index a625423..b70b676 100644 --- a/composer.json +++ b/composer.json @@ -16,19 +16,13 @@ "liip/theme-bundle": "1.3.*" }, "require-dev": { - "sulu/sulu": "dev-feature/extract-theme-bundle", + "sulu/sulu": "dev-develop", "jackalope/jackalope-jackrabbit": "~1.2.0", "jackalope/jackalope-doctrine-dbal": "~1.2.0", "sulu/document-manager": "@dev", "symfony/symfony": "~2.8", "phpunit/phpunit": ">=4.8.0" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/wachterjohannes/sulu" - } - ], "autoload": { "psr-0": { "Sulu\\Bundle\\ThemeBundle": ""