Passed
Push — develop ( fc59e1...90305f )
by Jens
02:30
created

Application::startServices()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 9.4285
1
<?php
2
3
namespace CloudControl\Cms\cc {
4
5
    use CloudControl\Cms\components\Component;
6
    use CloudControl\Cms\services\FileService;
7
    use CloudControl\Cms\services\ImageService;
8
    use CloudControl\Cms\storage\Storage;
9
    use Whoops\Handler\PrettyPageHandler;
10
    use Whoops\Run;
11
12
    class Application
13
    {
14
        /**
15
         * @var string
16
         */
17
        protected $rootDir;
18
        /**
19
         * @var string
20
         */
21
        protected $configPath;
22
        /**
23
         * @var \stdClass
24
         */
25
        private $config;
26
        /**
27
         * @var \CloudControl\Cms\storage\Storage
28
         */
29
        private $storage;
30
31
        /**
32
         * @var \CloudControl\Cms\cc\Request
33
         */
34
        private $request;
35
36
        /**
37
         * @var array
38
         */
39
        private $matchedSitemapItems = array();
40
41
        /**
42
         * @var array
43
         */
44
        private $applicationComponents = array();
45
46
        /**
47
         * Application constructor.
48
         * @param string $rootDir
49
         * @param string $configPath
50
         */
51
        public function __construct($rootDir, $configPath)
52
        {
53
            $this->rootDir = $rootDir;
54
            $this->configPath = $configPath;
55
56
            $this->config();
57
            $this->storage();
58
59
            $this->request = new Request();
60
61
            $this->setExceptionHandler();
62
63
            $this->startServices();
64
65
            $this->urlMatching();
66
67
            $this->getApplicationComponents();
68
69
            $this->run();
70
            $this->render();
71
        }
72
73
        /**
74
         * Initialize the config
75
         *
76
         * @throws \Exception
77
         */
78
        private function config()
79
        {
80
            if (realpath($this->configPath) !== false) {
81
                $json = file_get_contents($this->configPath);
82
                $this->config = json_decode($json);
83
                $this->config->rootDir = $this->rootDir;
84
            } else {
85
                throw new \Exception('Framework not initialized yet. Consider running composer install');
86
            }
87
        }
88
89
        /**
90
         * Initialize the storage
91
         */
92
        private function storage()
93
        {
94
            $this->storage = new Storage($this->config->rootDir . DIRECTORY_SEPARATOR . $this->config->storageDir, $this->config->rootDir . DIRECTORY_SEPARATOR . $this->config->imagesDir, $this->config->filesDir);
95
        }
96
97
        /**
98
         * @param Request $request
99
         * @throws \Exception
100
         */
101
        private function redirectMatching($request)
102
        {
103
            $redirects = $this->storage->getRedirects()->getRedirects();
104
            $relativeUri = '/' . $request::$relativeUri;
105
106
            foreach ($redirects as $redirect) {
107
                if (preg_match_all($redirect->fromUrl, $relativeUri, $matches)) {
108
                    $toUrl = preg_replace($redirect->fromUrl, $redirect->toUrl, $relativeUri);
109
                    if (substr($toUrl, 0, 1) == '/') {
110
                        $toUrl = substr($toUrl, 1);
111
                    }
112
                    if ($redirect->type == '301') {
113
                        header('HTTP/1.1 301 Moved Permanently');
114
                        header('Location: ' . $request::$subfolders . $toUrl);
115
                        exit;
116
                    } elseif ($redirect->type == '302') {
117
                        header('Location: ' . $request::$subfolders . $toUrl, true, 302);
118
                        exit;
119
                    } else {
120
                        throw new \Exception('Invalid redirect type.');
121
                    }
122
                }
123
            }
124
        }
125
126
        /**
127
         * Loop through sitemap items and see if one matches the requestUri.
128
         * If it does, add it tot the matchedSitemapItems array
129
         *
130
         * @param Request $request
131
         */
132
        private function sitemapMatching($request)
133
        {
134
            $sitemap = $this->storage->getSitemap()->getSitemap();
135
            $relativeUri = '/' . $request::$relativeUri;
136
137
            foreach ($sitemap as $sitemapItem) {
138
                if ($sitemapItem->regex) {
139
                    $matches = array();
140
                    if (preg_match_all($sitemapItem->url, $relativeUri, $matches)) {
141
                        // Make a clone, so it doesnt add the matches to the original
142
                        $matchedClone = clone $sitemapItem;
143
                        $matchedClone->matches = $matches;
144
                        $this->matchedSitemapItems[] = $matchedClone;
145
                        return;
146
                    }
147
                } else {
148
                    if ($sitemapItem->url == $relativeUri) {
149
                        $this->matchedSitemapItems[] = $sitemapItem;
150
                        return;
151
                    }
152
                }
153
            }
154
        }
155
156
        /**
157
         * Loop through all application components and run them
158
         *
159
         * @throws \Exception
160
         */
161
        private function runApplicationComponents()
162
        {
163
            foreach ($this->applicationComponents as $key => $applicationComponent) {
164
                $class = $applicationComponent->component;
165
                $parameters = $applicationComponent->parameters;
166
                $this->applicationComponents[$key]->{'object'} = $this->getComponentObject($class, null, $parameters, null);
167
                $this->applicationComponents[$key]->{'object'}->run($this->storage);
168
            }
169
        }
170
171
        /**
172
         * Loop through all (matched) sitemap components and run them
173
         *
174
         * @throws \Exception
175
         */
176
        private function runSitemapComponents()
177
        {
178
            foreach ($this->matchedSitemapItems as $key => $sitemapItem) {
179
                $class = $sitemapItem->component;
180
                $template = $sitemapItem->template;
181
                $parameters = $sitemapItem->parameters;
182
183
                $this->matchedSitemapItems[$key]->object = $this->getComponentObject($class, $template, $parameters, $sitemapItem);
184
185
                $this->matchedSitemapItems[$key]->object->run($this->storage);
186
            }
187
        }
188
189
        /**
190
         * @param string $class
191
         * @param string $template
192
         * @param array $parameters
193
         * @param \stdClass|null $matchedSitemapItem
194
         *
195
         * @return Component
196
         * @throws \Exception
197
         */
198
        private function getComponentObject($class = '', $template = '', $parameters = array(), $matchedSitemapItem)
199
        {
200
            $libraryComponentName = '\\CloudControl\Cms\\components\\' . $class;
201
            $userComponentName = '\\components\\' . $class;
202
203
            if (class_exists($libraryComponentName)) {
204
                $component = new $libraryComponentName($template, $this->request, $parameters, $matchedSitemapItem);
205
            } elseif (class_exists($userComponentName)) {
206
                $component = new $userComponentName($template, $this->request, $parameters, $matchedSitemapItem);
207
            } else {
208
                throw new \Exception('Could not load component ' . $class);
209
            }
210
211
            if (!$component instanceof Component) {
212
                throw new \Exception('Component not of type Component. Must inherit \CloudControl\Cms\components\Component');
213
            }
214
215
            return $component;
216
        }
217
218
        /**
219
         * Loop through all application components and render them
220
         */
221
        private function renderApplicationComponents()
222
        {
223
            foreach ($this->applicationComponents as $applicationComponent) {
224
                $applicationComponent->{'object'}->render();
225
            }
226
        }
227
228
        /**
229
         * Loop through all (matched) sitemap components and render them
230
         */
231
        private function renderSitemapComponents()
232
        {
233
            foreach ($this->matchedSitemapItems as $sitemapItem) {
234
                $this->setCachingHeaders();
235
                $sitemapItem->object->render($this);
236
                ob_clean();
237
                echo $sitemapItem->object->get();
238
                ob_end_flush();
239
                exit;
240
            }
241
        }
242
243
        public function getAllApplicationComponentParameters()
244
        {
245
            $allParameters = array();
246
            foreach ($this->applicationComponents as $applicationComponent) {
247
                $parameters = $applicationComponent->{'object'}->getParameters();
248
                $allParameters[] = $parameters;
249
            }
250
            return $allParameters;
251
        }
252
253
        public function unlockApplicationComponentParameters()
254
        {
255
            foreach ($this->applicationComponents as $applicationComponent) {
256
                $parameters = $applicationComponent->{'object'}->getParameters();
257
                extract($parameters);
258
            }
259
        }
260
261
        /**
262
         * Set the default caching of pages to 2 days
263
         */
264
        public function setCachingHeaders()
265
        {
266
            header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + (60 * 60 * 24 * 2))); // 2 days
267
            header("Cache-Control: max-age=" . (60 * 60 * 24 * 2));
268
        }
