Completed
Push — master ( 742e02...35dbd5 )
by Vladimir
02:24
created

PageManager::updatePageView()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace allejo\stakx\Manager;
4
5
use allejo\stakx\Exception\TrackedItemNotFoundException;
6
use allejo\stakx\Object\ContentItem;
7
use allejo\stakx\Object\PageView;
8
use allejo\stakx\System\FileExplorer;
9
use allejo\stakx\System\Folder;
10
use Twig_Error_Syntax;
11
use Twig_Template;
12
13
/**
14
 * This class is responsible for handling all of the PageViews within a website.
15
 *
16
 * PageManager will parse all available dynamic and static PageViews. After, dynamic PageViews will be prepared by
17
 * setting the appropriate values for each ContentItem such as permalinks. Lastly, this class will compile all of the
18
 * PageViews and write them to the target directory.
19
 *
20
 * @package allejo\stakx\Manager
21
 */
22
class PageManager extends TrackingManager
23
{
24
    /**
25
     * @var ContentItem[][]
26
     */
27
    private $collections;
28
29
    /**
30
     * @var Folder
31
     */
32
    private $targetDir;
33
34
    private $siteMenu;
35
36
    /**
37
     * @var \Twig_Environment
38
     */
39
    private $twig;
40
41
    /**
42
     * PageManager constructor
43
     */
44
    public function __construct()
45
    {
46
        parent::__construct();
47
    }
48
49
    public function setCollections (&$collections)
50
    {
51
        if (empty($collections)) { return; }
52
53
        $this->collections = &$collections;
54
    }
55
56
    /**
57
     * @param Folder $folder The relative target directory as specified from the configuration file
58
     */
59
    public function setTargetFolder (&$folder)
60
    {
61
        $this->targetDir = &$folder;
62
    }
63
64
    public function configureTwig ($configuration, $options)
65
    {
66
        $twig = new TwigManager();
67
        $twig->configureTwig($configuration, $options);
68
69
        $this->twig = TwigManager::getInstance();
70
    }
71
72
    /**
73
     * An array representing the website's menu structure with children and grandchildren made from static PageViews
74
     *
75
     * @return array
76
     */
77
    public function getSiteMenu ()
78
    {
79
        return $this->siteMenu;
80
    }
81
82
    /**
83
     * Go through all of the PageView directories and create a respective PageView for each and classify them as a
84
     * dynamic or static PageView.
85
     *
86
     * @param $pageViewFolders
87
     */
88
    public function parsePageViews ($pageViewFolders)
89
    {
90
        if (empty($pageViewFolders)) { return; }
91
92
        /**
93
         * The name of the folder where PageViews are located
94
         *
95
         * @var $pageViewFolder string
96
         */
97
        foreach ($pageViewFolders as $pageViewFolderName)
98
        {
99
            $pageViewFolder = $this->fs->absolutePath($pageViewFolderName);
100
101
            if (!$this->fs->exists($pageViewFolder))
102
            {
103
                continue;
104
            }
105
106
            // @TODO Replace this with a regular expression or have wildcard support
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
107
            $this->scanTrackableItems($pageViewFolder, array(
108
                'refresh' => false,
109
                'fileExplorer' => FileExplorer::INCLUDE_ONLY_FILES
110
            ), array('.html', '.twig'));
111
            $this->saveFolderDefinition($pageViewFolderName);
112
        }
113
    }
114
115
    /**
116
     * Compile dynamic and static PageViews
117
     */
118
    public function compileAll ()
119
    {
120
        foreach (array_keys($this->trackedItemsFlattened) as $filePath)
121
        {
122
            $this->compileFromFilePath($filePath);
123
        }
124
    }
125
126
    public function compileSome ($filter = array())
127
    {
128
        /** @var PageView $pageView */
129
        foreach ($this->trackedItemsFlattened as $pageView)
130
        {
131
            if ($pageView->hasTwigDependency($filter['namespace'], $filter['dependency']))
132
            {
133
                $this->compilePageView($pageView);
134
            }
135
        }
136
    }
137
138
    /**
139
     * @param ContentItem $contentItem
140
     */
141
    public function compileContentItem (&$contentItem)
142
    {
143
        $pageView = $contentItem->getPageView();
144
145
        // This ContentItem doesn't have an individual PageView dedicated to displaying this item
146
        if (is_null($pageView))
147
        {
148
            return;
149
        }
150
151
        $template = $this->createTemplate($pageView);
152
        $contentItem->evaluateFrontMatter(
153
            $pageView->getFrontMatter(false)
154
        );
155
156
        $output = $template->render(array(
157
            'this' => $contentItem
158
        ));
159
160
        $this->targetDir->writeFile($contentItem->getTargetFile(), $output);
161
    }
162
163
    /**
164
     * Add a new ContentItem to the respective parent PageView of the ContentItem
165
     *
166
     * @param ContentItem $contentItem
167
     */
168
    public function updatePageView ($contentItem)
169
    {
170
        /** @var PageView $pageView */
171
        foreach ($this->trackedItems['dynamic'] as &$pageView)
172
        {
173
            $fm = $pageView->getFrontMatter(false);
174
175
            if ($fm['collection'] == $contentItem->getCollection())
176
            {
177
                $pageView->addContentItem($contentItem);
178
            }
179
        }
180
    }
181
182
    /**
183
     * Update an existing Twig variable that's injected globally
184
     *
185
     * @param string $variable
186
     * @param string $value
187
     */
188
    public function updateTwigVariable ($variable, $value)
189
    {
190
        $this->twig->addGlobal($variable, $value);
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196
    public function refreshItem($filePath)
197
    {
198
        $this->compileFromFilePath($filePath, true);
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204
    protected function handleTrackableItem($filePath, $options = array())
205
    {
206
        $pageView = new PageView($filePath);
207
        $namespace = 'static';
208
209
        if ($pageView->isDynamicPage())
210
        {
211
            $namespace = 'dynamic';
212
            $frontMatter = $pageView->getFrontMatter(false);
213
            $collection = $frontMatter['collection'];
214
215
            foreach ($this->collections[$collection] as &$item)
216
            {
217
                $item->evaluateFrontMatter($frontMatter);
218
                $pageView->addContentItem($item);
219
            }
220
        }
221
222
        $this->addObjectToTracker($pageView, $pageView->getRelativeFilePath(), $namespace);
223
        $this->saveTrackerOptions($pageView->getRelativeFilePath(), array(
224
            'viewType' => $namespace
225
        ));
226
227
        if ($namespace === 'static')
228
        {
229
            $this->addToSiteMenu($pageView->getFrontMatter());
230
        }
231
    }
232
233
    /**
234
     * Compile a given PageView
235
     *
236
     * @param string $filePath The file path to the PageView to compile
237
     * @param bool   $refresh  When set to true, the PageView will reread its contents
238
     *
239
     * @throws \Exception
240
     */
241
    private function compileFromFilePath ($filePath, $refresh = false)
242
    {
243
        if (!$this->isTracked($filePath))
244
        {
245
            throw new TrackedItemNotFoundException('PageView not found');
246
        }
247
248
        /** @var PageView $pageView */
249
        $pageView = &$this->trackedItemsFlattened[$filePath];
250
251
        $this->compilePageView($pageView, $refresh);
252
    }
253
254
    /**
255
     * @param PageView $pageView
256
     * @param bool     $refresh
257
     */
258
    private function compilePageView ($pageView, $refresh = false)
259
    {
260
        if ($refresh)
261
        {
262
            $pageView->refreshFileContent();
263
        }
264
265
        if ($pageView->isDynamicPage())
266
        {
267
            $this->compileDynamicPageView($pageView);
268
        }
269
        else
270
        {
271
            $this->compileStaticPageView($pageView);
272
        }
273
    }
274
275
    /**
276
     * @param PageView $pageView
277
     */
278
    private function compileDynamicPageView (&$pageView)
279
    {
280
        $template = $this->createTemplate($pageView);
281
282
        $pageViewFrontMatter = $pageView->getFrontMatter(false);
283
        $collection = $pageViewFrontMatter['collection'];
284
285
        /** @var ContentItem $contentItem */
286
        foreach ($this->collections[$collection] as &$contentItem)
287
        {
288
            $output = $template->render(array(
289
                'this' => $contentItem
290
            ));
291
292
            $this->output->notice("Writing file: {file}", array('file' => $contentItem->getTargetFile()));
293
            $this->targetDir->writeFile($contentItem->getTargetFile(), $output);
294
        }
295
    }
296
297
    /**
298
     * @param PageView $pageView
299
     */
300
    private function compileStaticPageView (&$pageView)
301
    {
302
        $this->twig->addGlobal('__currentTemplate', $pageView->getFilePath());
303
304
        $template = $this->createTemplate($pageView);
305
        $output = $template->render(array(
306
            'this' => $pageView->getFrontMatter()
307
        ));
308
309
        $this->output->notice("Writing file: {file}", array('file' => $pageView->getTargetFile()));
310
        $this->targetDir->writeFile($pageView->getTargetFile(), $output);
311
    }
312
313
    /**
314
     * Add a static PageView to the menu array. Dynamic PageViews are not added to the menu
315
     *
316
     * @param array $frontMatter
317
     */
318
    private function addToSiteMenu ($frontMatter)
319
    {
320
        if (!array_key_exists('permalink', $frontMatter) ||
321
            (array_key_exists('menu', $frontMatter) && !$frontMatter['menu']))
322
        {
323
            return;
324
        }
325
326
        $url = $frontMatter['permalink'];
327
        $root = &$this->siteMenu;
328
        $permalink = trim($url, DIRECTORY_SEPARATOR);
329
        $dirs = explode(DIRECTORY_SEPARATOR, $permalink);
330
331
        while (count($dirs) > 0)
332
        {
333
            $name = array_shift($dirs);
334
            $name = (!empty($name)) ? $name : '.';
335
336
            if (!isset($root[$name]) && !is_null($name) && count($dirs) == 0)
337
            {
338
                $link = (pathinfo($url, PATHINFO_EXTENSION) !== "") ? $url : $permalink . DIRECTORY_SEPARATOR;
339
340
                $root[$name] = array_merge($frontMatter, array(
341
                    "url"  => '/' . $link,
342
                    "children" => array()
343
                ));
344
            }
345
346
            $root = &$root[$name]['children'];
347
        }
348
    }
349
350
    /**
351
     * @param PageView $pageView
352
     *
353
     * @return Twig_Template
354
     * @throws Twig_Error_Syntax
355
     */
356
    private function createTemplate ($pageView)
357
    {
358
        try
359
        {
360
            return $this->twig->createTemplate($pageView->getContent());
361
        }
362
        catch (Twig_Error_Syntax $e)
363
        {
364
            $e->setTemplateFile($pageView->getRelativeFilePath());
365
366
            throw $e;
367
        }
368
    }
369
}