Passed
Push — master ( 2eecbd...d351da )
by Victor
01:58
created

src/Pipeline.php (1 issue)

1
<?php
2
declare(strict_types=1);
3
4
namespace Shoot\Shoot;
5
6
use Shoot\Shoot\Twig\NodeVisitor\ModelNodeVisitor;
7
use Shoot\Shoot\Twig\TokenParser\ModelTokenParser;
8
use Twig_ExtensionInterface as ExtensionInterface;
9
use Twig_Filter as TwigFilter;
10
use Twig_Function as TwigFunction;
11
use Twig_NodeVisitorInterface as NodeVisitorInterface;
12
use Twig_Test as TwigTest;
13
use Twig_TokenParserInterface as TokenParserInterface;
14
15
final class Pipeline implements ExtensionInterface, PipelineInterface
16
{
17
    /** @var Context */
18
    private $context;
19
20
    /** @var callable */
21
    private $middleware;
22
23
    /**
24
     * @param MiddlewareInterface[] $middleware
25
     */
26 9
    public function __construct(array $middleware = [])
27
    {
28 9
        $this->middleware = $this->chainMiddleware($middleware);
29
30 9
        $this->clearContext();
31 9
    }
32
33
    /**
34
     * Chains the middleware into a single callable.
35
     *
36
     * @param MiddlewareInterface[] $middleware
37
     *
38
     * @return callable
39
     */
40 9
    private function chainMiddleware(array $middleware): callable
41
    {
42 9
        $middleware = array_reverse($middleware);
43
44
        return array_reduce($middleware, function (callable $next, MiddlewareInterface $middleware) {
45 6
            return function (View $view) use ($middleware, $next): View {
46 5
                return $middleware->process($view, $this->context, $next);
47 6
            };
48
        }, function (View $view): View {
49 4
            $view->render();
50
51 4
            return $view;
52 9
        });
53
    }
54
55
    /**
56
     * Applies the given context to the pipeline, executes the given callback, and clears the context.
57
     *
58
     * @param ContextInterface $context
59
     * @param callable         $callback
60
     *
61
     * @return mixed The result as returned by the callback (if any).
62
     */
63 1
    public function withContext(ContextInterface $context, callable $callback)
64
    {
65
        try {
66 1
            $this->applyContext($context);
67
68 1
            return $callback();
69
        } finally {
70 1
            $this->clearContext();
71
        }
72
    }
73
74
    /**
75
     * Apply the given context attributes to the pipeline.
76
     *
77
     * @param ContextInterface $context
78
     *
79
     * @return void
80
     */
81 9
    private function applyContext(ContextInterface $context)
82
    {
83 9
        $this->context = $context;
0 ignored issues
show
Documentation Bug introduced by
$context is of type Shoot\Shoot\ContextInterface, but the property $context was declared to be of type Shoot\Shoot\Context. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
84 9
    }
85
86
    /**
87
     * Clear the current context.
88
     *
89
     * @return void
90
     */
91 9
    private function clearContext()
92
    {
93 9
        $this->applyContext(new Context());
94 9
    }
95
96
    /**
97
     * @internal This method is used by the compiled Twig templates to access the pipeline. It should not be used
98
     * directly.
99
     *
100
     * @param View $view
101
     *
102
     * @return void
103
     */
104 6
    public function process(View $view)
105
    {
106 6
        call_user_func($this->middleware, $view);
107 6
    }
108
109
    /**
110
111
     * Returns a list of filters to add to the existing list.
112
     *
113
     * @return TwigFilter[]
114
     */
115
    public function getFilters(): array
116
    {
117
        return [
118 5
            new TwigFilter('variables', function (PresentationModel $presentationModel): array {
119 2
                return $presentationModel->getVariables();
120 5
            }),
121
        ];
122
    }
123
124
    /**
125
     * Returns a list of functions to add to the existing list.
126
     *
127
     * @return TwigFunction[]
128
     */
129 4
    public function getFunctions(): array
130
    {
131 4
        return [];
132
    }
133
134
    /**
135
     * Returns the node visitor instances to add to the existing list.
136
     *
137
     * @return NodeVisitorInterface[]
138
     */
139 4
    public function getNodeVisitors(): array
140
    {
141 4
        return [new ModelNodeVisitor()];
142
    }
143
144
    /**
145
     * Returns a list of operators to add to the existing list.
146
     *
147
     * @return array[] First array of unary operators, second array of binary operators
148
     */
149 4
    public function getOperators(): array
150
    {
151 4
        return [];
152
    }
153
154
    /**
155
     * Returns a list of tests to add to the existing list.
156
     *
157
     * @return TwigTest[]
158
     */
159
    public function getTests(): array
160
    {
161
        return [
162 5
            new TwigTest('model', function ($value): bool {
163 2
                return $value instanceof PresentationModel;
164 5
            }),
165
        ];
166
    }
167
168
    /**
169
     * Returns the token parser instances to add to the existing list.
170
     *
171
     * @return TokenParserInterface[]
172
     */
173 4
    public function getTokenParsers(): array
174
    {
175 4
        return [new ModelTokenParser()];
176
    }
177
}
178