269
270
        /**
271
         * @return string
272
         */
273
        public function getTemplateDir()
274
        {
275
            return $this->config->templateDir;
276
        }
277
278
        /**
279
         * @return string
280
         */
281
        public function getStorageDir()
282
        {
283
            return $this->config->storageDir;
284
        }
285
286
        public function getApplicationComponents()
287
        {
288
            $this->applicationComponents = $this->storage->getApplicationComponents()->getApplicationComponents();
289
        }
290
291
        /**
292
         * @return string
293
         */
294
        public function getRootDir()
295
        {
296
            return $this->config->rootDir;
297
        }
298
299
        private function setExceptionHandler()
300
        {
301
            $whoops = new Run;
302
            $whoops->pushHandler(new PrettyPageHandler);
0 ignored issues
show
Documentation introduced by
new \Whoops\Handler\PrettyPageHandler() is of type object<Whoops\Handler\PrettyPageHandler>, but the function expects a callable.

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...
303
            $whoops->register();
304
        }
305
306
        private function urlMatching()
307
        {
308
            $this->redirectMatching($this->request);
309
            $this->sitemapMatching($this->request);
310
        }
311
312
        private function run()
313
        {
314
            $this->runApplicationComponents();
315
            $this->runSitemapComponents();
316
        }
317
318
        private function render()
319
        {
320
            $this->renderApplicationComponents();
321
            $this->renderSitemapComponents();
322
        }
323
324
        private function startServices()
325
        {
326
            FileService::getInstance()->init($this->storage);
327
            ImageService::getInstance()->init($this->storage);
328
        }
329
    }
330
}