Completed
Push — develop ( 667cd2...043012 )
by Vladimir
01:48
created

Compiler::writeToFilesystem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
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\Document\BasePageView;
11
use allejo\stakx\Document\CollectableItem;
12
use allejo\stakx\Document\DynamicPageView;
13
use allejo\stakx\Document\PermalinkDocument;
14
use allejo\stakx\Document\RepeaterPageView;
15
use allejo\stakx\Document\StaticPageView;
16
use allejo\stakx\Document\TemplateReadyDocument;
17
use allejo\stakx\Event\CompilerPostRenderDynamicPageView;
18
use allejo\stakx\Event\CompilerPostRenderRepeaterPageView;
19
use allejo\stakx\Event\CompilerPostRenderStaticPageView;
20
use allejo\stakx\Event\CompilerPreRenderDynamicPageView;
21
use allejo\stakx\Event\CompilerPreRenderRepeaterPageView;
22
use allejo\stakx\Event\CompilerPreRenderStaticPageView;
23
use allejo\stakx\Event\CompilerTemplateCreation;
24
use allejo\stakx\Event\RedirectPreOutput;
25
use allejo\stakx\Exception\FileAwareException;
26
use allejo\stakx\Filesystem\WritableFolder;
27
use allejo\stakx\FrontMatter\ExpandedValue;
28
use allejo\stakx\Manager\CollectionManager;
29
use allejo\stakx\Manager\DataManager;
30
use allejo\stakx\Manager\MenuManager;
31
use allejo\stakx\Manager\PageManager;
32
use allejo\stakx\Templating\TemplateBridgeInterface;
33
use allejo\stakx\Templating\TemplateErrorInterface;
34
use allejo\stakx\Templating\TemplateInterface;
35
use Psr\Log\LoggerInterface;
36
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
37
38
/**
39
 * This class takes care of rendering the Twig body of PageViews with the respective information and it also takes care
40
 * of writing the rendered Twig to the filesystem.
41
 *
42
 * @since 0.1.1
43
 */
