Completed
Push — master ( 79d087...07f491 )
by Vitaly
14:29
created

Module::router()   C

Complexity

Conditions 8
Paths 18

Size

Total Lines 63
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 63
rs 6.8825
cc 8
eloc 24
nc 18
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace samsonphp\router;
3
4
use samsonframework\core\SystemInterface;
5
use samsonframework\routing\Core;
6
use samsonframework\routing\generator\Structure;
7
use samsonframework\routing\Route;
8
9
/**
10
 * SamsonPHP Routing module implementation.
11
 *
12
 * @package samsonphp\router
13
 */
14
class Module extends \samson\core\CompressableExternalModule
15
{
16
    /** @var string Module identifier */
17
    public $id = 'router';
18
19
    /** @var string Default controller module identifier */
20
    public $defaultModule = 'main';
21
22
    /** @var string Path to routing logic cache file */
23
    protected $cacheFile;
24
25
    /**
26
     * Old generic "main_page" route callback searcher to match old logic.
27
     *
28
     * @return Route Default application route "/"
29
     */
30
    protected function findGenericDefaultAction()
31
    {
32
        $callback = null;
33
        // If callback is passed  - function name
34
        if (is_callable($this->defaultModule)) {
35
            // Use it as main controller callback
36
            $callback = $this->defaultModule;
37
            // Consider as module identifier is passed
38
        } elseif (isset($this->system->module_stack[$this->defaultModule])) {
0 ignored issues
show
Bug introduced by
Accessing module_stack on the interface samsonframework\core\SystemInterface 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...
39
            // Try to find module universal controller action
40
            $callback = $this->system->module_stack[$this->defaultModule]->id.'#'.self::CTR_UNI;
0 ignored issues
show
Bug introduced by
Accessing module_stack on the interface samsonframework\core\SystemInterface 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...
41
        }
42
43
        return new Route('/', $callback, 'main_page');
0 ignored issues
show
Bug introduced by
It seems like $callback defined by null on line 32 can also be of type null; however, samsonframework\routing\Route::__construct() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
44
    }
45
46
    /**
47
     * Module initialization.
48
     *
49
     * @param array $params Initialization parameters collection
50
     * @return bool Initialization result
51
     */
52
    public function init(array $params = array())
53
    {
54
        //[PHPCOMPRESSOR(remove,start)]
55
        // Create SamsonPHP routing table from loaded modules
56
        $rg = new GenericRouteGenerator($this->system->module_stack);
0 ignored issues
show
Bug introduced by
Accessing module_stack on the interface samsonframework\core\SystemInterface 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...
57
58
        // Generate web-application routes
59
        $routes = $rg->generate();
60
        $routes->add($this->findGenericDefaultAction());
61
62
        // Create cache marker
63
        $this->cacheFile = $routes->hash().'.php';
64
        // If we need to refresh cache
65
        if ($this->cache_refresh($this->cacheFile)) {
66
            $generator = new Structure($routes, new \samsonphp\generator\Generator());
67
            // Generate routing logic function
68
            $routerLogic = $generator->generate();
69
70
            // Store router logic in cache
71
            file_put_contents($this->cacheFile, '<?php '."\n".$routerLogic);
72
        }
73
74
        require($this->cacheFile);
75
        //[PHPCOMPRESSOR(remove,end)]
76
77
        // Subscribe to samsonphp\core routing event
78
        \samsonphp\event\Event::subscribe('core.routing', array($this, 'router'));
79
80
        // Continue initialization
81
        return parent::init($params);
82
    }
83
84
    /** @see \samson\core\CompressableExternalModule::afterCompress() */
85
    public function afterCompress(&$obj = null, array &$code = null)
86
    {
87
        // Compress generated php code
88
        $obj->compress_php($this->cacheFile, $this, $code, '');
89
    }
90
91
    /**
92
     * Define if HTTP request is asynchronous.
93
     *
94
     * @return bool True if request is asynchronous
95
     */
96
    public function isAsynchronousRequest()
97
    {
98
        return $_SERVER['HTTP_ACCEPT'] == '*/*'
99
        || isset($_SERVER['HTTP_SJSASYNC'])
100
        || isset($_POST['SJSASYNC']);
101
    }
102
103
    /**
104
     * Parse route parameters received from router logic function.
105
     *
106
     * @param callable $callback Route instance
107
     * @param array $receivedParameters Collection of parsed parameters
108
     * @return array Collection of route callback needed parameters
109
     */
110
    protected function parseParameters($callback, array $receivedParameters)
111
    {
112
        $parameters = array();
113
        // Parse callback signature and get parameters list
114
        if (is_callable($callback)) {
115
            $reflectionMethod = is_array($callback)
116
                ? new \ReflectionMethod($callback[0], $callback[1])
117
                : new \ReflectionFunction($callback);
118
            foreach ($reflectionMethod->getParameters() as $parameter) {
119
                $parameters[] = $parameter->getName();
120
            }
121
        }
122
123
        // Gather parsed route parameters in correct order
124
        $foundParameters = array();
125
        foreach ($parameters as $name) {
126
            // Add to parameters collection
127
            $foundParameters[] = &$receivedParameters[$name];
128
        }
129
        return $foundParameters;
130
    }
131
132
    /**
133
     * SamsonPHP core.routing event handler
134
     *
135
     * @param SystemInterface $core Pointer to core object
136
     * @param mixed $result Return value as routing result
137
     * @return bool Routing result
138
     */
139
    public function router(SystemInterface &$core, &$result)
140
    {
141
        //elapsed('Start routing');
142
        // Flag for matching SamsonPHP asynchronous requests
143
        $async = $this->isAsynchronousRequest();
144
        // Get HTTP request path
145
        $path = $_SERVER['REQUEST_URI'];
146
        // Get HTTP request method
147
        $method = $_SERVER['REQUEST_METHOD'];
148
        // Prepend HTTP request type, true - asynchronous
149
        $method = ($async ? GenericRouteGenerator::ASYNC_PREFIX : '').$method;
150
151
        $result = false;
152
153
        //$path = strtok(rtrim($method.'/'.ltrim($path, '/'),'/'),'?');
154
155
        /** @var mixed $routeMetadata Dispatching result route metadata */
156
        if (is_array($routeMetadata = call_user_func(Core::ROUTING_LOGIC_FUNCTION, $path, $method))) {
157
            // Get callback info
158
            list($module, $method) = explode("#", $routeMetadata[2]);
159
            // Get module
160
            $module = $core->module($module);
161
            // Create callback
162
            $callback = array($module, $method);
163
164
            // Check if we have vaild callback
165
            if (is_callable($callback)) {
166
                // Routing result
167
                $result = call_user_func_array(
168
                    $callback,
169
                    $this->parseParameters($callback, $routeMetadata[1])
170
                );
171
172
                // Get object from callback and set it as current active core module
173
                $core->active($module);
174
175
                // If this route is asynchronous
176
                if ($async) {
177
                    // Set async response
178
                    $core->async(true);
179
180
                    // If controller action has failed
181
                    if (!isset($result['status']) || !$result['status']) {
182
                        $result['message'] = "\n" . 'Event failed: ' . $routeMetadata[0];
183
                        $result['status'] = 0;
184
                    }
185
186
                    // Encode event result as json object
187
                    echo json_encode($result, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
188
189
                    // Mark as successful
190
                    $result = true;
191
                }
192
            }
193
194
            // If no result is passed - consider success
195
            $result = $result !== false ? true : $result;
196
        }
197
198
        //elapsed('Finished routing');
199
        // Return true or false depending on $result
200
        return $result;
201
    }
202
}
203