|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
if (!defined('EVENT_ESPRESSO_VERSION')) |
|
4
|
|
|
exit('No direct script access allowed'); |
|
5
|
|
|
|
|
6
|
|
|
/** |
|
7
|
|
|
* |
|
8
|
|
|
* EEME_Base |
|
9
|
|
|
* For magically adding fields, relations, and functions onto existing models. |
|
10
|
|
|
* example child class: adds a class called EEME_Sample_Attendee which adds an extra table for |
|
11
|
|
|
* meta info that we want to use for frequent querying (otherwise we could just use the extra meta features), |
|
12
|
|
|
* and adds a field named 'ATT_foobar' on the Attendee model, |
|
13
|
|
|
* which is actually a foreign key to transactions, and |
|
14
|
|
|
* a relation to transactions, and a function called new_func() onto EEM_Attendee which |
|
15
|
|
|
* gets all attendees which have a direct relation to the specified transaction. |
|
16
|
|
|
* For example, |
|
17
|
|
|
* |
|
18
|
|
|
* class EEME_Sample_Attendee extends EEME_Base{ |
|
19
|
|
|
function __construct() { |
|
20
|
|
|
$this->_model_name_extended = 'Attendee'; |
|
21
|
|
|
$this->_extra_tables = array( |
|
22
|
|
|
'Mock_Attendee_Meta' => new EE_Secondary_Table('esp_mock_attendee_meta', 'MATTM_ID', 'ATT_ID' ) |
|
23
|
|
|
); |
|
24
|
|
|
$this->_extra_fields = array('Mock_Attendee_Meta'=>array( |
|
25
|
|
|
'MATTM_ID'=> new EE_DB_Only_Int_Field('MATTM_ID', __('Mock Attendee Meta Row ID','event_espresso'), false), |
|
26
|
|
|
'MATT_ID_fk'=>new EE_DB_Only_Int_Field('ATT_ID', __("Foreign Key to Attendee in Post Table", "event_espresso"), false), |
|
27
|
|
|
'ATT_foobar'=>new EE_Foreign_Key_Int_Field('ATT_foobar', __("Foobar", 'event_espresso'), true,0,'Transaction'))); |
|
28
|
|
|
$this->_extra_relations = array('Transaction'=>new EE_Belongs_To_Relation()); |
|
29
|
|
|
parent::__construct(); |
|
30
|
|
|
} |
|
31
|
|
|
function ext_new_func($arg1){ |
|
32
|
|
|
return $this->_->get_all(array(array('Transaction.TXN_ID'=>$arg1))); |
|
33
|
|
|
} |
|
34
|
|
|
} |
|
35
|
|
|
* |
|
36
|
|
|
* example usage: early you need to simply construct this extension, and it will automatically |
|
37
|
|
|
* add any of its needed hooks. Like so: new EEME_Sample_Attendee(); |
|
38
|
|
|
* then you can use that field, relation, and function on the EEM_Attendee singleton. Eg. |
|
39
|
|
|
* $attendees_directly_related_to_txn_1 = EEM_Attendee::instance()->new_func(1); |
|
40
|
|
|
* |
|
41
|
|
|
* @package Event Espresso |
|
42
|
|
|
* @subpackage |
|
43
|
|
|
* @author Mike Nelson |
|
44
|
|
|
* |
|
45
|
|
|
*/ |
|
46
|
|
|
abstract class EEME_Base { |
|
47
|
|
|
|
|
48
|
|
|
const extending_method_prefix = 'ext_'; |
|
49
|
|
|
const dynamic_callback_method_prefix = 'dynamic_callback_method_'; |
|
50
|
|
|
|
|
51
|
|
|
protected $_extra_tables = array(); |
|
52
|
|
|
protected $_extra_fields = array(); |
|
53
|
|
|
protected $_extra_relations = array(); |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* The model name that is extended (not classname) |
|
57
|
|
|
* @var string |
|
58
|
|
|
*/ |
|
59
|
|
|
protected $_model_name_extended = NULL; |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* The model this extends |
|
63
|
|
|
* @var EEM_Base |
|
64
|
|
|
*/ |
|
65
|
|
|
protected $_ = NULL; |
|
66
|
|
|
|
|
67
|
|
|
|
|
68
|
|
|
|
|
69
|
|
|
/** |
|
70
|
|
|
* @throws \EE_Error |
|
71
|
|
|
*/ |
|
72
|
|
|
public function __construct(){ |
|
73
|
|
|
if( ! $this->_model_name_extended){ |
|
74
|
|
|
throw new EE_Error( |
|
75
|
|
|
__( "When declaring a model extension, you must define its _model_name_extended property. It should be a model name like 'Attendee' or 'Event'", |
|
76
|
|
|
"event_espresso" ) |
|
77
|
|
|
); |
|
78
|
|
|
} |
|
79
|
|
|
$construct_end_action = 'AHEE__EEM_'.$this->_model_name_extended.'__construct__end'; |
|
80
|
|
|
if ( did_action( $construct_end_action )) { |
|
81
|
|
|
throw new EE_Error( |
|
82
|
|
|
sprintf( |
|
83
|
|
|
__( "Hooked in model extension '%s' too late! The model %s has already been used! We know because the action %s has been fired", "event_espresso"), |
|
84
|
|
|
get_class($this), |
|
85
|
|
|
$this->_model_name_extended, |
|
86
|
|
|
$construct_end_action |
|
87
|
|
|
) |
|
88
|
|
|
); |
|
89
|
|
|
} |
|
90
|
|
|
add_filter('FHEE__EEM_'.$this->_model_name_extended.'__construct__tables',array($this,'add_extra_tables_on_filter')); |
|
91
|
|
|
add_filter('FHEE__EEM_'.$this->_model_name_extended.'__construct__fields',array($this,'add_extra_fields_on_filter')); |
|
92
|
|
|
add_filter('FHEE__EEM_'.$this->_model_name_extended.'__construct__model_relations',array($this,'add_extra_relations_on_filter')); |
|
93
|
|
|
$this->_register_extending_methods(); |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
|
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* @param array $existing_tables |
|
100
|
|
|
* @return array |
|
101
|
|
|
*/ |
|
102
|
|
|
public function add_extra_tables_on_filter( $existing_tables ){ |
|
103
|
|
|
return array_merge( (array)$existing_tables, $this->_extra_tables ); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
|
|
107
|
|
|
|
|
108
|
|
|
/** |
|
109
|
|
|
* @param array $existing_fields |
|
110
|
|
|
* @return array |
|
111
|
|
|
*/ |
|
112
|
|
|
public function add_extra_fields_on_filter( $existing_fields ){ |
|
113
|
|
|
if( $this->_extra_fields){ |
|
|
|
|
|
|
114
|
|
|
foreach($this->_extra_fields as $table_alias => $fields){ |
|
115
|
|
|
if( ! isset( $existing_fields[ $table_alias ] ) ){ |
|
116
|
|
|
$existing_fields[ $table_alias ] = array(); |
|
117
|
|
|
} |
|
118
|
|
|
$existing_fields[$table_alias] = array_merge( |
|
119
|
|
|
(array)$existing_fields[$table_alias], |
|
120
|
|
|
$this->_extra_fields[$table_alias] |
|
121
|
|
|
); |
|
122
|
|
|
|
|
123
|
|
|
} |
|
124
|
|
|
} |
|
125
|
|
|
return $existing_fields; |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
|
|
129
|
|
|
|
|
130
|
|
|
/** |
|
131
|
|
|
* @param array $existing_relations |
|
132
|
|
|
* @return array |
|
133
|
|
|
*/ |
|
134
|
|
|
public function add_extra_relations_on_filter( $existing_relations ){ |
|
135
|
|
|
return array_merge((array)$existing_relations,$this->_extra_relations); |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
|
|
139
|
|
|
|
|
140
|
|
|
/** |
|
141
|
|
|
* scans the child of EEME_Base for functions starting with ext_, and magically makes them functions on the |
|
142
|
|
|
* model extended. (Internally uses filters, and the __call magic method) |
|
143
|
|
|
*/ |
|
144
|
|
View Code Duplication |
protected function _register_extending_methods(){ |
|
|
|
|
|
|
145
|
|
|
$all_methods = get_class_methods(get_class($this)); |
|
146
|
|
|
foreach($all_methods as $method_name){ |
|
147
|
|
|
if(strpos($method_name, self::extending_method_prefix) === 0){ |
|
148
|
|
|
$method_name_on_model = str_replace(self::extending_method_prefix, '', $method_name); |
|
149
|
|
|
$callback_name = "FHEE__EEM_{$this->_model_name_extended}__$method_name_on_model"; |
|
150
|
|
|
add_filter($callback_name,array($this,self::dynamic_callback_method_prefix.$method_name_on_model),10,10); |
|
151
|
|
|
} |
|
152
|
|
|
} |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* scans the child of EEME_Base for functions starting with ext_, and magically REMOVES them as functions on the |
|
157
|
|
|
* model extended. (Internally uses filters, and the __call magic method) |
|
158
|
|
|
*/ |
|
159
|
|
|
public function deregister(){ |
|
160
|
|
|
remove_filter('FHEE__EEM_'.$this->_model_name_extended.'__construct__tables',array($this,'add_extra_tables_on_filter')); |
|
161
|
|
|
remove_filter('FHEE__EEM_'.$this->_model_name_extended.'__construct__fields',array($this,'add_extra_fields_on_filter')); |
|
162
|
|
|
remove_filter('FHEE__EEM_'.$this->_model_name_extended.'__construct__model_relations',array($this,'add_extra_relations_on_filter')); |
|
163
|
|
|
$all_methods = get_class_methods(get_class($this)); |
|
164
|
|
|
foreach($all_methods as $method_name){ |
|
165
|
|
|
if(strpos($method_name, self::extending_method_prefix) === 0){ |
|
166
|
|
|
$method_name_on_model = str_replace(self::extending_method_prefix, '', $method_name); |
|
167
|
|
|
$callback_name = "FHEE__EEM_{$this->_model_name_extended}__$method_name_on_model"; |
|
168
|
|
|
remove_filter($callback_name,array($this,self::dynamic_callback_method_prefix.$method_name_on_model),10); |
|
169
|
|
|
} |
|
170
|
|
|
} |
|
171
|
|
|
/** @var EEM_Base $model_to_reset */ |
|
172
|
|
|
$model_to_reset = 'EEM_' . $this->_model_name_extended; |
|
173
|
|
|
if ( class_exists( $model_to_reset ) ) { |
|
174
|
|
|
$model_to_reset::reset(); |
|
175
|
|
|
} |
|
176
|
|
|
} |
|
177
|
|
|
|
|
178
|
|
|
|
|
179
|
|
|
|
|
180
|
|
|
/** |
|
181
|
|
|
* @param string $callback_method_name |
|
182
|
|
|
* @param array $args |
|
183
|
|
|
* @return mixed |
|
184
|
|
|
* @throws EE_Error |
|
185
|
|
|
*/ |
|
186
|
|
|
public function __call( $callback_method_name, $args){ |
|
187
|
|
|
if(strpos($callback_method_name, self::dynamic_callback_method_prefix) === 0){ |
|
188
|
|
|
//it's a dynamic callback for a method name |
|
189
|
|
|
$method_called_on_model = str_replace(self::dynamic_callback_method_prefix, '', $callback_method_name); |
|
190
|
|
|
list( $original_return_val, $model_called, $args_provided_to_method_on_model ) = (array) $args; |
|
|
|
|
|
|
191
|
|
|
$this->_ = $model_called; |
|
192
|
|
|
$extending_method = self::extending_method_prefix.$method_called_on_model; |
|
193
|
|
|
if(method_exists($this, $extending_method)){ |
|
194
|
|
|
return call_user_func_array(array($this,$extending_method), $args_provided_to_method_on_model); |
|
195
|
|
|
}else{ |
|
196
|
|
|
throw new EE_Error( |
|
197
|
|
|
sprintf( |
|
198
|
|
|
__("An odd error occurred. Model '%s' had a method called on it that it didn't recognize. So it passed it onto the model extension '%s' (because it had a function named '%s' which should be able to handle it), but the function '%s' doesnt exist!)", "event_espresso"), |
|
199
|
|
|
$this->_model_name_extended, |
|
200
|
|
|
get_class($this), |
|
201
|
|
|
$extending_method,$extending_method |
|
202
|
|
|
) |
|
203
|
|
|
); |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
}else{ |
|
207
|
|
|
throw new EE_Error( |
|
208
|
|
|
sprintf( |
|
209
|
|
|
__("There is no method named '%s' on '%s'", "event_espresso"), |
|
210
|
|
|
$callback_method_name, |
|
211
|
|
|
get_class($this) |
|
212
|
|
|
) |
|
213
|
|
|
); |
|
214
|
|
|
} |
|
215
|
|
|
} |
|
216
|
|
|
|
|
217
|
|
|
} |
|
218
|
|
|
// End of file EEME_Base.model.php |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.