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 ©() |
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); |
|
|
|
|
88
|
|
|
} else { // Call default module behaviour |
89
|
|
|
// Call default module behaviour |
90
|
|
|
parent::view($this->view_path); |
91
|
|
|
|
92
|
|
|
return $this; |
|
|
|
|
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); |
|
|
|
|
140
|
|
|
|
141
|
|
|
return true; |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
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:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.