Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version bump to Twig 2.0 #13

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 74 additions & 57 deletions LambdaExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,70 +11,80 @@
namespace DPolac\TwigLambda;

use DPolac\Dictionary;

class LambdaExtension extends \Twig_Extension
use DPolac\TwigLambda\NodeExpression\Arguments;
use DPolac\TwigLambda\NodeExpression\SimpleLambda;
use DPolac\TwigLambda\NodeExpression\LambdaWithArguments;
use Twig\Error\RuntimeError;
use Twig\ExpressionParser;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;

class LambdaExtension extends AbstractExtension
{

public function getOperators()
{
return [
[
'=>' => [
'==>' => [
'precedence' => 0,
'class' => '\DPolac\TwigLambda\NodeExpression\SimpleLambda'
'class' => SimpleLambda::class,
],
],
[
'=>' => [
'==>' => [
'precedence' => 0,
'class' => '\DPolac\TwigLambda\NodeExpression\LambdaWithArguments',
'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT
'class' => LambdaWithArguments::class,
'associativity' => ExpressionParser::OPERATOR_LEFT
],
';' => [
'precedence' => 5,
'class' => '\DPolac\TwigLambda\NodeExpression\Arguments',
'associativity' => \Twig_ExpressionParser::OPERATOR_RIGHT
'class' => Arguments::class,
'associativity' => ExpressionParser::OPERATOR_RIGHT
],
]
];
}

public function getFunctions()
{
return [
new \Twig_SimpleFunction('call', '\DPolac\TwigLambda\LambdaExtension::call'),
new TwigFunction('call', [ LambdaExtension::class, 'call' ]),
];
}

public function getTests()
{
return [
new \Twig_SimpleTest('every', '\DPolac\TwigLambda\LambdaExtension::every'),
new \Twig_SimpleTest('any', '\DPolac\TwigLambda\LambdaExtension::any'),
new TwigTest('every', [ LambdaExtension::class, 'every' ]),
new TwigTest('any', [ LambdaExtension::class, 'any' ]),
];
}

public function getFilters()
{
return [
new \Twig_SimpleFilter('map', '\DPolac\TwigLambda\LambdaExtension::map'),
new \Twig_SimpleFilter('select', '\DPolac\TwigLambda\LambdaExtension::map'),
new TwigFilter('map', [ LambdaExtension::class, 'map' ]),
new TwigFilter('select', [ LambdaExtension::class, 'map' ]),

new \Twig_SimpleFilter('filter', '\DPolac\TwigLambda\LambdaExtension::filter'),
new \Twig_SimpleFilter('where', '\DPolac\TwigLambda\LambdaExtension::filter'),
new TwigFilter('filter', [ LambdaExtension::class, 'filter' ]),
new TwigFilter('where', [ LambdaExtension::class, 'filter' ]),

new \Twig_SimpleFilter('unique_by', '\DPolac\TwigLambda\LambdaExtension::uniqueBy'),
new \Twig_SimpleFilter('group_by', '\DPolac\TwigLambda\LambdaExtension::groupBy'),
new \Twig_SimpleFilter('sort_by', '\DPolac\TwigLambda\LambdaExtension::sortBy'),
new \Twig_SimpleFilter('count_by', '\DPolac\TwigLambda\LambdaExtension::countBy'),
new TwigFilter('unique_by', [ LambdaExtension::class, 'uniqueBy' ]),
new TwigFilter('group_by', [ LambdaExtension::class, 'groupBy' ]),
new TwigFilter('sort_by', [ LambdaExtension::class, 'sortBy' ]),
new TwigFilter('count_by', [ LambdaExtension::class, 'countBy' ]),
];
}


/**
* @throws RuntimeError
*/
public static function map($array, $callback)
{
if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "map" must be callable, but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "map" must be callable, but is "%s".', gettype($callback)));
}

if (is_array($array)) {
Expand All @@ -86,18 +96,19 @@ public static function map($array, $callback)
}
$array = $result;
} else {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "map" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "map" must be array or Traversable, but is "%s".', gettype($array)));
}

return $array;
}

/**
* @throws RuntimeError
*/
public static function filter($array, $callback)
{
if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "filter" must be callable, but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "filter" must be callable, but is "%s".', gettype($callback)));
}

if (is_array($array)) {
Expand All @@ -111,27 +122,27 @@ public static function filter($array, $callback)
}
$array = $result;
} else {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "filter" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "filter" must be array or Traversable, but is "%s".', gettype($array)));
}

return $array;
}

/**
* @throws RuntimeError
*/
public static function uniqueBy($array, $callback)
{
if (!is_array($array) && !($array instanceof \Traversable)) {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "unique_by" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "unique_by" must be array or Traversable, but is "%s".', gettype($array)));
}

if ('==' === $callback) {
$callback = function($item1, $item2) { return $item1 == $item2; };
} else if ('===' === $callback) {
$callback = function($item1, $item2) { return $item1 === $item2; };
} else if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "unique_by" must be callable, "==" or "===", but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "unique_by" must be callable, "==" or "===", but is "%s".', gettype($callback)));
}

if ($array instanceof \Traversable) {
Expand All @@ -158,17 +169,18 @@ public static function uniqueBy($array, $callback)
return $result;
}

/**
* @throws RuntimeError
*/
public static function groupBy($array, $callback)
{

if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "group_by" must be callable, but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "group_by" must be callable, but is "%s".', gettype($callback)));
}

if (!is_array($array) && !($array instanceof \Traversable)) {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "group_by" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "group_by" must be array or Traversable, but is "%s".', gettype($array)));
}

$results = new Dictionary();
Expand All @@ -187,16 +199,17 @@ public static function groupBy($array, $callback)
return $results;
}

