Skip to content

Commit

Permalink
Support custom backend routes (see #512).
Browse files Browse the repository at this point in the history
  • Loading branch information
Jim Schmid authored and leofeyer committed Jan 24, 2017
1 parent 0afc1f9 commit 33be460
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 12 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"symfony/yaml": "^3.2",
"sensio/framework-extra-bundle": "^3.0.2",
"psr/log": "^1.0",
"twig/twig": "^1.20",
"twig/twig": "^1.26",
"doctrine/dbal": "^2.5",
"doctrine/doctrine-bundle": "^1.6",
"doctrine/doctrine-cache-bundle": "^1.3",
Expand Down
9 changes: 9 additions & 0 deletions src/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,12 @@ services:
- "_contao_fe_attributes"
calls:
- ["setName", ["contao_frontend"]]

contao.twig.template_extension:
class: Contao\CoreBundle\Twig\Extension\ContaoTemplateExtension
public: false
arguments:
- "@request_stack"
- "@contao.framework"
tags:
- { name: twig.extension }
9 changes: 7 additions & 2 deletions src/Resources/contao/classes/BackendUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Contao\CoreBundle\Exception\RedirectResponseException;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;


/**
Expand Down Expand Up @@ -459,6 +460,9 @@ public function navigation($blnShowAll=false)
/** @var AttributeBagInterface $objSessionBag */
$objSessionBag = \System::getContainer()->get('session')->getBag('contao_backend');

/** @var RouterInterface $router */
$router = \System::getContainer()->get('router');

$arrModules = array();
$session = $objSessionBag->all();

Expand All @@ -477,7 +481,8 @@ public function navigation($blnShowAll=false)
$arrModules[$strGroupName]['class'] = ' node-expanded';
$arrModules[$strGroupName]['title'] = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['collapseNode']);
$arrModules[$strGroupName]['label'] = (($label = is_array($GLOBALS['TL_LANG']['MOD'][$strGroupName]) ? $GLOBALS['TL_LANG']['MOD'][$strGroupName][0] : $GLOBALS['TL_LANG']['MOD'][$strGroupName]) != false) ? $label : $strGroupName;
$arrModules[$strGroupName]['href'] = \Controller::addToUrl('mtg=' . $strGroupName);
$arrModules[$strGroupName]['href'] = $router->generate('contao_backend', array('do'=>\Input::get('do'), 'mtg'=>$strGroupName, 'ref'=>TL_REFERER_ID));
$arrModules[$strGroupName]['ajaxUrl'] = $router->generate('contao_backend');

// Do not show the modules if the group is closed
if (!$blnShowAll && isset($session['backend_modules'][$strGroupName]) && $session['backend_modules'][$strGroupName] < 1)
Expand All @@ -497,7 +502,7 @@ public function navigation($blnShowAll=false)
$arrModules[$strGroupName]['modules'][$strModuleName]['title'] = \StringUtil::specialchars($GLOBALS['TL_LANG']['MOD'][$strModuleName][1]);
$arrModules[$strGroupName]['modules'][$strModuleName]['label'] = (($label = is_array($GLOBALS['TL_LANG']['MOD'][$strModuleName]) ? $GLOBALS['TL_LANG']['MOD'][$strModuleName][0] : $GLOBALS['TL_LANG']['MOD'][$strModuleName]) != false) ? $label : $strModuleName;
$arrModules[$strGroupName]['modules'][$strModuleName]['class'] = 'navigation ' . $strModuleName;
$arrModules[$strGroupName]['modules'][$strModuleName]['href'] = TL_SCRIPT . '?do=' . $strModuleName . '&amp;ref=' . TL_REFERER_ID;
$arrModules[$strGroupName]['modules'][$strModuleName]['href'] = $router->generate('contao_backend', array('do'=>$strModuleName, 'ref'=>TL_REFERER_ID));

// Mark the active module and its group
if (\Input::get('do') == $strModuleName)
Expand Down
64 changes: 64 additions & 0 deletions src/Resources/contao/controllers/BackendCustom.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

/**
* Contao Open Source CMS
*
* Copyright (c) 2005-2016 Leo Feyer
*
* @license LGPL-3.0+
*/

namespace Contao;

