Completed
Pull Request — master (#86)
by Vladimir
38:05 queued 09:07
created

Compiler   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 502
Duplicated Lines 12.95 %

Coupling/Cohesion

Components 1
Dependencies 27

Test Coverage

Coverage 68.52%

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 27
dl 65
loc 502
ccs 111
cts 162
cp 0.6852
rs 9.84
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A writeToFilesystem() 0 8 1
A compileStandardRedirects() 13 18 2
A compileExpandedRedirects() 13 26 3
A buildRepeaterPageViewHTML() 0 24 1
A __construct() 0 28 1
A setTargetFolder() 0 4 1
A setThemeName() 0 4 1
A getTemplateMappings() 0 4 1
A renderStaticPageView() 0 6 1
A renderDynamicPageView() 0 6 1
A renderRepeaterPageView() 0 6 1
A compileAll() 0 7 2
B compilePageView() 0 39 5
A compileStaticPageView() 0 8 1
A compileDynamicPageView() 0 25 4
A compileRepeaterPageView() 0 14 2
A buildDynamicPageViewHTML() 19 19 1
A buildStaticPageViewHTML() 20 20 1
A createTwigTemplate() 0 26 2

How to fix   Duplicated Code   

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:

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\Exception\FileAwareException;
25
use allejo\stakx\Filesystem\Folder;
26
use allejo\stakx\FrontMatter\ExpandedValue;
27
use allejo\stakx\Manager\CollectionManager;
28
use allejo\stakx\Manager\DataManager;
29
use allejo\stakx\Manager\MenuManager;
30
use allejo\stakx\Manager\PageManager;
31
use allejo\stakx\Templating\TemplateBridgeInterface;
32
use allejo\stakx\Templating\TemplateErrorInterface;
33
use allejo\stakx\Templating\TemplateInterface;
34
use Psr\Log\LoggerInterface;
35
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
36
37
/**
38
 * This class takes care of rendering the Twig body of PageViews with the respective information and it also takes care
39
 * of writing the rendered Twig to the filesystem.
40
 *
41
 * @since 0.1.1
42
 */
43
class Compiler
44
{
45
    /** @var string|false */
46
    private $redirectTemplate;
47
48
    /**
49
     * All of the PageViews handled by this Compiler instance indexed by their file paths relative to the site root.
50
     *
51
     * ```
52
     * array['_pages/index.html.twig'] = &PageView;
53
     * ```
54
     *
55
     * @var BasePageView[]
56
     */
57
    private $pageViewsFlattened;
58
59
    /** @var string[] */
60
    private $templateMapping;
61
62
    /** @var Folder */
63
    private $folder;
64
65
    /** @var string */
66
    private $theme;
67
68
    private $templateBridge;
69
    private $pageManager;
70
    private $eventDispatcher;
71
    private $configuration;
72
    private $logger;
73
74 12
    public function __construct(
75
        TemplateBridgeInterface $templateBridge,
76
        Configuration $configuration,
77
        CollectionManager $collectionManager,
78
        DataManager $dataManager,
79
        MenuManager $menuManager,
80
        PageManager $pageManager,
81
        EventDispatcherInterface $eventDispatcher,
82
        LoggerInterface $logger
83
    ) {
84 12
        $this->templateBridge = $templateBridge;
85 12
        $this->theme = '';
86 12
        $this->pageManager = $pageManager;
87 12
        $this->eventDispatcher = $eventDispatcher;
88 12
        $this->logger = $logger;
89 12
        $this->configuration = $configuration;
90
91 12
        $this->pageViewsFlattened = &$pageManager->getPageViewsFlattened();
92 12
        $this->redirectTemplate = $this->configuration->getRedirectTemplate();
93
94
        // Global variables maintained by stakx
95 12
        $this->templateBridge->setGlobalVariable('site', $configuration->getConfiguration());
96 12
        $this->templateBridge->setGlobalVariable('data', $dataManager->getJailedDataItems());
97 12
        $this->templateBridge->setGlobalVariable('collections', $collectionManager->getJailedCollections());
98 12
        $this->templateBridge->setGlobalVariable('menu', $menuManager->getSiteMenu());
99 12
        $this->templateBridge->setGlobalVariable('pages', $pageManager->getJailedStaticPageViews());
100 12
        $this->templateBridge->setGlobalVariable('repeaters', $pageManager->getJailedRepeaterPageViews());
101 12
    }
102
103
    /**
104
     * @param Folder $folder
105
     */
106 12
    public function setTargetFolder(Folder $folder)
107
    {
108 12
        $this->folder = $folder;
109 12
    }
110
111
    /**
112
     * @param string $themeName
113
     */
114
    public function setThemeName($themeName)
115
    {
116
        $this->theme = $themeName;
117
    }
118
119
    ///
120
    // Twig parent templates
121
    ///
122
123
    public function getTemplateMappings()
124
    {
125
        return $this->templateMapping;
126
    }
127
128
    ///
129
    // Rendering HTML Functionality
130
    ///
131
132
    /**
133
     * Get the HTML for a Static PageView.
134
     *
135
     * This function just **renders** the HTML but does not write it to the filesystem. Use `compilePageView()` for that
136
     * instead.
137
     *
138
     * @param StaticPageView $pageView
139
     *
140
     * @throws TemplateErrorInterface
141
     *
142
     * @return string the HTML for a Static PageView
143
     */
144 10
    public function renderStaticPageView(StaticPageView $pageView)
145
    {
146 10
        $pageView->compile();
147
148 10
        return $this->buildStaticPageViewHTML($pageView);
149
    }
150
151
    /**
152
     * Get the HTML for a Dynamic PageView and ContentItem.
153
     *
154
     * This function just **renders** the HTML but does not write it to the filesystem. Use `compileDynamicPageView()`
155
     * for that instead.
156
     *
157
     * @param DynamicPageView       $pageView
158
     * @param TemplateReadyDocument $contentItem
159
     *
160
     * @throws TemplateErrorInterface
161
     *
162
     * @return string
163
     */
164
    public function renderDynamicPageView(DynamicPageView $pageView, TemplateReadyDocument $contentItem)
165
    {
166
        $template = $this->createTwigTemplate($pageView);
167
168
        return $this->buildDynamicPageViewHTML($template, $contentItem);
169
    }
170
171
    /**
172
     * Get the HTML for a Repeater PageView.
173
     *
174
     * @param RepeaterPageView $pageView
175
     * @param ExpandedValue    $expandedValue
176
     *
177
     * @throws TemplateErrorInterface
178
     *
179
     * @return string
180
     */
181
    public function renderRepeaterPageView(RepeaterPageView $pageView, ExpandedValue $expandedValue)
182
    {
183
        $template = $this->createTwigTemplate($pageView);
184
185
        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...
186
    }
187
188
    ///
189
    // IO Functionality
190
    ///
191
192
    /**
193
     * Compile all of the PageViews registered with the compiler.
194
     *
195
     * @since 0.1.0
196
     */
197 12
    public function compileAll()
198
    {
199 12
        foreach ($this->pageViewsFlattened as &$pageView)
200
        {
201 12
            $this->compilePageView($pageView);
202
        }
203 12
    }
204
205
    /**
206
     * Compile an individual PageView item.
207
     *
208
     * This function will take care of determining *how* to treat the PageView and write the compiled output to a the
209
     * respective target file.
210
     *
211
     * @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...
212
     *
213
     * @since 0.1.1
214
     */
215 12
    public function compilePageView(BasePageView &$pageView)
216
    {
217 12
        Service::setOption('currentTemplate', $pageView->getAbsoluteFilePath());
218 12
        $this->logger->debug('Compiling {type} PageView: {pageview}', [
219 12
            'pageview' => $pageView->getRelativeFilePath(),
220 12
            'type' => $pageView->getType(),
221
        ]);
222
223
        try
224
        {
225 12
            switch ($pageView->getType())
226
            {
227
                case BasePageView::STATIC_TYPE:
228 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...
229 10
                    $this->compileStandardRedirects($pageView);
230 10
                    break;
231
232
                case BasePageView::DYNAMIC_TYPE:
233
                    $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...
234
                    $this->compileStandardRedirects($pageView);
235
                    break;
236
237
                case BasePageView::REPEATER_TYPE:
238 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...
239 3
                    $this->compileExpandedRedirects($pageView);
240 12
                    break;
241
            }
242
        }
243
        catch (TemplateErrorInterface $e)
244
        {
245
            throw new FileAwareException(
246
                $e->getMessage(),
247
                $e->getCode(),
248
                $e,
249
                $pageView->getRelativeFilePath(),
250
                $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...
251
            );
252
        }
253 12
    }
254
255
    /**
256
     * Write the compiled output for a static PageView.
257
     *
258
     * @since 0.1.1
259
     *
260
     * @throws TemplateErrorInterface
261
     */
262 10
    private function compileStaticPageView(StaticPageView &$pageView)
263
    {
264 10
        $this->writeToFilesystem(
265 10
            $pageView->getTargetFile(),
266 10
            $this->renderStaticPageView($pageView),
267 10
            BasePageView::STATIC_TYPE
268
        );
269 10
    }
270
271
    /**
272
     * Write the compiled output for a dynamic PageView.
273
     *
274
     * @param DynamicPageView $pageView
275
     *
276
     * @since 0.1.1
277
     *
278
     * @throws TemplateErrorInterface
279
     */
280
    private function compileDynamicPageView(DynamicPageView &$pageView)
281
    {
282
        $contentItems = $pageView->getCollectableItems();
283
        $template = $this->createTwigTemplate($pageView);
284
285
        foreach ($contentItems as &$contentItem)
286
        {
287
            if ($contentItem->isDraft() && !Service::hasRunTimeFlag(RuntimeStatus::USING_DRAFTS))
288
            {
289
                $this->logger->debug('{file}: marked as a draft', [
290
                    'file' => $contentItem->getRelativeFilePath(),
291
                ]);
292
293
                continue;
294
            }
295
296
            $this->writeToFilesystem(
297
                $contentItem->getTargetFile(),
298
                $this->buildDynamicPageViewHTML($template, $contentItem),
299
                BasePageView::DYNAMIC_TYPE
300
            );
301
302
            $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...
303
        }
304
    }
305
306
    /**
307
     * Write the compiled output for a repeater PageView.
308
     *
309
     * @param RepeaterPageView $pageView
310
     *
311
     * @since 0.1.1
312
     *
313
     * @throws TemplateErrorInterface
314
     */
315 3
    private function compileRepeaterPageView(RepeaterPageView &$pageView)
316
    {
317 3
        $template = $this->createTwigTemplate($pageView);
318 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...
319
320 3
        foreach ($permalinks as $permalink)
321
        {
322 3
            $this->writeToFilesystem(
323 3
                $pageView->getTargetFile($permalink->getEvaluated()),
324 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...
325 3
                BasePageView::REPEATER_TYPE
326
            );
327
        }
328 3
    }
329
330
    /**
331
     * Write the given $output to the $targetFile as a $fileType PageView.
332
     *
333
     * @param string $targetFile
334
     * @param string $output
335
     * @param string $fileType
336
     */
337 12
    private function writeToFilesystem($targetFile, $output, $fileType)
338
    {
339 12
        $this->logger->notice('Writing {type} PageView file: {file}', [
340 12
            'type' => $fileType,
341 12
            'file' => $targetFile,
342
        ]);
343 12
        $this->folder->writeFile($targetFile, $output);
344 12
    }
345
346
    ///
347
    // Redirect handling
348
    ///
349
350
    /**
351
     * Write redirects for standard redirects.
352
     *
353
     * @throws TemplateErrorInterface
354
     *
355
     * @since 0.1.1
356
     */
357 10
    private function compileStandardRedirects(PermalinkDocument &$pageView)
358
    {
359 10
        $redirects = $pageView->getRedirects();
360
361 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...
362
        {
363 1
            $redirectPageView = BasePageView::createRedirect(
364 1
                $redirect,
365 1
                $pageView->getPermalink(),
366 1
                $this->redirectTemplate
367
            );
368 1
            $redirectPageView->evaluateFrontMatter([], [
369 1
                'site' => $this->configuration->getConfiguration(),
370
            ]);
371
372 1
            $this->compileStaticPageView($redirectPageView);
373
        }
374 10
    }
375
376
    /**
377
     * Write redirects for expanded redirects.
378
     *
379
     * @param RepeaterPageView $pageView
380
     *
381
     * @since 0.1.1
382
     */
383 3
    private function compileExpandedRedirects(RepeaterPageView &$pageView)
384
    {
385 3
        $permalinks = $pageView->getRepeaterPermalinks();
386
387
        /** @var ExpandedValue[] $repeaterRedirect */
388 3
        foreach ($pageView->getRepeaterRedirects() as $repeaterRedirect)
389
        {
390
            /**
391
             * @var int
392
             * @var ExpandedValue $redirect
393
             */
394 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...
395
            {
396 1
                $redirectPageView = BasePageView::createRedirect(
397 1
                    $redirect->getEvaluated(),
398 1
                    $permalinks[$index]->getEvaluated(),
399 1
                    $this->redirectTemplate
400
                );
401 1
                $redirectPageView->evaluateFrontMatter([], [
402 1
                    'site' => $this->configuration->getConfiguration(),
403
                ]);
404
405 1
                $this->compilePageView($redirectPageView);
406
            }
407
        }
408 3
    }
409
410
    ///
411
    // Twig Functionality
412
    ///
413
414
    /**
415
     * Get the compiled HTML for a specific iteration of a repeater PageView.
416
     *
417
     * @param TemplateInterface $template
418
     * @param RepeaterPageView  $pageView
419
     * @param ExpandedValue     $expandedValue
420
     *
421
     * @since  0.1.1
422
     *
423
     * @return string
424
     */
425 3
    private function buildRepeaterPageViewHTML(TemplateInterface &$template, RepeaterPageView &$pageView, ExpandedValue &$expandedValue)
426
    {
427
        $defaultContext = [
428 3
            'this' => $pageView->createJail(),
429
        ];
430
431 3
        $pageView->evaluateFrontMatter([
432 3
            'permalink' => $expandedValue->getEvaluated(),
433 3
            'iterators' => $expandedValue->getIterators(),
434
        ]);
435
436 3
        $preEvent = new CompilerPreRenderRepeaterPageView($pageView, $expandedValue);
437 3
        $this->eventDispatcher->dispatch(CompilerPreRenderRepeaterPageView::NAME, $preEvent);
438
439 3
        $context = array_merge($preEvent->getCustomVariables(), $defaultContext);
440
        $output = $template
441 3
            ->render($context)
442
        ;
443
444 3
        $postEvent = new CompilerPostRenderRepeaterPageView($pageView, $expandedValue, $output);
445 3
        $this->eventDispatcher->dispatch(CompilerPostRenderRepeaterPageView::NAME, $postEvent);
446
447 3
        return $postEvent->getCompiledOutput();
448
    }
449
450
    /**
451
     * Get the compiled HTML for a specific ContentItem.
452
     *
453
     * @param CollectableItem|TemplateReadyDocument $twigItem
454
     *
455
     * @since  0.1.1
456
     *
457
     * @return string
458
     */
459 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...
460
    {
461
        $defaultContext = [
462
            '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...
463
        ];
464
465
        $preEvent = new CompilerPreRenderDynamicPageView($twigItem);
0 ignored issues
show
Bug introduced by
It seems like $twigItem defined by parameter $twigItem on line 459 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...
466
        $this->eventDispatcher->dispatch(CompilerPreRenderDynamicPageView::NAME, $preEvent);
467
468
        $context = array_merge($preEvent->getCustomVariables(), $defaultContext);
469
        $output = $template
470
            ->render($context)
471
        ;
472
473
        $postEvent = new CompilerPostRenderDynamicPageView($twigItem, $output);
0 ignored issues
show
Bug introduced by
It seems like $twigItem defined by parameter $twigItem on line 459 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...
474
        $this->eventDispatcher->dispatch(CompilerPostRenderDynamicPageView::NAME, $postEvent);
475
476
        return $postEvent->getCompiledOutput();
477
    }
478
479
    /**
480
     * Get the compiled HTML for a static PageView.
481
     *
482
     * @since  0.1.1
483
     *
484
     * @throws TemplateErrorInterface
485
     *
486
     * @return string
487
     */
488 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...
489
    {
490
        $defaultContext = [
491 10
            'this' => $pageView->createJail(),
492
        ];
493
494 10
        $preEvent = new CompilerPreRenderStaticPageView($pageView);
495 10
        $this->eventDispatcher->dispatch(CompilerPreRenderStaticPageView::NAME, $preEvent);
496
497 10
        $context = array_merge($preEvent->getCustomVariables(), $defaultContext);
498
        $output = $this
499 10
            ->createTwigTemplate($pageView)
500 10
            ->render($context)
501
        ;
502
503 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...
504 10
        $this->eventDispatcher->dispatch(CompilerPostRenderStaticPageView::NAME, $postEvent);
505
506 10
        return $postEvent->getCompiledOutput();
507
    }
508
509
    /**
510
     * Create a Twig template that just needs an array to render.
511
     *
512
     * @since  0.1.1
513
     *
514
     * @throws TemplateErrorInterface
515
     *
516
     * @return TemplateInterface
517
     */
518 12
    private function createTwigTemplate(BasePageView &$pageView)
519
    {
520
        try
521
        {
522 12
            $template = $this->templateBridge->createTemplate($pageView->getContent());
523
524 12
            $this->templateMapping[$template->getTemplateName()] = $pageView->getRelativeFilePath();
525
526 12
            $event = new CompilerTemplateCreation($pageView, $template, $this->theme);
527 12
            $this->eventDispatcher->dispatch(CompilerTemplateCreation::NAME, $event);
528
529 12
            return $template;
530
        }
531
        catch (TemplateErrorInterface $e)
532
        {
533
            $e
534
                ->setTemplateLine($e->getTemplateLine() + $pageView->getLineOffset())
535
                ->setContent($pageView->getContent())
536
                ->setName($pageView->getRelativeFilePath())
537
                ->setRelativeFilePath($pageView->getRelativeFilePath())
538
                ->buildException()
539
            ;
540
541
            throw $e;
542
        }
543
    }
544
}
545