Test Failed
Push — develop ( d3d02f...9481b3 )
by Brent
04:21
created

SiteParser::parse()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 15
nc 24
nop 2
dl 0
loc 24
rs 8.5125
c 0
b 0
f 0
1
<?php
2
3
namespace Brendt\Stitcher\Parser\Site;
4
5
use Pageon\Html\Meta\Meta;
6
use Brendt\Stitcher\Event\Event;
7
use Brendt\Stitcher\Exception\InvalidSiteException;
8
use Brendt\Stitcher\Exception\TemplateNotFoundException;
9
use Brendt\Stitcher\Site\Http\Htaccess;
10
use Brendt\Stitcher\Site\Page;
11
use Brendt\Stitcher\Site\Site;
12
use Pageon\Pcntl\Manager;
13
use Pageon\Pcntl\PageRenderProcess;
14
use Pageon\Pcntl\ThreadHandlerCollection;
15
use Symfony\Component\EventDispatcher\EventDispatcher;
16
use Symfony\Component\Finder\Finder;
17
use Symfony\Component\Finder\SplFileInfo;
18
use Symfony\Component\Yaml\Exception\ParseException;
19
use Symfony\Component\Yaml\Yaml;
20
21
class SiteParser
22
{
23
    const EVENT_PARSER_INIT = 'parser.initialised';
24
25
    const EVENT_PAGE_PARSING = 'page.parsing';
26
27
    const EVENT_PAGE_PARSED = 'page.parsed';
28
29
    const TOKEN_REDIRECT = 'redirect';
30
31
    /**
32
     * @var string
33
     */
34
    private $filter;
35
36
    /**
37
     * @var string
38
     */
39
    private $srcDir;
40
41
    /**
42
     * @var array
43
     */
44
    private $metaConfig;
45
46
    /**
47
     * @var EventDispatcher
48
     */
49
    private $eventDispatcher;
50
51
    /**
52
     * @var PageParser
53
     */
54
    private $pageParser;
55
56
    /**
57
     * @var Htaccess
58
     */
59
    private $htaccess;
60
61
    /**
62
     * @var string
63
     */
64
    private $publicDir;
65
66
    /**
67
     * @var bool
68
     */
69
    private $async;
70
71
    /**
72
     * SiteParser constructor.
73
     *
74
     * @param string          $srcDir
75
     * @param string          $publicDir
76
     * @param bool            $async
77
     * @param EventDispatcher $eventDispatcher
78
     * @param PageParser      $pageParser
79
     * @param Htaccess        $htaccess
80
     * @param array           $metaConfig
81
     */
82
    public function __construct(
83
        string $srcDir,
84
        string $publicDir,
85
        bool $async,
86
        EventDispatcher $eventDispatcher,
87
        PageParser $pageParser,
88
        Htaccess $htaccess,
89
        array $metaConfig = []
90
    ) {
91
        $this->srcDir = $srcDir;
92
        $this->publicDir = $publicDir;
93
        $this->eventDispatcher = $eventDispatcher;
94
        $this->pageParser = $pageParser;
95
        $this->htaccess = $htaccess;
96
        $this->metaConfig = $metaConfig;
97
        $this->async = $async;
98
    }
99
100
    /**
101
     * Load a site from YAML configuration files in the `directories.src`/site directory.
102
     * All YAML files are loaded and parsed into Page objects and added to a Site collection.
103
     *
104
     * @param array $routes
105
     *
106
     * @return Site
107
     * @throws InvalidSiteException
108
     * @see \Brendt\Stitcher\Site\Page
109
     * @see \Brendt\Stitcher\Site\Site
110
     */
111
    public function loadSite(array $routes = []) : Site {
112
        /** @var SplFileInfo[] $files */
113
        $files = Finder::create()->files()->in("{$this->srcDir}/site")->name('*.yml');
114
        $site = new Site();
115
116
        foreach ($files as $file) {
117
            try {
118
                $fileContents = (array) Yaml::parse($file->getContents());
119
            } catch (ParseException $e) {
120
                throw new InvalidSiteException("{$file->getRelativePathname()}: {$e->getMessage()}");
121
            }
122
123
            foreach ($fileContents as $route => $config) {
124
                if (count($routes) && !in_array($route, $routes)) {
125
                    continue;
126
                }
127
128
                $this->loadPage($site, $route, $config);
129
            }
130
        }
131
132
        return $site;
133
    }
134
135
    /**
136
     * @param Site   $site
137
     * @param string $route
138
     * @param array  $config
139
     */
140
    private function loadPage(Site $site, string $route, array $config) {
141
        if (isset($config[self::TOKEN_REDIRECT])) {
142
            $this->htaccess->addRedirect($route, $config[self::TOKEN_REDIRECT]);
143
144
            return;
145
        }
146
147
        $page = new Page($route, $config, $this->createMeta());
148
        $site->addPage($page);
149
    }
150
151
    /**
152
     * Parse a path into usable data.
153
     *
154
     * @param array  $routes
155
     * @param string $filterValue
156
     *
157
     * @throws TemplateNotFoundException
158
     */
159
    public function parse($routes = [], string $filterValue = null) {
160
        $manager = extension_loaded('pcntl') && $this->async ? new Manager($this->eventDispatcher) : null;
161
        $threadHandlerCollection = new ThreadHandlerCollection();
162
163
        $site = $this->loadSite((array) $routes);
164
        $this->eventDispatcher->dispatch(self::EVENT_PARSER_INIT, Event::create(['site' => $site]));
165
166
        foreach ($site as $page) {
167
            $this->eventDispatcher->dispatch(self::EVENT_PAGE_PARSING, Event::create(['page' => $page]));
168
169
            $pageRenderProcess = new PageRenderProcess($this->pageParser, $page, $this->publicDir, $filterValue);
170
171
            if ($manager) {
172
                $threadHandlerCollection[] = $manager->async($pageRenderProcess);
173
            } else {
174
                $event = $pageRenderProcess->execute();
175
                $this->eventDispatcher->dispatch($event->getEventHook(), $event);
176
            }
177
        }
178
179
        if ($manager) {
180
            $manager->wait($threadHandlerCollection);
181
        }
182
    }
183
184
    /**
185
     * @param string $filter
186
     *
187
     * @return SiteParser
188
     */
189
    public function setFilter(string $filter) : SiteParser {
190
        $this->filter = $filter;
191
192
        return $this;
193
    }
194
195
    /**
196
     * @return Meta
197
     */
198
    private function createMeta() : Meta {
199
        $meta = new Meta();
200
201
        foreach ($this->metaConfig as $name => $value) {
202
            $meta->name($name, $value);
203
        }
204
205
        return $meta;
206
    }
207
}
208