/**
* Back end custom controller.
*
* @author Jim Schmid <https://github.com/sheeep>
*/
class BackendCustom extends BackendMain
{

/**
* Constructor.
*/
public function __construct()
{
parent::__construct();

// Initialize the template in the constructor so it is available in the getTemplateObject() method
$this->Template = new \BackendTemplate('be_main');
}


/**
* Return the template object
*
* @return BackendTemplate|object
*/
public function getTemplateObject()
{
return $this->Template;
}


/**
* Run the controller and parse the template
*
* @return Response
*/
public function run()
{
$packages = $this->getContainer()->getParameter('kernel.packages');

$this->Template->version = $packages['contao/core-bundle'];

// Ajax request
if ($_POST && \Environment::get('isAjaxRequest'))
{
$this->objAjax = new \Ajax(\Input::post('action'));
$this->objAjax->executePreActions();
}

return $this->output();
}
}
2 changes: 1 addition & 1 deletion src/Resources/contao/templates/backend/be_main.html5
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<a href="<?= $this->request ?>#skipNavigation" class="invisible"><?= $this->skipNavigation ?></a>
<ul class="tl_level_1">
<?php foreach ($this->modules as $strGroup=>$arrModules): ?>
<li class="tl_level_1_group<?= $arrModules['class'] ?>"><a href="<?= $arrModules['href'] ?>" title="<?= $arrModules['title']; ?>" class="group-<?= $strGroup ?>" onclick="return AjaxRequest.toggleNavigation(this,'<?= $strGroup ?>')"><?= $arrModules['label'] ?></a></li>
<li class="tl_level_1_group<?= $arrModules['class'] ?>"><a href="<?= $arrModules['href'] ?>" title="<?= $arrModules['title']; ?>" class="group-<?= $strGroup ?>" onclick="return AjaxRequest.toggleNavigation(this,'<?= $strGroup ?>', '<?= $arrModules['ajaxUrl']; ?>')"><?= $arrModules['label'] ?></a></li>
<?php if ($arrModules['modules']): ?>
<li class="tl_parent" id="<?= $strGroup ?>">
<ul class="tl_level_2">
Expand Down
12 changes: 7 additions & 5 deletions src/Resources/public/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ var AjaxRequest =
/**
* Toggle the navigation menu
*
* @param {object} el The DOM element
* @param {string} id The ID of the menu item
* @param {object} el The DOM element
* @param {string} id The ID of the menu item
* @param {string} url The Ajax URL
*
* @returns {boolean}
*/
toggleNavigation: function(el, id) {
toggleNavigation: function(el, id, url) {
el.blur();

var item = $(id),
Expand All @@ -39,17 +40,18 @@ var AjaxRequest =
item.setStyle('display', null);
parent.removeClass('node-collapsed').addClass('node-expanded');
$(el).store('tip:title', Contao.lang.collapse);
new Request.Contao().post({'action':'toggleNavigation', 'id':id, 'state':1, 'REQUEST_TOKEN':Contao.request_token});
new Request.Contao({ url: url }).post({'action':'toggleNavigation', 'id':id, 'state':1, 'REQUEST_TOKEN':Contao.request_token});
} else {
item.setStyle('display', 'none');
parent.removeClass('node-expanded').addClass('node-collapsed');
$(el).store('tip:title', Contao.lang.expand);
new Request.Contao().post({'action':'toggleNavigation', 'id':id, 'state':0, 'REQUEST_TOKEN':Contao.request_token});
new Request.Contao({ url: url }).post({'action':'toggleNavigation', 'id':id, 'state':0, 'REQUEST_TOKEN':Contao.request_token});
}
return false;
}

