Skip to content

Commit

Permalink
provide better template handling by using filter_ prefixed templates
Browse files Browse the repository at this point in the history
  • Loading branch information
Rico Kaltofen committed Apr 25, 2018
1 parent 8ea28c4 commit 9be7ed5
Show file tree
Hide file tree
Showing 16 changed files with 242 additions and 64 deletions.
64 changes: 64 additions & 0 deletions README.md
Expand Up @@ -7,6 +7,70 @@

This bundle offers a generic filter module to use with arbitrary contao entities containing standard filter with initial filters and filter form types including [symfony form type representations](https://symfony.com/doc/current/reference/forms/types).


## Templates (filter)

There are two ways to define your templates.

#### 1. By Prefix

The first one is to simply deploy twig templates inside any `templates` or bundles `views` directory with the following prefixes:

** filter template prefixes**

- `filter_`

**More prefixes can be defined, see 2nd way.**

#### 2. By config.yml

The second on is to extend the `config.yml` and define a strict template:

**Plugin.php**
```
<?php
class Plugin implements BundlePluginInterface, ExtensionPluginInterface
{
/**
* {@inheritdoc}
*/
public function getBundles(ParserInterface $parser)
{
}
/**
* {@inheritdoc}
*/
public function getExtensionConfig($extensionName, array $extensionConfigs, ContainerBuilder $container)
{
return ContainerUtil::mergeConfigFile(
'huh_filter',
$extensionName,
$extensionConfigs,
__DIR__ .'/../Resources/config/config.yml'
);
}
}
```

**config.yml**
```
huh:
filter:
templates:
- {name: form_div_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_div_layout.html.twig'}
- {name: form_table_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_table_layout.html.twig'}
- {name: bootstrap_3_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_3_layout.html.twig'}
- {name: bootstrap_3_horizontal_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_3_horizontal_layout.html.twig'}
- {name: bootstrap_4_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_layout.html.twig'}
- {name: bootstrap_4_horizontal_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_horizontal_layout.html.twig'}
- {name: foundation_5_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_foundation_5_layout.html.twig'}
template_prefixes:
- filter_
```

## Bootstrap 4 form snippets

The following bootstrap 4 form theme snippets can be used to generate uncommon, but existing bootstrap 4 form widgets within your custom `filter_form_bootstrap4*.html.twig` template.
Expand Down
21 changes: 14 additions & 7 deletions src/Choice/TemplateChoice.php
Expand Up @@ -8,6 +8,7 @@

namespace HeimrichHannot\FilterBundle\Choice;

use Contao\System;
use HeimrichHannot\UtilsBundle\Choice\AbstractChoice;

class TemplateChoice extends AbstractChoice
Expand All @@ -18,19 +19,25 @@ class TemplateChoice extends AbstractChoice
protected function collect()
{
$choices = [];
$config = System::getContainer()->getParameter('huh.filter');

$config = \System::getContainer()->getParameter('huh.filter');

if (!isset($config['filter']['templates'])) {
return $choices;
if (isset($config['filter']['template_prefixes'])) {
$choices = System::getContainer()->get('huh.utils.choice.twig_template')->setContext($config['filter']['template_prefixes'])->getCachedChoices();
}

$templates = $config['filter']['templates'];
if (isset($config['filter']['templates'])) {
foreach ($config['filter']['templates'] as $template) {
// remove duplicates returned by `huh.utils.choice.twig_template`
if (false !== ($idx = array_search($template['template'], $choices))) {
unset($choices[$idx]);
}

foreach ($templates as $config) {
$choices[$config['name']] = $config['template'];
$choices[$template['name']] = $template['template'] . ' (Yaml)';
}
}

asort($choices);

return $choices;
}
}
22 changes: 22 additions & 0 deletions src/Config/FilterConfig.php
Expand Up @@ -450,4 +450,26 @@ protected function mapFormsToData()

$this->builder->setData($data);
}

/**
* {@inheritdoc}
*/
public function getFilterTemplateByName(string $name)
{
$config = System::getContainer()->getParameter('huh.filter');

if (!isset($config['filter']['templates'])) {
return System::getContainer()->get('huh.utils.template')->getTemplate($name);
}

$templates = $config['filter']['templates'];

foreach ($templates as $template) {
if ($template['name'] == $name) {
return $template['template'];
}
}

return System::getContainer()->get('huh.utils.template')->getTemplate($name);
}
}
3 changes: 3 additions & 0 deletions src/DependencyInjection/Configuration.php
Expand Up @@ -57,6 +57,9 @@ public function getConfigTreeBuilder()
->end()
->end()
->end()
->arrayNode('template_prefixes')
->prototype('scalar')
->end()->end()
->end()
->end()
->end();
Expand Down
18 changes: 8 additions & 10 deletions src/Module/ModuleFilter.php
Expand Up @@ -27,12 +27,12 @@ class ModuleFilter extends \Contao\Module
public function generate()
{
if (TL_MODE === 'BE') {
$objTemplate = new \BackendTemplate('be_wildcard');
$objTemplate->wildcard = '### '.Utf8::strtoupper($GLOBALS['TL_LANG']['FMD'][$this->type][0]).' ###';
$objTemplate->title = $this->headline;
$objTemplate->id = $this->id;
$objTemplate->link = $this->name;
$objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id='.$this->id;
$objTemplate = new \BackendTemplate('be_wildcard');
$objTemplate->wildcard = '### ' . Utf8::strtoupper($GLOBALS['TL_LANG']['FMD'][$this->type][0]) . ' ###';
$objTemplate->title = $this->headline;
$objTemplate->id = $this->id;
$objTemplate->link = $this->name;
$objTemplate->href = 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id=' . $this->id;

return $objTemplate->parse();
}
Expand Down Expand Up @@ -75,15 +75,13 @@ protected function compile()
$twig->hasExtension('\Twig_Extensions_Extension_Date') ?: $twig->addExtension(new \Twig_Extensions_Extension_Date());
$twig->hasExtension('Urodoz\Truncate\Bridge\Twig\TruncateExtension') ?: $twig->addExtension(new TruncateExtension(TruncateService::create()));

$templates = System::getContainer()->get('huh.filter.choice.template')->getChoices();

$this->Template->filter = $this->config;

$this->Template->form = $twig->render(
$templates[$filter['template']],
$this->config->getFilterTemplateByName($filter['template']),
[
'filter' => $this->config,
'form' => $form->createView(),
'form' => $form->createView(),
]
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Resources/config/config.yml
Expand Up @@ -41,3 +41,5 @@ huh:
- {name: bootstrap_4_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_layout.html.twig'}
- {name: bootstrap_4_horizontal_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_horizontal_layout.html.twig'}
- {name: foundation_5_layout, template: '@HeimrichHannotContaoFilter/filter/filter_form_foundation_5_layout.html.twig'}
template_prefixes:
- filter_
66 changes: 47 additions & 19 deletions tests/Choice/TemplateChoiceTest.php
Expand Up @@ -8,13 +8,18 @@

namespace HeimrichHannot\FilterBundle\Test\Choice;

use Contao\CoreBundle\Config\ResourceFinder;
use Contao\DataContainer;
use Contao\ManagerPlugin\PluginLoader;
use Contao\System;
use Contao\TestCase\ContaoTestCase;
use Contao\ThemeModel;
use HeimrichHannot\FilterBundle\Choice\TemplateChoice;
use HeimrichHannot\FilterBundle\Choice\TypeChoice;
use HeimrichHannot\FilterBundle\ContaoManager\Plugin;
use HeimrichHannot\UtilsBundle\Choice\TwigTemplateChoice;
use HeimrichHannot\UtilsBundle\Container\ContainerUtil;
use HeimrichHannot\UtilsBundle\Template\TemplateUtil;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;

Expand Down Expand Up @@ -52,7 +57,7 @@ public function setUp(): void

$containerBuilder = new \Contao\ManagerPlugin\Config\ContainerBuilder($this->mockPluginLoader($this->never()), []);

$config = $plugin->getExtensionConfig('huh_filter', [[]], $containerBuilder);
$config = $plugin->getExtensionConfig('huh_filter', [[]], $containerBuilder);
$this->config['filter'] = $config['huh']['filter'];
}

Expand All @@ -67,7 +72,7 @@ public function testCanBeInstantiated()
System::setContainer($this->container);

$framework = $this->mockContaoFramework();
$instance = new TemplateChoice($framework);
$instance = new TemplateChoice($framework);

$this->assertInstanceOf('HeimrichHannot\FilterBundle\Choice\TemplateChoice', $instance);
}
Expand All @@ -83,8 +88,8 @@ public function testCollectWithoutTypes()
System::setContainer($this->container);

$framework = $this->mockContaoFramework();
$instance = new TemplateChoice($framework);
$choices = $instance->getChoices();
$instance = new TemplateChoice($framework);
$choices = $instance->getChoices();

System::setContainer($this->container);

Expand All @@ -96,38 +101,53 @@ public function testCollectWithoutTypes()
*/
public function testCollectWithExistingTypesWithoutContext()
{
$this->container->set('kernel', $this->kernel);
$themeModelAdapter = $this->mockAdapter(['findAll']);
$themeModelAdapter->method('findAll')->willReturn(null);

$finder = new ResourceFinder(([
$this->getFixturesDir(),
]));

$this->container->set('contao.resource_finder', $finder);

$framework = $this->mockContaoFramework([ThemeModel::class => $themeModelAdapter]);
$this->container->setParameter('huh.filter', $this->config);
$this->container->set('huh.utils.template', new TemplateUtil($framework));
$this->container->set('huh.utils.container', new ContainerUtil($framework));
$this->container->set('huh.utils.choice.twig_template', new TwigTemplateChoice($framework));
$this->container->set('kernel', $this->kernel);
$this->container->setParameter('kernel.project_dir', $this->getFixturesDir());

System::setContainer($this->container);

$framework = $this->mockContaoFramework();
$instance = new TemplateChoice($framework);
$choices = $instance->getChoices();
$choices = $instance->getChoices();

$this->assertNotEmpty($choices);
$this->assertArrayHasKey('form_div_layout', $choices);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_div_layout.html.twig', $choices['form_div_layout']);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_div_layout.html.twig (Yaml)', $choices['form_div_layout']);
$this->assertArrayHasKey('form_table_layout', $choices);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_table_layout.html.twig', $choices['form_table_layout']);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_table_layout.html.twig (Yaml)', $choices['form_table_layout']);
$this->assertArrayHasKey('bootstrap_3_layout', $choices);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_3_layout.html.twig', $choices['bootstrap_3_layout']);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_3_layout.html.twig (Yaml)', $choices['bootstrap_3_layout']);
$this->assertArrayHasKey('bootstrap_3_horizontal_layout', $choices);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_3_horizontal_layout.html.twig', $choices['bootstrap_3_horizontal_layout']);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_3_horizontal_layout.html.twig (Yaml)', $choices['bootstrap_3_horizontal_layout']);
$this->assertArrayHasKey('bootstrap_4_layout', $choices);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_layout.html.twig', $choices['bootstrap_4_layout']);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_layout.html.twig (Yaml)', $choices['bootstrap_4_layout']);
$this->assertArrayHasKey('bootstrap_4_horizontal_layout', $choices);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_horizontal_layout.html.twig', $choices['bootstrap_4_horizontal_layout']);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_bootstrap_4_horizontal_layout.html.twig (Yaml)', $choices['bootstrap_4_horizontal_layout']);
$this->assertArrayHasKey('foundation_5_layout', $choices);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_foundation_5_layout.html.twig', $choices['foundation_5_layout']);
$this->assertSame('@HeimrichHannotContaoFilter/filter/filter_form_foundation_5_layout.html.twig (Yaml)', $choices['foundation_5_layout']);
$this->assertArrayHasKey('filter_test', $choices);
$this->assertSame('filter_test.html.twig (../../Fixtures/templates)', $choices['filter_test']);
}

