Test Failed
Push — master ( 539796...4ba9a1 )
by Gabor
04:03
created

ServiceAdapter::setDomain()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 8
cts 8
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 15
nc 8
nop 0
crap 7
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 7.1
6
 *
7
 * @copyright 2012 - 2017 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
declare(strict_types = 1);
13
14
namespace WebHemi\Environment\ServiceAdapter\Base;
15
16
use Exception;
17
use InvalidArgumentException;
18
use LayerShifter\TLDExtract\Extract;
19
use LayerShifter\TLDExtract\Result;
20
use WebHemi\Configuration\ServiceInterface as ConfigurationInterface;
21
use WebHemi\Environment\AbstractAdapter;
22
23
/**
24
 * Class ServiceAdapter.
25
 * @SuppressWarnings(PHPMD.TooManyFields)
26
 */
27
class ServiceAdapter extends AbstractAdapter
28
{
29
    /** @var Extract */
30
    private $domainAdapter;
31
32
    /**
33
     * ServiceAdapter constructor.
34
     *
35
     * @param ConfigurationInterface $configuration
36
     * @param array                  $getData
37
     * @param array                  $postData
38
     * @param array                  $serverData
39
     * @param array                  $cookieData
40
     * @param array                  $filesData
41
     * @param array                  $optionsData
42
     * @throws Exception
43
     */
44 6
    public function __construct(
45
        ConfigurationInterface $configuration,
46
        array $getData,
47
        array $postData,
48
        array $serverData,
49
        array $cookieData,
50
        array $filesData,
51
        array $optionsData
52
    ) {
53 6
        $this->configuration = $configuration->getConfig('applications');
54 6
        $this->domainAdapter = new Extract();
55 6
        $this->applicationRoot = realpath(__DIR__.'/../../../../../');
56
        // In case when the backend sources are out of the document root.
57 6
        $this->documentRoot = realpath($this->applicationRoot.'/');
58 6
        $this->options = $optionsData;
59
60 6
        if (isset($serverData['HTTP_REFERER'])) {
61 6
            $serverData['HTTP_REFERER'] = urldecode($serverData['HTTP_REFERER']);
62
        }
63
64 6
        $this->environmentData = [
65 6
            'GET'    => $getData,
66 6
            'POST'   => $postData,
67 6
            'SERVER' => $serverData,
68 6
            'COOKIE' => $cookieData,
69 6
            'FILES'  => $filesData,
70
        ];
71
72 6
        $this->isHttps = isset($this->environmentData['SERVER']['HTTPS']) && $this->environmentData['SERVER']['HTTPS'];
73 6
        $this->url = 'http'.($this->isHttps ? 's' : '').'://'
74 6
            .$this->environmentData['SERVER']['HTTP_HOST']
75 6
            .$this->environmentData['SERVER']['REQUEST_URI']; // contains also the query string
76
77 6
        $this->selectedModule = self::DEFAULT_MODULE;
78 6
        $this->selectedApplication = self::DEFAULT_APPLICATION;
79 6
        $this->selectedTheme = self::DEFAULT_THEME;
80 6
        $this->selectedThemeResourcePath = self::DEFAULT_THEME_RESOURCE_PATH;
81 6
        $this->selectedApplicationUri = self::DEFAULT_APPLICATION_URI;
82
83 6
        $this->setDomain()
84 5
            ->setApplication();
85 5
    }
86
87
    /**
88
     * Gets the request URI
89
     *
90
     * @return string
91
     */
92 1
    public function getRequestUri() : string
93
    {
94 1
        return rtrim($this->environmentData['SERVER']['REQUEST_URI'], '/');
95
    }
96
97
    /**
98
     * Gets the request method.
99
     *
100
     * @return string
101
     */
102 1
    public function getRequestMethod(): string
103
    {
104 1
        return $this->environmentData['SERVER']['REQUEST_METHOD'] ?? 'GET';
105
    }
106
107
    /**
108
     * Gets environment data.
109
     *
110
     * @param string $key
111
     * @return array
112
     */
113 10
    public function getEnvironmentData(string $key) : array
114
    {
115 10
        if (!isset($this->environmentData[$key])) {
116 1
            throw new InvalidArgumentException(sprintf('The "%s" is not a valid environment key.', $key));
117
        }
118
119 10
        return $this->environmentData[$key];
120
    }
121
122
    /**
123
     * Gets the client IP address.
124
     *
125
     * @return string
126
     */
127 1
    public function getClientIp() : string
128
    {
129 1
        $ipAddress = '';
130
131 1
        if (!empty($this->environmentData['SERVER']['HTTP_X_FORWARDED_FOR'])) {
132 1
            $ipAddress = $this->environmentData['SERVER']['HTTP_X_FORWARDED_FOR'];
133 1
        } elseif (!empty($this->environmentData['SERVER']['REMOTE_ADDR'])) {
134 1
            $ipAddress = $this->environmentData['SERVER']['REMOTE_ADDR'];
135
        }
136
137 1
        return (string) $ipAddress;
138
    }
139
140
    /**
141
     * Parses server data and tries to set domain information.
142
     *
143
     * @throws Exception
144
     * @return ServiceAdapter
145
     */
146 6
    private function setDomain() : ServiceAdapter
147
    {
148
        // @codeCoverageIgnoreStart
149
        if (!defined('PHPUNIT_WEBHEMI_TESTSUITE') &&'dev' == getenv('APPLICATION_ENV')) {
150
            $this->domainAdapter->setExtractionMode(Extract::MODE_ALLOW_NOT_EXISTING_SUFFIXES);
151
        }
152
        // @codeCoverageIgnoreEnd
153
154
        /** @var Result $domainParts */
155 6
        $domainParts = $this->domainAdapter->parse($this->url);
156
157 6
        if (empty($domainParts->getSuffix())) {
158 1
            throw new Exception('This application does not support IP access');
159
        }
160
161
        // Redirecting to www when no subdomain is present
162
        // @codeCoverageIgnoreStart
163
        if (!defined('PHPUNIT_WEBHEMI_TESTSUITE') && empty($domainParts->getSubdomain())) {
164
            $schema = 'http'.($this->isSecuredApplication() ? 's' : '').'://';
165
            $uri = $this->environmentData['SERVER']['REQUEST_URI'];
166
            header('Location: '.$schema.'www.'.$domainParts->getFullHost().$uri);
167
            exit;
168
        }
169
        // @codeCoverageIgnoreEnd
170
171 5
        $this->subDomain = $domainParts->getSubdomain();
172 5
        $this->mainDomain = $domainParts->getHostname().'.'.$domainParts->getSuffix();
173 5
        $this->applicationDomain = $domainParts->getFullHost();
174
175 5
        return $this;
176
    }
177
178
    /**
179
     * Sets application related data.
180
     *
181
     * @throws Exception
182
     * @return ServiceAdapter
183
     */
184 5
    private function setApplication() : ServiceAdapter
185
    {
186
        // For safety purposes only, But it can't happen unless somebody change/overwrite the constructor.
187
        // @codeCoverageIgnoreStart
188
        if (!isset($this->applicationDomain)) {
189
            throw new Exception('Domain is not set');
190
        }
191
        // @codeCoverageIgnoreEnd
192
193 5
        $urlParts = parse_url($this->url);
194 5
        list($subDirectory) = explode('/', ltrim($urlParts['path'], '/'), 2);
195
196 5
        $applications = $this->configuration->toArray();
197 5
        $aplicationNames = array_keys($applications);
198 5
        $selectedApplication = $this->getSelectedApplicationName($aplicationNames, $subDirectory);
199
200 5
        $applicationData = $applications[$selectedApplication];
201
202 5
        $this->selectedModule = $applicationData['module'] ?? self::DEFAULT_MODULE;
203 5
        $this->selectedApplication = $selectedApplication;
204 5
        $this->selectedTheme = $applicationData['theme'] ?? self::DEFAULT_THEME;
205 5
        $this->selectedApplicationUri = $applicationData['type'] == self::APPLICATION_TYPE_DIRECTORY
206 1
            ? '/'.$subDirectory
207 4
            : '/';
208
209
        // Final check for config and resources.
210 5
        if ($this->selectedTheme !== self::DEFAULT_THEME) {
211 1
            $this->selectedThemeResourcePath = '/resources/vendor_themes/'.$this->selectedTheme;
212
        }
213
214 5
        return $this;
215
    }
216
217
    /**
218
     * Gets the selected application's name.
219
     *
220
     * @param array $aplicationNames
221
     * @param string $subDirectory
222
     * @return string
223
     */
224 5
    private function getSelectedApplicationName(array $aplicationNames, string $subDirectory) : string
225
    {
226 5
        $selectedApplication = self::DEFAULT_APPLICATION;
227
228
        /** @var string $applicationName */
229 5
        foreach ($aplicationNames as $applicationName) {
230 5
            if ($this->checkDirectoryIsValid($applicationName, $subDirectory)
231 5
                || $this->checkDomainIsValid($applicationName)
232
            ) {
233 5
                $selectedApplication = (string) $applicationName;
234 5
                break;
235
            }
236
        }
237
238 5
        return $selectedApplication;
239
    }
240
241
    /**
242
     * Checks from type, path it the current URI segment is valid.
243
     *
244
     * @param string $applicationName
245
     * @param string $subDirectory
246
     * @return bool
247
     */
248 5
    private function checkDirectoryIsValid(string $applicationName, string $subDirectory) : bool
249
    {
250 5
        $applications = $this->configuration->toArray();
251 5
        $applicationData = $applications[$applicationName];
252
253 5
        return $applicationName != 'website'
254 5
            && $this->applicationDomain == $applicationData['domain']
255 5
            && !empty($subDirectory)
256 5
            && $applicationData['type'] == self::APPLICATION_TYPE_DIRECTORY
257 5
            && $applicationData['path'] == '/'.$subDirectory;
258
    }
259
260
    /**
261
     * Checks from type and path if the domain is valid. If so, it sets the $subDirectory to the default.
262
     *
263
     * @param string $applicationName
264
     * @return bool
265
     */
266 4
    private function checkDomainIsValid(string $applicationName) : bool
267
    {
268 4
        $applications = $this->configuration->toArray();
269 4
        $applicationData = $applications[$applicationName];
270
271 4
        return $this->applicationDomain == $applicationData['domain']
272 4
            && $applicationData['type'] == self::APPLICATION_TYPE_DOMAIN;
273
    }
274
}
275