Completed
Push — master ( 7c5d16...1e7423 )
by Vitaly
03:53
created

ExternalModule::view()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 22
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 4 Features 1
Metric Value
c 6
b 4
f 1
dl 0
loc 22
rs 9.2
cc 3
eloc 7
nc 2
nop 1
1
<?php
2
namespace samson\core;
3
4
use samsonframework\core\RequestInterface;
5
use samsonframework\core\ResourcesInterface;
6
use samsonframework\core\SystemInterface;
7
use samsonphp\event\Event;
8
9
/**
10
 * SamsonPHP external module
11
 *
12
 * @author Vitaly Iegorov <[email protected]>
13
 */
14
class ExternalModule extends Module implements iExternalModule
15
{
16
    /** @var Module Pointer to parent module */
17
    public $parent = null;
18
19
    /** Коллекция связанных модулей с текущим */
20
    protected $requirements = array();
21
22
    /**
23
     * ExternalModule constructor.
24
     *
25
     * @param string $path
26
     * @param ResourcesInterface $resources
27
     * @param SystemInterface $system
28
     */
29
    public function __construct($path, ResourcesInterface $resources, SystemInterface $system)
30
    {
31
        // Module identifier not specified - set it to NameSpace\Classname
32
        if (!isset($this->id{0})) {
33
            // Generate identifier from module class
34
            //$this->id = AutoLoader::oldClassName(get_class($this));
35
            $this->id = str_replace('/', '', $path);
36
        }
37
38
        // Subscribe to an config ready core event
39
        Event::subscribe('core.started', array(& $this, 'init'));
40
41
        // Call parent constructor
42
        parent::__construct($this->id, $path, $resources, $system);
43
    }
44
45
    /** @see \samson\core\iExternalModule::copy() */
46
    public function &copy()
47
    {
48
        // Get current class name
49
        $classname = get_class($this);
50
51
        // Create copy instance
52
        $clone = new $classname($this->path, $this->resourceMap, $this->system);
53
        $clone->views = &$this->views;
54
        $clone->parent = &$this->parent;
55
        $clone->path = $this->path;
56
57
        return $clone;
58
    }
59
60
    /** Обработчик сериализации объекта */
61
    public function __sleep()
62
    {
63
        // Remove all unnecessary fields from serialization
64
        return array_diff(array_keys(get_object_vars($this)), array('view_path', 'view_html', 'view_data'));
65
    }
66
67
    /**
68
     * Set current view for rendering.
69
     *
70
     * @param string $viewPath Path for view searching
71
     * @return self Chaining
72
     */
73
    public function view($viewPath)
74
    {
75
        //elapsed('['.$this->id.'] Setting view context: ['.$viewPath.']');
76
        // Find full path to view file
77
        $this->view_path = $this->findView($viewPath);
78
79
        // If we have not found view in current module but we have parent module
80
        if (isset($this->parent) && $this->view_path === false) {
81
            //elapsed('['.$this->id.'] Cannot set view['.$viewPath.'] - passing it to parent['.$this->parent->id.']');
82
83
            /*
84
             * Call parent module view setting and return PARENT module to chain
85
             * actually switching current module in chain
86
             */
87
            return $this->parent->view($viewPath);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->parent->view($viewPath); (samson\core\Module) is incompatible with the return type declared by the interface samsonframework\core\ViewInterface::view of type samsonframework\core\IViewable.

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...
88
        } else { // Call default module behaviour
89
            // Call default module behaviour
90
            parent::view($this->view_path);
91
92
            return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (samson\core\ExternalModule) is incompatible with the return type declared by the interface samsonframework\core\ViewInterface::view of type samsonframework\core\IViewable.

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...
93
        }
94
    }
95
96
    /**
97
     * Overloading default module rendering behaviour
98
     * as it is used in templates and views using m()->render()
99
     * without specifying concrete module or passing a variable.
100
     *
101
     * @param string $controller Controller action name
102
     */
103
    public function render($controller = null)
104
    {
105
        // If we have parent module connection and have no view set
106
        if (isset($this->parent) && $this->view_path == false) {
107
            // Merge current and parent module view data
108
            $this->parent->view_data = array_merge($this->parent->view_data, $this->view_data);
109
            // Set internal view context data pointer
110
            $this->parent->data = &$this->parent->view_data[$this->parent->view_context];
111
            // Call parent render
112
            $this->parent->render($controller);
113
        } else { // Call default module behaviour
114
            parent::render($controller);
115
        }
116
    }
117
118
    /**
119
     * Module preparation handler.
120
     * This function is triggered after module instance is being created.
121
     *
122
     * @return bool Preparation result
123
     */
124
    public function prepare()
125
    {
126
        return true;
127
    }
128
129
    /**
130
     * Module initialization.
131
     * This function is triggered when system has started. So here
132
     * we have all modules already prepared and loaded.
133
     *
134
     * @param array $params Collection of module initialization parameters
135
     * @return bool Initialization result
136
     */
137
    public function init(array $params = array())
138
    {
139
        $this->set($params);
0 ignored issues
show
Documentation introduced by
$params is of type array, but the function expects a string.

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...
140
141
        return true;
142
    }
143
}
144