Completed
Pull Request — master (#11)
by Vladimir
02:33
created

PageManager::updateTwigVariable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace allejo\stakx\Manager;
4
5
use allejo\stakx\Object\ContentItem;
6
use allejo\stakx\Object\PageView;
7
use allejo\stakx\System\Folder;
8
use Symfony\Component\Finder\Finder;
9
use Twig_Error_Syntax;
10
use Twig_Template;
11
12
/**
13
 * This class is responsible for handling all of the PageViews within a website.
14
 *
15
 * PageManager will parse all available dynamic and static PageViews. After, dynamic PageViews will be prepared by
16
 * setting the appropriate values for each ContentItem such as permalinks. Lastly, this class will compile all of the
17
 * PageViews and write them to the target directory.
18
 *
19
 * @package allejo\stakx\Manager
20
 */
21
class PageManager extends BaseManager
22
{
23
    /**
24
     * @var PageView[]
25
     */
26
    private $dynamicPageViews;
27
28
    /**
29
     * @var PageView[]
30
     */
31
    private $staticPageViews;
32
33
    /**
34
     * @var ContentItem[][]
35
     */
36
    private $collections;
37
38
    /**
39
     * @var Folder
40
     */
41
    private $targetDir;
42
43
    private $siteMenu;
44
45
    /**
46
     * @var \Twig_Environment
47
     */
48
    private $twig;
49
50
    /**
51
     * PageManager constructor
52
     */
53
    public function __construct()
54
    {
55
        parent::__construct();
56
57
        $this->dynamicPageViews = array();
58
        $this->staticPageViews  = array();
59
    }
60
61
    public function configureTwig ($configuration, $options)
62
    {
63
        $twig = new TwigManager();
64
        $twig->configureTwig($configuration, $options);
65
66
        $this->twig = TwigManager::getInstance();
67
    }
68
69
    /**
70
     * An array representing the website's menu structure with children and grandchildren made from static PageViews
71
     *
72
     * @return array
73
     */
74
    public function getSiteMenu ()
75
    {
76
        return $this->siteMenu;
77
    }
78
79
    /**
80
     * Go through all of the PageView directories and create a respective PageView for each and classify them as a
81
     * dynamic or static PageView.
82
     *
83
     * @param $pageViewFolders
84
     */
85
    public function parsePageViews ($pageViewFolders)
86
    {
87
        if (empty($pageViewFolders)) { return; }
88
89
        /**
90
         * The name of the folder where PageViews are located
91
         *
92
         * @var $pageViewFolder string
93
         */
94
        foreach ($pageViewFolders as $pageViewFolderName)
95
        {
96
            $pageViewFolder = $this->fs->absolutePath($pageViewFolderName);
97
98
            if (!$this->fs->exists($pageViewFolder))
99
            {
100
                continue;
101
            }
102
103
            $finder = new Finder();
104
            $finder->files()
105
                   ->name('/\.(html|twig)/')
106
                   ->ignoreDotFiles(true)
107
                   ->ignoreUnreadableDirs()
108
                   ->in($pageViewFolder);
109
110
            foreach ($finder as $viewFile)
111
            {
112
                $newPageView = new PageView($viewFile);
113
                $file_id = $this->fs->getRelativePath($newPageView->getFilePath()->getPathName());
0 ignored issues
show
Bug introduced by
The method getPathName cannot be called on $newPageView->getFilePath() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
114
115
                if ($newPageView->isDynamicPage())
116
                {
117
                    $this->dynamicPageViews[$file_id] = $newPageView;
118
                }
119
                else
120
                {
121
                    $this->addToSiteMenu($newPageView->getFrontMatter());
122
                    $this->staticPageViews[$file_id] = $newPageView;
123
                }
124
            }
125
        }
126
    }
127
128
    /**
129
     * Go through all of the dynamic PageViews and prepare the necessary information for each one.
130
     *
131
     * For example, permalinks are dynamic generated based on FrontMatter so this function sets the permalink for each
132
     * ContentItem in a collection. This is called before dynamic PageViews are compiled in order to allow access to
133
     * this information to Twig by the time it is compiled.
134
     *
135
     * @param ContentItem[] $collections
136
     */
137
    public function prepareDynamicPageViews ($collections)
138
    {
139
        if (empty($collections)) { return; }
140
141
        $this->collections = $collections;
0 ignored issues
show
Documentation Bug introduced by
It seems like $collections of type array<integer,object<all...kx\Object\ContentItem>> is incompatible with the declared type array<integer,array<inte...x\Object\ContentItem>>> of property $collections.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
142
143
        foreach ($this->dynamicPageViews as &$pageView)
144
        {
145
            $frontMatter = $pageView->getFrontMatter(false);
146
            $collection = $frontMatter['collection'];
147
148
            /** @var $item ContentItem */
149
            foreach ($collections[$collection] as &$item)
0 ignored issues
show
Bug introduced by
The expression $collections[$collection] of type object<allejo\stakx\Object\ContentItem> is not traversable.
Loading history...
150
            {
151
                $item->evaluateFrontMatter($frontMatter);
152
                $pageView->addContentItem($item);
153
            }
154
        }
155
    }
156
157
    /**
158
     * Compile dynamic and static PageViews
159
     *
160
     * @param Folder $targetDir The relative target directory as specified from the configuration file
161
     */
162
    public function compileAll (&$targetDir)
163
    {
164
        $this->targetDir = $targetDir;
165
166
        $this->compileDynamicPageViews();
167
        $this->compileStaticPageViews();
168
    }
169
170
    /**
171
     * Compile a single PageView into the appropriate output path
172
     *
173
     * @param string $filePath
174
     */
175
    public function compileSingle ($filePath)
176
    {
177
        if (array_key_exists($filePath, $this->staticPageViews))
178
        {
179
            $this->output->notice("Compiling static page: {file}", array('file' => $filePath));
180
181
            $this->staticPageViews[$filePath]->refreshFileContent();
182
            $this->compileStaticPageView($this->staticPageViews[$filePath]);
183
184
            return;
185
        }
186
        else if (array_key_exists($filePath, $this->dynamicPageViews))
187
        {
188
            $this->output->notice("Compiling dynamic page: {file}", array('file' => $filePath));
189
190
            $this->dynamicPageViews[$filePath]->refreshFileContent();
191
            $this->compileDynamicPageView($this->dynamicPageViews[$filePath]);
192
193
            return;
194
        }
195
196
        throw new \InvalidArgumentException('The given file path to compile is not a Page View');
197
    }
198
199
    /**
200
     * @param ContentItem $contentItem
201
     */
202
    public function compileContentItem (&$contentItem)
203
    {
204
        $pageView = $contentItem->getPageView();
205
        $template = $this->createTemplate($pageView);
206
207
        $contentItem->evaluateFrontMatter(
208
            $pageView->getFrontMatter(false)
209
        );
210
211
        $output = $template->render(array(
212
            'this' => $contentItem
213
        ));
214
215
        $this->targetDir->writeFile($contentItem->getTargetFile(), $output);
216
    }
217
218
    /**
219
     * Check whether or not a given file path is Page View
220
     *
221
     * @param  string $filePath
222
     *
223
     * @return bool True if the file path given is to a Page View
224
     */
225
    public function isPageView ($filePath)
226
    {
227
        return (array_key_exists($filePath, $this->staticPageViews) || array_key_exists($filePath, $this->dynamicPageViews));
228
    }
229
230
    /**
231
     * Update an existing Twig variable that's injected globally
232
     *
233
     * @param string $variable
234
     * @param string $value
235
     */
236
    public function updateTwigVariable ($variable, $value)
237
    {
238
        $this->twig->addGlobal($variable, $value);
239
    }
240
241
    /**
242
     * A dynamic PageView is one that is built from a collection and each collection item deserves its own page. This
243
     * function goes through all of the dynamic PageViews and compiles each page
244
     */
245
    private function compileDynamicPageViews ()
246
    {
247
        foreach ($this->dynamicPageViews as $pageView)
248
        {
249
            $this->compileDynamicPageView($pageView);
250
        }
251
    }
252
253
    /**
254
     * A static PageView is built from a single Twig file and is not automatically rendered based on a collection's
255
     * content. This function goes through all of the static PageViews and compiles them.
256
     *
257
     * @throws \Exception
258
     */
259
    private function compileStaticPageViews ()
260
    {
261
        foreach ($this->staticPageViews as $pageView)
262
        {
263
            $this->compileStaticPageView($pageView);
264
        }
265
    }
266
267
    /**
268
     * @param PageView $pageView
269
     */
270
    private function compileDynamicPageView ($pageView)
271
    {
272
        $template = $this->createTemplate($pageView);
273
274
        $pageViewFrontMatter = $pageView->getFrontMatter(false);
275
        $collection = $pageViewFrontMatter['collection'];
276
277
        /** @var $contentItem ContentItem */
278
        foreach ($this->collections[$collection] as $contentItem)
279
        {
280
            $output = $template->render(array(
281
                'this' => $contentItem
282
            ));
283
284
            $this->targetDir->writeFile($contentItem->getTargetFile(), $output);
285
        }
286
    }
287
288
    /**
289
     * @param PageView $pageView
290
     */
291
    private function compileStaticPageView ($pageView)
292
    {
293
        $this->twig->addGlobal('__currentTemplate', $pageView->getFilePath());
294
295
        $template = $this->createTemplate($pageView);
296
        $output = $template->render(array(
297
            'this' => $pageView->getFrontMatter()
298
        ));
299
300
        $this->targetDir->writeFile($pageView->getTargetFile(), $output);
301
    }
302
303
    /**
304
     * Add a static PageView to the menu array. Dynamic PageViews are not added to the menu
305
     *
306
     * @param array $frontMatter
307
     */
308
    private function addToSiteMenu ($frontMatter)
309
    {
310
        if (!array_key_exists('permalink', $frontMatter) ||
311
            (array_key_exists('menu', $frontMatter) && !$frontMatter['menu']))
312
        {
313
            return;
314
        }
315
316
        $url = $frontMatter['permalink'];
317
        $root = &$this->siteMenu;
318
        $permalink = trim($url, DIRECTORY_SEPARATOR);
319
        $dirs = explode(DIRECTORY_SEPARATOR, $permalink);
320
321
        while (count($dirs) > 0)
322
        {
323
            $name = array_shift($dirs);
324
            $name = (!empty($name)) ? $name : '.';
325
326
            if (!isset($root[$name]) && !is_null($name) && count($dirs) == 0)
327
            {
328
                $link = (pathinfo($url, PATHINFO_EXTENSION) !== "") ? $url : $permalink . DIRECTORY_SEPARATOR;
329
330
                $root[$name] = array_merge($frontMatter, array(
331
                    "url"  => '/' . $link,
332
                    "children" => array()
333
                ));
334
            }
335
336
            $root = &$root[$name]['children'];
337
        }
338
    }
339
340
    /**
341
     * @param PageView $pageView
342
     *
343
     * @return Twig_Template
344
     * @throws Twig_Error_Syntax
345
     */
346
    private function createTemplate ($pageView)
347
    {
348
        try
349
        {
350
            return $this->twig->createTemplate($pageView->getContent());
351
        }
352
        catch (Twig_Error_Syntax $e)
353
        {
354
            $e->setTemplateFile($pageView->getRelativeFilePath());
355
356
            throw $e;
357
        }
358
    }
359
}