1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Class for WordPoints apps. |
5
|
|
|
* |
6
|
|
|
* @package wordpoints-hooks-api |
7
|
|
|
* @since 1.0.0 |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* An app for WordPoints. |
12
|
|
|
* |
13
|
|
|
* Apps are self-contained APIs that can include sub-apps. |
14
|
|
|
* |
15
|
|
|
* The sub-apps are not required to be instances of WordPoints_App themselves, they |
16
|
|
|
* can be any sort of object. |
17
|
|
|
* |
18
|
|
|
* @since 1.0.0 |
19
|
|
|
* |
20
|
|
|
* @property-read WordPoints_Class_Registry_Persistent $sub_apps Child apps registry. |
21
|
|
|
* @property-read object $* Child app objects. |
22
|
|
|
*/ |
23
|
|
|
class WordPoints_App { |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* The main app. |
27
|
|
|
* |
28
|
|
|
* @since 1.0.0 |
29
|
|
|
* |
30
|
|
|
* @var WordPoints_App |
31
|
|
|
*/ |
32
|
|
|
public static $main; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* The slug of this app. |
36
|
|
|
* |
37
|
|
|
* @since 1.0.0 |
38
|
|
|
* |
39
|
|
|
* @var string |
40
|
|
|
*/ |
41
|
|
|
protected $slug; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* The full slug of this app, prefixed with the slug of the parent app. |
45
|
|
|
* |
46
|
|
|
* @since 1.0.0 |
47
|
|
|
* |
48
|
|
|
* @var string |
49
|
|
|
*/ |
50
|
|
|
protected $full_slug; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* A registry for child apps. |
54
|
|
|
* |
55
|
|
|
* @since 1.0.0 |
56
|
|
|
* |
57
|
|
|
* @var WordPoints_Class_Registry_Persistent |
58
|
|
|
*/ |
59
|
|
|
protected $sub_apps; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* The parent of this app, if this is a sub-app. |
63
|
|
|
* |
64
|
|
|
* @since 1.0.0 |
65
|
|
|
* |
66
|
|
|
* @var WordPoints_App |
67
|
|
|
*/ |
68
|
|
|
protected $parent; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Whether to skip calling an action when each registry is initialized. |
72
|
|
|
* |
73
|
|
|
* @since 1.0.0 |
74
|
|
|
* |
75
|
|
|
* @var bool |
76
|
|
|
*/ |
77
|
|
|
protected $silent = false; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Keeps track of which registries have been initialized. |
81
|
|
|
* |
82
|
|
|
* @since 1.0.0 |
83
|
|
|
* |
84
|
|
|
* @var bool[] |
85
|
|
|
*/ |
86
|
|
|
protected $did_init = array(); |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Whether properties are allowed to be set. |
90
|
|
|
* |
91
|
|
|
* @since 1.0.0 |
92
|
|
|
* |
93
|
|
|
* @var bool |
94
|
|
|
*/ |
95
|
|
|
protected $allow_set = false; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @since 1.0.0 |
99
|
|
|
*/ |
100
|
|
|
public function __construct( $slug, $parent = null ) { |
101
|
|
|
|
102
|
|
|
$this->slug = $slug; |
103
|
|
|
$this->full_slug = $slug; |
104
|
|
|
|
105
|
|
|
if ( $parent instanceof WordPoints_App ) { |
106
|
|
|
$this->parent = $parent; |
107
|
|
|
|
108
|
|
|
if ( 'apps' !== $this->parent->full_slug ) { |
109
|
|
|
$this->full_slug = $this->parent->full_slug . '-' . $this->full_slug; |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
$this->sub_apps = new WordPoints_Class_Registry_Persistent(); |
114
|
|
|
|
115
|
|
|
$this->init(); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @since 1.0.0 |
120
|
|
|
*/ |
121
|
|
|
public function __isset( $var ) { |
122
|
|
|
return $this->sub_apps->is_registered( $var ); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* @since 1.0.0 |
127
|
|
|
*/ |
128
|
|
|
public function __get( $var ) { |
129
|
|
|
|
130
|
|
|
if ( 'sub_apps' === $var ) { |
131
|
|
|
return $this->$var; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
$sub = $this->sub_apps->get( $var, array( $this ) ); |
135
|
|
|
|
136
|
|
|
if ( ! $sub ) { |
137
|
|
|
return null; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
if ( |
141
|
|
|
empty( $this->did_init[ $var ] ) |
142
|
|
|
&& ! self::$main->silent |
143
|
|
|
&& $this->should_do_registry_init( $sub ) |
144
|
|
|
) { |
145
|
|
|
|
146
|
|
|
$is_protected_property = array_key_exists( $var, get_object_vars( $this ) ); |
147
|
|
|
|
148
|
|
|
// When the below action is called it is possible that some hooked code |
149
|
|
|
// may attempt to access the property that is being initialized. However, |
150
|
|
|
// the __get() function will not be called recursively, meaning that |
151
|
|
|
// instead of the true value the code will get null. To solve this, we |
152
|
|
|
// temporarily set this as a public property. However, we can't do this |
153
|
|
|
// for properties that the class has declared, because otherwise it would |
154
|
|
|
// be possible to modify and then unset protected class properties. |
155
|
|
View Code Duplication |
if ( ! $is_protected_property ) { |
|
|
|
|
156
|
|
|
$this->allow_set = true; |
157
|
|
|
$this->$var = $sub; |
158
|
|
|
$this->allow_set = false; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Initialization of an app registry. |
163
|
|
|
* |
164
|
|
|
* The $var is the slug of the registry. |
165
|
|
|
* |
166
|
|
|
* @since 1.0.0 |
167
|
|
|
* |
168
|
|
|
* @param WordPoints_Class_RegistryI|WordPoints_Class_Registry_ChildrenI |
169
|
|
|
* $registry The registry object. |
170
|
|
|
*/ |
171
|
|
|
do_action( "wordpoints_init_app_registry-{$this->full_slug}-{$var}", $sub ); |
172
|
|
|
|
173
|
|
|
// Because this property was public, it's possible that it might have |
174
|
|
|
// been modified inadvertently. If this happens we give a warning. |
175
|
|
|
if ( $sub !== $this->$var ) { |
176
|
|
|
_doing_it_wrong( |
177
|
|
|
__METHOD__ |
178
|
|
|
, esc_html( "Do not modify the {$var} property directly." ) |
179
|
|
|
, '1.0.0' |
180
|
|
|
); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
View Code Duplication |
if ( ! $is_protected_property ) { |
|
|
|
|
184
|
|
|
$this->allow_set = true; |
185
|
|
|
unset( $this->$var ); |
186
|
|
|
$this->allow_set = false; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
$this->did_init[ $var ] = true; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
return $sub; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* @since 1.0.0 |
197
|
|
|
*/ |
198
|
|
|
public function __set( $var, $value ) { |
199
|
|
|
|
200
|
|
|
if ( $this->allow_set ) { |
201
|
|
|
$this->$var = $value; |
202
|
|
|
} else { |
203
|
|
|
_doing_it_wrong( |
204
|
|
|
__METHOD__ |
205
|
|
|
, 'Sub apps must be registered using $app->sub_apps->register().' |
206
|
|
|
, '1.0.0' |
207
|
|
|
); |
208
|
|
|
} |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* @since 1.0.0 |
213
|
|
|
*/ |
214
|
|
|
public function __unset( $var ) { |
215
|
|
|
|
216
|
|
|
if ( $this->allow_set ) { |
217
|
|
|
unset( $this->$var ); |
218
|
|
|
} else { |
219
|
|
|
_doing_it_wrong( |
220
|
|
|
__METHOD__ |
221
|
|
|
, 'Sub apps must be deregistered using $app->sub_apps->deregister().' |
222
|
|
|
, '1.0.0' |
223
|
|
|
); |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Check whether to call the init action for a registry sub-app. |
229
|
|
|
* |
230
|
|
|
* @since 1.0.0 |
231
|
|
|
* |
232
|
|
|
* @param object $registry The sub-app object. |
233
|
|
|
* |
234
|
|
|
* @return bool Whether to call the init action or not. |
235
|
|
|
*/ |
236
|
|
|
protected function should_do_registry_init( $registry ) { |
237
|
|
|
return ( |
238
|
|
|
$registry instanceof WordPoints_Class_RegistryI |
239
|
|
|
|| $registry instanceof WordPoints_Class_Registry_ChildrenI |
240
|
|
|
); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Initialize this app. |
245
|
|
|
* |
246
|
|
|
* @since 1.0.0 |
247
|
|
|
*/ |
248
|
|
|
protected function init() { |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* WordPoints app initialized. |
252
|
|
|
* |
253
|
|
|
* The dynamic portion of the action is the slug of the app being |
254
|
|
|
* initialized. |
255
|
|
|
* |
256
|
|
|
* @since 1.0.0 |
257
|
|
|
* |
258
|
|
|
* @param WordPoints_App $app The app object. |
259
|
|
|
*/ |
260
|
|
|
do_action( "wordpoints_init_app-{$this->full_slug}", $this ); |
261
|
|
|
} |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
// EOF |
265
|
|
|
|
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.