Passed
Push — master ( f9f203...243e60 )
by Jens
07:30
created

Application::run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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