Passed
Push — master ( b01812...3926c4 )
by Gabor
03:44
created

EnvironmentManager::getDocumentRoot()   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
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
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 selected module.
164
     *
165
     * @return string
166
     */
167 1
    public function getSelectedModule()
168
    {
169 1
        return $this->selectedModule;
170
    }
171
172
    /**
173
     * Gets the selected theme.
174
     *
175
     * @return string
176
     */
177 1
    public function getSelectedTheme()
178
    {
179 1
        return $this->selectedTheme;
180
    }
181
182
    /**
183
     * Gets the resource path for the selected theme.
184
     *
185
     * @return string
186
     */
187 2
    public function getResourcePath()
188
    {
189 2
        return $this->selectedThemeResourcePath;
190
    }
191
192
    /**
193
     * Gets environment data.
194
     *
195
     * @param string $key
196
     *
197
     * @return array
198
     */
199 1
    public function getEnvironmentData($key)
200
    {
201 1
        if (!isset($this->environmentData[$key])) {
202 1
            throw new InvalidArgumentException(sprintf('The "%s" is not a valid environment key.', $key));
203
        }
204
205 1
        return $this->environmentData[$key];
206
    }
207
208
    /**
209
     * Parses server data and tries to set domain information.
210
     *
211
     * @return $this
212
     */
213 4
    private function setDomain()
214
    {
215 4
        $domain = $this->environmentData['SERVER']['SERVER_NAME'];
216 4
        $subDomain = '';
217 4
        $urlParts = parse_url($this->url);
218
219
        // If the host is not an IP address, then check the sub-domain-based module names too
220 4
        if (!preg_match(
221 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])$/',
222 4
            $urlParts['host']
223 4
        )) {
224 4
            $domainParts = explode('.', $urlParts['host']);
225
            // @todo find out how to support complex TLDs like `.co.uk` or `.com.br`
226 4
            $tld = array_pop($domainParts);
227 4
            $domain = array_pop($domainParts).'.'.$tld;
228
            // the rest is the sub-domain
229 4
            $subDomain = implode('.', $domainParts);
230 4
        }
231
232
        // If no sub-domain presents, then it should be handled as the default sub-domain set for the 'website'
233 4
        if (empty($subDomain)) {
234 2
            $subDomain = $this->configuration->getData('website/path');
235 2
        }
236
237 4
        $this->subDomain = $subDomain;
238 4
        $this->mainDomain = $domain;
239 4
        $this->applicationDomain = $this->subDomain.'.'. $this->mainDomain;
240
241
        // Redirecting when the app domain is not equal to the server data
242
        // @codeCoverageIgnoreStart
243
        if (!defined('PHPUNIT_WEBHEMI_TESTSUITE')
244
            && $this->environmentData['SERVER']['SERVER_NAME'] != $this->applicationDomain
245
        ) {
246
            $schema = 'http'.($this->isSecuredApplication() ? 's' : '').'://';
247
            $uri = $this->environmentData['SERVER']['REQUEST_URI'];
248
            header('Location: '.$schema.$this->applicationDomain.$uri);
249
            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...
250
        }
251
        // @codeCoverageIgnoreEnd
252
253 4
        return $this;
254
    }
255
256
    /**
257
     * From the parsed domain data, selects the application, module and theme.
258
     *
259
     * @return $this
260
     */
261 4
    private function selectModuleApplicationAndTheme()
262
    {
263 4
        $urlParts = parse_url($this->url);
264 4
        $applications = $this->configuration->toArray();
265
266
        // Only the first segment is important (if exists).
267 4
        list($subDirectory) = explode('/', ltrim($urlParts['path'], '/'), 2);
268
269
        $applicationDataFixture = [
270 4
            'type' => self::APPLICATION_TYPE_DIRECTORY,
271 4
            'module' => self::DEFAULT_MODULE,
272 4
            'theme' => self::DEFAULT_THEME,
273 4
        ];
274
275
        // Run through the available application-modules to validate and find active module
276 4
        foreach ($applications as $applicationName => $applicationData) {
277
            // Don't risk, fix.
278 4
            $applicationData = array_merge($applicationDataFixture, $applicationData);
279
280 4
            if ($this->checkDirectoryIsValid($applicationName, $applicationData, $subDirectory)
281 3
                || $this->checkDomainIsValid($applicationName, $applicationData, $subDirectory)
282 4
            ) {
283 4
                $this->selectedModule = $applicationData['module'];
284 4
                $this->selectedApplication = (string)$applicationName;
285 4
                $this->selectedTheme = $applicationData['theme'];
286
287 4
                $this->selectedApplicationUri = '/'.$subDirectory;
288 4
                break;
289
            }
290 4
        }
291
292
        // Final check for config and resources.
293 4
        if ($this->selectedTheme !== self::DEFAULT_THEME) {
294 1
            $this->selectedThemeResourcePath = '/resources/vendor_themes/'.$this->selectedTheme;
295 1
        }
296
297 4
        return $this;
298
    }
299
300
    /**
301
     * Checks from type, path it the current URI segment is valid.
302
     *
303
     * @param string $applicationName
304
     * @param array  $applicationData
305
     * @param string $subDirectory
306
     *
307
     * @return bool
308
     */
309 4
    private function checkDirectoryIsValid($applicationName, $applicationData, $subDirectory)
310
    {
311 4
        return $this->subDomain == $this->configuration->getData('website/path')
312 4
            && $applicationName != 'website'
313 4
            && !empty($subDirectory)
314 4
            && $applicationData['type'] == self::APPLICATION_TYPE_DIRECTORY
315 4
            && $applicationData['path'] == $subDirectory;
316
    }
317
318
    /**
319
     * Checks from type and path if the domain is valid. If so, it sets the $subDirectory to the default.
320
     *
321
     * @param string $applicationName
322
     * @param array  $applicationData
323
     * @param string $subDirectory
324
     *
325
     * @return bool
326
     */
327 3
    private function checkDomainIsValid($applicationName, $applicationData, &$subDirectory)
328
    {
329
        $isSubdomain = $applicationName == 'website'
330 3
            || (
331 2
                $this->subDomain != $this->configuration->getData('website/path')
332 2
                && $applicationData['type'] == self::APPLICATION_TYPE_DOMAIN
333 2
                && $applicationData['path'] == $this->subDomain
334 3
            );
335
336
        // If this method get called and will return TRUE, it means the $subDirectory paramtere will be used only for
337
        // setting the right selectedApplicationUri. To avoid complexity, we change it here. Doesn't matter.
338 3
        if ($isSubdomain) {
339 3
            $subDirectory = '';
340 3
        }
341
342 3
        return $isSubdomain;
343
    }
344
}
345