Completed
Push — master ( 6e89de...023d00 )
by Mihail
02:41
created

Request::getAdd()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Ffcms\Core\Network;
4
5
use Ffcms\Core\Helper\Type\Arr;
6
use Ffcms\Core\Helper\Type\Obj;
7
use Ffcms\Core\Helper\Type\Str;
8
use Symfony\Component\HttpFoundation\Request as FoundationRequest;
9
use Symfony\Component\HttpFoundation\RedirectResponse as Redirect;
10
use Ffcms\Core\App;
11
12
class Request extends FoundationRequest
13
{
14
    protected $language;
15
    protected $languageInPath = false;
16
17
    // special variable for route aliasing
18
    protected $aliasPathTarget = false;
19
    // special variable for route callback binding
20
    protected $callbackClass = false;
21
22
    // fast access for controller building
23
    protected $controller;
24
    protected $action;
25
    protected $argumentId;
26
    protected $argumentAdd;
27
28
    public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
29
    {
30
        parent::__construct($query, $request, $attributes, $cookies, $files, $server, $content);
31
        $this->afterInitialize();
32
    }
33
34
    /**
35
     * Sets the parameters for this request.
36
     *
37
     * This method also re-initializes all properties.
38
     *
39
     * @param array $query The GET parameters
40
     * @param array $request The POST parameters
41
     * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
42
     * @param array $cookies The COOKIE parameters
43
     * @param array $files The FILES parameters
44
     * @param array $server The SERVER parameters
45
     * @param string $content The raw body data
46
     *
47
     * @api
48
     */
49
    public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
50
    {
51
        parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content);
52
53
        $basePath = trim(App::$Properties->get('basePath'), '/');
54
        if ($basePath !== null && Str::length($basePath) > 0) {
55
            $basePath = '/' . $basePath;
56
        }
57
58
        if (!defined('env_no_uri') || env_no_uri === false) {
59
            $basePath .= '/' . strtolower(env_name);
60
        }
61
62
        // we never try to use path's without friendly url's
63
        $this->basePath = $this->baseUrl = $basePath;
64
    }
65
66
    protected function afterInitialize()
67
    {
68
        // multi-language is enabled?
69
        if (App::$Properties->get('multiLanguage') === true) {
70
            // maybe its a language domain alias?
71
            if (Obj::isArray(App::$Properties->get('languageDomainAlias'))) {
72
                /** @var array $domainAlias */
73
                $domainAlias = App::$Properties->get('languageDomainAlias');
74
                if (Obj::isArray($domainAlias) && !Str::likeEmpty($domainAlias[$this->getHost()])) {
75
                    $this->language = $domainAlias[$this->getHost()];
76
                }
77
            } else {
78
                // try to find language in pathway
79
                foreach (App::$Properties->get('languages') as $lang) {
0 ignored issues
show
Bug introduced by
The expression \Ffcms\Core\App::$Properties->get('languages') of type boolean is not traversable.
Loading history...
80
                    if (Str::startsWith('/' . $lang, $this->getPathInfo())) {
81
                        $this->language = $lang;
82
                        $this->languageInPath = true;
83
                    }
84
                }
85
86
                // try to find in ?lang get
87
                if ($this->language === null && Arr::in($this->query->get('lang'), App::$Properties->get('languages'))) {
0 ignored issues
show
Documentation introduced by
\Ffcms\Core\App::$Properties->get('languages') is of type boolean, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
88
                    $this->language = $this->query->get('lang');
89
                }
90
91
                // language still not defined?!
92
                if ($this->language === null) {
93
                    $userLang = App::$Properties->get('singleLanguage');
94
                    $browserAccept = $this->getLanguages();
95
                    if (Obj::isArray($browserAccept) && count($browserAccept) > 0) {
96
                        foreach ($browserAccept as $bLang) {
97
                            if (Arr::in($bLang, App::$Properties->get('languages'))) {
0 ignored issues
show
Documentation introduced by
\Ffcms\Core\App::$Properties->get('languages') is of type boolean, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
98
                                $userLang = $bLang;
99
                                break; // stop calculating, language is founded in priority
100
                            }
101
                        }
102
                    }
103
104
                    $queryString = null;
105
                    if (count($this->query->all()) > 0) {
106
                        $queryString = '?' . http_build_query($this->query->all());
107
                    }
108
109
                    $response = new Redirect($this->getSchemeAndHttpHost() . $this->basePath . '/' . $userLang . $this->getPathInfo() . $queryString);
110
                    $response->send();
111
                    exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method afterInitialize() 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...
112
                }
113
            }
114
        } else { // multi-language is disabled? Use default language
115
            $this->language = App::$Properties->get('singleLanguage');
116
        }
117
118
        // calculated depend of language
119
        $pathway = $this->getPathInfo();
120
        $routing = App::$Properties->getAll('Routing');
121
122
        // try to find static routing alias
123
        /** @var bool|array $aliasMap */
124
        $aliasMap = false;
125 View Code Duplication
        if (isset($routing['Alias']) && isset($routing['Alias'][env_name])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
126
            $aliasMap = $routing['Alias'][env_name];
127
        }
128
129
        if (Obj::isArray($aliasMap) && array_key_exists($pathway, $aliasMap)) {
130
            $pathway = $aliasMap[$pathway];
131
            $this->aliasPathTarget = $pathway;
132
        }
133
134
        // check if pathway is the same with target and redirect to source from static routing
135
        if (Obj::isArray($aliasMap) && Arr::in($this->getPathInfo(), $aliasMap)) {
136
            $source = array_search($this->getPathInfo(), $aliasMap);
137
            $targetUri = $this->getSchemeAndHttpHost() . $this->getBasePath() . '/';
138
            if (App::$Properties->get('multiLanguage') === true) {
139
                $targetUri .= $this->language . '/';
140
            }
141
            $targetUri .= ltrim($source, '/');
142
            $response = new Redirect($targetUri);
143
            $response->send();
144
            exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method afterInitialize() 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...
145
        }
146
147
        // define data from pathway
148
        $this->setPathdata(explode('/', trim($pathway, '/')));
149
150
        if ($this->action == null) { // can be null or string(0)""
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
151
            $this->action = 'Index';
152
        }
153
154
        // empty or contains backslashes? set to main
155
        if ($this->controller == null || Str::contains('\\', $this->controller)) {
156
            $this->controller = 'Main';
157
        }
158
159
        $callbackMap = false;
160 View Code Duplication
        if (isset($routing['Callback']) && isset($routing['Callback'][env_name])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
161
            $callbackMap = $routing['Callback'][env_name];
162
        }
163
164
        // check is dynamic callback map exist
165
        if (isset($callbackMap[$this->controller])) {
166
            $callbackClass = $callbackMap[$this->controller];
167
            // check if rule for current controller is exist
168
            if ($callbackClass !== null) {
169
                $this->callbackClass = $callbackClass;
170
            }
171
        }
172
    }