44
class Compiler
45
{
46
    /** @var string|false */
47
    private $redirectTemplate;
48
49
    /**
50
     * All of the PageViews handled by this Compiler instance indexed by their file paths relative to the site root.
51
     *
52
     * ```
53
     * array['_pages/index.html.twig'] = &PageView;
54
     * ```
55
     *
56
     * @var BasePageView[]
57
     */
58
    private $pageViewsFlattened;
59
60
    /** @var string[] */
61
    private $templateMapping;
62
63
    /** @var WritableFolder */
64
    private $folder;
65
66
    /** @var string */
67
    private $theme;
68
69
    private $templateBridge;
70
    private $pageManager;
71
    private $eventDispatcher;
72
    private $configuration;
73
    private $logger;
74
75 12
    public function __construct(
76
        TemplateBridgeInterface $templateBridge,
77
        Configuration $configuration,
78
        CollectionManager $collectionManager,
79
        DataManager $dataManager,
80
        MenuManager $menuManager,
81
        PageManager $pageManager,
82
        RedirectMapper $redirectMapper,
83
        EventDispatcherInterface $eventDispatcher,
84
        LoggerInterface $logger
85
    ) {
86 12
        $this->templateBridge = $templateBridge;
87 12
        $this->theme = '';
88 12
        $this->pageManager = $pageManager;
89 12
        $this->eventDispatcher = $eventDispatcher;
90 12
        $this->logger = $logger;
91 12
        $this->configuration = $configuration;
92
93 12
        $this->pageViewsFlattened = &$pageManager->getPageViewsFlattened();
94 12
        $this->redirectTemplate = $this->configuration->getRedirectTemplate();
95
96
        // Global variables maintained by stakx
97 12
        $this->templateBridge->setGlobalVariable('site', $configuration->getConfiguration());
98 12
        $this->templateBridge->setGlobalVariable('data', $dataManager->getJailedDataItems());
99 12
        $this->templateBridge->setGlobalVariable('collections', $collectionManager->getJailedCollections());
100 12
        $this->templateBridge->setGlobalVariable('menu', $menuManager->getSiteMenu());
101 12
        $this->templateBridge->setGlobalVariable('pages', $pageManager->getJailedStaticPageViews());
102 12
        $this->templateBridge->setGlobalVariable('repeaters', $pageManager->getJailedRepeaterPageViews());
103 12
        $this->templateBridge->setGlobalVariable('redirects', $redirectMapper->getRedirects());
104 12
    }
105
106
    /**
107
     * @param WritableFolder $folder
108
     */
109 12
    public function setTargetFolder(WritableFolder $folder)
110
    {
111 12
        $this->folder = $folder;
112 12
    }
113
114
    /**
115
     * @param string $themeName
116
     */
117
    public function setThemeName($themeName)
118
    {
119
        $this->theme = $themeName;
120
    }
121
122
    ///
123
    // Twig parent templates
124
    ///
125
126
    public function getTemplateBridge()
127
    {
128
        return $this->templateBridge;
129
    }
130
131
    public function getTemplateMappings()
132
    {
133
        return $this->templateMapping;
134
    }
135
136
    ///
137
    // Rendering HTML Functionality
138
    ///
139
140
    /**
141
     * Get the HTML for a Static PageView.
142
     *
143
     * This function just **renders** the HTML but does not write it to the filesystem. Use `compilePageView()` for that
144
     * instead.
145
     *
146
     * @param StaticPageView $pageView
147
     *
148
     * @throws TemplateErrorInterface
149
     *
150
     * @return string the HTML for a Static PageView
151
     */
152 10
    public function renderStaticPageView(StaticPageView $pageView)
153
    {
154 10
        $pageView->compile();
155
156 10
        return $this->buildStaticPageViewHTML($pageView);
157
    }
158
159
    /**
160
     * Get the HTML for a Dynamic PageView and ContentItem.
161
     *
162
     * This function just **renders** the HTML but does not write it to the filesystem. Use `compileDynamicPageView()`
163
     * for that instead.
164
     *
165
     * @param DynamicPageView       $pageView
166
     * @param TemplateReadyDocument $contentItem
167
     *
168
     * @throws TemplateErrorInterface
169
     *
170
     * @return string
171
     */
172
    public function renderDynamicPageView(DynamicPageView $pageView, TemplateReadyDocument $contentItem)
173
    {
174
        $template = $this->createTwigTemplate($pageView);
175
176
        return $this->buildDynamicPageViewHTML($template, $contentItem);
177
    }
178
179
    /**
180
     * Get the HTML for a Repeater PageView.
181
     *
182
     * @param RepeaterPageView $pageView
183
     * @param ExpandedValue    $expandedValue
184
     *
185
     * @throws TemplateErrorInterface
186
     *
187
     * @return string
188
     */
189
    public function renderRepeaterPageView(RepeaterPageView $pageView, ExpandedValue $expandedValue)
190
    {
191
        $template = $this->createTwigTemplate($pageView);
192
193
        return $this->buildRepeaterPageViewHTML($template, $pageView, $expandedValue);
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...
194
    }
195
196
    ///
197
    // IO Functionality
198
    ///
199
200
    /**
201
     * Compile all of the PageViews registered with the compiler.
202
     *
203
     * @since 0.1.0
204
     */
205 12
    public function compileAll()
206
    {
207 12
        foreach ($this->pageViewsFlattened as &$pageView)
208
        {
209 12
            $this->compilePageView($pageView);
210
        }
211 12
    }
212
213
    /**
214
     * Compile an individual PageView item.
215
     *
216
     * This function will take care of determining *how* to treat the PageView and write the compiled output to a the
217
     * respective target file.
218
     *
219
     * @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...
220
     *
221
     * @since 0.1.1
222
     */
223 12
    public function compilePageView(BasePageView &$pageView)
224
    {
225 12
        Service::setOption('currentTemplate', $pageView->getAbsoluteFilePath());
226 12
        $this->logger->debug('Compiling {type} PageView: {pageview}', [
227 12
            'pageview' => $pageView->getRelativeFilePath(),
228 12
            'type' => $pageView->getType(),
229
        ]);
230
231
        try
232
        {
233 12
            switch ($pageView->getType())
234
            {
235
                case BasePageView::STATIC_TYPE:
236 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...
237 10
                    $this->compileStandardRedirects($pageView);
238 10
                    break;
239
240
                case BasePageView::DYNAMIC_TYPE:
241
                    $this->compileDynamicPageView($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...
242
                    $this->compileStandardRedirects($pageView);
243
                    break;
244
245
                case BasePageView::REPEATER_TYPE:
246 3
                    $this->compileRepeaterPageView($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...
247 3
                    $this->compileExpandedRedirects($pageView);
248 12
                    break;
249
            }
250
        }
251
        catch (TemplateErrorInterface $e)
252
        {
253
            throw new FileAwareException(
254
                $e->getMessage(),
255
                $e->getCode(),
256
                $e,
257
                $pageView->getRelativeFilePath(),
258
                $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...
259
            );
260
        }
261 12
    }
262
263
    /**
264
     * Write the compiled output for a static PageView.
265
     *
266
     * @since 0.1.1
267
     *
268
     * @throws TemplateErrorInterface
269
     */
270 10
    private function compileStaticPageView(StaticPageView &$pageView)
271
    {
272 10
        $this->writeToFilesystem(
273 10
            $pageView->getTargetFile(),
274 10
            $this->renderStaticPageView($pageView),
275 10
            BasePageView::STATIC_TYPE
276
        );
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 compileDynamicPageView(DynamicPageView &$pageView)
289
    {
290
        $contentItems = $pageView->getCollectableItems();
291
        $template = $this->createTwigTemplate($pageView);
292
293
        foreach ($contentItems as &$contentItem)
294
        {
295
            if ($contentItem->isDraft() && !Service::hasRunTimeFlag(RuntimeStatus::USING_DRAFTS))
296
            {
297
                $this->logger->debug('{file}: marked as a draft', [
298
                    'file' => $contentItem->getRelativeFilePath(),
299
                ]);
300
301
                continue;
302
            }
303
304
            $this->writeToFilesystem(
305
                $contentItem->getTargetFile(),
306
                $this->buildDynamicPageViewHTML($template, $contentItem),
307
                BasePageView::DYNAMIC_TYPE
308
            );
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 compileRepeaterPageView(RepeaterPageView &$pageView)
324
    {
325 3
        $template = $this->createTwigTemplate($pageView);
326 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...
327
328 3
        foreach ($permalinks as $permalink)
329
        {
330 3
            $this->writeToFilesystem(
331 3
                $pageView->getTargetFile($permalink->getEvaluated()),
332 3
                $this->buildRepeaterPageViewHTML($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...
333 3
                BasePageView::REPEATER_TYPE
334
            );
335
        }
336 3
    }
337
338
    /**
339
     * Write the given $output to the $targetFile as a $fileType PageView.
340
     *
341
     * @param string $targetFile
342
     * @param string $output
343
     * @param string $fileType
344
     */
345 12
    private function writeToFilesystem($targetFile, $output, $fileType)
346
    {
347 12
        $this->logger->notice('Writing {type} PageView file: {file}', [
348 12
            'type' => $fileType,
349 12
            'file' => $targetFile,
350
        ]);
351 12
        $this->folder->writeFile($targetFile, $output);
352 12
    }
353
354
    ///
355
    // Redirect handling
356
    ///
357
358
    /**
359
     * Write redirects for standard redirects.
360
     *
361
     * @throws TemplateErrorInterface
362
     *
363
     * @since 0.1.1
364
     */
365 10
    private function compileStandardRedirects(PermalinkDocument &$pageView)
366
    {
367 10
        $redirects = $pageView->getRedirects();
368
369 10
        foreach ($redirects as $redirect)
370
        {
371 1
            $redirectPageView = BasePageView::createRedirect(
372 1
                $redirect,
373 1
                $pageView->getPermalink(),
374 1
                $this->redirectTemplate
375
            );
376 1
            $redirectPageView->evaluateFrontMatter([], [
377 1
                'site' => $this->configuration->getConfiguration(),
378
            ]);
379
380 1
            $redirectEvent = new RedirectPreOutput(
381 1
                $redirect,
382 1
                $pageView->getPermalink(),
383 1
                $pageView,
0 ignored issues
show
Compatibility introduced by
$pageView of type object<allejo\stakx\Document\PermalinkDocument> is not a sub-type of object<allejo\stakx\Document\BasePageView>. It seems like you assume a concrete implementation of the interface allejo\stakx\Document\PermalinkDocument 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...
384 1
                $redirectPageView
385
            );
386 1
            $this->eventDispatcher->dispatch(RedirectPreOutput::NAME, $redirectEvent);
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
            foreach ($repeaterRedirect as $index => $redirect)
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
                $redirectEvent = new RedirectPreOutput(
422 1
                    $redirect->getEvaluated(),
423 1
                    $permalinks[$index]->getEvaluated(),
424 1
                    $pageView,
425 1
                    $redirectPageView
426
                );
427 1
                $this->eventDispatcher->dispatch(RedirectPreOutput::NAME, $redirectEvent);
428
429 1
                $this->compilePageView($redirectPageView);
430
            }
431
        }
432 3
    }
433
434
    ///
435
    // Twig Functionality
436
    ///
437
438
    /**
439
     * Get the compiled HTML for a specific iteration of a repeater PageView.
440
     *
441
     * @param TemplateInterface $template
442
     * @param RepeaterPageView  $pageView
443
     * @param ExpandedValue     $expandedValue
444
     *
445
     * @since  0.1.1
446
     *
447
     * @return string
448
     */
449 3
    private function buildRepeaterPageViewHTML(TemplateInterface &$template, RepeaterPageView &$pageView, ExpandedValue &$expandedValue)
450
    {
451
        $defaultContext = [
452 3
            'this' => $pageView->createJail(),
453
        ];
454
455 3
        $pageView->evaluateFrontMatter([
456 3
            'permalink' => $expandedValue->getEvaluated(),
457 3
            'iterators' => $expandedValue->getIterators(),
458
        ]);
459
460 3
        $preEvent = new CompilerPreRenderRepeaterPageView($pageView, $expandedValue);
461 3
        $this->eventDispatcher->dispatch(CompilerPreRenderRepeaterPageView::NAME, $preEvent);
462
463 3
        $context = array_merge($preEvent->getCustomVariables(), $defaultContext);
464
        $output = $template
465 3
            ->render($context)
466
        ;
467
468 3
        $postEvent = new CompilerPostRenderRepeaterPageView($pageView, $expandedValue, $output);
469 3
        $this->eventDispatcher->dispatch(CompilerPostRenderRepeaterPageView::NAME, $postEvent);
470
471 3
        return $postEvent->getCompiledOutput();
472
    }
473
474
    /**
475
     * Get the compiled HTML for a specific ContentItem.
476
     *
477
     * @param CollectableItem|TemplateReadyDocument $twigItem
478
     *
479
     * @since  0.1.1
480
     *
481
     * @return string
482
     */
483 View Code Duplication
    private function buildDynamicPageViewHTML(TemplateInterface &$template, &$twigItem)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
484
    {
485
        $defaultContext = [
486
            'this' => $twigItem->createJail(),
0 ignored issues
show
Bug introduced by
The method createJail does only exist in allejo\stakx\Document\TemplateReadyDocument, but not in allejo\stakx\Document\CollectableItem.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
487
        ];
488
489
        $preEvent = new CompilerPreRenderDynamicPageView($twigItem);
0 ignored issues
show
Bug introduced by
It seems like $twigItem defined by parameter $twigItem on line 483 can also be of type object<allejo\stakx\Docu...\TemplateReadyDocument>; however, allejo\stakx\Event\Compi...PageView::__construct() does only seem to accept object<allejo\stakx\Document\CollectableItem>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
490
        $this->eventDispatcher->dispatch(CompilerPreRenderDynamicPageView::NAME, $preEvent);
491
492
        $context = array_merge($preEvent->getCustomVariables(), $defaultContext);
493
        $output = $template
494
            ->render($context)
495
        ;
496
497
        $postEvent = new CompilerPostRenderDynamicPageView($twigItem, $output);
0 ignored issues
show
Bug introduced by
It seems like $twigItem defined by parameter $twigItem on line 483 can also be of type object<allejo\stakx\Docu...\TemplateReadyDocument>; however, allejo\stakx\Event\Compi...PageView::__construct() does only seem to accept object<allejo\stakx\Document\CollectableItem>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
498
        $this->eventDispatcher->dispatch(CompilerPostRenderDynamicPageView::NAME, $postEvent);
499
500
        return $postEvent->getCompiledOutput();
501
    }
502
503
    /**
504
     * Get the compiled HTML for a static PageView.
505
     *
506
     * @since  0.1.1
507
     *
508
     * @throws TemplateErrorInterface
509
     *
510
     * @return string
511
     */
512 10 View Code Duplication
    private function buildStaticPageViewHTML(StaticPageView &$pageView)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
513
    {
514
        $defaultContext = [
515 10
            'this' => $pageView->createJail(),
516
        ];
517
518 10
        $preEvent = new CompilerPreRenderStaticPageView($pageView);
519 10
        $this->eventDispatcher->dispatch(CompilerPreRenderStaticPageView::NAME, $preEvent);
520
521 10
        $context = array_merge($preEvent->getCustomVariables(), $defaultContext);
522
        $output = $this
523 10
            ->createTwigTemplate($pageView)
524 10
            ->render($context)
525
        ;
526
527 10
        $postEvent = new CompilerPostRenderStaticPageView($pageView, $output);
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...
528 10
        $this->eventDispatcher->dispatch(CompilerPostRenderStaticPageView::NAME, $postEvent);
529
530 10
        return $postEvent->getCompiledOutput();
531
    }
532
533
    /**
534
     * Create a Twig template that just needs an array to render.
535
     *
536
     * @since  0.1.1
537
     *
538
     * @throws TemplateErrorInterface
539
     *
540
     * @return TemplateInterface
541
     */
542 12
    private function createTwigTemplate(BasePageView &$pageView)
543
    {
544
        try
545
        {
546 12
            $template = $this->templateBridge->createTemplate($pageView->getContent());
547
548 12
            $this->templateMapping[$template->getTemplateName()] = $pageView->getRelativeFilePath();
549
550 12
            $event = new CompilerTemplateCreation($pageView, $template, $this->theme);
551 12
            $this->eventDispatcher->dispatch(CompilerTemplateCreation::NAME, $event);
552
553 12
            return $template;
554
        }
555
        catch (TemplateErrorInterface $e)
556
        {
557
            $e
558
                ->setTemplateLine($e->getTemplateLine() + $pageView->getLineOffset())
559
                ->setContent($pageView->getContent())
560
                ->setName($pageView->getRelativeFilePath())
561
                ->setRelativeFilePath($pageView->getRelativeFilePath())
562
                ->buildException()
563
            ;
564
565
            throw $e;
566
        }
567
    }
568
}
569