Completed
Push — master ( 0af16c...507aa8 )
by Vladimir
02:26
created

PageManager::handleTrackableDynamicPageView()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0067

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 16
ccs 10
cts 11
cp 0.9091
crap 3.0067
rs 9.4285
c 0
b 0
f 0
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\Manager;
9
10
use allejo\stakx\Exception\FileAwareException;
11
use allejo\stakx\Exception\TrackedItemNotFoundException;
12
use allejo\stakx\FrontMatter\ExpandedValue;
13
use allejo\stakx\Object\ContentItem;
14
use allejo\stakx\Object\DynamicPageView;
15
use allejo\stakx\Object\JailObject;
16
use allejo\stakx\Object\PageView;
17
use allejo\stakx\Object\RepeaterPageView;
18
use allejo\stakx\System\FileExplorer;
19
use allejo\stakx\System\Folder;
20
use Twig_Error_Syntax;
21
use Twig_Template;
22
23
/**
24
 * This class is responsible for handling all of the PageViews within a website.
25
 *
26
 * PageManager will parse all available dynamic and static PageViews. After, dynamic PageViews will be prepared by
27
 * setting the appropriate values for each ContentItem such as permalinks. Lastly, this class will compile all of the
28
 * PageViews and write them to the target directory.
29
 *
30
 * @package allejo\stakx\Manager
31
 */