/**
* @throws RuntimeError
*/
public static function sortBy($array, $callback, $direction = 'ASC')
{
if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "sort_by" must be callable, but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "sort_by" must be callable, but is "%s".', gettype($callback)));
}

if (!is_array($array) && !($array instanceof \Traversable)) {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "sort_by" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "sort_by" must be array or Traversable, but is "%s".', gettype($array)));
}

if ($array instanceof \Traversable) {
Expand All @@ -214,16 +227,17 @@ public static function sortBy($array, $callback, $direction = 'ASC')
}
}

/**
* @throws RuntimeError
*/
public static function countBy($array, $callback)
{
if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "count_by" must be callable, but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "count_by" must be callable, but is "%s".', gettype($callback)));
}

if (!is_array($array) && !($array instanceof \Traversable)) {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "count_by" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "count_by" must be array or Traversable, but is "%s".', gettype($array)));
}

$result = new Dictionary();
Expand All @@ -242,17 +256,18 @@ public static function countBy($array, $callback)
}
return $result;
}


/**
* @throws RuntimeError
*/
public static function every($array, $callback)
{
if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "every" must be callable, but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "every" must be callable, but is "%s".', gettype($callback)));
}

if (!is_array($array) && !($array instanceof \Traversable)) {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "every" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "every" must be array or Traversable, but is "%s".', gettype($array)));
}

foreach ($array as $i => $item) {
Expand All @@ -263,17 +278,18 @@ public static function every($array, $callback)

return true;
}


/**
* @throws RuntimeError
*/
public static function any($array, $callback)
{
if (!is_callable($callback)) {
throw new \Twig_Error_Runtime(sprintf(
'Second argument of "any" must be callable, but is "%s".', gettype($callback)));
throw new RuntimeError(sprintf('Second argument of "any" must be callable, but is "%s".', gettype($callback)));
}

if (!is_array($array) && !($array instanceof \Traversable)) {
throw new \Twig_Error_Runtime(sprintf(
'First argument of "any" must be array or Traversable, but is "%s".', gettype($array)));
throw new RuntimeError(sprintf('First argument of "any" must be array or Traversable, but is "%s".', gettype($array)));
}

foreach ($array as $i => $item) {
Expand All @@ -290,6 +306,7 @@ public static function call($callback, array $args = [])
if (!is_callable($callback)) {
throw new \InvalidArgumentException('First argument must be callable.');
}

return call_user_func_array($callback, $args);
}

Expand Down
13 changes: 9 additions & 4 deletions NodeExpression/Arguments.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@

namespace DPolac\TwigLambda\NodeExpression;

class Arguments extends \Twig_Node_Expression
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;
use Twig\Compiler;

class Arguments extends AbstractExpression
{
private $arguments;

public function __construct(\Twig_Node $left, \Twig_Node $right, $lineno)
public function __construct(Node $left, Node $right, int $lineno)
{
$arguments = [];
foreach ([$left, $right] as $node) {
if ($node instanceof Arguments) {
$arguments[] = $node->getArguments();
} elseif ($node instanceof \Twig_Node_Expression_Name) {
} elseif ($node instanceof NameExpression) {
$arguments[] = [$node->getAttribute('name')];
} else {
throw new \InvalidArgumentException('Invalid argument.');
Expand All @@ -32,7 +37,7 @@ public function __construct(\Twig_Node $left, \Twig_Node $right, $lineno)
parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
}

public function compile(\Twig_Compiler $compiler)
public function compile(Compiler $compiler)
{
throw new \Exception('Semicolon-separated list of arguments can be only used in lambda expression.');
}
Expand Down
7 changes: 4 additions & 3 deletions NodeExpression/Lambda.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@

namespace DPolac\TwigLambda\NodeExpression;

use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;

abstract class Lambda extends \Twig_Node_Expression
abstract class Lambda extends AbstractExpression
{
protected function compileWithArguments(
\Twig_Compiler $compiler, $expressionNode, array $arguments)
protected function compileWithArguments(Compiler $compiler, $expressionNode, array $arguments)
{
$compiler->raw("\n");
$compiler->indent();
Expand Down
11 changes: 7 additions & 4 deletions NodeExpression/LambdaWithArguments.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@

namespace DPolac\TwigLambda\NodeExpression;

use Twig\Compiler;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;

class LambdaWithArguments extends Lambda
{
private $arguments = [];

public function __construct(\Twig_Node $left, \Twig_Node $right, $lineno)
public function __construct(Node $left, Node $right, int $lineno)
{
parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);

if ($left instanceof \Twig_Node_Expression_Name) {
if ($left instanceof NameExpression) {
$this->arguments = [ $left->getAttribute('name') ];
} elseif ($left instanceof Arguments) {
$this->arguments = $left->getArguments();
Expand All @@ -33,8 +36,8 @@ public function __construct(\Twig_Node $left, \Twig_Node $right, $lineno)

}

public function compile(\Twig_Compiler $compiler)
public function compile(Compiler $compiler)
{
$this->compileWithArguments($compiler, 'right', $this->arguments);
}
}
}
8 changes: 5 additions & 3 deletions NodeExpression/SimpleLambda.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@

namespace DPolac\TwigLambda\NodeExpression;

use Twig\Compiler;
use Twig\Node\Node;

class SimpleLambda extends Lambda
{
public function __construct(\Twig_Node $node, $lineno)
public function __construct(Node $node, int $lineno)
{
parent::__construct(array('node' => $node), array(), $lineno);
}

public function compile(\Twig_Compiler $compiler)
public function compile(Compiler $compiler)
{
$this->compileWithArguments($compiler, 'node', ['_']);
}
}
}
Loading