Skip to content

Commit

Permalink
Merge pull request #19 from victorwelling/master
Browse files Browse the repository at this point in the history
Fixes compatibility with Twig v2.9
  • Loading branch information
victorwelling committed May 1, 2019
2 parents eabe48a + bb50c67 commit ade588a
Show file tree
Hide file tree
Showing 19 changed files with 86 additions and 75 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
vendor/
.phpunit.result.cache
composer.lock
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# Changelog
All notable changes to Shoot will be documented in this file.

## [3.0.0] - 2019-05-01
### Changed
- Shoot now requires Twig v2.9. In addition, it's now also pinned to this minor version, as Twig doesn't seem to follow
SemVer with regards to non-breaking changes in its APIs. As this on its own is a breaking change for Shoot, this
warrants a major version bump.

### Fixed
- Compatibility issues with Twig v2.9 have been fixed.

## [2.0.0] - 2019-03-04
### Added
- Documentation on nesting presentation models and the `optional` tag.
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
"psr/http-message": "^1.0",
"psr/http-server-middleware": "^1.0",
"psr/log": "^1.1",
"twig/twig": "^2.6"
"twig/twig": "~2.9.0"
},
"require-dev": {
"phpunit/phpunit": "^8.0"
"phpunit/phpunit": "^8.1"
},
"autoload": {
"psr-4": {
Expand Down
12 changes: 6 additions & 6 deletions src/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
use Shoot\Shoot\Twig\NodeVisitor\ModelNodeVisitor;
use Shoot\Shoot\Twig\TokenParser\ModelTokenParser;
use Shoot\Shoot\Twig\TokenParser\OptionalTokenParser;
use Twig_ExtensionInterface as ExtensionInterface;
use Twig_Filter as TwigFilter;
use Twig_Function as TwigFunction;
use Twig_NodeVisitorInterface as NodeVisitorInterface;
use Twig_Test as TwigTest;
use Twig_TokenParserInterface as TokenParserInterface;
use Twig\Extension\ExtensionInterface;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;

/**
* This extension for Twig will enable the use of Shoot.
Expand Down
2 changes: 1 addition & 1 deletion src/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace Shoot\Shoot;

use Shoot\Shoot\Twig\PatchingCompiler;
use Twig_Environment as Environment;
use Twig\Environment;

/**
* Installs Shoot in an instance of Twig.
Expand Down
1 change: 0 additions & 1 deletion src/Pipeline.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
namespace Shoot\Shoot;

use Psr\Http\Message\ServerRequestInterface;
use Shoot\Shoot\Middleware\SuppressionMiddleware;

/**
* The processing pipeline of Shoot. Holds the middleware that enables Shoot's functionality. It's called from the Twig
Expand Down
14 changes: 9 additions & 5 deletions src/Twig/Node/DisplayEndNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
use Shoot\Shoot\Extension;
use Shoot\Shoot\SuppressedException;
use Shoot\Shoot\View;
use Twig_Compiler as Compiler;
use Twig_Node as Node;
use Twig_Node_Module as ModuleNode;
use Twig\Compiler;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Source;

/**
* This node is added to the bottom of the display method of a Twig template and is used by Shoot to wrap its contents
Expand All @@ -30,7 +31,7 @@ public function __construct(ModuleNode $module)

$this->module = $module;

$this->setTemplateName($module->getTemplateName());
$this->setSourceContext($module->getSourceContext());
}

/**
Expand All @@ -44,9 +45,12 @@ public function compile(Compiler $compiler): void
return;
}

/** @var Source $source */
$source = $this->getSourceContext();
$templateName = $source->getName();

$extensionClass = Extension::class;
$suppressedExceptionClass = SuppressedException::class;
$templateName = $this->getTemplateName();
$viewClass = View::class;

$compiler
Expand Down
11 changes: 5 additions & 6 deletions src/Twig/Node/DisplayStartNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

namespace Shoot\Shoot\Twig\Node;

use Twig_Compiler as Compiler;
use Twig_Node as Node;
use Twig_Node_Module as ModuleNode;
use Twig\Compiler;
use Twig\Node\ModuleNode;
use Twig\Node\Node;

/**
* This node is added to the top of the display method of a Twig template and is used by Shoot to wrap the method's
Expand All @@ -32,8 +32,7 @@ public function __construct(ModuleNode $module, FindPresentationModelInterface $
$this->module = $module;
$this->findPresentationModel = $findPresentationModel;

$this->setTemplateName($module->getTemplateName());

$this->setSourceContext($module->getSourceContext());
}

/**
Expand All @@ -47,7 +46,7 @@ public function compile(Compiler $compiler): void
return;
}

$presentationModel = $this->findPresentationModel->for($this->getTemplateName());
$presentationModel = $this->findPresentationModel->for($this->getSourceContext());

$compiler
->write("\$presentationModel = new $presentationModel(\$context);\n")
Expand Down
6 changes: 4 additions & 2 deletions src/Twig/Node/FindPresentationModelInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

namespace Shoot\Shoot\Twig\Node;

use Twig\Source;

/**
* Finds the presentation model for a given view.
*
Expand All @@ -13,9 +15,9 @@ interface FindPresentationModelInterface
/**
* Returns the presentation model for the given view.
*
* @param string $view
* @param Source $source
*
* @return string
*/
public function for(string $view): string;
public function for(Source $source): string;
}
2 changes: 1 addition & 1 deletion src/Twig/Node/ModelNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Shoot\Shoot\Twig\Node;

use Twig_Node as Node;
use Twig\Node\Node;

/**
* Represents the model tag used to assign a presentation model to a view.
Expand Down
6 changes: 3 additions & 3 deletions src/Twig/Node/OptionalNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
namespace Shoot\Shoot\Twig\Node;

use Shoot\Shoot\SuppressedException;
use Twig_Compiler as Compiler;
use Twig_Error_Runtime as RuntimeError;
use Twig_Node as Node;
use Twig\Compiler;
use Twig\Error\RuntimeError;
use Twig\Node\Node;

/**
* Represents the optional tag used to suppress runtime exceptions in templates.
Expand Down
44 changes: 27 additions & 17 deletions src/Twig/NodeVisitor/ModelNodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@

namespace Shoot\Shoot\Twig\NodeVisitor;

use LogicException;
use Shoot\Shoot\ModelAlreadyAssignedException;
use Shoot\Shoot\PresentationModel;
use Shoot\Shoot\Twig\Node\DisplayEndNode;
use Shoot\Shoot\Twig\Node\DisplayStartNode;
use Shoot\Shoot\Twig\Node\FindPresentationModelInterface;
use Shoot\Shoot\Twig\Node\ModelNode;
use Twig_Environment as Environment;
use Twig_Node as Node;
use Twig_Node_Module as ModuleNode;
use Twig_NodeVisitorInterface as NodeVisitorInterface;
use SplObjectStorage;
use Twig\Environment;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\Source;

/**
* Walks through model tags to assign presentation models to templates.
Expand All @@ -22,8 +23,13 @@
*/
final class ModelNodeVisitor implements FindPresentationModelInterface, NodeVisitorInterface
{
/** @var string[] */
private $presentationModels = [];
/** @var SplObjectStorage */
private $presentationModels;

public function __construct()
{
$this->presentationModels = new SplObjectStorage();
}

/**
* @param Node $node
Expand All @@ -34,7 +40,7 @@ final class ModelNodeVisitor implements FindPresentationModelInterface, NodeVisi
public function enterNode(Node $node, Environment $environment): Node
{
if ($node instanceof ModelNode) {
$this->assign($node->getTemplateName(), $node->getAttribute('presentation_model'));
$this->assign($node->getSourceContext(), $node->getAttribute('presentation_model'));
}

return $node;
Expand Down Expand Up @@ -68,13 +74,17 @@ public function leaveNode(Node $node, Environment $environment): Node
/**
* Returns the presentation model for the given view.
*
* @param string $view
* @param Source $source
*
* @return string
*/
public function for(string $view): string
public function for(Source $source): string
{
return $this->presentationModels[$view] ?? PresentationModel::class;
if (isset($this->presentationModels[$source])) {
return (string)$this->presentationModels[$source];
}

return PresentationModel::class;
}

/**
Expand All @@ -87,19 +97,19 @@ public function getPriority(): int
}

/**
* @param string $view
* @param Source $source
* @param string $presentationModel
*
* @return void
*
* @throws LogicException
* @throws ModelAlreadyAssignedException
*/
private function assign(string $view, string $presentationModel): void
private function assign(Source $source, string $presentationModel): void
{
if (isset($this->presentationModels[$view])) {
throw new ModelAlreadyAssignedException("A presentation model has already been assigned to {$view}");
if (isset($this->presentationModels[$source])) {
throw new ModelAlreadyAssignedException("A presentation model has already been assigned to {$source->getName()}");
}

$this->presentationModels[$view] = $presentationModel;
$this->presentationModels[$source] = $presentationModel;
}
}
2 changes: 1 addition & 1 deletion src/Twig/PatchingCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Shoot\Shoot\Twig;

use Twig_Compiler as Compiler;
use Twig\Compiler;

/**
* This compiler patches a few crucial lines in some core Twig classes. It allows Shoot to be used with extend, embed,
Expand Down
9 changes: 6 additions & 3 deletions src/Twig/TokenParser/ModelTokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
namespace Shoot\Shoot\Twig\TokenParser;

use Shoot\Shoot\Twig\Node\ModelNode;
use Twig_Node as Node;
use Twig_Token as Token;
use Twig_TokenParser as AbstractTokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\Node;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;

/**
* Parses model tags in the token stream.
Expand All @@ -19,6 +20,8 @@ final class ModelTokenParser extends AbstractTokenParser
* @param Token $token
*
* @return Node
*
* @throws SyntaxError
*/
public function parse(Token $token): Node
{
Expand Down
9 changes: 6 additions & 3 deletions src/Twig/TokenParser/OptionalTokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
namespace Shoot\Shoot\Twig\TokenParser;

use Shoot\Shoot\Twig\Node\OptionalNode;
use Twig_Node as Node;
use Twig_Token as Token;
use Twig_TokenParser as AbstractTokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\Node;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;

/**
* Parses optional tags in the token stream.
Expand All @@ -19,6 +20,8 @@ final class OptionalTokenParser extends AbstractTokenParser
* @param Token $token
*
* @return Node
*
* @throws SyntaxError
*/
public function parse(Token $token): Node
{
Expand Down
6 changes: 1 addition & 5 deletions src/View.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@ final class View
*/
public function __construct(string $name, PresentationModel $presentationModel, callable $callback)
{
if ($name === '') {
throw new InvalidArgumentException('The name of a view cannot be empty');
}

$this->name = $name;
$this->name = $name !== '' ? $name : 'unknown template';
$this->presentationModel = $presentationModel;
$this->callback = $callback;
}
Expand Down
4 changes: 2 additions & 2 deletions tests/Integration/IntegrationTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
use Shoot\Shoot\Middleware\PresenterMiddleware;
use Shoot\Shoot\MiddlewareInterface;
use Shoot\Shoot\Pipeline;
use Twig_Environment as Environment;
use Twig_Loader_Filesystem as FilesystemLoader;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

abstract class IntegrationTestCase extends TestCase
{
Expand Down
4 changes: 2 additions & 2 deletions tests/Unit/ExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
use Shoot\Shoot\Pipeline;
use Shoot\Shoot\PresentationModel;
use Shoot\Shoot\Tests\Fixtures\ViewFactory;
use Twig_Filter as TwigFilter;
use Twig_Test as TwigTest;
use Twig\TwigFilter;
use Twig\TwigTest;

final class ExtensionTest extends TestCase
{
Expand Down
15 changes: 0 additions & 15 deletions tests/Unit/ViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,13 @@

namespace Shoot\Shoot\Tests\Unit;

use InvalidArgumentException;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Shoot\Shoot\PresentationModel;
use Shoot\Shoot\Tests\Fixtures\ViewFactory;
use Shoot\Shoot\View;
use stdClass;

final class ViewTest extends TestCase
{
public function testShouldNotAllowEmptyNames(): void
{
$presentationModel = new PresentationModel();
$callback = function () {
// noop
};

$this->expectException(InvalidArgumentException::class);

new View('', $presentationModel, $callback);
}

public function testShouldExecuteCallback(): void
{
/** @var callable|MockObject $callback */
Expand Down

0 comments on commit ade588a

Please sign in to comment.