Passed
Push — master ( 7e0f83...5c9096 )
by Gabor
03:19
created

EnvironmentManager::getRequestUri()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
namespace WebHemi\Application;
13
14
use InvalidArgumentException;
15
use WebHemi\Config\ConfigInterface;
16
17
/**
18
 * Class EnvironmentManager.
19
 */
20
class EnvironmentManager
21
{
22
    const APPLICATION_TYPE_DIRECTORY = 'directory';
23
    const APPLICATION_TYPE_DOMAIN = 'domain';
24
25
    const COOKIE_AUTO_LOGIN_PREFIX = 'atln';
26
    const COOKIE_SESSION_PREFIX = 'atsn';
27
28
    const DEFAULT_APPLICATION = 'website';
29
    const DEFAULT_APPLICATION_URI = '/';
30
    const DEFAULT_MODULE = 'Website';
31
    const DEFAULT_THEME = 'default';
32
    const DEFAULT_THEME_RESOURCE_PATH = '/resources/default_theme';
33
34
    const SESSION_SALT = 'WebHemi';
35
36
    /** @var ConfigInterface */
37
    private $configuration;
38
    /** @var string */
39
    private $url;
40
    /** @var string */
41
    private $subDomain;
42
    /** @var string */
43
    private $mainDomain;
44
    /** @var string */
45
    private $applicationDomain;
46
    /** @var string */
47
    private $documentRoot;
48
    /** @var string */
49
    private $selectedModule;
50
    /** @var string */
51
    private $selectedApplication;
52
    /** @var string */
53
    private $selectedApplicationUri;
54
    /** @var string */
55
    private $selectedTheme;
56
    /** @var string */
57
    private $selectedThemeResourcePath;
58
    /** @var array  */
59
    private $environmentData;
60
    /** @var bool */
61
    private $isHttps;
62
63
    /**
64
     * ModuleManager constructor.
65
     *
66
     * @param ConfigInterface $configuration
67
     * @param array           $getData
68
     * @param array           $postData
69
     * @param array           $serverData
70
     * @param array           $cookieData
71
     * @param array           $filesData
72
     */
73 4
    public function __construct(
74
        ConfigInterface $configuration,
75
        array $getData,
76
        array $postData,
77
        array $serverData,
78
        array $cookieData,
79
        array $filesData
80
    ) {
81 4
        $this->configuration = $configuration->getConfig('applications');
82 4
        $this->documentRoot = realpath(__DIR__.'/../../../');
83
84 4
        if (isset($serverData['HTTP_REFERER'])) {
85 4
            $serverData['HTTP_REFERER'] = urldecode($serverData['HTTP_REFERER']);
86 4
        }
87
88 4
        $this->environmentData = [
89 4
            'GET'    => $getData,
90 4
            'POST'   => $postData,
91 4
            'SERVER' => $serverData,
92 4
            'COOKIE' => $cookieData,
93 4
            'FILES'  => $filesData,
94
        ];
95
96 4
        $this->isHttps = isset($this->environmentData['SERVER']['HTTPS']) && $this->environmentData['SERVER']['HTTPS'];
97 4
        $this->url = 'http'.($this->isHttps ? 's' : '').'://'
98 4
            .$this->environmentData['SERVER']['HTTP_HOST']
99 4
            .$this->environmentData['SERVER']['REQUEST_URI']; // contains also the query string
100
101 4
        $this->selectedModule = self::DEFAULT_MODULE;
102 4
        $this->selectedApplication = self::DEFAULT_APPLICATION;
103 4
        $this->selectedTheme = self::DEFAULT_THEME;
104 4
        $this->selectedThemeResourcePath = self::DEFAULT_THEME_RESOURCE_PATH;
105 4
        $this->selectedApplicationUri = self::DEFAULT_APPLICATION_URI;
106
107 4
        $this->setDomain()
108 4
            ->selectModuleApplicationAndTheme();
109 4
    }
110
111
    /**
112
     * Gets the document root path.
113
     *
114
     * @return string
115
     */
116 1
    public function getDocumentRoot()
117
    {
118 1
        return $this->documentRoot;
119
    }
120
121
    /**
122
     * Gets the application domain.
123
     *
124
     * @return string
125
     */
126 1
    public function getApplicationDomain()
127
    {
128 1
        return $this->applicationDomain;
129
    }
130
131
    /**
132
     * Gets the application SSL status.
133
     *
134
     * @return bool
135
     */
136 1
    public function isSecuredApplication()
137
    {
138 1
        return $this->isHttps;
139
    }
140
141
    /**
142
     * Gets the selected application.
143
     *
144
     * @return string
145
     */
146 4
    public function getSelectedApplication()
147
    {
148 4
        return $this->selectedApplication;
149
    }
150
151
    /**
152
     * Get the URI path for the selected application. Required for the RouterAdapter to work with directory-based
153
     * applications correctly.
154
     *
155
     * @return string
156
     */
157 4
    public function getSelectedApplicationUri()
158
    {
159 4
        return $this->selectedApplicationUri;
160
    }
161
162
    /**
163
     * Gets the request URI
164
     *
165
     * @return string
166
     */
167 1
    public function getRequestUri()
168
    {
169 1
        return $this->environmentData['SERVER']['REQUEST_URI'];
170
    }
171
172
    /**
173
     * Gets the selected module.
174
     *
175
     * @return string
176
     */
177 1
    public function getSelectedModule()
178
    {
179 1
        return $this->selectedModule;
180
    }
181
182
    /**
183
     * Gets the selected theme.
184
     *
185
     * @return string
186
     */
187 1
    public function getSelectedTheme()
188
    {
189 1
        return $this->selectedTheme;
190
    }
191
192
    /**
193
     * Gets the resource path for the selected theme.
194
     *
195
     * @return string
196
     */
197 2
    public function getResourcePath()
198
    {
199 2
        return $this->selectedThemeResourcePath;
200
    }
201
202
    /**
203
     * Gets environment data.
204
     *
205
     * @param string $key
206
     *
207
     * @return array
208
     */
209 1
    public function getEnvironmentData($key)
210
    {
211 1
        if (!isset($this->environmentData[$key])) {
212 1
            throw new InvalidArgumentException(sprintf('The "%s" is not a valid environment key.', $key));
213
        }
214
215 1
        return $this->environmentData[$key];
216
    }
217
218
    /**
219
     * Parses server data and tries to set domain information.
220
     *
221
     * @return $this
222
     */
223 4
    private function setDomain()
224
    {
225 4
        $domain = $this->environmentData['SERVER']['SERVER_NAME'];
226 4
        $subDomain = '';
227 4
        $urlParts = parse_url($this->url);
228
229
        // If the host is not an IP address, then check the sub-domain-based module names too
230 4
        if (!preg_match(
231 4
            '/^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/',
232 4
            $urlParts['host']
233 4
        )) {
234 4
            $domainParts = explode('.', $urlParts['host']);
235
            // @todo find out how to support complex TLDs like `.co.uk` or `.com.br`
236 4
            $tld = array_pop($domainParts);
237 4
            $domain = array_pop($domainParts).'.'.$tld;
238
            // the rest is the sub-domain
239 4
            $subDomain = implode('.', $domainParts);
240 4
        }
241
242
        // If no sub-domain presents, then it should be handled as the default sub-domain set for the 'website'
243 4
        if (empty($subDomain)) {
244 2
            $subDomain = $this->configuration->getData('website/path');
245 2
        }
246
247 4
        $this->subDomain = $subDomain;
248 4
        $this->mainDomain = $domain;
249 4
        $this->applicationDomain = $this->subDomain.'.'. $this->mainDomain;
250
251
        // Redirecting when the app domain is not equal to the server data
252
        // @codeCoverageIgnoreStart
253
        if (!defined('PHPUNIT_WEBHEMI_TESTSUITE')
254
            && $this->environmentData['SERVER']['SERVER_NAME'] != $this->applicationDomain
255
        ) {
256
            $schema = 'http'.($this->isSecuredApplication() ? 's' : '').'://';
257
            $uri = $this->environmentData['SERVER']['REQUEST_URI'];
258
            header('Location: '.$schema.$this->applicationDomain.$uri);
259
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method setDomain() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
260
        }
261
        // @codeCoverageIgnoreEnd
262
263 4
        return $this;
264
    }
265
266
    /**
267
     * From the parsed domain data, selects the application, module and theme.
268
     *
269
     * @return $this
270
     */
271 4
    private function selectModuleApplicationAndTheme()
272
    {
273 4
        $urlParts = parse_url($this->url);
274 4
        $applications = $this->configuration->toArray();
275
276
        // Only the first segment is important (if exists).
277 4
        list($subDirectory) = explode('/', ltrim($urlParts['path'], '/'), 2);
278
279
        $applicationDataFixture = [
280 4
            'type' => self::APPLICATION_TYPE_DIRECTORY,
281 4
            'module' => self::DEFAULT_MODULE,
282 4
            'theme' => self::DEFAULT_THEME,
283 4
        ];
284
285
        // Run through the available application-modules to validate and find active module
286 4
        foreach ($applications as $applicationName => $applicationData) {
287
            // Don't risk, fix.
288 4
            $applicationData = array_merge($applicationDataFixture, $applicationData);
289
290 4
            if ($this->checkDirectoryIsValid($applicationName, $applicationData, $subDirectory)
291 3
                || $this->checkDomainIsValid($applicationName, $applicationData, $subDirectory)
292 4
            ) {
293 4
                $this->selectedModule = $applicationData['module'];
294 4
                $this->selectedApplication = (string)$applicationName;
295 4
                $this->selectedTheme = $applicationData['theme'];
296
297 4
                $this->selectedApplicationUri = '/'.$subDirectory;
298 4
                break;
299
            }
300 4
        }
301
302
        // Final check for config and resources.
303 4
        if ($this->selectedTheme !== self::DEFAULT_THEME) {
304 1
            $this->selectedThemeResourcePath = '/resources/vendor_themes/'.$this->selectedTheme;
305 1
        }
306
307 4
        return $this;
308
    }
309
310
    /**
311
     * Checks from type, path it the current URI segment is valid.
312
     *
313
     * @param string $applicationName
314
     * @param array  $applicationData
315
     * @param string $subDirectory
316
     *
317
     * @return bool
318
     */
319 4
    private function checkDirectoryIsValid($applicationName, $applicationData, $subDirectory)
320
    {
321 4
        return $this->subDomain == $this->configuration->getData('website/path')
322 4
            && $applicationName != 'website'
323 4
            && !empty($subDirectory)
324 4
            && $applicationData['type'] == self::APPLICATION_TYPE_DIRECTORY
325 4
            && $applicationData['path'] == $subDirectory;
326
    }
327
328
    /**
329
     * Checks from type and path if the domain is valid. If so, it sets the $subDirectory to the default.
330
     *
331
     * @param string $applicationName
332
     * @param array  $applicationData
333
     * @param string $subDirectory
334
     *
335
     * @return bool
336
     */
337 3
    private function checkDomainIsValid($applicationName, $applicationData, &$subDirectory)
338
    {
339
        $isSubdomain = $applicationName == 'website'
340 3
            || (
341 2
                $this->subDomain != $this->configuration->getData('website/path')
342 2
                && $applicationData['type'] == self::APPLICATION_TYPE_DOMAIN
343 2
                && $applicationData['path'] == $this->subDomain
344 3
            );
345
346
        // If this method get called and will return TRUE, it means the $subDirectory paramtere will be used only for
347
        // setting the right selectedApplicationUri. To avoid complexity, we change it here. Doesn't matter.
348 3
        if ($isSubdomain) {
349 3
            $subDirectory = '';
350 3
        }
351
352 3
        return $isSubdomain;
353
    }
354
}
355