Completed
Push — master ( ef1e9b...ffc375 )
by Gabor
05:15
created

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