Skip to content

Commit

Permalink
Merge branch 'constraint'
Browse files Browse the repository at this point in the history
  • Loading branch information
boekkooi committed Aug 8, 2014
2 parents 7a818d3 + f115084 commit a22ea33
Show file tree
Hide file tree
Showing 13 changed files with 478 additions and 23 deletions.
18 changes: 13 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@ language: php
php: [5.3.3, 5.3, 5.4, 5.5, 5.6, hhvm]

env:
- SYMFONY_VERSION=2.1.*
- SYMFONY_VERSION=2.2.*
- SYMFONY_VERSION=2.3.*
- SYMFONY_VERSION=2.4.*
- SYMFONY_VERSION=2.5.*

matrix:
fast_finish: true
include:
- php: 5.3.3
env: "SYMFONY_VERSION=2.1.* TWIG_VERSION=1.15"
- php: 5.5
env: "SYMFONY_VERSION=2.2.*"
- php: 5.5
env: "SYMFONY_VERSION=2.3.*"
- php: 5.5
env: "SYMFONY_VERSION=2.4.*"
allow_failures:
- php: hhvm

before_script:
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --no-update symfony/framework-bundle=$SYMFONY_VERSION; composer require --no-update symfony/twig-bundle=$SYMFONY_VERSION; fi;'
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --no-update symfony/framework-bundle=$SYMFONY_VERSION; fi;'
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --no-update symfony/twig-bundle=$SYMFONY_VERSION; fi;'
- sh -c 'if [ "$TWIG_VERSION" != "" ]; then composer require --no-update twig/twig=$TWIG_VERSION; fi;'
- composer install --dev
- mkdir -p build/logs

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ Use `{% extends "!@<bundle>" %}` to inherit from the root bundle. [more...](doc/
[The Doctrine Loader](doc/twig-doctrine-loader.md)
-------------
Add one or multiple doctrine/database template loaders to twig with optional translation support. [more...](doc/twig-doctrine-loader.md)

[Twig syntax constraint](doc/twig-syntax-validator.md)
-------------
Validate that a string is a valid twig template. [more...](doc/twig-syntax-validator.md)
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
"require": {
"php": ">=5.3.3",
"symfony/framework-bundle": "~2.1",
"symfony/twig-bundle": "~2.1"
"symfony/twig-bundle": "~2.1",
"twig/twig": "~1.15"
},
"suggest": {
"doctrine/common": "Needed to use the twig doctrine loader functionality."
"doctrine/common": "Needed to use the twig doctrine loader functionality.",
"symfony/validator": "Allows the twig constraint to be used"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
"symfony/validator": "~2.1",
"doctrine/common": "~2.1"
},
"license": "MIT",
Expand Down
50 changes: 50 additions & 0 deletions doc/twig-syntax-validator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Twig Syntax Validator
=============
This Twig Syntax Validator adds an validation constraint that will validate a string as containing valid twig syntax.

Example
-------------
Enable the validator
```YAML
# app/config/config.yml
boekkooi_twig_jack:
...
constraint: true
```
Use the constraint.
```php
use Boekkooi\Bundle\TwigJackBundle\Validator\Constraint as TwigAssert;
use Symfony\Component\Validator\Constraints as Assert;

class MyClass {
// ...

/**
* @Assert\NotBlank()
* @TwigAssert\TwigSyntax()
*/
public $template;

/**
* Check this variable based on syntax only and not availability of the methods, filters, etc. used
*
* @Assert\NotBlank()
* @TwigAssert\TwigSyntax(parse=false)
*/
public $remote_template;

// ...
}
```

Full configuration
-------------
Default configuration:
```yaml
# app/config/config.yml
boekkooi_twig_jack:
constraint:
enabled: true
environment: 'twig' # Reference to the twig environment service to use by default.
```
27 changes: 23 additions & 4 deletions src/DependencyInjection/BoekkooiTwigJackExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ public function load(array $config, ContainerBuilder $container)
$processor = new Processor();
$config = $processor->processConfiguration(new Configuration(), $config);

if ($config['defer']['enabled']) {
$container->setParameter('boekkooi.twig_jack.defer.prefix', $config['defer']['prefix']);
$loader->load('defer.yml');
}
$this->loadDefer($container, $loader, $config);
$this->loadConstraint($container, $loader, $config);

if ($config['exclamation']) {
$loader->load('exclamation.yml');
Expand Down Expand Up @@ -109,4 +107,25 @@ private function createLoaderRepository(ContainerBuilder $container, $loaderName

return $repositoryService;
}

private function loadDefer(ContainerBuilder $container, LoaderInterface $loader, array $config)
{
if (!$config['defer']['enabled']) {
return;
}

$container->setParameter('boekkooi.twig_jack.defer.prefix', $config['defer']['prefix']);
$loader->load('defer.yml');
}

private function loadConstraint(ContainerBuilder $container, LoaderInterface $loader, array $config)
{
if (!$config['constraint']['enabled']) {
return;
}

$loader->load('constraint.yml');
$container->getDefinition('boekkooi.twig_jack.constraint_validator')
->replaceArgument(0, new Reference($config['constraint']['environment']));
}
}
48 changes: 38 additions & 10 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,10 @@ public function getConfigTreeBuilder()

$rootNode = $treeBuilder->root('boekkooi_twig_jack');
$rootNode->append($this->loadLoadersNode());
$rootNode->append($this->loadDeferNode());
$rootNode->append($this->loadConstraintNode());
$rootNode
->children()
->arrayNode('defer')
->addDefaultsIfNotSet()
->treatNullLike(array())
->treatFalseLike(array('enabled' => false))
->treatTrueLike(array('enabled' => true))
->children()
->booleanNode('enabled')->defaultTrue()->end()
->scalarNode('prefix')->defaultValue('_defer_ref_')->end()
->end()
->end()
->booleanNode('exclamation')->defaultTrue()->end()
->end();

Expand Down Expand Up @@ -66,4 +58,40 @@ private function loadLoadersNode()

return $node;
}

