Passed
Push — master ( 30ae21...a0c229 )
by Gabor
03:31
created

EnvironmentManager::getModuleRouteSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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 $config;
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 $config
67
     * @param array           $getData
68
     * @param array           $postData
69
     * @param array           $serverData
70
     * @param array           $cookieData
71
     * @param array           $filesData
72
     */
73 9
    public function __construct(
74
        ConfigInterface $config,
75
        array $getData,
76
        array $postData,
77
        array $serverData,
78
        array $cookieData,
79
        array $filesData
80
    ) {
81 9
        $this->config = $config;
82 9
        $this->documentRoot = realpath(__DIR__.'/../../../');
83
84 9
        $this->environmentData = [
85 9
            'GET'    => $getData,
86 9
            'POST'   => $postData,
87 9
            'SERVER' => $serverData,
88 9
            'COOKIE' => $cookieData,
89 9
            'FILES'  => $filesData,
90
        ];
91
92 9
        $this->isHttps = isset($this->environmentData['SERVER']['HTTPS']) && $this->environmentData['SERVER']['HTTPS'];
93 9
        $this->url = 'http'.($this->isHttps ? 's' : '').'://'
94 9
            .$this->environmentData['SERVER']['HTTP_HOST']
95 9
            .$this->environmentData['SERVER']['REQUEST_URI']; // contains also the query string
96
97 9
        $this->selectedModule = self::DEFAULT_MODULE;
98 9
        $this->selectedApplication = self::DEFAULT_APPLICATION;
99 9
        $this->selectedTheme = self::DEFAULT_THEME;
100 9
        $this->selectedThemeResourcePath = self::DEFAULT_THEME_RESOURCE_PATH;
101 9
        $this->selectedApplicationUri = self::DEFAULT_APPLICATION_URI;
102
103 9
        $this->setDomain()
104 9
            ->selectModuleApplicationAndTheme();
105 9
    }
106
107
    /**
108
     * Gets the application domain.
109
     *
110
     * @return string
111
     */
112 1
    public function getApplicationDomain()
113
    {
114 1
        return $this->applicationDomain;
115
    }
116
117
    /**
118
     * Gets the application SSL status.
119
     *
120
     * @return bool
121
     */
122 1
    public function isSecuredApplication()
123
    {
124 1
        return $this->isHttps;
125
    }
126
127
    /**
128
     * Gets the selected application.
129
     *
130
     * @return string
131
     */
132 4
    public function getSelectedApplication()
133
    {
134 4
        return $this->selectedApplication;
135
    }
136
137
    /**
138
     * Get the URI path for the selected application. Required for the RouterAdapter to work with directory-based
139
     * applications correctly.
140
     *
141
     * @return string
142
     */
143 8
    public function getSelectedApplicationUri()
144
    {
145 8
        return $this->selectedApplicationUri;
146
    }
147
148
    /**
149
     * Gets the selected module.
150
     *
151
     * @return string
152
     */
153 5
    public function getSelectedModule()
154
    {
155 5
        return $this->selectedModule;
156
    }
157
158
    /**
159
     * Gets the selected theme.
160
     *
161
     * @return string
162
     */
163 5
    public function getSelectedTheme()
164
    {
165 5
        return $this->selectedTheme;
166
    }
167
168
    /**
169
     * Gets the resource path for the selected theme.
170
     *
171
     * @return string
172
     */
173 6
    public function getResourcePath()
174
    {
175 6
        return $this->selectedThemeResourcePath;
176
    }
177
178
    /**
179
     * Gets environment data.
180
     *
181
     * @param string $key
182
     *
183
     * @return array
184
     */
185 5
    public function getEnvironmentData($key)
186
    {
187 5
        if (!isset($this->environmentData[$key])) {
188 1
            throw new InvalidArgumentException(sprintf('The "%s" is not a valid environment key.', $key));
189
        }
190
191 5
        return $this->environmentData[$key];
192
    }
193
194
    /**
195
     * Gets the template settings for a specific theme.
196
     *
197
     * @param string $theme
198
     *
199
     * @codeCoverageIgnore - @see \WebHemiTest\Config\ConfigTest
200
     *
201
     * @return ConfigInterface
202
     */
203
    public function getApplicationTemplateSettings($theme = self::DEFAULT_THEME)
204
    {
205
        return $this->config->getConfig('themes/'.$theme);
206
    }
207
208
    /**
209
     * Gets the routing settings for the selected module.
210
     *
211
     * @codeCoverageIgnore - @see \WebHemiTest\Config\ConfigTest
212
     *
213
     * @return ConfigInterface
214
     */
215
    public function getModuleRouteSettings()
216
    {
217
        return $this->config->getConfig('modules/'.$this->getSelectedModule().'/routing');
218
    }
219
220
    /**
221
     * Parses server data and tries to set domain information.
222
     *
223
     * @return $this
224
     */
225 9
    private function setDomain()
