Completed
Pull Request — master (#69)
by Vladimir
05:36
created

PageManager   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 17

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 300
c 0
b 0
f 0
wmc 29
lcom 2
cbo 17
rs 10
ccs 0
cts 112
cp 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 21 1
A compileManager() 0 5 1
A parseAssetPageViews() 0 35 5
A parsePageViews() 0 20 3
A getPageViews() 0 4 1
A getPageViewsFlattened() 0 4 1
A getStaticPageViews() 0 4 1
A getJailedStaticPageViews() 0 11 2
A trackNewContentItem() 0 5 1
A handleTrackableItem() 0 32 4
A handleTrackableStaticPageView() 0 13 2
B handleTrackableDynamicPageView() 0 41 6
A handleTrackableRepeaterPageView() 0 7 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\Manager;
9
10
use allejo\stakx\AssetEngine\AssetEngine;
11
use allejo\stakx\AssetEngine\AssetEngineManager;
12
use allejo\stakx\Configuration;
13
use allejo\stakx\Document\BasePageView;
14
use allejo\stakx\Document\ContentItem;
15
use allejo\stakx\Document\DataItem;
16
use allejo\stakx\Document\DynamicPageView;
17
use allejo\stakx\Document\JailedDocument;
18
use allejo\stakx\Document\RepeaterPageView;
19
use allejo\stakx\Document\StaticPageView;
20
use allejo\stakx\Event\PageViewAdded;
21
use allejo\stakx\Event\PageViewDefinitionAdded;
22
use allejo\stakx\Exception\CollectionNotFoundException;
23
use allejo\stakx\Filesystem\File;
24
use allejo\stakx\Filesystem\FileExplorer;
25
use allejo\stakx\Filesystem\FilesystemLoader as fs;
26
use Psr\Log\LoggerInterface;
27
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
28
29
/**
30
 * This class is responsible for handling all of the PageViews within a website.
31
 *
32
 * PageManager will parse all available dynamic and static PageViews. After, dynamic PageViews will be prepared by
33
 * setting the appropriate values for each ContentItem such as permalinks.
34
 */
35
class PageManager extends TrackingManager
36
{
37
    /** @var StaticPageView[] A place to store a reference to static PageViews with titles. */
38
    private $staticPages;
39
    private $configuration;
40
    private $assetEngineManager;
41
    private $collectionManager;
42
    private $dataManager;
43
    private $eventDispatcher;
44
    private $logger;
45
46
    /**
47
     * PageManager constructor.
48
     */
49
    public function __construct(
50
        Configuration $configuration,
51
        AssetEngineManager $assetEngineManager,
52
        CollectionManager $collectionManager,
53
        DataManager $dataManager,
54
        EventDispatcherInterface $eventDispatcher,
55
        LoggerInterface $logger
56
    ) {
57
        $this->trackedItems = [
58
            BasePageView::STATIC_TYPE => [],
59
            BasePageView::DYNAMIC_TYPE => [],
60
            BasePageView::REPEATER_TYPE => [],
61
        ];
62
        $this->staticPages = [];
63
        $this->configuration = $configuration;
64
        $this->assetEngineManager = $assetEngineManager;
65
        $this->collectionManager = $collectionManager;
66
        $this->dataManager = $dataManager;
67
        $this->eventDispatcher = $eventDispatcher;
68
        $this->logger = $logger;
69
    }
70
71
    /**
72
     * {@inheritdoc}
73
     */
74
    public function compileManager()
75
    {
76
        $this->parseAssetPageViews();
77
        $this->parsePageViews($this->configuration->getPageViewFolders());
78
    }
79
80
    public function parseAssetPageViews()
81
    {
82
        /**
83
         * @var string      $folder
84
         * @var AssetEngine $engine
85
         */
86
        foreach ($this->assetEngineManager->getFoldersToWatch() as $folder => $engine)
87
        {
88
            $assetFolder = fs::absolutePath($folder);
0 ignored issues
show
Documentation introduced by
$folder is of type integer|string, but the function expects a object<string>.

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...
89
90
            if (!fs::exists($assetFolder))
91
            {
92
                continue;
93
            }
94
95
            $extensions = [];
96
97
            foreach ($engine->getExtensions() as $extension)
98
            {
99
                $extensions[] = "/.{$extension}.twig$/";
100
            }
101
102
            $explorer = FileExplorer::create($assetFolder, [], $extensions, FileExplorer::IGNORE_DIRECTORIES);
103
104
            foreach ($explorer as $file)
105
            {
106
                $assetPageView = new StaticPageView($file);
107
                $compiled = $engine->parse($assetPageView->getContent());
108
                $assetPageView->setContent($compiled);
109
110
                $this->handleTrackableStaticPageView($assetPageView);
111
                $this->addObjectToTracker($assetPageView, $assetPageView->getType());
112
            }
113
        }
114
    }
115
116
    /**
117
     * Go through all of the PageView directories and create a respective PageView for each and classify them by type.
118
     *
119
     * @param string[] $pageViewFolders
120
     *
121
     * @since 0.1.0
122
     */
123
    public function parsePageViews(array $pageViewFolders)
124
    {
125
        foreach ($pageViewFolders as $pageViewFolderName)
126
        {
127
            $pageViewFolderPath = fs::absolutePath($pageViewFolderName);
0 ignored issues
show
Documentation introduced by
$pageViewFolderName is of type string, but the function expects a object<string>.

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...
128
129
            if (!fs::exists($pageViewFolderPath))
130
            {
131
                $this->logger->warning("The '$pageViewFolderName' folder could not be found");
132
                continue;
133
            }
134
135
            $event = new PageViewDefinitionAdded($pageViewFolderName);
136
            $this->eventDispatcher->dispatch(PageViewDefinitionAdded::NAME, $event);
137
138
            $this->scanTrackableItems($pageViewFolderPath, [
139
                'fileExplorer' => FileExplorer::INCLUDE_ONLY_FILES,
140
            ], ['/.html$/', '/.twig$/']);
141
        }
142
    }
143
144
    /**
145
     * Get all of the PageViews in an associative array with PageView types as the keys.
146
     *
147
     * @since  0.1.1
148
     *
149
     * @return BasePageView[][]
150
     */
151
    public function &getPageViews()
152
    {
153
        return $this->trackedItems;
154
    }
155
156
    /**
157
     * Get all of the PageViews in flat array.
158
     *
159
     * @since  0.1.1
160
     *
161
     * @return BasePageView[]
162
     */
163
    public function &getPageViewsFlattened()
164
    {
165
        return $this->trackedItemsFlattened;
166
    }
167
168
    /**
169
     * Get the static PageViews tracked by this manager indexed by their title.
170
     *
171
     * @since 0.1.0
172
     *
173
     * @return StaticPageView[]
174
     */
175
    public function getStaticPageViews()
176
    {
177
        return $this->staticPages;
178
    }
179
180
    /**
181
     * Get the jailed version of the static PageViews indexed by their title.
182
     *
183
     * @since 0.1.0
184
     *
185
     * @return JailedDocument[]
186
     */
187
    public function getJailedStaticPageViews()
188
    {
189
        $jailedObjects = [];
190
191
        foreach ($this->staticPages as $key => $value)
192
        {
193
            $jailedObjects[$key] = $value->createJail();
194
        }
195
196
        return $jailedObjects;
197
    }
198
199
    /**
200
     * Add a new ContentItem to the respective parent PageView of the ContentItem.
201
     *
202
     * @param ContentItem $contentItem
203
     *
204
     * @since 0.1.0
205
     */
206
    public function trackNewContentItem(&$contentItem)
207
    {
208
        $collection = $contentItem->getNamespace();
209
        $this->trackedItems[BasePageView::DYNAMIC_TYPE][$collection]->addCollectableItem($contentItem);
210
    }
211
212
    /**
213
     * {@inheritdoc}
214
     */
215
    protected function &handleTrackableItem(File $filePath, array $options = [])
216
    {
217
        $pageView = BasePageView::create($filePath, [
218
            'site' => $this->configuration->getConfiguration(),
219
        ]);
220
        $namespace = $pageView->getType();
221
222
        switch ($namespace)
223
        {
224
            case BasePageView::STATIC_TYPE:
225
                $this->handleTrackableStaticPageView($pageView);
0 ignored issues
show
Bug introduced by
It seems like $pageView defined by \allejo\stakx\Document\B...n->getConfiguration())) on line 217 can also be of type object<allejo\stakx\Document\DynamicPageView> or object<allejo\stakx\Document\RepeaterPageView>; however, allejo\stakx\Manager\Pag...ackableStaticPageView() does only seem to accept object<allejo\stakx\Document\StaticPageView>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
226
                break;
227
228
            case BasePageView::DYNAMIC_TYPE:
229
                $this->handleTrackableDynamicPageView($pageView);
0 ignored issues
show
Bug introduced by
It seems like $pageView defined by \allejo\stakx\Document\B...n->getConfiguration())) on line 217 can also be of type object<allejo\stakx\Document\RepeaterPageView> or object<allejo\stakx\Document\StaticPageView>; however, allejo\stakx\Manager\Pag...ckableDynamicPageView() does only seem to accept object<allejo\stakx\Document\DynamicPageView>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
230
                break;