private function loadDeferNode()
{
$treeBuilder = new TreeBuilder();

$node = $treeBuilder->root('defer');
$node
->addDefaultsIfNotSet()
->treatNullLike(array())
->treatFalseLike(array('enabled' => false))
->treatTrueLike(array('enabled' => true))
->children()
->booleanNode('enabled')->defaultTrue()->end()
->scalarNode('prefix')->defaultValue('_defer_ref_')->end()
->end();

return $node;
}

private function loadConstraintNode()
{
$treeBuilder = new TreeBuilder();

$node = $treeBuilder->root('constraint');
$node
->addDefaultsIfNotSet()
->treatNullLike(array())
->treatFalseLike(array('enabled' => false))
->treatTrueLike(array('enabled' => true))
->children()
->booleanNode('enabled')->defaultFalse()->end()
->scalarNode('environment')->defaultValue('twig')->end()
->end();

return $node;
}
}
10 changes: 10 additions & 0 deletions src/Resources/config/constraint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
parameters:
boekkooi.twig_jack.constraint_validator.class: Boekkooi\Bundle\TwigJackBundle\Validator\Constraint\TwigSyntaxValidator

services:
# defer extension
boekkooi.twig_jack.constraint_validator:
class: %boekkooi.twig_jack.constraint_validator.class%
arguments: [ null ]
tags:
- { name: validator.constraint_validator, alias: 'TwigSyntaxValidator' }
4 changes: 2 additions & 2 deletions src/Twig/Node/DeferReference.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class DeferReference extends Twig_Node_BlockReference
{
/**
* @param string $name
* @param string $variable
* @param string|false $variable
* @param boolean $unique
* @param boolean $reference
* @param string $reference
* @param integer $lineno The line number
* @param string $tag The tag name associated with the Node
*/
Expand Down
29 changes: 29 additions & 0 deletions src/Validator/Constraint/TwigSyntax.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
namespace Boekkooi\Bundle\TwigJackBundle\Validator\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\InvalidOptionsException;

/**
* @author Warnar Boekkooi <[email protected]>
*/
class TwigSyntax extends Constraint
{
public $message = 'This value is not a valid twig template.';
public $parse = true;
public $environment = null;

public function __construct($options = null)
{
parent::__construct($options);

if ($this->environment !== null && !$this->environment instanceof \Twig_Environment) {
throw new InvalidOptionsException(sprintf('Option "environment" must be null or a Twig_Environment instance for constraint %s', __CLASS__), array('environment'));
}
}

public function validatedBy()
{
return 'TwigSyntaxValidator';
}
}
51 changes: 51 additions & 0 deletions src/Validator/Constraint/TwigSyntaxValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
namespace Boekkooi\Bundle\TwigJackBundle\Validator\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

/**
* @author Warnar Boekkooi <[email protected]>
*/
class TwigSyntaxValidator extends ConstraintValidator
{
protected $environment;

public function __construct(\Twig_Environment $environment)
{
$this->environment = $environment;
}

public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof TwigSyntax) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\TwigSyntax');
}

if ($value === '' || $value === null) {
return;
}

$env = $this->getEnvironment($constraint);
try {
$tokeStream = $env->tokenize($value);
if ($constraint->parse) {
$env->parse($tokeStream);
}
} catch (\Twig_Error_Syntax $e) {
$this->context->addViolation($constraint->message, array(
'{{ value }}' => $this->formatValue($value),
));
}
}

protected function getEnvironment(TwigSyntax $constraint)
{
$env = $constraint->environment;
if ($env !== null) {
return $env;
}
return $this->environment;
}
}
30 changes: 30 additions & 0 deletions tests/DependencyInjection/BoekkooiTwigJackExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function testLoad()
$this->extension->load(array('boekkooi_twig_jack' => array()), $container);

$this->assertTrue($container->has('boekkooi.twig_jack.defer.extension'));
$this->assertFalse($container->has('boekkooi.twig_jack.constraint_validator'));
$this->assertTrue($container->hasParameter('boekkooi.twig_jack.defer.prefix'));
$this->assertTrue($container->hasParameter('templating.name_parser.class'));
$this->assertEquals('Boekkooi\Bundle\TwigJackBundle\Templating\TemplateNameParser', $container->getParameter('templating.name_parser.class'));
Expand Down Expand Up @@ -267,4 +268,33 @@ public function getLoadersInvalid()
);
}

/**
* @dataProvider getLoadConstraint
*/
public function testLoadConstraint($options, $envServiceName)
{
$container = new ContainerBuilder();
$this->extension->load(array('boekkooi_twig_jack' => $options), $container);

$this->assertTrue($container->has('boekkooi.twig_jack.constraint_validator'));

/** @var \Symfony\Component\DependencyInjection\Reference $envReference */
$envReference = $container->getDefinition('boekkooi.twig_jack.constraint_validator')->getArgument(0);
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $envReference);
$this->assertEquals($envServiceName, (string)$envReference);
}

public function getLoadConstraint()
{
return array(
array(
array('constraint' => true),
'twig'
),
array(
array('constraint' => array('enabled' => true, 'environment' => 'new_twig')),
'new_twig'
)
);
}
}
Loading

0 comments on commit a22ea33

Please sign in to comment.