1 <?php
2 /**
3 * @package FrameworkOnFramework
4 * @subpackage model
5 * @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
6 * @license GNU General Public License version 2 or later; see LICENSE.txt
7 */
8
9 // Protect from unauthorized access
10 defined('FOF_INCLUDED') or die;
11
12 /**
13 * FrameworkOnFramework model behavior class
14 *
15 * @package FrameworkOnFramework
16 * @since 2.1
17 */
18 abstract class FOFModelField
19 {
20 protected $_db = null;
21
22 /**
23 * The column name of the table field
24 *
25 * @var string
26 */
27 protected $name = '';
28
29 /**
30 * The column type of the table field
31 *
32 * @var string
33 */
34 protected $type = '';
35
36 /**
37 * The alias of the table used for filtering
38 *
39 * @var string
40 */
41 protected $table_alias = false;
42
43 /**
44 * The null value for this type
45 *
46 * @var mixed
47 */
48 public $null_value = null;
49
50 /**
51 * Constructor
52 *
53 * @param FOFDatabaseDriver $db The database object
54 * @param object $field The field informations as taken from the db
55 * @param string $table_alias The table alias to use when filtering
56 */
57 public function __construct($db, $field, $table_alias = false)
58 {
59 $this->_db = $db;
60
61 $this->name = $field->name;
62 $this->type = $field->type;
63 $this->filterzero = $field->filterzero;
64 $this->table_alias = $table_alias;
65 }
66
67 /**
68 * Is it a null or otherwise empty value?
69 *
70 * @param mixed $value The value to test for emptiness
71 *
72 * @return boolean
73 */
74 public function isEmpty($value)
75 {
76 return (($value === $this->null_value) || empty($value))
77 && !($this->filterzero && $value === "0");
78 }
79
80 /**
81 * Returns the default search method for a field. This always returns 'exact'
82 * and you are supposed to override it in specialised classes. The possible
83 * values are exact, partial, between and outside, unless something
84 * different is returned by getSearchMethods().
85 *
86 * @see self::getSearchMethods()
87 *
88 * @return string
89 */
90 public function getDefaultSearchMethod()
91 {
92 return 'exact';
93 }
94
95 /**
96 * Return the search methods available for this field class,
97 *
98 * @return array
99 */
100 public function getSearchMethods()
101 {
102 $ignore = array('isEmpty', 'getField', 'getFieldType', '__construct', 'getDefaultSearchMethod', 'getSearchMethods');
103
104 $class = new ReflectionClass(__CLASS__);
105 $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
106
107 $tmp = array();
108
109 foreach ($methods as $method)
110 {
111 $tmp[] = $method->name;
112 }
113
114 $methods = $tmp;
115
116 if ($methods = array_diff($methods, $ignore))
117 {
118 return $methods;
119 }
120
121 return array();
122 }
123
124 /**
125 * Perform an exact match (equality matching)
126 *
127 * @param mixed $value The value to compare to
128 *
129 * @return string The SQL where clause for this search
130 */
131 public function exact($value)
132 {
133 if ($this->isEmpty($value))
134 {
135 return '';
136 }
137
138 if (is_array($value))
139 {
140 $db = FOFPlatform::getInstance()->getDbo();
141 $value = array_map(array($db, 'quote'), $value);
142
143 return '(' . $this->getFieldName() . ' IN (' . implode(',', $value) . '))';
144 }
145 else
146 {
147 return $this->search($value, '=');
148 }
149 }
150
151 /**
152 * Perform a partial match (usually: search in string)
153 *
154 * @param mixed $value The value to compare to
155 *
156 * @return string The SQL where clause for this search
157 */
158 abstract public function partial($value);
159
160 /**
161 * Perform a between limits match (usually: search for a value between
162 * two numbers or a date between two preset dates). When $include is true
163 * the condition tested is:
164 * $from <= VALUE <= $to
165 * When $include is false the condition tested is:
166 * $from < VALUE < $to
167 *
168 * @param mixed $from The lowest value to compare to
169 * @param mixed $to The higherst value to compare to
170 * @param boolean $include Should we include the boundaries in the search?
171 *
172 * @return string The SQL where clause for this search
173 */
174 abstract public function between($from, $to, $include = true);
175
176 /**
177 * Perform an outside limits match (usually: search for a value outside an
178 * area or a date outside a preset period). When $include is true
179 * the condition tested is:
180 * (VALUE <= $from) || (VALUE >= $to)
181 * When $include is false the condition tested is:
182 * (VALUE < $from) || (VALUE > $to)
183 *
184 * @param mixed $from The lowest value of the excluded range
185 * @param mixed $to The higherst value of the excluded range
186 * @param boolean $include Should we include the boundaries in the search?
187 *
188 * @return string The SQL where clause for this search
189 */
190 abstract public function outside($from, $to, $include = false);
191
192 /**
193 * Perform an interval search (usually: a date interval check)
194 *
195 * @param string $from The value to search
196 * @param string|array|object $interval The interval
197 *
198 * @return string The SQL where clause for this search
199 */
200 abstract public function interval($from, $interval);
201
202 /**
203 * Perform a between limits match (usually: search for a value between
204 * two numbers or a date between two preset dates). When $include is true
205 * the condition tested is:
206 * $from <= VALUE <= $to
207 * When $include is false the condition tested is:
208 * $from < VALUE < $to
209 *
210 * @param mixed $from The lowest value to compare to
211 * @param mixed $to The higherst value to compare to
212 * @param boolean $include Should we include the boundaries in the search?
213 *
214 * @return string The SQL where clause for this search
215 */
216 abstract public function range($from, $to, $include = true);
217
218 /**
219 * Perform an modulo search
220 *
221 * @param integer|float $value The starting value of the search space
222 * @param integer|float $interval The interval period of the search space
223 * @param boolean $include Should I include the boundaries in the search?
224 *
225 * @return string The SQL where clause
226 */
227 abstract public function modulo($from, $interval, $include = true);
228
229 /**
230 * Return the SQL where clause for a search
231 *
232 * @param mixed $value The value to search for
233 * @param string $operator The operator to use
234 *
235 * @return string The SQL where clause for this search
236 */
237 public function search($value, $operator = '=')
238 {
239 if ($this->isEmpty($value))
240 {
241 return '';
242 }
243
244 return '(' . $this->getFieldName() . ' ' . $operator . ' ' . $this->_db->quote($value) . ')';
245 }
246
247 /**
248 * Get the field name with the given table alias
249 *
250 * @return string The field name
251 */
252 public function getFieldName()
253 {
254 $name = $this->_db->qn($this->name);
255
256 if ($this->table_alias)
257 {
258 $name = $this->_db->qn($this->table_alias) . '.' . $name;
259 }
260
261 return $name;
262 }
263
264 /**
265 * Creates a field Object based on the field column type
266 *
267 * @param object $field The field informations
268 * @param array $config The field configuration (like the db object to use)
269 *
270 * @return FOFModelField The Field object
271 */
272 public static function getField($field, $config = array())
273 {
274 $type = $field->type;
275
276 $classType = self::getFieldType($type);
277
278 $className = 'FOFModelField' . $classType;
279
280 if (class_exists($className))
281 {
282 if (isset($config['dbo']))
283 {
284 $db = $config['dbo'];
285 }
286 else
287 {
288 $db = FOFPlatform::getInstance()->getDbo();
289 }
290
291 if (isset($config['table_alias']))
292 {
293 $table_alias = $config['table_alias'];
294 }
295 else
296 {
297 $table_alias = false;
298 }
299
300 $field = new $className($db, $field, $table_alias);
301
302 return $field;
303 }
304
305 return false;
306 }
307
308 /**
309 * Get the classname based on the field Type
310 *
311 * @param string $type The type of the field
312 *
313 * @return string the class suffix
314 */
315 public static function getFieldType($type)
316 {
317 switch ($type)
318 {
319 case 'varchar':
320 case 'text':
321 case 'smalltext':
322 case 'longtext':
323 case 'char':
324 case 'mediumtext':
325 case 'character varying':
326 case 'nvarchar':
327 case 'nchar':
328 $type = 'Text';
329 break;
330
331 case 'date':
332 case 'datetime':
333 case 'time':
334 case 'year':
335 case 'timestamp':
336 case 'timestamp without time zone':
337 case 'timestamp with time zone':
338 $type = 'Date';
339 break;
340
341 case 'tinyint':
342 case 'smallint':
343 $type = 'Boolean';
344 break;
345
346 default:
347 $type = 'Number';
348 break;
349 }
350
351 return $type;
352 }
353 }
354