Completed
Pull Request — master (#66)
by Vladimir
02:51
created

Compiler::compilePageView()   B

Complexity

Conditions 5
Paths 11

Size

Total Lines 39
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6.4222

Importance

Changes 0
Metric Value
dl 0
loc 39
ccs 16
cts 26
cp 0.6153
rs 8.439
c 0
b 0
f 0
cc 5
eloc 26
nc 11
nop 1
crap 6.4222
1
<?php
2
3
/**
4
 * @copyright 2018 Vladimir Jimenez
5
 * @license   https://github.com/stakx-io/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx;
9
10
use allejo\stakx\Command\BuildableCommand;
11
use allejo\stakx\Document\BasePageView;
12
use allejo\stakx\Document\ContentItem;
13
use allejo\stakx\Document\DynamicPageView;
14
use allejo\stakx\Document\PermalinkDocument;
15
use allejo\stakx\Document\RepeaterPageView;
16
use allejo\stakx\Document\StaticPageView;
17
use allejo\stakx\Document\TemplateReadyDocument;
18
use allejo\stakx\Exception\FileAwareException;
19
use allejo\stakx\Filesystem\FilesystemLoader as fs;
20
use allejo\stakx\Filesystem\FilesystemPath;
21
use allejo\stakx\Filesystem\Folder;
22
use allejo\stakx\FrontMatter\ExpandedValue;
23
use allejo\stakx\Manager\PageManager;
24
use allejo\stakx\Manager\ThemeManager;
25
use allejo\stakx\Templating\TemplateBridgeInterface;
26
use allejo\stakx\Templating\TemplateErrorInterface;
27
use allejo\stakx\Templating\TemplateInterface;
28
use Psr\Log\LoggerInterface;
29
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
30
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
31
32
/**
33
 * This class takes care of rendering the Twig body of PageViews with the respective information and it also takes care
34
 * of writing the rendered Twig to the filesystem.
35
 *
36
 * @internal
37
 *
38
 * @since 0.1.1
39
 */
40
class Compiler
41
{
42
    /** @var string|false */
43
    private $redirectTemplate;
44
45
    /** @var BasePageView[][] */
46
    private $importDependencies;
47
48
    /**
49
     * Any time a PageView extends another template, that relationship is stored in this array. This is necessary so
50
     * when watching a website, we can rebuild the necessary PageViews when these base templates change.
51
     *
52
     * ```
53
     * array['_layouts/base.html.twig'] = &PageView;
54
     * ```
55
     *
56
     * @var TemplateInterface[]
57
     */
58
    private $templateDependencies;
59
60
    /**
61
     * All of the PageViews handled by this Compiler instance indexed by their file paths relative to the site root.
62
     *
63
     * ```
64
     * array['_pages/index.html.twig'] = &PageView;
65
     * ```
66
     *
67
     * @var BasePageView[]
68
     */
69
    private $pageViewsFlattened;
70
71
    /** @var string[] */
72
    private $templateMapping;
73
74
    /** @var Folder */
75
    private $folder;
76
77
    /** @var string */
78
    private $theme;
79
80
    private $templateBridge;
81
    private $pageManager;
82
    private $eventDispatcher;
83
    private $configuration;
84
85 12
    public function __construct(TemplateBridgeInterface $templateBridge, Configuration $configuration, PageManager $pageManager, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger)
86
    {
87 12
        $this->templateBridge = $templateBridge;
88 12
        $this->theme = '';
89 12
        $this->pageManager = $pageManager;
90 12
        $this->eventDispatcher = $eventDispatcher;
91 12
        $this->logger = $logger;
0 ignored issues
show
Bug introduced by
The property logger does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
92 12
        $this->configuration = $configuration;
93
94 12
        $this->pageViewsFlattened = &$pageManager->getPageViewsFlattened();
95 12
        $this->redirectTemplate = $this->configuration->getRedirectTemplate();
96 12
    }
97
98
    /**
99
     * @param Folder $folder
100
     */
101 12
    public function setTargetFolder(Folder $folder)
102
    {
103 12
        $this->folder = $folder;
104 12
    }
105
106
    /**
107
     * @param string $themeName
108
     */
109
    public function setThemeName($themeName)
110
    {
111
        $this->theme = $themeName;
112
    }
113
114
    ///
115
    // Twig parent templates
116
    ///
117
118
    public function isImportDependency($filePath)
119
    {
120
        return isset($this->importDependencies[$filePath]);
121
    }
122
123
    /**
124
     * Check whether a given file path is used as a parent template by a PageView.
125
     *
126
     * @param string $filePath
127
     *
128
     * @return bool
129
     */
130
    public function isParentTemplate($filePath)
131
    {
132
        return isset($this->templateDependencies[$filePath]);
133
    }
134
135
    /**
136
     * Rebuild all of the PageViews that used a given template as a parent.
137
     *
138
     * @param string $filePath The file path to the parent Twig template
139
     */
140
    public function refreshParent($filePath)
141
    {
142
        foreach ($this->templateDependencies[$filePath] as &$parentTemplate)
0 ignored issues
show
Bug introduced by
The expression $this->templateDependencies[$filePath] of type object<allejo\stakx\Templating\TemplateInterface> is not traversable.
Loading history...
143
        {
144
            $this->compilePageView($parentTemplate);
145
        }
146
    }
147
148
    public function getTemplateMappings()
149
    {
150
        return $this->templateMapping;
151
    }
152
153
    ///
154
    // IO Functionality
155
    ///
156
157
    /**
158
     * Compile all of the PageViews registered with the compiler.
159
     *
160
     * @since 0.1.0
161
     */
162 12
    public function compileAll()
163
    {
164 12
        foreach ($this->pageViewsFlattened as &$pageView)
165
        {
166 12
            $this->compilePageView($pageView);
167
        }
168 12
    }
169
170
    public function compileImportDependencies($filePath)
171
    {
172
        foreach ($this->importDependencies[$filePath] as &$dependent)
173
        {
174
            $this->compilePageView($dependent);
175
        }
176
    }
177
178
    public function compileSome(array $filter = [])
179
    {
180
        /** @var BasePageView $pageView */
181
        foreach ($this->pageViewsFlattened as &$pageView)
182
        {
183
            $ns = $filter['namespace'];
184
185
            if ($pageView->hasDependencyOnCollection($ns, $filter['dependency']) ||
186
                $pageView->hasDependencyOnCollection($ns, null)
187
            ) {
188
                $this->compilePageView($pageView);
189
            }
190
        }
191
    }
192
193
    /**
194
     * Compile an individual PageView from a given path.
195
     *
196
     * @param string $filePath
197
     *
198
     * @throws FileNotFoundException when the given file path isn't tracked by the Compiler
199
     */
200
    public function compilePageViewFromPath($filePath)
201
    {
202
        if (!isset($this->pageViewsFlattened[$filePath]))
203
        {
204
            throw new FileNotFoundException(sprintf('The "%s" PageView is not being tracked by this compiler.', $filePath));
205
        }
206
207
        $this->compilePageView($this->pageViewsFlattened[$filePath]);
208
    }
209
210
    /**
211
     * Compile an individual PageView item.
212
     *
213
     * This function will take care of determining *how* to treat the PageView and write the compiled output to a the
214
     * respective target file.
215
     *
216
     * @param DynamicPageView|RepeaterPageView|StaticPageView $pageView The PageView that needs to be compiled
0 ignored issues
show
Documentation introduced by
Should the type for parameter $pageView not be BasePageView?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
217
     *
218
     * @since 0.1.1
219
     */
220 12
    public function compilePageView(BasePageView &$pageView)
221
    {
222 12
        $this->templateBridge->setGlobalVariable('__currentTemplate', $pageView->getAbsoluteFilePath());
223 12
        $this->logger->debug('Compiling {type} PageView: {pageview}', [
224 12
            'pageview' => $pageView->getRelativeFilePath(),
225 12
            'type' => $pageView->getType(),
226
        ]);
227
228
        try
229
        {
230 12
            switch ($pageView->getType())
231
            {
232 12
                case BasePageView::STATIC_TYPE:
233 10
                    $this->compileStaticPageView($pageView);
0 ignored issues
show
Compatibility introduced by
$pageView of type object<allejo\stakx\Document\BasePageView> is not a sub-type of object<allejo\stakx\Document\StaticPageView>. It seems like you assume a child class of the class allejo\stakx\Document\BasePageView to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
234 10
                    $this->compileStandardRedirects($pageView);
235 10
                    break;
236
237 3
                case BasePageView::DYNAMIC_TYPE:
238
                    $this->compileDynamicPageViews($pageView);
0 ignored issues
show
Compatibility introduced by
$pageView of type object<allejo\stakx\Document\BasePageView> is not a sub-type of object<allejo\stakx\Document\DynamicPageView>. It seems like you assume a child class of the class allejo\stakx\Document\BasePageView to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
239
                    $this->compileStandardRedirects($pageView);
240
                    break;
241
242 3
                case BasePageView::REPEATER_TYPE:
243 3
                    $this->compileRepeaterPageViews($pageView);
0 ignored issues
show
Compatibility introduced by
$pageView of type object<allejo\stakx\Document\BasePageView> is not a sub-type of object<allejo\stakx\Document\RepeaterPageView>. It seems like you assume a child class of the class allejo\stakx\Document\BasePageView to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
244 3
                    $this->compileExpandedRedirects($pageView);
245 12
                    break;
246
            }
247
        }
248
        catch (TemplateErrorInterface $e)
249
        {
250
            throw new FileAwareException(
251
                $e->getMessage(),
252
                $e->getCode(),
253
                $e,
254
                $pageView->getRelativeFilePath(),
255
                $e->getTemplateLine() + $pageView->getLineOffset()
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface allejo\stakx\Document\PermalinkDocument as the method getLineOffset() does only exist in the following implementations of said interface: allejo\stakx\Document\BasePageView, allejo\stakx\Document\ContentItem, allejo\stakx\Document\DynamicPageView, allejo\stakx\Document\PermalinkFrontMatterDocument, allejo\stakx\Document\RepeaterPageView, allejo\stakx\Document\StaticPageView.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
256
            );
257
        }
258 12
    }
259
260
    /**
261
     * Write the compiled output for a static PageView.
262
     *
263
     * @since 0.1.1
264
     *
265
     * @throws TemplateErrorInterface
266
     */
267 10
    private function compileStaticPageView(StaticPageView &$pageView)
268
    {
269 10
        $pageView->compile();
270
271 10
        $targetFile = $pageView->getTargetFile();
272 10
        $output = $this->renderStaticPageView($pageView);
273
274 10
        $this->logger->notice('Writing file: {file}', ['file' => $targetFile]);
275 10
        $this->folder->writeFile($targetFile, $output);
276 10
    }
277
278
    /**
279
     * Write the compiled output for a dynamic PageView.
280
     *
281
     * @param DynamicPageView $pageView
282
     *
283
     * @since 0.1.1
284
     *
285
     * @throws TemplateErrorInterface
286
     */
287
    private function compileDynamicPageViews(DynamicPageView &$pageView)
288
    {
289
        $contentItems = $pageView->getCollectableItems();
290
        $template = $this->createTwigTemplate($pageView);
291
292
        foreach ($contentItems as &$contentItem)
293
        {
294
            if ($contentItem->isDraft() && !Service::getParameter(BuildableCommand::USE_DRAFTS))
295
            {
296
                $this->logger->debug('{file}: marked as a draft', [
297
                    'file' => $contentItem->getRelativeFilePath(),
298
                ]);
299
300
                continue;
301
            }
302
303
            $targetFile = $contentItem->getTargetFile();
304
            $output = $this->renderDynamicPageView($template, $contentItem);
0 ignored issues
show
Documentation introduced by
$contentItem is of type object<allejo\stakx\Document\CollectableItem>, but the function expects a object<allejo\stakx\Docu...\TemplateReadyDocument>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
305
306
            $this->logger->notice('Writing file: {file}', ['file' => $targetFile]);
307
            $this->folder->writeFile($targetFile, $output);
308
309
            $this->compileStandardRedirects($contentItem);
0 ignored issues
show
Documentation introduced by
$contentItem is of type object<allejo\stakx\Docu...\TemplateReadyDocument>, but the function expects a object<allejo\stakx\Document\PermalinkDocument>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
310
        }
311
    }
312
313
    /**
314
     * Write the compiled output for a repeater PageView.
315
     *
316
     * @param RepeaterPageView $pageView
317
     *
318
     * @since 0.1.1
319
     *
320
     * @throws TemplateErrorInterface
321
     */
322 3
    private function compileRepeaterPageViews(RepeaterPageView &$pageView)
323
    {
324 3
        $pageView->rewindPermalink();
325
326 3
        $template = $this->createTwigTemplate($pageView);
327 3
        $permalinks = $pageView->getRepeaterPermalinks();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class allejo\stakx\Document\BasePageView as the method getRepeaterPermalinks() does only exist in the following sub-classes of allejo\stakx\Document\BasePageView: allejo\stakx\Document\RepeaterPageView. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
328
329 3
        foreach ($permalinks as $permalink)
330
        {
331 3
            $pageView->bumpPermalink();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class allejo\stakx\Document\BasePageView as the method bumpPermalink() does only exist in the following sub-classes of allejo\stakx\Document\BasePageView: allejo\stakx\Document\RepeaterPageView. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
332 3
            $targetFile = $pageView->getTargetFile();
333 3
            $output = $this->renderRepeaterPageView($template, $pageView, $permalink);
0 ignored issues
show
Compatibility introduced by
$pageView of type object<allejo\stakx\Document\BasePageView> is not a sub-type of object<allejo\stakx\Document\RepeaterPageView>. It seems like you assume a child class of the class allejo\stakx\Document\BasePageView to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
334
335 3
            $this->logger->notice('Writing repeater file: {file}', ['file' => $targetFile]);
336 3
            $this->folder->writeFile($targetFile, $output);
337
        }
338 3
    }
339
340
    /**
341
     * @deprecated
342
     *
343
     * @todo This function needs to be rewritten or removed. Something
344
     *
345
     * @param ContentItem $contentItem
346
     */
347
    public function compileContentItem(ContentItem &$contentItem)
348
    {
349
        $pageView = &$contentItem->getPageView();
0 ignored issues
show
Bug introduced by
The method getPageView() does not seem to exist on object<allejo\stakx\Document\ContentItem>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
350
        $template = $this->createTwigTemplate($pageView);
351
352
        $this->templateBridge->setGlobalVariable('__currentTemplate', $pageView->getAbsoluteFilePath());
353
        $contentItem->evaluateFrontMatter($pageView->getFrontMatter(false));
354
355
        $targetFile = $contentItem->getTargetFile();
356
        $output = $this->renderDynamicPageView($template, $contentItem);
357
358
        $this->logger->notice('Writing file: {file}', ['file' => $targetFile]);
359
        $this->folder->writeFile($targetFile, $output);
360
    }
361
362
    ///
363
    // Redirect handling
364
    ///
365
366
    /**
367
     * Write redirects for standard redirects.
368
     *
369
     * @throws TemplateErrorInterface
370
     *
371
     * @since 0.1.1
372
     */
373 10
    private function compileStandardRedirects(PermalinkDocument &$pageView)
374
    {
375 10
        $redirects = $pageView->getRedirects();
376
377 10 View Code Duplication
        foreach ($redirects as $redirect)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
378
        {
379 1
            $redirectPageView = BasePageView::createRedirect(
380 1
                $redirect,
381 1
                $pageView->getPermalink(),
382 1
                $this->redirectTemplate
383
            );
384 1
            $redirectPageView->evaluateFrontMatter([], [
385 1
                'site' => $this->configuration->getConfiguration(),
386
            ]);
387
388 1
            $this->compileStaticPageView($redirectPageView);
389
        }
390 10
    }
391
392
    /**
393
     * Write redirects for expanded redirects.
394
     *
395
     * @param RepeaterPageView $pageView
396
     *
397
     * @since 0.1.1
398
     */
399 3
    private function compileExpandedRedirects(RepeaterPageView &$pageView)
400
    {
401 3
        $permalinks = $pageView->getRepeaterPermalinks();
402
403
        /** @var ExpandedValue[] $repeaterRedirect */
404 3
        foreach ($pageView->getRepeaterRedirects() as $repeaterRedirect)
405
        {
406
            /**
407
             * @var int
408
             * @var ExpandedValue $redirect
409
             */
410 1 View Code Duplication
            foreach ($repeaterRedirect as $index => $redirect)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
411
            {
412 1
                $redirectPageView = BasePageView::createRedirect(
413 1
                    $redirect->getEvaluated(),
414 1
                    $permalinks[$index]->getEvaluated(),
415 1
                    $this->redirectTemplate
416
                );
417 1
                $redirectPageView->evaluateFrontMatter([], [
418 1
                    'site' => $this->configuration->getConfiguration(),
419
                ]);
420
421 1
                $this->compilePageView($redirectPageView);
422
            }
423
        }
424 3
    }
425
426
    ///
427
    // Twig Functionality
428
    ///
429
430
    /**
431
     * Get the compiled HTML for a specific iteration of a repeater PageView.
432
     *
433
     * @param TemplateInterface $template
434
     * @param RepeaterPageView  $pageView
435
     * @param ExpandedValue     $expandedValue
436
     *
437
     * @since  0.1.1
438
     *
439
     * @return string
440
     */
441 3
    private function renderRepeaterPageView(TemplateInterface &$template, RepeaterPageView &$pageView, ExpandedValue &$expandedValue)
442
    {
443 3
        $pageView->evaluateFrontMatter([
444 3
            'permalink' => $expandedValue->getEvaluated(),
445 3
            'iterators' => $expandedValue->getIterators(),
446
        ]);
447
448
        return $template
449 3
            ->render([
450 3
                'this' => $pageView->createJail(),
451
            ])
452
        ;
453
    }
454
455
    /**
456
     * Get the compiled HTML for a specific ContentItem.
457
     *
458
     * @since  0.1.1
459
     *
460
     * @return string
461
     */
462
    private function renderDynamicPageView(TemplateInterface &$template, TemplateReadyDocument &$twigItem)
463
    {
464
        return $template
465
            ->render([
466
                'this' => $twigItem->createJail(),
467
            ])
468
        ;
469
    }
470
471
    /**
472
     * Get the compiled HTML for a static PageView.
473
     *
474
     * @since  0.1.1
475
     *
476
     * @throws TemplateErrorInterface
477
     *
478
     * @return string
479
     */
480 10
    private function renderStaticPageView(StaticPageView &$pageView)
481
    {
482
        return $this
483 10
            ->createTwigTemplate($pageView)
484 10
            ->render([
485 10
                'this' => $pageView->createJail(),
0 ignored issues
show
Bug introduced by
The method createJail() does not exist on allejo\stakx\Document\BasePageView. Did you maybe mean create()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
486
            ])
487
        ;
488
    }
489
490
    /**
491
     * Create a Twig template that just needs an array to render.
492
     *
493
     * @since  0.1.1
494
     *
495
     * @throws TemplateErrorInterface
496
     *
497
     * @return TemplateInterface
498
     */
499 12
    private function createTwigTemplate(BasePageView &$pageView)
500
    {
501
        try
502
        {
503 12
            $template = $this->templateBridge->createTemplate($pageView->getContent());
504
505 12
            $this->templateMapping[$template->getTemplateName()] = $pageView->getRelativeFilePath();
506
507 12
            if (Service::getParameter(BuildableCommand::WATCHING))
508
            {
509
                // Keep track of import dependencies
510
                foreach ($pageView->getImportDependencies() as $dependency)
511
                {
512
                    $this->importDependencies[$dependency][$pageView->getBasename()] = &$pageView;
513
                }
514
515
                // Keep track of Twig extends'
516
                $parent = $template->getParentTemplate();
517
518
                while ($parent !== false)
519
                {
520
                    // Replace the '@theme' namespace in Twig with the path to the theme folder and create a FilesystemPath object from the given path
521
                    $path = str_replace('@theme', fs::appendPath(ThemeManager::THEME_FOLDER, $this->theme), $parent->getTemplateName());
522
                    $path = new FilesystemPath($path);
523
524
                    $this->templateDependencies[(string)$path][$pageView->getBasename()] = &$pageView;
525
526
                    $parent = $parent->getParentTemplate();
527
                }
528
            }
529
530 12
            return $template;
531
        }
532
        catch (TemplateErrorInterface $e)
533
        {
534
            $e
535
                ->setTemplateLine($e->getTemplateLine() + $pageView->getLineOffset())
536
                ->setContent($pageView->getContent())
537
                ->setName($pageView->getRelativeFilePath())
538
                ->setRelativeFilePath($pageView->getRelativeFilePath())
539
                ->buildException()
540
            ;
541
542
            throw $e;
543
        }
544
    }
545
}
546