From 93a378f71f9e13c8fcc27a5e12defc65d84c6e4f Mon Sep 17 00:00:00 2001 From: Tim Eulitz Date: Tue, 8 May 2018 18:32:36 +0200 Subject: [PATCH] Load custom templates for content pages In order to add custom design / JavaScript into content pages, the PageDisplayHandler class was created which uses the page ID to find existing twig templates for pages and uses them. If no template is found, a base template is used. T182698 --- app/RouteHandlers/PageDisplayHandler.php | 70 ++++++++++++ app/routes.php | 26 +---- .../10h16/templates/Display_Page_Layout.twig | 56 ---------- .../templates/page_layouts/base.html.twig | 56 ++++++++++ skins/cat17/src/scripts/supporters.js | 0 .../base.html.twig} | 0 .../page_layouts/supporters.html.twig | 6 + .../base.html.twig} | 0 .../templates/page_layouts/test.html.twig | 5 + src/Factories/FunFunFactory.php | 10 +- .../Routes/DisplayPageRouteTest.php | 103 ++++++++++-------- 11 files changed, 206 insertions(+), 126 deletions(-) create mode 100644 app/RouteHandlers/PageDisplayHandler.php delete mode 100644 skins/10h16/templates/Display_Page_Layout.twig create mode 100644 skins/10h16/templates/page_layouts/base.html.twig create mode 100644 skins/cat17/src/scripts/supporters.js rename skins/cat17/templates/{Display_Page_Layout.twig => page_layouts/base.html.twig} (100%) create mode 100644 skins/cat17/templates/page_layouts/supporters.html.twig rename skins/test/templates/{Display_Page_Layout.twig => page_layouts/base.html.twig} (100%) create mode 100644 skins/test/templates/page_layouts/test.html.twig diff --git a/app/RouteHandlers/PageDisplayHandler.php b/app/RouteHandlers/PageDisplayHandler.php new file mode 100644 index 000000000..b017e1437 --- /dev/null +++ b/app/RouteHandlers/PageDisplayHandler.php @@ -0,0 +1,70 @@ + + * @author Gabriel Birke < gabriel.birke@wikimedia.de > + */ +class PageDisplayHandler { + + private $ffFactory; + private $app; + + public function __construct( FunFunFactory $ffFactory, Application $app ) { + $this->ffFactory = $ffFactory; + $this->app = $app; + } + + function handle( $pageName ) { + $pageSelector = $this->ffFactory->getContentPagePageSelector(); + + try { + $pageId = $pageSelector->getPageId( $pageName ); + } + catch ( PageNotFoundException $exception ) { + throw new NotFoundHttpException( "Page page name '$pageName' not found." ); + } + + try { + return $this->getPageTemplate( $pageId )->render( [ 'page_id' => $pageId ] ); + } + catch ( \Twig_Error_Runtime $exception ) { + if ( $exception->getPrevious() instanceof ContentNotFoundException ) { + throw new NotFoundHttpException( "Content for page id '$pageId' not found." ); + } + + throw $exception; + } + } + + /** + * Checks if file matching page ID exists in page_layouts directory and loads template if it exists + * Otherwise, falls back to base.twig template + * + * @param string $pageId + * @param array $context Additional variables for template + * + * @return TwigTemplate + */ + public function getPageTemplate( string $pageId, array $context = [] ): TwigTemplate { + $template = 'page_layouts' . DIRECTORY_SEPARATOR . 'base.html.twig'; + $pageTemplate = 'page_layouts' . DIRECTORY_SEPARATOR . $pageId . '.html.twig'; + + if ( file_exists( $this->ffFactory->getAbsoluteSkinDirectory() . DIRECTORY_SEPARATOR . $pageTemplate ) ) { + $template = $pageTemplate; + } + + return $this->ffFactory->getLayoutTemplate($template, $context); + } +} \ No newline at end of file diff --git a/app/routes.php b/app/routes.php index 74737fe5d..f2b22a43f 100644 --- a/app/routes.php +++ b/app/routes.php @@ -12,7 +12,6 @@ use Silex\Application; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Validation; @@ -41,8 +40,6 @@ use WMDE\Fundraising\MembershipContext\UseCases\ShowApplicationConfirmation\ShowAppConfirmationRequest; use WMDE\Fundraising\PaymentContext\Domain\Model\Iban; use WMDE\Fundraising\PaymentContext\UseCases\GenerateIban\GenerateIbanRequest; -use WMDE\Fundraising\Frontend\Presentation\ContentPage\ContentNotFoundException; -use WMDE\Fundraising\Frontend\Presentation\ContentPage\PageNotFoundException; use WMDE\Fundraising\Frontend\Presentation\DonationMembershipApplicationAdapter; use WMDE\Fundraising\Frontend\UseCases\GetInTouch\GetInTouchRequest; use WMDE\Fundraising\Frontend\Validation\ConstraintViolationListMapper; @@ -184,26 +181,9 @@ function( Request $request ) use ( $app, $ffFactory ) { $app->get( 'page/{pageName}', - function( $pageName ) use ( $ffFactory ) { - $pageSelector = $ffFactory->getContentPagePageSelector(); - - try { - $pageId = $pageSelector->getPageId( $pageName ); - } catch ( PageNotFoundException $exception ) { - throw new NotFoundHttpException( "Page page name '$pageName' not found." ); - } - - try { - return $ffFactory->getLayoutTemplate( 'Display_Page_Layout.twig' )->render( [ - 'page_id' => $pageId - ] ); - } catch ( Twig_Error_Runtime $exception ) { - if ($exception->getPrevious() instanceof ContentNotFoundException) { - throw new NotFoundHttpException( "Content for page id '$pageId' not found." ); - } - - throw $exception; - } + function( Application $app, $pageName ) use ( $ffFactory ) { + return ( new \WMDE\Fundraising\Frontend\App\RouteHandlers\PageDisplayHandler( $ffFactory, $app ) ) + ->handle( $pageName ); } ) ->bind( 'page' ); diff --git a/skins/10h16/templates/Display_Page_Layout.twig b/skins/10h16/templates/Display_Page_Layout.twig deleted file mode 100644 index e8a38b9ae..000000000 --- a/skins/10h16/templates/Display_Page_Layout.twig +++ /dev/null @@ -1,56 +0,0 @@ -{% extends 'Base_Layout.html.twig' %} - -{% block page_identifier %}page-{$ page_id $}{% endblock %} - -{% block main %} -
-
-
-   -
- -
-
-
- {$ page_id|trans({}, 'pageTitles') $} -
- - -
-
- -
- - - {% if page_id == 'supporters' %} -
-

- Spenden auch Sie! -

- -

- Unterstützen Sie die Wikipedia und Freies Wissen mit Ihrer Spende. -

-
- {% else %} -
-

- Spenden -

-

- Zurück zur Spendenseite -

-
- {% endif %} -
-
-
-{% endblock %} diff --git a/skins/10h16/templates/page_layouts/base.html.twig b/skins/10h16/templates/page_layouts/base.html.twig new file mode 100644 index 000000000..c33ceee91 --- /dev/null +++ b/skins/10h16/templates/page_layouts/base.html.twig @@ -0,0 +1,56 @@ +{% extends 'Base_Layout.html.twig' %} + +{% block page_identifier %}page-{$ page_id $}{% endblock %} + +{% block main %} +
+
+
+   +
+ +
+
+
+ {$ page_id|trans({}, 'pageTitles') $} +
+ + +
+
+ +
+ + + {% if page_id == 'supporters' %} +
+

+ Spenden auch Sie! +

+ +

+ Unterstützen Sie die Wikipedia und Freies Wissen mit Ihrer Spende. +

+
+ {% else %} +
+

+ Spenden +

+

+ Zurück zur Spendenseite +

+
+ {% endif %} +
+
+
+{% endblock %} diff --git a/skins/cat17/src/scripts/supporters.js b/skins/cat17/src/scripts/supporters.js new file mode 100644 index 000000000..e69de29bb diff --git a/skins/cat17/templates/Display_Page_Layout.twig b/skins/cat17/templates/page_layouts/base.html.twig similarity index 100% rename from skins/cat17/templates/Display_Page_Layout.twig rename to skins/cat17/templates/page_layouts/base.html.twig diff --git a/skins/cat17/templates/page_layouts/supporters.html.twig b/skins/cat17/templates/page_layouts/supporters.html.twig new file mode 100644 index 000000000..a02a011fe --- /dev/null +++ b/skins/cat17/templates/page_layouts/supporters.html.twig @@ -0,0 +1,6 @@ +{% extends 'page_layouts/base.html.twig' %} +{% set page_works_without_js = false %} + +{% block scripts %} + +{% endblock %} \ No newline at end of file diff --git a/skins/test/templates/Display_Page_Layout.twig b/skins/test/templates/page_layouts/base.html.twig similarity index 100% rename from skins/test/templates/Display_Page_Layout.twig rename to skins/test/templates/page_layouts/base.html.twig diff --git a/skins/test/templates/page_layouts/test.html.twig b/skins/test/templates/page_layouts/test.html.twig new file mode 100644 index 000000000..c08b7a40a --- /dev/null +++ b/skins/test/templates/page_layouts/test.html.twig @@ -0,0 +1,5 @@ +{% extends 'page_layouts/base.html.twig' %} + +{% block main %} +
Test
+{% endblock %} diff --git a/src/Factories/FunFunFactory.php b/src/Factories/FunFunFactory.php index 67baf1b59..6fe1f4d23 100644 --- a/src/Factories/FunFunFactory.php +++ b/src/Factories/FunFunFactory.php @@ -330,7 +330,7 @@ public function register( Container $container ): void { $container['twig'] = function() { $config = $this->config['twig']; - $config['loaders']['filesystem']['template-dir'] = 'skins/' . $this->getSkinSettings()->getSkin() . '/templates'; + $config['loaders']['filesystem']['template-dir'] = $this->getSkinDirectory(); $twigFactory = $this->newTwigFactory( $config ); $configurator = $twigFactory->newTwigEnvironmentConfigurator(); @@ -1602,4 +1602,12 @@ public function newDonationAmountConstraint(): ValidatorConstraint { public function newIsCustomDonationAmountValidator(): IsCustomAmountValidator { return new IsCustomAmountValidator( $this->getPresetAmountsSettings( 'donations' ) ); } + + public function getSkinDirectory(): string { + return 'skins/' . $this->getSkinSettings()->getSkin() . '/templates'; + } + + public function getAbsoluteSkinDirectory(): string { + return $this->getAbsolutePath( $this->getSkinDirectory() ); + } } diff --git a/tests/EdgeToEdge/Routes/DisplayPageRouteTest.php b/tests/EdgeToEdge/Routes/DisplayPageRouteTest.php index d6ff7f217..d1e18a5bc 100644 --- a/tests/EdgeToEdge/Routes/DisplayPageRouteTest.php +++ b/tests/EdgeToEdge/Routes/DisplayPageRouteTest.php @@ -18,36 +18,32 @@ */ class DisplayPageRouteTest extends WebRouteTestCase { - public function testWhenPageDoesNotExist_missingResponseIsReturnedAndHasHeaderAndFooter(): void { - $client = $this->createClient( + public function testWhenPageHasCustomTemplate_customTemplateIsRendered(): void { + $this->createEnvironment( [], - function ( FunFunFactory $factory ): void { - $pageSelector = $this->createMock( PageSelector::class ); - $pageSelector - ->method( 'getPageId' ) - ->with( 'kittens' ) - ->willThrowException( new PageNotFoundException() ); - $factory->setContentPagePageSelector( $pageSelector ); - } - ); - $client->request( 'GET', '/page/kittens' ); + function ( Client $client, FunFunFactory $factory ): void { + $factory->setContentPagePageSelector( $this->getMockPageSelector( 'test' ) ); + $factory->setContentProvider( $this->getVfsContentProvider( [ 'test.twig' => '' ] ) ); - $content = $client->getResponse()->getContent(); + $crawler = $client->request( 'GET', '/page/test' ); - $this->assertContains( - 'page_not_found', - $content + $this->assertCount( 1, $crawler->filter( '.test-block' ) ); + } ); + } - $this->assertContains( - 'page header', - $content + public function testWhenPageDoesNotExist_missingResponseIsReturnedAndHasHeaderAndFooter(): void { + $client = $this->createClient( [], + function ( FunFunFactory $factory ): void { + $factory->setContentPagePageSelector( $this->getNotFoundPageSelector( 'kittens' ) ); + } ); + $client->request( 'GET', '/page/kittens' ); + $content = $client->getResponse()->getContent(); - $this->assertContains( - 'page footer', - $content - ); + $this->assertContains( 'page_not_found', $content ); + $this->assertContains( 'page header', $content ); + $this->assertContains( 'page footer', $content ); } public function testWhenPageDoesNotExist_noUnescapedPageNameIsShown(): void { @@ -74,30 +70,14 @@ public function testWhenRequestedContentPageExists_itGetsEmbeddedAndHasHeaderAnd $this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void { + $factory->setContentPagePageSelector( $this->getMockPageSelector( 'unicorns' ) ); + $factory->setContentProvider( + $this->getVfsContentProvider( + [ 'unicorns.twig' => '

Rosa plüsch einhorns tanzen auf Regenbogen

' ] + ) + ); - $pageSelector = $this->createMock( PageSelector::class ); - $pageSelector - ->method( 'getPageId' ) - ->willReturnArgument( 0 ) - ->with( 'einhorns' ) - ->willReturn( 'unicorns' ); - $factory->setContentPagePageSelector( $pageSelector ); - - $content = vfsStream::setup( 'content', null, [ - 'web' => [ - 'pages' => [ - 'unicorns.twig' => '

Rosa plüsch einhorns tanzen auf Regenbogen

', - ] - ], - 'mail' => [], - 'shared' => [], - ] ); - $provider = new ContentProvider( [ - 'content_path' => $content->url() - ] ); - $factory->setContentProvider( $provider ); - - $crawler = $client->request( 'GET', '/page/einhorns' ); + $crawler = $client->request( 'GET', '/page/unicorns' ); $this->assertCount( 1, $crawler->filter( 'body.page-unicorns' ) ); $this->assertCount( 1, $crawler->filter( 'header:contains("page header")' ) ); @@ -115,4 +95,35 @@ public function testWhenPageNameContainsSlash_404isReturned(): void { $this->assert404( $client->getResponse() ); } + + private function getMockPageSelector( string $pageId ): PageSelector { + $pageSelector = $this->createMock( PageSelector::class ); + $pageSelector + ->method( 'getPageId' ) + ->willReturnArgument( 0 ) + ->with( $pageId ) + ->willReturn( $pageId ); + return $pageSelector; + } + + private function getNotFoundPageSelector( string $pageId ): PageSelector { + $pageSelector = $this->createMock( PageSelector::class ); + $pageSelector + ->method( 'getPageId' ) + ->with( $pageId ) + ->willThrowException( new PageNotFoundException() ); + return $pageSelector; + } + + private function getVfsContentProvider( array $pages ): ContentProvider { + $content = vfsStream::setup( 'content', null, + [ + 'web' => [ 'pages' => $pages ], + 'mail' => [], + 'shared' => [], + ] + ); + $provider = new ContentProvider( [ 'content_path' => $content->url() ] ); + return $provider; + } }