226
    {
227 9
        $domain = $this->environmentData['SERVER']['SERVER_NAME'];
228 9
        $subDomain = '';
229 9
        $urlParts = parse_url($this->url);
230
231
        // If the host is not an IP address, then check the sub-domain-based module names too
232 9
        if (!preg_match(
233 9
            '/^((\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])$/',
234 9
            $urlParts['host']
235 9
        )) {
236 9
            $domainParts = explode('.', $urlParts['host']);
237
            // @todo find out how to support complex TLDs like `.co.uk` or `.com.br`
238 9
            $tld = array_pop($domainParts);
239 9
            $domain = array_pop($domainParts).'.'.$tld;
240
            // the rest is the sub-domain
241 9
            $subDomain = implode('.', $domainParts);
242 9
        }
243
244
        // If no sub-domain presents, then it should be handled as 'www'
245 9
        if (empty($subDomain)) {
246 7
            $subDomain = 'www';
247 7
        }
248
249 9
        $this->subDomain = $subDomain;
250 9
        $this->mainDomain = $domain;
251 9
        $this->applicationDomain = $this->subDomain.'.'. $this->mainDomain;
252
253
        // Redirecting when the app domain is not equal to the server data
254
        // @codeCoverageIgnoreStart
255
        if (!defined('PHPUNIT_WEBHEMI_TESTSUITE')
256
            && $this->environmentData['SERVER']['SERVER_NAME'] != $this->applicationDomain
257
        ) {
258
            $schema = 'http'.($this->isSecuredApplication() ? 's' : '').'://';
259
            $uri = $this->environmentData['SERVER']['REQUEST_URI'];
260
            header('Location: '.$schema.$this->applicationDomain.$uri);
261
            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...
262
        }
263
        // @codeCoverageIgnoreEnd
264
265 9
        return $this;
266
    }
267
268
    /**
269
     * From the parsed domain data, selects the application, module and theme.
270
     *
271
     * @return $this
272
     */
273 9
    private function selectModuleApplicationAndTheme()
274
    {
275 9
        $urlParts = parse_url($this->url);
276 9
        $applications = $this->config->getData('applications');
277
278
        // Only the first segment is important (if exists).
279 9
        list($subDirectory) = explode('/', ltrim($urlParts['path'], '/'), 2);
280
281
        $applicationDataFixture = [
282 9
            'type' => self::APPLICATION_TYPE_DIRECTORY,
283 9
            'module' => self::DEFAULT_MODULE,
284 9
            'theme' => self::DEFAULT_THEME,
285 9
        ];
286
287
        // Run through the available application-modules to validate and find active module
288 9
        foreach ($applications as $applicationName => $applicationData) {
289
            // Don't risk, fix.
290 9
            $applicationData = array_merge($applicationDataFixture, $applicationData);
291
292 9
            if ($this->checkDirectoryIsValid($applicationName, $applicationData, $subDirectory)
293 9
                || $this->checkDomainIsValid($applicationName, $applicationData, $subDirectory)
294 9
            ) {
295 3
                $this->selectedModule = $applicationData['module'];
296 3
                $this->selectedApplication = (string)$applicationName;
297 3
                $this->selectedTheme = $applicationData['theme'];
298
299 3
                $this->selectedApplicationUri = '/'.$subDirectory;
300 3
                break;
301
            }
302 9
        }
303
304 9
        if ($this->selectedTheme !== self::DEFAULT_THEME) {
305 1
            $this->selectedThemeResourcePath = '/resources/vendor_themes/'.$this->selectedTheme;
306 1
        }
307
308 9
        return $this;
309
    }
310
311
    /**
312
     * Checks from type, path it the current URI segment is valid.
313
     *
314
     * @param string $applicationName
315
     * @param array  $applicationData
316
     * @param string $subDirectory
317
     *
318
     * @return bool
319
     */
320 9
    private function checkDirectoryIsValid($applicationName, $applicationData, $subDirectory)
321
    {
322 9
        return $this->subDomain == 'www'
323 9
            && $applicationName != 'website'
324 9
            && !empty($subDirectory)
325 9
            && $applicationData['type'] == self::APPLICATION_TYPE_DIRECTORY
326 9
            && $applicationData['path'] == $subDirectory;
327
    }
328
329
    /**
330
     * Checks from type and path if the domain is valid. If so, it sets the $subDirectory to the default.
331
     *
332
     * @param string $applicationName
333
     * @param array  $applicationData
334
     * @param string $subDirectory
335
     *
336
     * @return bool
337
     */
338 9
    private function checkDomainIsValid($applicationName, $applicationData, &$subDirectory)
339
    {
340
        $isSubdomain = $applicationName == 'website'
341 9
            || (
342 9
                $this->subDomain != 'www'
343 9
                && $applicationData['type'] == self::APPLICATION_TYPE_DOMAIN
344 9
                && $applicationData['path'] == $this->subDomain
345 9
            );
346
347
        // If this method get called and will return TRUE, it means the $subDirectory paramtere will be used only for
348
        // setting the right selectedApplicationUri. To avoid complexity, we change it here. Doesn't matter.
349 9
        if ($isSubdomain) {
350 2
            $subDirectory = '';
351 2
        }
352
353 9
        return $isSubdomain;
354
    }
355
}
356