231
232
            case BasePageView::REPEATER_TYPE:
233
                $this->handleTrackableRepeaterPageView($pageView);
0 ignored issues
show
Bug introduced by
It seems like $pageView defined by \allejo\stakx\Document\B...n->getConfiguration())) on line 217 can also be of type object<allejo\stakx\Document\DynamicPageView> or object<allejo\stakx\Document\StaticPageView>; however, allejo\stakx\Manager\Pag...kableRepeaterPageView() does only seem to accept object<allejo\stakx\Document\RepeaterPageView>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
234
                break;
235
236
            default:
237
                break;
238
        }
239
240
        $event = new PageViewAdded($pageView);
241
        $this->eventDispatcher->dispatch(PageViewAdded::NAME, $event);
242
243
        $this->addObjectToTracker($pageView, $namespace);
244
245
        return $pageView;
246
    }
247
248
    /**
249
     * Handle special behavior and treatment for static PageViews while we're iterating through them.
250
     *
251
     * @param StaticPageView $pageView
252
     *
253
     * @since 0.1.0
254
     */
255
    private function handleTrackableStaticPageView(&$pageView)
256
    {
257
        $pageView->evaluateFrontMatter([], [
258
            'site' => $this->configuration->getConfiguration(),
259
        ]);
260
261
        if (empty($pageView['title']))
262
        {
263
            return;
264
        }
265
266
        $this->staticPages[$pageView['title']] = &$pageView;
267
    }
