Completed
Pull Request — master (#62)
by Vladimir
02:42
created

Compiler   C

Complexity

Total Complexity 44

Size/Duplication

Total Lines 503
Duplicated Lines 5.17 %

Coupling/Cohesion

Components 1
Dependencies 19

Test Coverage

Coverage 54.77%

Importance

Changes 0
Metric Value
wmc 44
lcom 1
cbo 19
dl 26
loc 503
ccs 86
cts 157
cp 0.5477
rs 5.5062
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A setTargetFolder() 0 4 1
A setThemeName() 0 4 1
A isImportDependency() 0 4 1
A isParentTemplate() 0 4 1
A refreshParent() 0 7 2
A getTemplateMappings() 0 4 1
A compileAll() 0 7 2
A compileImportDependencies() 0 7 2
A compileSome() 0 14 4
A compilePageViewFromPath() 0 9 2
B compilePageView() 0 39 5
A compileStaticPageView() 0 10 1
B compileDynamicPageViews() 0 25 4
A compileRepeaterPageViews() 0 17 2
A compileContentItem() 0 14 1
A compileStandardRedirects() 13 18 2
B compileExpandedRedirects() 13 26 3
A renderRepeaterPageView() 0 12 1
A renderDynamicPageView() 0 7 1
A renderStaticPageView() 0 8 1
B createTwigTemplate() 0 46 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Compiler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Compiler, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/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\FrontMatter\ExpandedValue;
22
use allejo\stakx\Manager\PageManager;
23
use allejo\stakx\Manager\ThemeManager;
24
use allejo\stakx\Filesystem\Folder;
25
use allejo\stakx\System\FilePath;
26
use allejo\stakx\Templating\TemplateBridgeInterface;
27
use allejo\stakx\Templating\TemplateErrorInterface;
28
use allejo\stakx\Templating\TemplateInterface;
29
use Psr\Log\LoggerInterface;
30
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
31
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
32
33
/**
34
 * This class takes care of rendering the Twig body of PageViews with the respective information and it also takes care
35
 * of writing the rendered Twig to the filesystem.
36
 *
37
 * @internal
38
 *
39
 * @since 0.1.1
40
 */
41
class Compiler
42
{
43
    /** @var string|false */
44
    private $redirectTemplate;
45
46
    /** @var BasePageView[][] */
47
    private $importDependencies;
48
49
    /**
50
     * Any time a PageView extends another template, that relationship is stored in this array. This is necessary so
51
     * when watching a website, we can rebuild the necessary PageViews when these base templates change.
52
     *
53
     * ```
54
     * array['_layouts/base.html.twig'] = &PageView;
55
     * ```
56
     *
57
     * @var TemplateInterface[]
58
     */
59
    private $templateDependencies;
60
61
    /**
62
     * All of the PageViews handled by this Compiler instance indexed by their file paths relative to the site root.
63
     *
64
     * ```
65
     * array['_pages/index.html.twig'] = &PageView;
66
     * ```
67
     *
68
     * @var BasePageView[]
69
     */
70
    private $pageViewsFlattened;
71
72
    /** @var string[] */
73
    private $templateMapping;
74
75
    /** @var Folder */
76
    private $folder;
77
78
    /** @var string */
79
    private $theme;
80
81
    private $templateBridge;
82
    private $pageManager;
83
    private $eventDispatcher;
84
    private $configuration;
85
86 12
    public function __construct(TemplateBridgeInterface $templateBridge, Configuration $configuration, PageManager $pageManager, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger)
87
    {
88 12
        $this->templateBridge = $templateBridge;
89 12
        $this->theme = '';
90 12
        $this->pageManager = $pageManager;
91 12
        $this->eventDispatcher = $eventDispatcher;
92 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...
93 12
        $this->configuration = $configuration;
94
95 12
        $this->pageViewsFlattened = &$pageManager->getPageViewsFlattened();
96 12
        $this->redirectTemplate = $this->configuration->getRedirectTemplate();
97 12
    }
98
99
    /**
100
     * @param Folder $folder
101
     */
102 12
    public function setTargetFolder(Folder $folder)
103
    {
104 12
        $this->folder = $folder;
105 12
    }
106
107
    /**
108
     * @param string $themeName
109
     */
110
    public function setThemeName($themeName)
111
    {
112
        $this->theme = $themeName;
113
    }
114
115
    ///
116
    // Twig parent templates
117
    ///
118
119
    public function isImportDependency($filePath)
120
    {
121
        return isset($this->importDependencies[$filePath]);
122
    }
123
124
    /**
125
     * Check whether a given file path is used as a parent template by a PageView
126
     *
127
     * @param  string $filePath
128
     *
129
     * @return bool
130
     */
131
    public function isParentTemplate($filePath)
132
    {
133
        return isset($this->templateDependencies[$filePath]);
134
    }
135
136
    /**
137
     * Rebuild all of the PageViews that used a given template as a parent
138
     *
139
     * @param string $filePath The file path to the parent Twig template
140
     */
141
    public function refreshParent($filePath)
142
    {
143
        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...
144
        {
145
            $this->compilePageView($parentTemplate);
146
        }
147
    }
148
149
    public function getTemplateMappings()
150
    {
151
        return $this->templateMapping;
152
    }
153
154
    ///
155
    // IO Functionality
156
    ///
157
158
    /**
159
     * Compile all of the PageViews registered with the compiler.
160
     *
161
     * @since 0.1.0
162
     */
163 12
    public function compileAll()
164
    {
165 12
        foreach ($this->pageViewsFlattened as &$pageView)
166
        {
167 12
            $this->compilePageView($pageView);
168
        }
169 12
    }
170
171
    public function compileImportDependencies($filePath)
172
    {
173
        foreach ($this->importDependencies[$filePath] as &$dependent)
174
        {
175
            $this->compilePageView($dependent);
176
        }
177
    }
178
179
    public function compileSome(array $filter = array())
180
    {
181
        /** @var BasePageView $pageView */
182
        foreach ($this->pageViewsFlattened as &$pageView)
183
        {
184
            $ns = $filter['namespace'];
185
186
            if ($pageView->hasDependencyOnCollection($ns, $filter['dependency']) ||
187
                $pageView->hasDependencyOnCollection($ns, null)
188
            ) {
189
                $this->compilePageView($pageView);
190
            }
191
        }
192
    }
193
194
    /**
195
     * Compile an individual PageView from a given path.
196
     *
197
     * @param string $filePath
198
     *
199
     * @throws FileNotFoundException When the given file path isn't tracked by the Compiler.
200
     */
201
    public function compilePageViewFromPath($filePath)
202
    {
203
        if (!isset($this->pageViewsFlattened[$filePath]))
204
        {
205
            throw new FileNotFoundException(sprintf('The "%s" PageView is not being tracked by this compiler.', $filePath));
206
        }
207
208
        $this->compilePageView($this->pageViewsFlattened[$filePath]);
209
    }
210
211
    /**
212
     * Compile an individual PageView item.
213
     *
214
     * This function will take care of determining *how* to treat the PageView and write the compiled output to a the
215
     * respective target file.
216
     *
217
     * @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...
218
     *
219
     * @since 0.1.1
220
     */
221 12
    public function compilePageView(BasePageView &$pageView)
222
    {
223 12
        $this->templateBridge->setGlobalVariable('__currentTemplate', $pageView->getAbsoluteFilePath());
224 12
        $this->logger->debug('Compiling {type} PageView: {pageview}', array(
225 12
            'pageview' => $pageView->getRelativeFilePath(),
226 12
            'type' => $pageView->getType()
227
        ));
228
229
        try
230
        {
231 12
            switch ($pageView->getType())
232
            {
233
                case BasePageView::STATIC_TYPE:
234 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...
235 10
                    $this->compileStandardRedirects($pageView);
236 10
                    break;
237
238
                case BasePageView::DYNAMIC_TYPE:
239
                    $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...
240
                    $this->compileStandardRedirects($pageView);
241
                    break;
242
243
                case BasePageView::REPEATER_TYPE:
244 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...
245 3
                    $this->compileExpandedRedirects($pageView);
246 12
                    break;
247
            }
248
        }
249
        catch (TemplateErrorInterface $e)
250
        {
251
            throw new FileAwareException(
252
                $e->getMessage(),
253
                $e->getCode(),
254
                $e,
255
                $pageView->getRelativeFilePath(),
256
                $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...
257
            );
258
        }
259 12
    }
260
261
    /**
262
     * Write the compiled output for a static PageView.
263
     *
264
     * @since 0.1.1
265
     *
266
     * @throws TemplateErrorInterface
267
     */
268 10
    private function compileStaticPageView(StaticPageView &$pageView)
269
    {
270 10
        $pageView->compile();
271
272 10
        $targetFile = $pageView->getTargetFile();
273 10
        $output = $this->renderStaticPageView($pageView);
274
275 10
        $this->logger->notice('Writing file: {file}', array('file' => $targetFile));
276 10
        $this->folder->writeFile($targetFile, $output);
277 10
    }
278
279
    /**
280
     * Write the compiled output for a dynamic PageView.
281
     *
282
     * @param DynamicPageView $pageView
283
     *
284
     * @since 0.1.1
285
     *
286
     * @throws TemplateErrorInterface
287
     */
288
    private function compileDynamicPageViews(DynamicPageView &$pageView)
289
    {
290
        $contentItems = $pageView->getCollectableItems();
291
        $template = $this->createTwigTemplate($pageView);
292
293
        foreach ($contentItems as &$contentItem)
294
        {
295
            if ($contentItem->isDraft() && !Service::getParameter(BuildableCommand::USE_DRAFTS))
296
            {
297
                $this->logger->debug('{file}: marked as a draft', array(
298
                    'file' => $contentItem->getRelativeFilePath()
299
                ));
300
301
                continue;
302
            }
303
304
            $targetFile = $contentItem->getTargetFile();
305
            $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...
306
307
            $this->logger->notice('Writing file: {file}', array('file' => $targetFile));
308
            $this->folder->writeFile($targetFile, $output);
309
310
            $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...
311
        }
312
    }
313
314
    /**
315
     * Write the compiled output for a repeater PageView.
316
     *
317
     * @param RepeaterPageView $pageView
318
319
     * @since 0.1.1
320
     *
321
     * @throws TemplateErrorInterface
322
     */
323 3
    private function compileRepeaterPageViews(RepeaterPageView &$pageView)
324
    {
325 3
        $pageView->rewindPermalink();
326
327 3
        $template = $this->createTwigTemplate($pageView);
328 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...
329
330 3
        foreach ($permalinks as $permalink)
331
        {
332 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...
333 3
            $targetFile = $pageView->getTargetFile();
334 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...
335
336 3
            $this->logger->notice('Writing repeater file: {file}', ['file' => $targetFile]);
337 3
            $this->folder->writeFile($targetFile, $output);
338
        }
339 3
    }
340
341
    /**
342
     * @deprecated
343
     *
344
     * @todo This function needs to be rewritten or removed. Something
345
     *
346
     * @param ContentItem $contentItem
347
     */
348
    public function compileContentItem(ContentItem &$contentItem)
349
    {
350
        $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...
351
        $template = $this->createTwigTemplate($pageView);
352
353
        $this->templateBridge->setGlobalVariable('__currentTemplate', $pageView->getAbsoluteFilePath());
354
        $contentItem->evaluateFrontMatter($pageView->getFrontMatter(false));
355
356
        $targetFile = $contentItem->getTargetFile();
357
        $output = $this->renderDynamicPageView($template, $contentItem);
358
359
        $this->logger->notice('Writing file: {file}', array('file' => $targetFile));
360
        $this->folder->writeFile($targetFile, $output);
361
    }
362
363
    ///
364
    // Redirect handling
365
    ///
366
367
    /**
368
     * Write redirects for standard redirects.
369
     *
370
     * @throws TemplateErrorInterface
371
     *
372
     * @since 0.1.1
373
     */
374 10
    private function compileStandardRedirects(PermalinkDocument &$pageView)
375
    {
376 10
        $redirects = $pageView->getRedirects();
377
378 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...
379
        {
380 1
            $redirectPageView = BasePageView::createRedirect(
381 1
                $redirect,
382 1
                $pageView->getPermalink(),
383 1
                $this->redirectTemplate
384
            );
385 1
            $redirectPageView->evaluateFrontMatter([], [
386 1
                'site' => $this->configuration->getConfiguration(),
387
            ]);
388
389 1
            $this->compileStaticPageView($redirectPageView);
390
        }
391 10
    }
392
393
    /**
394
     * Write redirects for expanded redirects.
395
     *
396
     * @param RepeaterPageView $pageView
397
     *
398
     * @since 0.1.1
399
     */
400 3
    private function compileExpandedRedirects(RepeaterPageView &$pageView)
401
    {
402 3
        $permalinks = $pageView->getRepeaterPermalinks();
403
404
        /** @var ExpandedValue[] $repeaterRedirect */
405 3
        foreach ($pageView->getRepeaterRedirects() as $repeaterRedirect)
406
        {
407
            /**
408
             * @var int           $index
409
             * @var ExpandedValue $redirect
410
             */
411 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...
412
            {
413 1
                $redirectPageView = BasePageView::createRedirect(
414 1
                    $redirect->getEvaluated(),
415 1
                    $permalinks[$index]->getEvaluated(),
416 1
                    $this->redirectTemplate
417
                );
418 1
                $redirectPageView->evaluateFrontMatter([], [
419 1
                    'site' => $this->configuration->getConfiguration(),
420
                ]);
421
422 1
                $this->compilePageView($redirectPageView);
423
            }
424
        }
425 3
    }
426
427
    ///
428
    // Twig Functionality
429
    ///
430
431
    /**
432
     * Get the compiled HTML for a specific iteration of a repeater PageView.
433
     *
434
     * @param TemplateInterface $template
435
     * @param RepeaterPageView  $pageView
436
     * @param ExpandedValue     $expandedValue
437
     *
438
     * @since  0.1.1
439
     *
440
     * @return string
441
     */
442 3
    private function renderRepeaterPageView(TemplateInterface &$template, RepeaterPageView &$pageView, ExpandedValue &$expandedValue)
443
    {
444 3
        $pageView->evaluateFrontMatter([
445 3
            'permalink' => $expandedValue->getEvaluated(),
446 3
            'iterators' => $expandedValue->getIterators(),
447
        ]);
448
449
        return $template
450 3
            ->render(array(
451 3
                'this' => $pageView->createJail(),
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(array(
466
                'this' => $twigItem->createJail(),
467
            ));
468
    }
469
470
    /**
471
     * Get the compiled HTML for a static PageView.
472
     *
473
     * @since  0.1.1
474
     *
475
     * @throws TemplateErrorInterface
476
     *
477
     * @return string
478
     */
479 10
    private function renderStaticPageView(StaticPageView &$pageView)
480
    {
481
        return $this
482 10
            ->createTwigTemplate($pageView)
483 10
            ->render(array(
484 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...
485
            ));
486
    }
487
488
    /**
489
     * Create a Twig template that just needs an array to render.
490
     *
491
     * @since  0.1.1
492
     *
493
     * @throws TemplateErrorInterface
494
     *
495
     * @return TemplateInterface
496
     */
497 12
    private function createTwigTemplate(BasePageView &$pageView)
498
    {
499
        try
500
        {
501 12
            $template = $this->templateBridge->createTemplate($pageView->getContent());
502
503 12
            $this->templateMapping[$template->getTemplateName()] = $pageView->getRelativeFilePath();
504
505 12
            if (Service::getParameter(BuildableCommand::WATCHING))
506
            {
507
                // Keep track of import dependencies
508
                foreach ($pageView->getImportDependencies() as $dependency)
509
                {
510
                    $this->importDependencies[$dependency][$pageView->getBasename()] = &$pageView;
511
                }
512
513
                // Keep track of Twig extends'
514
                $parent = $template->getParentTemplate();
515
516
                while ($parent !== false)
517
                {
518
                    // Replace the '@theme' namespace in Twig with the path to the theme folder and create a FilesystemPath object from the given path
519
                    $path = str_replace('@theme', fs::appendPath(ThemeManager::THEME_FOLDER, $this->theme), $parent->getTemplateName());
520
                    $path = new FilesystemPath($path);
521
522
                    $this->templateDependencies[(string)$path][$pageView->getBasename()] = &$pageView;
523
524
                    $parent = $parent->getParentTemplate();
525
                }
526
            }
527
528 12
            return $template;
529
        }
530
        catch (TemplateErrorInterface $e)
531
        {
532
            $e
533
                ->setTemplateLine($e->getTemplateLine() + $pageView->getLineOffset())
534
                ->setContent($pageView->getContent())
535
                ->setName($pageView->getRelativeFilePath())
536
                ->setRelativeFilePath($pageView->getRelativeFilePath())
537
                ->buildException()
538
            ;
539
540
            throw $e;
541
        }
542
    }
543
}
544