173
174
    /**
175
     * Working with path array data
176
     * @param array|null $pathArray
177
     */
178
    private function setPathdata(array $pathArray = null)
179
    {
180
        if (!Obj::isArray($pathArray) || count($pathArray) < 1) {
181
            return;
182
        }
183
184
        /**
185
         * Switch path array as reverse without break point! Caution: drugs inside!
186
         */
187
        switch (count($pathArray)) {
188
            case 4:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
189
                $this->argumentAdd = Str::lowerCase($pathArray[3]);
190
            case 3:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
191
                $this->argumentId = Str::lowerCase($pathArray[2]);
192
            case 2:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
193
                $this->action = ucfirst(Str::lowerCase($pathArray[1]));
194
            case 1:
195
                $this->controller = ucfirst(Str::lowerCase($pathArray[0]));
196
                break;
197
        }
198
199
        return;
200
    }
201
202
    /**
203
     * Get pathway as string
204
     * @return string
205
     */
206
    public function getPathInfo()
207
    {
208
        $route = $this->languageInPath ? Str::sub(parent::getPathInfo(), Str::length($this->language) + 1) : parent::getPathInfo();
209
        if (!Str::startsWith('/', $route)) {
210
            $route = '/' . $route;
211
        }
212
        return $route;
213
    }
214
215
    public function languageInPath()
216
    {
217
        return $this->languageInPath;
218
    }
219
220
    /**
221
     * Get current language
222
     * @return string|null
223
     */
224
    public function getLanguage()
225
    {
226
        return $this->language;
227
    }
228
229
    /**
230
     * Get current controller name
231
     * @return string
232
     */
233
    public function getController()
234
    {
235
        return $this->controller;
236
    }
237
238
    /**
239
     * Get current controller action() name
240
     * @return string
241
     */
242
    public function getAction()
243
    {
244
        return $this->action;
245
    }
246
247
    /**
248
     * Get current $id argument for controller action
249
     * @return string|null
250
     */
251
    public function getID()
252
    {
253
        return urldecode($this->argumentId);
254
    }
255
256
    /**
257
     * Get current $add argument for controller action
258
     * @return string|null
259
     */
260
    public function getAdd()
261
    {
262
        return urldecode($this->argumentAdd);
263
    }
264
265
    /**
266
     * Get callback class alias if exist
267
     * @return bool|string
268
     */
269
    public function getCallbackAlias()
270
    {
271
        return $this->callbackClass;
272
    }
273
274
    /**
275
     * Get static alias of pathway if exist
276
     * @return bool
277
     */
278
    public function getStaticAlias()
279
    {
280
        return $this->aliasPathTarget;
281
    }
282
283
    /**
284
     * Check if current request is aliased by dynamic or static rule
285
     * @return bool
286
     */
287
    public function isPathInjected()
288
    {
289
        return $this->callbackClass !== false || $this->aliasPathTarget !== false;
290
    }
291
292
    /**
293
     * Get pathway without current controller/action path
294
     * @return string
295
     */
296
    public function getPathWithoutControllerAction()
297
    {
298
        $path = trim($this->getPathInfo(), '/');
299
        if ($this->aliasPathTarget !== false) {
300
            $path = trim($this->aliasPathTarget, '/');
301
        }
302
        $pathArray = explode('/', $path);
303
        if ($pathArray[0] === Str::lowerCase($this->getController())) {
304
            // unset controller
305
            array_shift($pathArray);
306
            if ($pathArray[0] === Str::lowerCase($this->getAction())) {
307
                // unset action
308
                array_shift($pathArray);
309
            }
310
        }
311
        return trim(implode('/', $pathArray), '/');
312
    }
313
314
    /**
315
     * Get current full request URI
316
     * @return string
317
     */
318
    public function getFullUrl()
319
    {
320
        return $this->getSchemeAndHttpHost() . $this->getRequestUri();
321
    }
322
323
}