268
269
    /**
270
     * Handle special behavior and treatment for dynamic PageViews while we're iterating through them.
271
     *
272
     * @param DynamicPageView $pageView
273
     *
274
     * @since 0.1.0
275
     *
276
     * @throws \Exception
277
     */
278
    private function handleTrackableDynamicPageView(&$pageView)
279
    {
280
        $frontMatter = $pageView->getRawFrontMatter();
281
        $dataSource = null;
282
        $namespace = null;
283
284
        if (isset($frontMatter['collection']))
285
        {
286
            $dataSource = &$this->collectionManager->getCollections();
287
            $namespace = 'collection';
288
        }
289
        elseif (isset($frontMatter['dataset']))
290
        {
291
            $dataSource = &$this->dataManager->getDataItems();
292
            $namespace = 'dataset';
293
        }
294
295
        if ($dataSource === null)
296
        {
297
            throw new \Exception('Invalid Dynamic PageView defined');
298
        }
299
300
        $collection = $frontMatter[$namespace];
301
302
        if (!isset($dataSource[$collection]))
303
        {
304
            throw new CollectionNotFoundException("The '$collection' $namespace is not defined");
305
        }
306
307
        /** @var ContentItem|DataItem $item */
308
        foreach ($dataSource[$collection] as &$item)
309
        {
310
            $item->evaluateFrontMatter($frontMatter, [
311
                'site' => $this->configuration->getConfiguration(),
312
            ]);
313
            $item->saveParentPageView($pageView);
314
            $item->buildPermalink(true);
315
316
            $pageView->addCollectableItem($item);
317
        }
318
    }
319
320
    /**
321
     * Handle special behavior and treatment for repeater PageViews while we're iterating through them.
322
     *
323
     * @param RepeaterPageView $pageView
324
     *
325
     * @since 0.2.0
326
     */
327
    private function handleTrackableRepeaterPageView(&$pageView)
328
    {
329
        $pageView->evaluateFrontMatter([], [
330
            'site' => $this->configuration->getConfiguration(),
331
        ]);
332
        $pageView->configurePermalinks();
333
    }
334
}
335