32
class PageManager extends TrackingManager
33
{
34
    /**
35
     * The relative (to the stakx project) file path to the redirect template
36
     *
37
     * @var string|bool
38
     */
39
    private $redirectTemplate;
40
41
    /**
42
     * @var PageView[]
43
     */
44
    private $twigExtendsDeps;
45
46
    /**
47
     * @var ContentItem[][]
48
     */
49
    private $collections;
50
51
    /**
52
     * @var Folder
53
     */
54
    private $targetDir;
55
56
    /**
57
     * @var PageView[]
58
     */
59
    private $flatPages;
60
61
    /**
62
     * @var PageView[]
63
     */
64
    private $siteMenu;
65
66
    /**
67
     * @var array
68
     */
69
    private $twigOpts;
70
71
    /**
72
     * @var \Twig_Environment
73
     */
74
    private $twig;
75
76
    /**
77
     * PageManager constructor
78
     */
79 3
    public function __construct()
80
    {
81 3
        parent::__construct();
82
83 3
        $this->redirectTemplate = false;
84 3
        $this->twigExtendsDeps = array();
85 3
        $this->collections = array();
86 3
        $this->flatPages = array();
87 3
        $this->siteMenu = array();
88 3
    }
89
90
    /**
91
     * Give this manager the collections we'll be using for dynamic PageViews
92
     *
93
     * @param ContentItem[][] $collections
94
     */
95 3
    public function setCollections (&$collections)
96
    {
97 3
        $this->collections = &$collections;
98 3
    }
99
100
    /**
101
     * Set the template used for redirects
102
     *
103
     * @param false|string $filePath The path to the redirect template
104
     */
105
    public function setRedirectTemplate ($filePath)
106
    {
107
        $this->redirectTemplate = $filePath;
108
    }
109
110
    /**
111
     * The location where the compiled website will be written to
112
     *
113
     * @param Folder $folder The relative target directory as specified from the configuration file
114
     */
115 3
    public function setTargetFolder (&$folder)
116
    {
117 3
        $this->targetDir = &$folder;
118 3
    }
119
120 3
    public function configureTwig ($configuration, $options)
121
    {
122 3
        $this->twigOpts['configuration'] = $configuration;
123 3
        $this->twigOpts['options']       = $options;
124
125 3
        $this->createTwigManager();
126 3
    }
127
128 1
    public function getFlatPages ()
129
    {
130 1
        return $this->flatPages;
131
    }
132
133
    /**
134
     * An array representing the website's menu structure with children and grandchildren made from static PageViews
135
     *
136
     * @return JailObject[]
137
     */
138 1
    public function getSiteMenu ()
139
    {
140 1
        $jailedMenu = array();
141
142 1
        foreach ($this->siteMenu as $key => $value)
143
        {
144
            // If it's an array, it means the parent is hidden from the site menu therefore its children should be too
145 1
            if (is_array($this->siteMenu[$key]))
146 1
            {
147
                continue;
148
            }
149
150 1
            $jailedMenu[$key] = $value->createJail();
151 1
        }
152
153 1
        return $jailedMenu;
154
    }
155
156
    /**
157
     * Go through all of the PageView directories and create a respective PageView for each and classify them as a
158
     * dynamic or static PageView.
159
     *
160
     * @param $pageViewFolders
161
     */
162 3
    public function parsePageViews ($pageViewFolders)
163
    {
164 3
        if (empty($pageViewFolders)) { return; }
165
166
        /**
167
         * The name of the folder where PageViews are located
168
         *
169
         * @var $pageViewFolder string
170
         */
171 3
        foreach ($pageViewFolders as $pageViewFolderName)
172
        {
173 3
            $pageViewFolder = $this->fs->absolutePath($pageViewFolderName);
174
175 3
            if (!$this->fs->exists($pageViewFolder))
176 3
            {
177
                continue;
178
            }
179
180 3
            $this->scanTrackableItems($pageViewFolder, array(
181
                'fileExplorer' => FileExplorer::INCLUDE_ONLY_FILES
182 3
            ), array('/.html$/', '/.twig$/'));
183 3
            $this->saveFolderDefinition($pageViewFolderName);
184 3
        }
185 3
    }
186
187
    /**
188
     * Compile dynamic and static PageViews
189
     */
190 3
    public function compileAll ()
191
    {
192 3
        foreach (array_keys($this->trackedItemsFlattened) as $filePath)
193
        {
194 3
            $this->compileFromFilePath($filePath);
195 3
        }
196 3
    }
197
198
    public function compileSome ($filter = array())
199
    {
200
        /** @var PageView $pageView */
201
        foreach ($this->trackedItemsFlattened as $pageView)
202
        {
203
            if ($pageView->hasTwigDependency($filter['namespace'], $filter['dependency']))
204
            {
205
                $this->compilePageView($pageView);
206
            }
207
        }
208
    }
209
210
    /**
211
     * @param ContentItem $contentItem
212
     */
213
    public function compileContentItem (&$contentItem)
214
    {
215
        $pageView = $contentItem->getPageView();
216
217
        // This ContentItem doesn't have an individual PageView dedicated to displaying this item
218
        if (is_null($pageView))
219
        {
220
            return;
221
        }
222
223
        $template = $this->createTemplate($pageView);
224
        $contentItem->evaluateFrontMatter(
225
            $pageView->getFrontMatter(false)
226
        );
227
228
        $output = $template->render(array(
229
            'this' => $contentItem
230
        ));
231
232
        $this->targetDir->writeFile($contentItem->getTargetFile(), $output);
233
    }
234
235
    /**
236
     * Add a new ContentItem to the respective parent PageView of the ContentItem
237
     *
238
     * @param ContentItem $contentItem
239
     */
240
    public function updatePageView ($contentItem)
241
    {
242
        /** @var DynamicPageView $pageView */
243
        foreach ($this->trackedItems['dynamic'] as &$pageView)
244
        {
245
            $fm = $pageView->getFrontMatter(false);
246
247
            if ($fm['collection'] == $contentItem->getCollection())
248
            {
249
                $pageView->addContentItem($contentItem);
250
            }
251
        }
252
    }
253
254
    /**
255
     * Update an existing Twig variable that's injected globally
256
     *
257
     * @param string $variable
258
     * @param string $value
259
     */
260
    public function updateTwigVariable ($variable, $value)
261
    {
262
        $this->twig->addGlobal($variable, $value);
263
    }
264
265
    /**
266
     * {@inheritdoc}
267
     */
268 3
    public function isTracked($filePath)
269
    {
270 3
        return (parent::isTracked($filePath) || isset($this->twigExtendsDeps[$filePath]));
271
    }
272
273
    /**
274
     * {@inheritdoc}
275
     */
276
    public function refreshItem($filePath)
277
    {
278
        if (parent::isTracked($filePath))
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (isTracked() instead of refreshItem()). Are you sure this is correct? If so, you might want to change this to $this->isTracked().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
279
        {
280
            $this->compileFromFilePath($filePath);
281
282
            return;
283
        }
284
285
        $this->createTwigManager();
286
287
        foreach ($this->twigExtendsDeps[$filePath] as $pageView)
0 ignored issues
show
Bug introduced by
The expression $this->twigExtendsDeps[$filePath] of type object<allejo\stakx\Object\PageView> is not traversable.
Loading history...
288
        {
289
            $this->compilePageView($pageView);
290
        }
291
    }
292
293
    /**
294
     * {@inheritdoc}
295
     */
296 3
    protected function handleTrackableItem($filePath, $options = array())
297
    {
298 3
        $pageView  = PageView::create($filePath);
299 3
        $namespace = $pageView->getType();
300
301
        switch ($namespace)
302
        {
303 3
            case PageView::DYNAMIC_TYPE:
304 3
                $this->handleTrackableDynamicPageView($pageView);
0 ignored issues
show
Compatibility introduced by
$pageView of type object<allejo\stakx\Object\PageView> is not a sub-type of object<allejo\stakx\Object\DynamicPageView>. It seems like you assume a child class of the class allejo\stakx\Object\PageView 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...
305 3
                break;
306
307 3
            case PageView::STATIC_TYPE:
308 3
                $this->handleTrackableStaticPageView($pageView);
309 3
                break;
310
311 3
            default:
312 3
                break;
313 3
        }
314
315 3
        $this->addObjectToTracker($pageView, $pageView->getRelativeFilePath(), $namespace);
316 3
        $this->saveTrackerOptions($pageView->getRelativeFilePath(), array(
317
            'viewType' => $namespace
318 3
        ));
319 3
    }
320
321
    /**
322
     * @param DynamicPageView $pageView
323
     */
324 3
    private function handleTrackableDynamicPageView ($pageView)
325
    {
326 3
        $frontMatter = $pageView->getFrontMatter(false);
327 3
        $collection = $frontMatter['collection'];
328
329 3
        if (!isset($this->collections[$collection]))
330 3
        {
331
            throw new \RuntimeException("The '$collection' collection is not defined");
332
        }
333
334 3
        foreach ($this->collections[$collection] as &$item)
335
        {
336 3
            $item->evaluateFrontMatter($frontMatter);
337 3
            $pageView->addContentItem($item);
338 3
        }
339 3
    }
340
341
    /**
342
     * @param PageView $pageView
343
     */
344 3
    private function handleTrackableStaticPageView ($pageView)
345
    {
346 3
        if (empty($pageView['title'])) { return; }
347
348 3
        $this->addToSiteMenu($pageView);
349 3
        $this->flatPages[$pageView['title']] = $pageView->createJail();
350 3
    }
351
352
    /**
353
     * Create a Twig environment
354
     */
355 3
    private function createTwigManager ()
356
    {
357 3
        $twig = new TwigManager();
358 3
        $twig->configureTwig(
359 3
            $this->twigOpts['configuration'],
360 3
            $this->twigOpts['options']
361 3
        );
362
363 3
        $this->twig = TwigManager::getInstance();
364 3
    }
365
366
    /**
367
     * Compile a given PageView
368
     *
369
     * @param string $filePath The file path to the PageView to compile
370
     *
371
     * @throws \Exception
372
     */
373 3
    private function compileFromFilePath ($filePath)
374
    {
375 3
        if (!$this->isTracked($filePath))
376 3
        {
377
            throw new TrackedItemNotFoundException('PageView not found');
378
        }
379
380
        /** @var DynamicPageView|PageView|RepeaterPageView $pageView */
381 3
        $pageView = &$this->trackedItemsFlattened[$filePath];
382
383
        try
384
        {
385 3
            $pageView->refreshFileContent();
386 3
            $this->compilePageView($pageView);
387
        }
388 3
        catch (\Exception $e)
389
        {
390
            throw FileAwareException::castException($e, $filePath);
391
        }
392 3
    }
393
394
    /**
395
     * @param DynamicPageView|RepeaterPageView|PageView $pageView
396
     */
397 3
    private function compilePageView ($pageView)
398
    {
399 3
        switch ($pageView->getType())
400
        {
401 3
            case PageView::REPEATER_TYPE:
402 3
                $this->compileRepeaterPageView($pageView);
0 ignored issues
show
Compatibility introduced by
$pageView of type object<allejo\stakx\Object\PageView> is not a sub-type of object<allejo\stakx\Object\RepeaterPageView>. It seems like you assume a child class of the class allejo\stakx\Object\PageView 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...
403 3
                $this->compileExpandedRedirects($pageView);
404 3
                break;
405
406 3
            case PageView::DYNAMIC_TYPE:
407 3
                $this->compileDynamicPageView($pageView);
408 3
                $this->compileNormalRedirects($pageView);
409 3
                break;
410
411 3
            case PageView::STATIC_TYPE:
412 3
                $this->compileStaticPageView($pageView);
413 3
                $this->compileNormalRedirects($pageView);
414 3
                break;
415 3
        }
416 3
    }
417
418
    /**
419
     * @param RepeaterPageView $pageView
420
     */
421 3
    private function compileRepeaterPageView (&$pageView)
422
    {
423 3
        $template = $this->createTemplate($pageView);
424 3
        $pageView->rewindPermalink();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class allejo\stakx\Object\PageView as the method rewindPermalink() does only exist in the following sub-classes of allejo\stakx\Object\PageView: allejo\stakx\Object\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...
425
426 3
        foreach ($pageView->getRepeaterPermalinks() as $permalink)
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class allejo\stakx\Object\PageView as the method getRepeaterPermalinks() does only exist in the following sub-classes of allejo\stakx\Object\PageView: allejo\stakx\Object\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...
427
        {
428 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\Object\PageView as the method bumpPermalink() does only exist in the following sub-classes of allejo\stakx\Object\PageView: allejo\stakx\Object\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...
429 3
            $pageView->setFrontMatter(array(
430 3
                'permalink' => $permalink->getEvaluated(),
431 3
                'iterators' => $permalink->getIterators()
432 3
            ));
433
434 3
            $output = $template->render(array(
435 3
                'this' => $pageView->createJail()
436 3
            ));
437
438 3
            $this->output->notice("Writing repeater file: {file}", array('file' => $pageView->getTargetFile()));
439 3
            $this->targetDir->writeFile($pageView->getTargetFile(), $output);
440 3
        }
441 3
    }
442
443
    /**
444
     * @param PageView $pageView
445
     */
446 3
    private function compileDynamicPageView (&$pageView)
447
    {
448 3
        $template = $this->createTemplate($pageView);
449
450 3
        $pageViewFrontMatter = $pageView->getFrontMatter(false);
451 3
        $collection = $pageViewFrontMatter['collection'];
452
453 3
        if (!isset($this->collections[$collection]))
454 3
        {
455
            throw new \RuntimeException("The '$collection' collection is not defined");
456
        }
457
458
        /** @var ContentItem $contentItem */
459 3
        foreach ($this->collections[$collection] as &$contentItem)
460
        {
461 3
            $output = $template->render(array(
462 3
                'this' => $contentItem->createJail()
463 3
            ));
464
465 3
            $this->output->notice("Writing file: {file}", array('file' => $contentItem->getTargetFile()));
466 3
            $this->targetDir->writeFile($contentItem->getTargetFile(), $output);
467 3
        }
468 3
    }
469
470
    /**
471
     * @param PageView $pageView
472
     */
473 3
    private function compileStaticPageView (&$pageView)
474
    {
475 3
        $this->twig->addGlobal('__currentTemplate', $pageView->getFilePath());
476
477 3
        $template = $this->createTemplate($pageView);
478 3
        $output = $template->render(array(
479 3
            'this' => $pageView->createJail()
480 3
        ));
481
482 3
        $this->output->notice("Writing file: {file}", array('file' => $pageView->getTargetFile()));
483 3
        $this->targetDir->writeFile($pageView->getTargetFile(), $output);
484 3
    }
485
486
    /**
487
     * @param DynamicPageView|PageView $pageView
488
     */
489 3
    private function compileNormalRedirects (&$pageView)
490
    {
491 3
        foreach ($pageView->getRedirects() as $redirect)
0 ignored issues
show
Bug introduced by
The expression $pageView->getRedirects() of type null|array<integer,string> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
492
        {
493
            $redirectPageView = PageView::createRedirect(
494 1
                $redirect,
495 1
                $pageView->getPermalink(),
496
                $this->redirectTemplate
497
            );
498
499
            $this->compilePageView($redirectPageView);
500 3
        }
501 3
    }
502
503
    /**
504
     * @param RepeaterPageView $pageView
505
     */
506 3
    private function compileExpandedRedirects (&$pageView)
507
    {
508 3
        $permalinks = $pageView->getRepeaterPermalinks();
509
510
        /** @var ExpandedValue[] $repeaterRedirect */
511 3
        foreach ($pageView->getRepeaterRedirects() as $repeaterRedirect)
512
        {
513
            /**
514
             * @var int           $index
515
             * @var ExpandedValue $redirect
516
             */
517
            foreach ($repeaterRedirect as $index => $redirect)
518
            {
519
                $redirectPageView = PageView::createRedirect(
520
                    $redirect->getEvaluated(),
521
                    $permalinks[$index]->getEvaluated(),
522
                    $this->redirectTemplate
523
                );
524
525
                $this->compilePageView($redirectPageView);
526
            }
527 3
        }
528 3
    }
529
530
    /**
531
     * Add a static PageView to the menu array. Dynamic PageViews are not added to the menu
532
     *
533
     * @param PageView $pageView
534
     */
535 3
    private function addToSiteMenu (&$pageView)
536
    {
537 3
        $frontMatter = $pageView->getFrontMatter();
538
539 3
        if (isset($frontMatter['menu']) && !$frontMatter['menu'])
540 3
        {
541
            return;
542
        }
543
544 3
        $url = trim($pageView->getPermalink(), '/');
545
546 3
        if (empty($url))
547 3
        {
548
            return;
549
        }
550
551 3
        $root = &$this->siteMenu;
552 3
        $dirs = explode('/', $url);
553
554 3
        while (count($dirs) > 0)
555
        {
556 3
            $name = array_shift($dirs);
557 3
            $name = (!empty($name)) ? $name : '.';
558
559 3
            if (!is_null($name) && count($dirs) == 0)
560 3
            {
561 3
                if (isset($root[$name]) && is_array($root[$name]))
562 3
                {
563 3
                    $children = &$pageView->getChildren();
564 3
                    $children = $root[$name]['children'];
565 3
                }
566
567 3
                $root[$name] = &$pageView;
568 3
            }
569
            else
570
            {
571 3
                if (!isset($root[$name]['children']))
572 3
                {
573 3
                    $root[$name]['children'] = array();
574 3
                }
575
576 3
                $root = &$root[$name]['children'];
577
            }
578 3
        }
579 3
    }
580
581
    /**
582
     * @param PageView $pageView
583
     *
584
     * @return Twig_Template
585
     * @throws Twig_Error_Syntax
586
     */
587 3
    private function createTemplate (&$pageView)
588
    {
589
        try
590
        {
591 3
            $template = $this->twig->createTemplate($pageView->getContent());
592
593 3
            $this->trackParentTwigTemplate($template, $pageView);
594
595 3
            return $template;
596
        }
597
        catch (Twig_Error_Syntax $e)
598
        {
599
            $e->setTemplateLine($e->getTemplateLine() + $pageView->getLineOffset());
600
            $e->setTemplateName($pageView->getRelativeFilePath());
0 ignored issues
show
Deprecated Code introduced by
The method Twig_Error::setTemplateName() has been deprecated with message: since 1.29 (to be removed in 2.0). Use setSourceContext() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
601
602
            throw $e;
603
        }
604
    }
605
606
    /**
607
     * Find the parent Twig templates of the given template and keep a list of it
608
     *
609
     * @param Twig_Template $template The template created from the PageView's content
610
     * @param PageView      $pageView The PageView that has this content. Used to keep a reference of PageViews
611
     */
612 3
    private function trackParentTwigTemplate ($template, &$pageView)
613
    {
614 3
        if (!$this->tracking) { return; }
615
616
        /** @var Twig_Template $parent */
617
        $parent = $template->getParent(array());
618
619
        while ($parent !== false)
620
        {
621
            $filePath = $this->fs->getRelativePath($parent->getSourceContext()->getPath());
622
623
            $this->twigExtendsDeps[$filePath][(string)$pageView->getFilePath()] = &$pageView;
624
            $parent = $parent->getParent(array());
625
        }
626
    }
627
}