Completed
Push — master ( 99527b...ffb88b )
by Oleg
03:03
created

HMVCResolver::getApplication()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
rs 8.8571
cc 5
eloc 9
nc 8
nop 0
1
<?php /** MicroHMVCResolver */
2
3
namespace Micro\Resolver;
4
5
use Micro\Base\Exception;
6
use Micro\Mvc\Controllers\IController;
7
8
/**
9
 * hMVC Resolver class file.
10
 *
11
 * @author Oleg Lunegov <[email protected]>
12
 * @link https://github.com/lugnsk/micro
13
 * @copyright Copyright &copy; 2013 Oleg Lunegov
14
 * @license /LICENSE
15
 * @package Micro
16
 * @subpackage Resolver
17
 * @version 1.0
18
 * @since 1.0
19
 */
20
class HMVCResolver extends Resolver
21
{
22
    /** @var string $uri converted URL */
23
    protected $uri;
24
    /** @var string $extensions Extensions in request */
25
    private $extensions;
26
    /** @var string $modules Modules in request */
27
    private $modules;
28
    /** @var string $controller IController to run */
29
    private $controller;
30
    /** @var string $action Action to run */
31
    private $action;
32
33
34
    /**
35
     * Get instance application
36
     *
37
     * @access public
38
     *
39
     * @return IController
40
     * @throws Exception
41
     */
42
    public function getApplication()
43
    {
44
        $query = $this->container->request->query('r') ?: '/default';
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
45
        $query = (substr($query, -1) === '/') ? substr($query, 0, -1) : $query;
46
47
        $this->uri = $this->container->router->parse($query, $this->container->request->getMethod());
0 ignored issues
show
Bug introduced by
Accessing router on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
48
49
        $this->initialize();
50
51
        /** @var string $cls */
52
        $cls = $this->getCalculatePath();
53
54
        if (!class_exists($cls) || !is_subclass_of($cls, '\Micro\Mvc\Controllers\IController')) {
55
            throw new Exception('Controller ' . $cls . ' not found or not a valid');
56
        }
57
58
        return new $cls($this->container, $this->getModules());
59
    }
60
61
    /**
62
     * Initialize request object
63
     *
64
     * @access public
65
     *
66
     * @return void
67
     */
68
    protected function initialize()
69
    {
70
        $key = strpos($this->uri, '?');
71
        $params = $key ? substr($this->uri, $key + 2) : null;
72
        $uriBlocks = explode('/', substr($this->uri, 0, $key ?: strlen($this->uri)));
73
74
        if (0 === strpos($this->uri, '/')) {
75
            array_shift($uriBlocks);
76
        }
77
78
        $this->prepareExtensions($uriBlocks);
79
        $this->prepareModules($uriBlocks);
80
        $this->prepareController($uriBlocks);
81
        $this->prepareAction($uriBlocks);
82
83
        if ($params) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $params of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
84
            $paramBlocks = explode('&', $params);
85
86
            foreach ($paramBlocks AS $param) {
87
                $val = explode('=', $param);
88
                $this->container->request->setQuery($val[0], $val[1]);
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
89
            }
90
        }
91
    }
92
93
    /**
94
     * Prepare extensions
95
     *
96
     * @access private
97
     *
98
     * @param array $uriBlocks uri blocks from URL
99
     *
100
     * @return void
101
     */
102
    protected function prepareExtensions(&$uriBlocks)
103
    {
104
        foreach ($uriBlocks AS $i => $block) {
105
            if (file_exists($this->container->kernel->getAppDir() . $this->extensions . '/extensions/' . $block)) {
0 ignored issues
show
Bug introduced by
Accessing kernel on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
106
                $this->extensions .= '/extensions/' . $block;
107
                unset($uriBlocks[$i]);
108
            } else {
109
                break;
110
            }
111
        }
112
        $this->extensions = str_replace('/', '\\', $this->extensions);
113
    }
114
115
    /**
116
     * Prepare modules
117
     *
118
     * @access private
119
     *
120
     * @global      Micro
121
     *
122
     * @param array $uriBlocks uri blocks from URL
123
     *
124
     * @return void
125
     */
126
    protected function prepareModules(&$uriBlocks)
127
    {
128
        $path = $this->container->kernel->getAppDir() . ($this->extensions ?: '');
0 ignored issues
show
Bug introduced by
Accessing kernel on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
129
130
        foreach ($uriBlocks AS $i => $block) {
131
            if ($block && file_exists($path . $this->modules . '/modules/' . $block)) {
132
                $this->modules .= '/modules/' . $block;
133
                unset($uriBlocks[$i]);
134
            } else {
135
                break;
136
            }
137
        }
138
139
        $this->modules = str_replace('/', '\\', $this->modules);
140
    }
141
142
    /**
143
     * Prepare controller
144
     *
145
     * @access private
146
     *
147
     * @param array $uriBlocks uri blocks from URL
148
     *
149
     * @return void
150
     */
151
    protected function prepareController(&$uriBlocks)
152
    {
153
        $path = $this->container->kernel->getAppDir() . ($this->extensions ?: '') . ($this->modules ?: '');
0 ignored issues
show
Bug introduced by
Accessing kernel on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
154
        $str = array_shift($uriBlocks);
155
156
        if (file_exists(str_replace('\\', '/', $path . '/controllers/' . ucfirst($str) . 'Controller.php'))) {
157
            $this->controller = $str;
158
        } else {
159
            $this->controller = 'default';
160
            array_unshift($uriBlocks, $str);
161
        }
162
    }
163
164
    /**
165
     * Prepare action
166
     *
167
     * @access private
168
     *
169
     * @param array $uriBlocks uri blocks from URL
170
     *
171
     * @return void
172
     */
173
    protected function prepareAction(&$uriBlocks)
174
    {
175
        $this->action = array_shift($uriBlocks) ?: 'index';
176
    }
177
178
179
    /**
180
     * Get calculate path to controller
181
     *
182
     * @access public
183
     *
184
     * @return string
185
     */
186
    public function getCalculatePath()
187
    {
188
        return '\\App' . $this->getExtensions() . $this->getModules() . '\\Controllers\\' . $this->getController();
189
    }
190
191
    /**
192
     * Get extensions from request
193
     *
194
     * @access public
195
     *
196
     * @return string
197
     */
198
    public function getExtensions()
199
    {
200
        return $this->extensions;
201
    }
202
203
    /**
204
     * Get modules from request
205
     *
206
     * @access public
207
     *
208
     * @return string
209
     */
210
    public function getModules()
211
    {
212
        return $this->modules;
213
    }
214
215
    /**
216
     * Get controller from request
217
     *
218
     * @access public
219
     *
220
     * @return string
221
     */
222
    public function getController()
223
    {
224
        return ucfirst($this->controller) . 'Controller';
225
    }
226
227
228
    /**
229
     * Get action from request
230
     *
231
     * @access public
232
     *
233
     * @return string
234
     */
235
    public function getAction()
236
    {
237
        return $this->action;
238
    }
239
}
240