Completed
Push — master ( b2b558...421e0c )
by Nikita
12:38 queued 01:03
created

Module::action()   F

Complexity

Conditions 23
Paths 3078

Size

Total Lines 108
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 23

Importance

Changes 6
Bugs 2 Features 2
Metric Value
c 6
b 2
f 2
dl 0
loc 108
ccs 39
cts 39
cp 1
rs 2
cc 23
eloc 39
nc 3078
nop 1
crap 23

How to fix   Long Method    Complexity   

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 samson\core;
3
4
// TODO: Разобраться почему с вызовом m()->render() во вьюхе, и почему не передаются параметры
5
use samsonframework\core\ResourcesInterface;
6
use samsonframework\core\SystemInterface;
7
8
/**
9
 * Модуль системы
10
 *
11
 * @author Vitaly Iegorov <[email protected]>
12
 * @version 1.0
13
 */
14
class Module implements iModule, \ArrayAccess
15
{
16
    /** Static module instances collection */
17
    public static $instances = array();
18
19
    /** Uniquer identifier to check pointers */
20
    public $uid;
21
22
    /** @var ResourcesInterface Pointer to module resource map */
23
    public $resourceMap;
24
25
    public $composerParameters = array();
26
27
    /** Collection for cachable callable controllers of module */
28
    protected $cacheControllers = array();
29
30
    /** Collection for callable controllers of module */
31
    protected $controllers = array();
32
33
    /** Module views collection */
34
    protected $views = array();
35
36
    /** Module location */
37
    protected $path = '';
38
39
    /** Unique module identifier */
40
    protected $id = '';
41
42
    /** Default module version */
43
    protected $version = '0.0.1';
44
45
    /** Path to view for rendering */
46
    protected $view_path = self::VD_POINTER_DEF;
47
48
    /** Pointer to view data entry */
49
    protected $data = array(self::VD_POINTER_DEF => array(self::VD_HTML => ''));
50
51
    /** Collection of data for view rendering, filled with default pointer */
52
    protected $view_data = array(self::VD_POINTER_DEF => array(self::VD_HTML => ''));
53
54
    /** Name of current view context entry */
55
    protected $view_context = self::VD_POINTER_DEF;
56
57
    /** Unique module cache path in local web-application */
58
    protected $cache_path;
59
60
    /** @var SystemInterface Instance for interaction with framework */
61
    protected $system;
62
63
    /**
64
     * Perform module view context switching
65
     * @param string $view_path New view context name
66 7
     */
67
    protected function viewContext($view_path)
68
    {
69 7
        // Pointer to NEW view data context
70
        $new = &$this->view_data[$view_path];
71
72 7
        // Pointer to OLD view data context
73
        $old = &$this->view_data[$this->view_context];
74 7
75
        // If we are trying to switch to NEW view context
76
        if ($this->view_context !== $view_path) {
77 7
            //elapsed( $this->id.' - Switching view context from '.$this->view_context.' to '.$view_path );
78
79
            // Create new entry in view data collection if it does not exists
80 7
            if (!isset($this->view_data[$view_path])) {
81
                // Create new view data record
82
                $new = array();
83 7
84
                // If current view data context has view data
85
                if (isset($old)) {
86 7
                    //elapsed($old);
87
                    //elapsed( $this->id.' - Copying previous view context view data '.$this->view_context.' to new view context '.$view_path.'('.sizeof($old).')');
88
89 7
                    // Copy default view context view data to new view context
90
                    $new = array_merge($new, $old);
91
                }
92 7
93
                // Clear plain HTML for new view context
94
                $new[self::VD_HTML] = '';
95 7
            }
96
97
            // Change view data pointer to appropriate view data entry
98
            $this->data = &$new;
99 7
100
            // Save current context name
101
            $this->view_context = $view_path;
102 7
        }
103
        //else elapsed( $this->id.' - NO need to switch view context from '.$this->view_context.' to '.$view_path );
104
    }
105 7
106
    /** Sort array by string length */
107
    protected function sortStrings($a, $b)
108 7
    {
109
        return strlen($b) - strlen($a);
110
    }
111 7
112 7
    /**
113
     * Find view file by its part in module view resources and return full path to it
114 7
     * @param string $viewPath Part of path to module view file
115
     * @return string Full path to view file
116 1
     */
117
    public function findView($viewPath)
118
    {
119
        // Remove file extension for correct array searching
120
        $viewPath = str_replace(array('.php', '.vphp'), '', $viewPath);
121
122
        // Try to find passed view_path in  resources views collection
123
        if (sizeof($view = preg_grep('/' . addcslashes($viewPath, '/\\') . '(\.php|\.vphp)/ui', $this->views))) {
124
            // Sort view paths to get the shortest path
125
            usort($view, array($this, 'sortStrings'));
126 1
127
            // Set current full view path as last found view
128 1
            return end($view);
129
        }
130 1
131
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by samson\core\Module::findView of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
132
    }
133
134 1
135
    /**    @see iModule::title() */
136 1
    public function title($title = null)
137
    {
138
        return $this->set('title', $title);
139
    }
140
141
    /**    @see iModule::id() */
142
    public function id()
143
    {
144
        return $this->id;
145
    }
146
147
    /** @see iModule::set() */
148
    public function set($field, $value = null)
149
    {
150
        $this->__set($field, $value);
151
152 1
        return $this;
153
    }
154 1
155
    /** @see iModuleViewable::toView() */
156 1
    public function toView($prefix = null, array $restricted = array())
157
    {
158
        // Get all module data variables
159 3
        $view_data = array_merge($this->data, get_object_vars($this));
160
161
        // Remove plain HTML from view data
162 3
        unset($view_data[self::VD_HTML]);
163
164
        return $view_data;
165 3
    }
166
167 3
    /** @see iModule::path() */
168
    public function path($value = null)
169
    {
170 3
        // Если передан параметр - установим его
171 3
        if (func_num_args()) {
172 1
            $this->path = isset($value{0}) ? rtrim(normalizepath($value), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : '';
173
174
            return $this;
175
        } // Вернем относительный путь к файлам модуля
176 3
        else return $this->path;
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
177
    }
178
179
    /** @see iModule::html() */
180
    public function html($value = null)
181
    {
182
        //elapsed($this->id.' - Setting HTML for '.array_search(  $this->data, $this->view_data ).'('.strlen($value).')');
183
184
        // Если передан параметр то установим его
185 3
        if (func_num_args()) {
186
            $this->data[self::VD_HTML] = $value;
187
        } else {
188 3
            return $this->data['html'];
189
        }
190
191 3
        return $this;
192
    }
193 3
194
    public function view($viewPath)
195
    {
196 3
        // Find full path to view file
197
        $viewPath = $this->findView($viewPath);
198
199 1
        //elapsed($this->id.' - Changing current view to '.$view_path);
200
201
        // Switch view context to founded module view
202
        $this->viewContext($viewPath);
203
204
        // Set current view path
205
        $this->view_path = $viewPath;
206 4
207
        // Продолжим цепирование
208
        return $this;
209 4
    }
210
211
    /**    @see iModule::output() */
212 4
    public function output($viewPath = null)
213
    {
214
        // If view path not specified - use current correct view path
215 4
        if (!isset($viewPath)) {
216
            $viewPath = $this->view_path;
217
        } elseif (isset($viewPath{0})) { // Direct rendering of specific view, not default view data entry
218
            elapsed('Outputting to a view is deprecated, split your rendering chain into ->view(..)->output()');
219 3
            $viewPath = $this->findView($viewPath);
220
        }
221 3
222
        //elapsed('['.$this->id.'] Rendering view context: ['.$viewPath.'] with ['.$renderer->id.']');
223
224 3
        // Switch view context to new module view
225
        $this->viewContext($viewPath);
226
227
        //elapsed($this->id.' - Outputing '.$view_path.'-'.sizeof($this->data));
228
        //elapsed(array_keys($this->view_data));
229 3
230 3
        // Get current view context plain HTML
231
        $out = $this->data[self::VD_HTML];
232
233 3
        // If view path specified
234 3
        if (isset($viewPath{0})) {
235
            // Временно изменим текущий модуль системы
236
            $old = s()->active($this);
237 3
238
            // Прорисуем представление модуля
239
            $out .= s()->render($this->path . $viewPath, $this->data);
240 3
241 3
            // Вернем на место текущий модуль системы
242
            s()->active($old);
243 4
        } elseif (!isset($out{0})) { // No plain HTML view data is set also
244
            return e('Cannot render view for module ## - No view path or data has been set', E_SAMSON_CORE_ERROR, $this->id);
245
        }
246 1
247
        // Clear currently outputted view context from VCS
248
        unset($this->view_data[$viewPath]);
249 1
250
        // Get last element from VCS
251
        end($this->view_data);
252 1
253
        // Get last element from VCS name
254
        $this->view_context = key($this->view_data);
255
256
        // Set internal view data pointer to last VCS entry
257 1
        $this->data = &$this->view_data[$this->view_context];
258 1
259 1
        // Return view path to previous state
260
        $this->view_path = $this->view_context;
261
262 1
        // Вернем результат прорисовки
263
        return $out;
264
    }
265 1
266
    /**    @see iModule::render() */
267 1
    public function render($controller = null)
268
    {
269 1
        //trace($this->id.'-'.$controller);
270
        // Временно изменим текущий модуль системы
271 1
        $old = &$this->system->active($this);
272 1
273 1
        // Если если передан контроллер модуля для выполнения перед его прорисовкой - выполним его
274
        if (isset($controller)) {
275 1
            // Выполним действие текущего модуля
276
            $this->action($controller == '' ? null : $controller);
277
        }
278 1
279
        //elapsed( $this->id.' - Rendering '.$this->view_path );
280
281 1
        // Прорисуем представление и выведем его в текущий поток вывода
282 1
        echo $this->output();
283
284
        // Ввостановим предыдущий текущий модуль контролера
285 3
        $this->system->active($old);
286
    }
287
288 3
    /** @see iModule::action() */
289
    public function action($methodName = null)
290
    {
291
        //trace( array_keys($this->controllers), true );
292
293 3
        // Get parameters from URL
294
        $parameters = url()->parameters;
295
296
        // NEW ASYNC EVENT CHAIN LOGIC
297
        // If this is AJAX request - try to call async handlers
298
        // Added support for SamsonJS special header
299 3
        if ((isset($_SERVER['HTTP_ACCEPT']) && $_SERVER['HTTP_ACCEPT'] == '*/*') || isset($_SERVER['HTTP_SJSASYNC']) || isset($_POST['SJSASYNC'])) {
300
            // Copy parameters
301
            $arguments = $parameters;
302 3
            array_unshift($arguments, url()->method);
303
304 2
            // Response
305
            $event_result = array();
306
307 2
            // Iterate supported methods
308
            for ($idx = 0; $idx < sizeof($arguments); $idx++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
309
                $controller_name = self::ASYNC_PREFIX . $arguments[$idx];
310 2
311 2
                // Build async method handler name and try to find method in arguments list
312
                $callback = &$this->controllers[$controller_name];
313
314 3
                // If async controller handler exists
315
                if (isset($callback)) {
316
                    // Get function arguments without function name
317 3
                    $f_args = array_slice($arguments, $idx + 1);
318
319
                    // Remove used cells from array
320 3
                    $arguments = array_slice($arguments, $idx + 1);
321
322
                    // Decrease index as we change arguments size
323 3
                    $idx--;
324
325
                    // Perform event and collect event result data
326 3
                    $_event_result = call_user_func_array($callback, $f_args);
327
328
                    // Anyway convert event result to array
329 3
                    if (!is_array($_event_result)) $_event_result = array($_event_result);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
330
331
                    // If event successfully completed
332
                    if (!isset($_event_result['status']) || !$_event_result['status']) {
333 1
                        // Handle event chain fail
334
                        $_event_result['message'] = "\n" . 'Event failed: ' . $controller_name;
335
336
                        // Add event result array to results collection
337
                        $event_result = array_merge($event_result, $_event_result);
338 1
339
                        // Stop event-chain execution
340 1
                        break;
341 1
                    } // Add event result array to results collection
342 1
                    else $event_result = array_merge($event_result, $_event_result);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
343 1
                }
344
            }
345 1
346
            // If at least one event has been executed
347
            if (sizeof($event_result)) {
348 1
                // Set async responce
349
                s()->async(true);
350
351
                // Send success status
352
                header("HTTP/1.0 200 Ok");
353
354 1
                // Encode event result as json object
355
                echo json_encode($event_result, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
356 1
357
                return A_SUCCESS;
0 ignored issues
show
Deprecated Code introduced by
The constant A_SUCCESS has been deprecated with message: Действие контроллера выполнено успешно

This class constant has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
358
            }
359
        }
360 1
361
        // Get HTTP request type
362
        $request_type = $_SERVER['REQUEST_METHOD'];
363 1
364
        // Controller by name
365
        $naming = $methodName;
366 1
        // Controller by server request type
367
        $request = !isset($methodName{0}) ? strtolower($request_type == 'GET' ? self::CTR_BASE : self::OBJ_PREFIX . $request_type) : '';
368
        // Universal controller
369 1
        $universal = self::CTR_UNI;
370 1
371
        // Controller selection logic chain
372
        $controller = (isset($this->controllers[$naming]) ? $this->controllers[$naming] :
373
            (isset($this->controllers[$request]) ? $this->controllers[$request] :
374
                (isset($this->controllers[$universal]) ? $this->controllers[$universal] : null)));
375 1
376
        // If we selected universal controller - change parameters signature
377 1
        if (isset($this->controllers[$universal]) && $controller == $this->controllers[$universal]) {
378 1
            // If method is specified - add it to universal controller parameters list
379
            if (isset(url()->method{0})) array_unshift($parameters, url()->method);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
380 2
        }
381
382 2
        // Retrieve controller action callback name
383
        $controllerName = is_array($controller) ? $controller[1] : $controller;
384
        // If this controller has cached marker
385
        if (stripos($controllerName, self::CTR_CACHE) !== false) {
386
            // perform caching
387 3
            s()->cached();
388
        }
389
        //elapsed('Performing #'.$this->id.' controller action -'.$controller);
390 3
391
        // Perform controller action
392
        $action_result = isset($controller) ? call_user_func_array($controller, $parameters) : A_FAILED;
0 ignored issues
show
Deprecated Code introduced by
The constant A_FAILED has been deprecated with message: Действие контроллера НЕ выполнено

This class constant has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
393 3
394 2
        // Stop candidate search
395 2
        return !isset($action_result) ? A_SUCCESS : $action_result;
0 ignored issues
show
Deprecated Code introduced by
The constant A_SUCCESS has been deprecated with message: Действие контроллера выполнено успешно

This class constant has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
396 1
    }
397
398
    /**
399
     * Constructor
400 2
     *
401
     * @param string $id Module unique identifier
402
     * @param string $path Module location
403 3
     * @param ResourcesInterface $resourceMap Pointer to module resource map
404
     */
405
    public function __construct($id, $path = null, ResourcesInterface $resourceMap = null)
406 3
    {
407 1
        // Store pointer to module resource map
408
        $this->resourceMap = &$resourceMap;
409
        // Save views list
410
        $this->views = $resourceMap->views;
0 ignored issues
show
Bug introduced by
Accessing views on the interface samsonframework\core\ResourcesInterface 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...
411 1
412 1
        // Set default view context name
413 1
        $this->view_context = self::VD_POINTER_DEF;
414 1
415 1
        // Set up default view data pointer
416 1
        $this->data = &$this->view_data[$this->view_context];
417 1
418 3
        // Set module identifier
419
        $this->id = $id;
420 3
421 3
        // Set path to module
422
        $this->path(realpath($path));
423 1
424
        // Generate unique module identifier
425 1
        $this->uid = rand(0, 9999999) . '_' . microtime(true);
426 1
427
        // Add to module identifier to view data stack
428 2
        $this->data['id'] = $this->id;
429
430 2
        // Generate unique module cache path in local web-application
431
        $this->cache_path = __SAMSON_CWD__ . __SAMSON_CACHE_PATH . $this->id . '/';
432
433
        // Save ONLY ONE copy of this instance in static instances collection,
434 1
        // avoiding rewriting by cloned modules
435
        !isset(self::$instances[$this->id]) ? self::$instances[$this->id] = &$this : '';
436 1
437
        // Find all controller actions
438
        $functions = get_defined_functions();
439
        foreach ($functions['user'] as $method) {
440
            // Try to find standard controllers
441
            switch (strtolower($method)) {
442
                // Ignore special controllers
443
                case $this->id . self::CTR_UNI        :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
444
                case $this->id . self::CTR_POST        :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
445
                case $this->id . self::CTR_PUT        :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
446 1
                case $this->id . self::CTR_DELETE        :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
447
                case $this->id . self::CTR_BASE        :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
448
                    break;
449 1
450 1
                // Default controller
451 1
                //case $this->id: $this->controllers[ $method ] = $method; break;
452
453
                // Check if regular controller
454 1
                default:
455
                    if (preg_match('/^' . $this->id . self::PROC_PREFIX . '(?<controller>.+)/i', $method, $matches)) {
456
                        $this->controllers[$matches['controller']] = $method;
457 1
                    }
458
            }
459 1
        }
460 1
461 1
        // Iterate class methods
462
        foreach (get_class_methods($this) as $method) {
463
            // Try to find standard controllers
464 1
            switch (strtolower($method)) {
465
                // Ignore special controllers
466
                case self::CTR_UNI:
467
                case self::CTR_POST    :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
468
                case self::CTR_PUT:
469
                case self::CTR_DELETE:
470
                case self::CTR_BASE    :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
471
                    break;
472
473
                // Ignore magic methods
474
                case '__call':
475 1
                case '__wakeup':
476
                case '__sleep':
477
                case '__construct':
478 1
                case '__destruct':
479
                case '__set':
480
                case '__get':
481 1
                    break;
482
483
                // Check if regular controller
484 1
                default:
485
                    if (preg_match('/^' . self::OBJ_PREFIX . '(?<cache>cache_)?(?<controller>.+)/i', $method, $matches)) {
486
                        // If this controller has a cachable mark - store them in special collection
487 1
                        if (isset($matches['cache']) && isset($matches['cache']{1})) {
488 1
                            $this->cacheControllers[$matches['controller']] = array($this, $method);
489
                        }
490
491
                        // Just regular controller
492
                        $this->controllers[$matches['controller']] = array($this, $method);
493
                    }
494
            }
495 1
        }
496
497
        if (function_exists($this->id)) $this->controllers[self::CTR_BASE] = $this->id;
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
498 1 View Code Duplication
        if (method_exists($this, self::CTR_BASE)) $this->controllers[self::CTR_BASE] = array($this, self::CTR_BASE);
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
499
        else if (method_exists($this, self::CTR_CACHE_BASE)) $this->controllers[self::CTR_BASE] = array($this, self::CTR_CACHE_BASE);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
500
501 1 View Code Duplication
        if (function_exists($this->id . self::CTR_POST)) $this->controllers[self::CTR_POST] = $this->id . self::CTR_POST;
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
502 1 View Code Duplication
        if (method_exists($this, self::CTR_POST)) $this->controllers[self::CTR_POST] = array($this, self::CTR_POST);
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
503
        else if (method_exists($this, self::CTR_CACHE_POST)) $this->controllers[self::CTR_POST] = array($this, self::CTR_CACHE_POST);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
504
505 View Code Duplication
        if (function_exists($this->id . self::CTR_PUT)) $this->controllers[self::CTR_PUT] = $this->id . self::CTR_PUT;
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
506 View Code Duplication
        if (method_exists($this, self::CTR_PUT)) $this->controllers[self::CTR_PUT] = array($this, self::CTR_PUT);
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
507
        else if (method_exists($this, self::CTR_CACHE_PUT)) $this->controllers[self::CTR_PUT] = array($this, self::CTR_CACHE_PUT);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
508
509 View Code Duplication
        if (function_exists($this->id . self::CTR_DELETE)) $this->controllers[self::CTR_DELETE] = $this->id . self::CTR_DELETE;
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
510 View Code Duplication
        if (method_exists($this, self::CTR_DELETE)) $this->controllers[self::CTR_DELETE] = array($this, self::CTR_DELETE);
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
511
        else if (method_exists($this, self::CTR_CACHE_DELETE)) $this->controllers[self::CTR_DELETE] = array($this, self::CTR_CACHE_DELETE);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
512
513 View Code Duplication
        if (function_exists($this->id . self::CTR_UNI)) $this->controllers[self::CTR_UNI] = $this->id . self::CTR_UNI;
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
514 View Code Duplication
        if (method_exists($this, self::CTR_UNI)) $this->controllers[self::CTR_UNI] = array($this, self::CTR_UNI);
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...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
515
        else if (method_exists($this, self::CTR_CACHE_UNI)) $this->controllers[self::CTR_UNI] = array($this, self::CTR_CACHE_UNI);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
516
517
        // Make view path relative to module - remove module path from view path
518
        $this->views = str_replace($this->path, '', $this->views);
519
520
        //elapsed('Registering module: '.$this->id.'('.$path.')' );
521
    }
522
523
    /** Обработчик уничтожения объекта */
524
    public function __destruct()
525
    {
526
        //trace('Уничтожение модуля:'.$this->id );
527
528
        // Очистим коллекцию загруженых модулей
529
        unset(Module::$instances[$this->id]);
530
    }
531
532
    // Магический метод для получения переменных представления модуля
533
    public function __get($field)
534
    {
535
        // Установим пустышку как значение переменной
536
        $result = null;
537
538
        // Если указанная переменная представления существует - получим её значение
539
        if (isset($this->data[$field])) $result = &$this->data[$field];
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
540
        // Выведем ошибку
541
        else return e('Ошибка получения данных модуля(##) - Требуемые данные(##) не найдены', E_SAMSON_CORE_ERROR, array($this->id, $field));
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
542
543
        // Иначе вернем пустышку
544
        return $result;
545
    }
546
547
548
    /**
549
     * Create unique module cache folder structure in local web-application
550
     * @param string $file Path to file relative to module cache location
551
     * @param boolean $clear Flag to perform generic cache folder clearence
552
     * @param string $dir Directory in the cache location
553
     * @return boolean TRUE if cache file has to be regenerated
554
     */
555
    protected function cache_refresh(& $file, $clear = true, $dir = null)
0 ignored issues
show
Coding Style introduced by
Method name "Module::cache_refresh" is not in camel caps format
Loading history...
556
    {
557
        // If module cache folder does not exists - create it
558
        if (!file_exists($this->cache_path)) mkdir($this->cache_path, 0777, TRUE);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected true, but found TRUE.
Loading history...
559
560
        $path = !isset($dir)?$this->cache_path:$this->cache_path.$dir.'/';
561
562
        // If module cache folder does not exists - create it
563
        if (!file_exists($path)) mkdir($path, 0777, TRUE);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected true, but found TRUE.
Loading history...
564
565
        // Build full path to cached file
566
        $file = $path . $file;
567
568
        // If cached file does not exsits
569
        if (file_exists($file)) return false;
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
570
        // Needed file does not exists
571
        else {
572
            // If clearence flag set to true - clear all files in module cache directory with same extension
573
            if ($clear) File::clear($path, pathinfo($file, PATHINFO_EXTENSION));
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
574
575
            // Singal for cache file regeneration
576
            return true;
577
        }
578
    }
579
580
    // TODO: Переделать обработчик в одинаковый вид для объектов и простых
581
582
    /**
583
     *
584
     * @param unknown $object
585
     * @param string $viewprefix
586
     */
587
    private function _setObject($object, $viewprefix = null)
588
    {
589
        // Generate viewprefix as only lowercase classname without NS if it is not specified
590
        $class_name = is_string($viewprefix) ? $viewprefix : '' . mb_strtolower(classname(get_class($object)), 'UTF-8');
591
592
        // Save object to view data
593
        $this->data[$class_name] = $object;
594
595
        // Add separator
596
        $class_name .= '_';
597
598
        // Generate objects view array data and merge it with view data
599
        $this->data = array_merge($this->data, $object->toView($class_name));
600
    }
601
602
    /**
603
     *
604
     * @param unknown $array
605
     * @param string $viewprefix
606
     */
607
    private function _setArray($array, $viewprefix = null)
608
    {
609
        // Save array to view data
610
        $this->data[$viewprefix] = $array;
611
612
        // Add array values to view data
613
        $this->data = array_merge($this->data, $array);
614
    }
615
616
    // Магический метод для установки переменных представления модуля
617
    public function __set($field, $value = null)
618
    {
619
        // This is object
620
        if (is_object($field)) {
621
            $implements = class_implements($field);
622
            // If iModuleViewable implements is passed
623
            if (
624
                // TODO: Remove old interface support in future
625
                in_array(ns_classname('iModuleViewable', 'samson\core'), $implements)
0 ignored issues
show
Deprecated Code introduced by
The function ns_classname() has been deprecated with message: use \samson\core\AutoLoader::className() and pass full class name to it without splitting into class name and namespace

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
626
                || in_array(AutoLoader::className('IViewSettable', 'samson\core'), $implements)
627
                || in_array('samsonframework\core\RenderInterface', $implements)
628
            ) {
629
                $this->_setObject($field, $value);
630
            }
631
        } // If array is passed
632
        else if (is_array($field)) $this->_setArray($field, $value);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
633
        // Set view variable
634
        else $this->data[$field] = $value;
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
635
    }
636
637
    /** Magic method for calling unexisting object methods */
638
    public function __call($method, $arguments)
639
    {
640
        //elapsed($this->id.' - __Call '.$method);
641
642
        // If value is passed - set it
643
        if (sizeof($arguments)) {
644
            // If first argument is object or array - pass method name as second parameter
645
            if (is_object($arguments[0]) || is_array($arguments[0])) $this->__set($arguments[0], $method);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
646
            // Standard logic
647
            else  $this->__set($method, $arguments[0]);
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSE keyword; 2 found
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
648
        }
649
650
        // Chaining
651
        return $this;
652
    }
653
654
    /** Обработчик сериализации объекта */
655
    public function __sleep()
656
    {
657
        return array('id', 'path', 'version', 'data', 'controllers', 'views');
658
    }
659
660
    /** Обработчик десериализации объекта */
661
    public function __wakeup()
662
    {
663
        // Fill global instances
664
        self::$instances[$this->id] = &$this;
665
666
        // Set up default view data pointer
667
        $this->view_data[self::VD_POINTER_DEF] = $this->data;
668
669
        // Set reference to view context entry
670
        $this->data = &$this->view_data[self::VD_POINTER_DEF];
671
    }
672
673
    /** Группа методов для доступа к аттрибутам в виде массива */
674
    public function offsetSet($offset, $value)
675
    {
676
        $this->__set($offset, $value);
677
    }
678
679
    public function offsetGet($offset)
680
    {
681
        return $this->__get($offset);
682
    }
683
684
    public function offsetUnset($offset)
685
    {
686
        $this->data[$offset] = '';
687
    }
688
689
    public function offsetExists($offset)
690
    {
691
        return isset($this->data[$offset]);
692
    }
693
}
694