/**
* Tests the type collection with existing types but missing text type class.
*/
public function testCollectWithExistingTypeWithMissingClassWithoutContext()
{
$config = $this->config;
$config = $this->config;
$config['filter']['types'][0]['class'] = '_NonExistingNamespace\NonExistingClass';

$this->container->set('kernel', $this->kernel);
Expand All @@ -136,8 +156,8 @@ public function testCollectWithExistingTypeWithMissingClassWithoutContext()
System::setContainer($this->container);

$framework = $this->mockContaoFramework();
$instance = new TypeChoice($framework);
$choices = $instance->getChoices();
$instance = new TypeChoice($framework);
$choices = $instance->getChoices();

$this->assertNotEmpty($choices);
$this->assertArrayNotHasKey('text', $choices);
Expand All @@ -154,7 +174,7 @@ public function testCollectWithExistingTypesWithDataContainerContext()
System::setContainer($this->container);

$framework = $this->mockContaoFramework();
$instance = new TypeChoice($framework);
$instance = new TypeChoice($framework);

$dataContainerMock = $this->createMock(DataContainer::class);

Expand All @@ -175,7 +195,7 @@ public function testCollectWithExistingTypesWithDataContainerContext()
* Mocks the plugin loader.
*
* @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expects
* @param array $plugins
* @param array $plugins
*
* @return PluginLoader|\PHPUnit_Framework_MockObject_MockObject
*/
Expand All @@ -187,4 +207,12 @@ private function mockPluginLoader(\PHPUnit_Framework_MockObject_Matcher_InvokedC

return $pluginLoader;
}

/**
* @return string
*/
protected function getFixturesDir(): string
{
return __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Fixtures';
}
}
2 changes: 1 addition & 1 deletion tests/Filter/Type/CheckboxTypeTest.php
Expand Up @@ -370,7 +370,7 @@ public function testBuildQuery()
$this->assertNotEmpty($config->getQueryBuilder()->getParameters());
$this->assertNotEmpty($config->getQueryBuilder()->getQueryPart('where'));
$this->assertSame('SELECT FROM tl_test WHERE test = :test', $config->getQueryBuilder()->getSQL());
$this->assertSame([':test' => 1], $config->getQueryBuilder()->getParameters());
$this->assertSame([':test' => '1'], $config->getQueryBuilder()->getParameters());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/Filter/Type/ChoiceTypeTest.php
Expand Up @@ -450,7 +450,7 @@ public function testBuildQuery()
$this->assertNotEmpty($config->getQueryBuilder()->getParameters());
$this->assertNotEmpty($config->getQueryBuilder()->getQueryPart('where'));
$this->assertSame('SELECT FROM tl_test WHERE test = :test', $config->getQueryBuilder()->getSQL());
$this->assertSame([':test' => 1], $config->getQueryBuilder()->getParameters());
$this->assertSame([':test' => '1'], $config->getQueryBuilder()->getParameters());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/Filter/Type/CountryTypeTest.php
Expand Up @@ -457,7 +457,7 @@ public function testBuildQuery()
$this->assertNotEmpty($config->getQueryBuilder()->getParameters());
$this->assertNotEmpty($config->getQueryBuilder()->getQueryPart('where'));
$this->assertSame('SELECT FROM tl_test WHERE test = :test', $config->getQueryBuilder()->getSQL());
$this->assertSame([':test' => 1], $config->getQueryBuilder()->getParameters());
$this->assertSame([':test' => '1'], $config->getQueryBuilder()->getParameters());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/Filter/Type/HiddenTypeTest.php
Expand Up @@ -231,7 +231,7 @@ public function testBuildQuery()
$this->assertNotEmpty($config->getQueryBuilder()->getParameters());
$this->assertNotEmpty($config->getQueryBuilder()->getQueryPart('where'));
$this->assertSame('SELECT FROM tl_test WHERE test = :test', $config->getQueryBuilder()->getSQL());
$this->assertSame([':test' => 1], $config->getQueryBuilder()->getParameters());
$this->assertSame([':test' => '1'], $config->getQueryBuilder()->getParameters());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/Filter/Type/LanguageTypeTest.php
Expand Up @@ -457,7 +457,7 @@ public function testBuildQuery()
$this->assertNotEmpty($config->getQueryBuilder()->getParameters());
$this->assertNotEmpty($config->getQueryBuilder()->getQueryPart('where'));
$this->assertSame('SELECT FROM tl_test WHERE test = :test', $config->getQueryBuilder()->getSQL());
$this->assertSame([':test' => 1], $config->getQueryBuilder()->getParameters());
$this->assertSame([':test' => '1'], $config->getQueryBuilder()->getParameters());
}

/**
Expand Down

0 comments on commit 9be7ed5

Please sign in to comment.