new Request.Contao({
url: url,
evalScripts: true,
onRequest: AjaxRequest.displayBox(Contao.lang.loading + ' …'),
onSuccess: function(txt) {
Expand Down
4 changes: 2 additions & 2 deletions src/Resources/public/core.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Resources/public/mootao.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Request.Contao = new Class(
},

initialize: function(options) {
if (options) {
if (options && !options.url) {
// Try to replace the URL with the form action
try {
this.options.url = options.field.getParent('form').getAttribute('action');
Expand Down
5 changes: 5 additions & 0 deletions src/Resources/views/Backend/be_page.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{ render_contao_backend_template({
main: block('main'),
error: block('headline'),
headline: block('error')
}) | raw }}
83 changes: 83 additions & 0 deletions src/Twig/Extension/ContaoTemplateExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

/**
* Contao Open Source CMS
*
* Copyright (c) 2005-2016 Leo Feyer
*
* @license LGPL-3.0+
*/

namespace Contao\CoreBundle\Twig\Extension;

use Contao\BackendCustom;
use Contao\CoreBundle\Framework\ContaoFrameworkInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* Contao template extension.
*
* @author Jim Schmid <https://github.com/sheeep>
*/
class ContaoTemplateExtension extends \Twig_Extension
{
/**
* @var RequestStack
*/
private $requestStack;

/**
* @var ContaoFrameworkInterface
*/
private $contaoFramework;

/**
* Constructor.
*
* @param RequestStack $requestStack
* @param ContaoFrameworkInterface $contaoFramework
*/
public function __construct(RequestStack $requestStack, ContaoFrameworkInterface $contaoFramework)
{
$this->requestStack = $requestStack;
$this->contaoFramework = $contaoFramework;
}

/**
* {@inheritdoc}
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('render_contao_backend_template', [$this, 'renderContaoBackendTemplate'])
];
}

/**
* Renders a Contao back end template with the given blocks.
*
* @param array $blocks
*
* @return string
*/
public function renderContaoBackendTemplate(array $blocks = [])
{
$scope = $this->requestStack->getCurrentRequest()->attributes->get('_scope');

if ('backend' !== $scope) {
return '';
}

/** @var BackendCustom $controller */
$controller = $this->contaoFramework->createInstance(BackendCustom::class);
$template = $controller->getTemplateObject();

foreach ($blocks as $key => $content) {
$template->{$key} = $content;
}

$response = $controller->run();

return $response->getContent();
}
}
115 changes: 115 additions & 0 deletions tests/Twig/Extension/ContaoTemplateExtensionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

/**
* Contao Open Source CMS
*
* Copyright (c) 2005-2016 Leo Feyer
*
* @license LGPL-3.0+
*/

namespace Contao\CoreBundle\Test\Twig;

use Contao\BackendCustom;
use Contao\CoreBundle\Test\TestCase;
use Contao\CoreBundle\Twig\Extension\ContaoTemplateExtension;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;

/**
* Tests the ContaoTemplateExtension class.
*
* @author Jim Schmid <https://github.com/sheeep>
*/
class ContaoTemplateExtensionTest extends TestCase
{
/**
* Tests the renderContaoBackendTemplate() method.
*/
public function testRenderContaoBackendTemplate()
{
$backendRoute = $this
->getMockBuilder(BackendCustom::class)
->disableOriginalConstructor()
->setMethods(['getTemplateObject', 'run'])
->getMock()
;

$template = new \stdClass();

$backendRoute
->expects($this->once())
->method('getTemplateObject')
->willReturn($template)
;

$backendRoute
->expects($this->once())
->method('run')
->willReturn(new Response())
;

$request = new Request();
$request->attributes->set('_scope', 'backend');

$requestStack = new RequestStack();
$requestStack->push($request);

$contaoFramework = $this->mockContaoFramework(null, null, [], [
BackendCustom::class => $backendRoute
]);

$extension = new ContaoTemplateExtension($requestStack, $contaoFramework);

$extension->renderContaoBackendTemplate([
'a' => 'a',
'b' => 'b',
'c' => 'c'
]);

$this->assertSame('a', $template->a);
$this->assertSame('b', $template->b);
$this->assertSame('c', $template->c);
}

/**
* Tests the getFunctions() method.
*/
public function testGetFunctions()
{
$request = new Request();
$request->attributes->set('_scope', 'backend');

$requestStack = new RequestStack();
$requestStack->push($request);

$contaoFramework = $this->mockContaoFramework(null, null, [], []);

$extension = new ContaoTemplateExtension($requestStack, $contaoFramework);
$functions = $extension->getFunctions();

$renderBaseTemplateFunction = array_filter($functions, function(\Twig_SimpleFunction $function) {
return $function->getName() === 'render_contao_backend_template';
});

$this->assertCount(1, $renderBaseTemplateFunction);
}

/**
* Tests the scope restriction.
*/
public function testScopeRestriction()
{
$request = new Request();
$request->attributes->set('_scope', 'frontend');

$requestStack = new RequestStack();
$requestStack->push($request);

$contaoFramework = $this->mockContaoFramework(null, null, [], []);
$extension = new ContaoTemplateExtension($requestStack, $contaoFramework);

$this->assertEmpty($extension->renderContaoBackendTemplate());
}
}

0 comments on commit 33be460

Please sign in to comment.