Completed
Push — 3.6 ( 6eff32...8c9e8f )
by
unknown
07:54
created

DBField::prepValueForDB()   A

Complexity

Conditions 6
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 2
nop 1
dl 0
loc 7
rs 9.2222
c 0
b 0
f 0
1
<?php
2
/**
3
 * Single field in the database.
4
 *
5
 * Every field from the database is represented as a sub-class of DBField.
6
 *
7
 * <b>Multi-value DBField objects</b>
8
 *
9
 * Sometimes you will want to make DBField classes that don't have a 1-1 match
10
 * to database fields.  To do this, there are a number of fields for you to
11
 * overload:
12
 *
13
 *  - Overload {@link writeToManipulation} to add the appropriate references to
14
 *		the INSERT or UPDATE command
15
 *  - Overload {@link addToQuery} to add the appropriate items to a SELECT
16
 *		query's field list
17
 *  - Add appropriate accessor methods
18
 *
19
 * <b>Subclass Example</b>
20
 *
21
 * The class is easy to overload with custom types, e.g. the MySQL "BLOB" type
22
 * (http://dev.mysql.com/doc/refman/5.0/en/blob.html).
23
 *
24
 * <code>
25
 * class Blob extends DBField {
26
 * 	function requireField() {
27
 * 		DB::requireField($this->tableName, $this->name, "blob");
28
 *  }
29
 * }
30
 * </code>
31
 *
32
 * @todo remove MySQL specific code from subclasses
33
 *
34
 * @package framework
35
 * @subpackage model
36
 */
37
abstract class DBField extends ViewableData {
38
39
	protected $value;
40
41
	protected $tableName;
42
43
	protected $name;
44
45
	protected $arrayValue;
46
47
	/**
48
	 * The escape type for this field when inserted into a template - either "xml" or "raw".
49
	 *
50
	 * @var string
51
	 * @config
52
	 */
53
	private static $escape_type = 'raw';
54
55
	/**
56
	 * Subclass of {@link SearchFilter} for usage in {@link defaultSearchFilter()}.
57
	 *
58
	 * @var string
59
	 * @config
60
	 */
61
	private static $default_search_filter_class = 'PartialMatchFilter';
62
63
	/**
64
	 * @var $default mixed Default-value in the database.
65
	 * Might be overridden on DataObject-level, but still useful for setting defaults on
66
	 * already existing records after a db-build.
67
	 */
68
	protected $defaultVal;
69
70
	public function __construct($name = null) {
71
		$this->name = $name;
72
73
		parent::__construct();
74
	}
75
76
	/**
77
	 * Create a DBField object that's not bound to any particular field.
78
	 *
79
	 * Useful for accessing the classes behaviour for other parts of your code.
80
	 *
81
	 * @param string $className class of field to construct
82
	 * @param mixed $value value of field
83
	 * @param string $name Name of field
84
	 * @param mixed $object Additional parameter to pass to field constructor
85
	 * @return DBField
86
	 */
87
	public static function create_field($className, $value, $name = null, $object = null) {
88
		$dbField = Object::create($className, $name, $object);
89
		$dbField->setValue($value, null, false);
0 ignored issues
show
Unused Code introduced by
The call to DBField::setValue() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
90
91
		return $dbField;
92
	}
93
94
	/**
95
	 * Set the name of this field.
96
	 *
97
	 * The name should never be altered, but it if was never given a name in
98
	 * the first place you can set a name.
99
	 *
100
	 * If you try an alter the name a warning will be thrown.
101
	 *
102
	 * @param string $name
103
	 *
104
	 * @return DBField
105
	 */
106
	public function setName($name) {
107
		if($this->name && $this->name !== $name) {
108
			user_error("DBField::setName() shouldn't be called once a DBField already has a name."
109
				. "It's partially immutable - it shouldn't be altered after it's given a value.", E_USER_WARNING);
110
		}
111
112
		$this->name = $name;
113
114
		return $this;
115
	}
116
117
	/**
118
	 * Returns the name of this field.
119
	 *
120
	 * @return string
121
	 */
122
	public function getName() {
123
		return $this->name;
124
	}
125
126
	/**
127
	 * Returns the value of this field.
128
	 *
129
	 * @return mixed
130
	 */
131
	public function getValue() {
132
		return $this->value;
133
	}
134
135
	/**
136
	 * Set the value on the field.
137
	 *
138
	 * Optionally takes the whole record as an argument, to pick other values.
139
	 *
140
	 * @param mixed $value
141
	 * @param array $record
142
	 */
143
	public function setValue($value, $record = null) {
144
		$this->value = $value;
145
	}
146
147
148
	/**
149
	 * Determines if the field has a value which is not considered to be 'null'
150
	 * in a database context.
151
	 *
152
	 * @return boolean
153
	 */
154
	public function exists() {
155
		return (bool)$this->value;
156
	}
157
158
	/**
159
	 * Return the transformed value ready to be sent to the database. This value
160
	 * will be escaped automatically by the prepared query processor, so it
161
	 * should not be escaped or quoted at all.
162
	 *
163
	 * The field values could also be in paramaterised format, such as
164
	 * array('MAX(?,?)' => array(42, 69)), allowing the use of raw SQL values such as
165
	 * array('NOW()' => array()).
166
	 *
167
	 * @see SQLWriteExpression::addAssignments for syntax examples
168
	 *
169
	 * @param $value mixed The value to check
170
	 * @return mixed The raw value, or escaped parameterised details
171
	 */
172
	public function prepValueForDB($value) {
173
		if($value === null || $value === "" || $value === false || ($this->scalarValueOnly() && !is_scalar($value))) {
174
			return null;
175
		} else {
176
			return $value;
177
		}
178
	}
179
180
	/**
181
	 * Prepare the current field for usage in a
182
	 * database-manipulation (works on a manipulation reference).
183
	 *
184
	 * Make value safe for insertion into
185
	 * a SQL SET statement by applying addslashes() -
186
	 * can also be used to apply special SQL-commands
187
	 * to the raw value (e.g. for GIS functionality).
188
	 * {@see prepValueForDB}
189
	 *
190
	 * @param array $manipulation
191
	 */
192
	public function writeToManipulation(&$manipulation) {
193
		$manipulation['fields'][$this->name] = $this->exists()
194
			? $this->prepValueForDB($this->value) : $this->nullValue();
195
	}
196
197
	/**
198
	 * Add custom query parameters for this field,
199
	 * mostly SELECT statements for multi-value fields.
200
	 *
201
	 * By default, the ORM layer does a
202
	 * SELECT <tablename>.* which
203
	 * gets you the default representations
204
	 * of all columns.
205
	 *
206
	 * @param SS_Query $query
207
	 */
208
	public function addToQuery(&$query) {
209
210
	}
211
212
	public function setTable($tableName) {
213
		$this->tableName = $tableName;
214
	}
215
216
	/**
217
	 * @return string
218
	 */
219
	public function forTemplate() {
220
		return $this->XML();
221
	}
222
223
	public function HTMLATT() {
224
		return Convert::raw2htmlatt($this->RAW());
225
	}
226
227
	public function URLATT() {
228
		return urlencode($this->RAW());
229
	}
230
231
	public function RAWURLATT() {
232
		return rawurlencode($this->RAW());
233
	}
234
235
	public function ATT() {
236
		return Convert::raw2att($this->RAW());
237
	}
238
239
	public function RAW() {
240
		return $this->value;
241
	}
242
243
	public function JS() {
244
		return Convert::raw2js($this->RAW());
245
	}
246
247
	/**
248
	 * Return JSON encoded value
249
	 * @return string
250
	 */
251
	public function JSON() {
252
		return Convert::raw2json($this->RAW());
253
	}
254
255
	public function HTML(){
256
		return Convert::raw2xml($this->RAW());
257
	}
258
259
	public function XML(){
260
		return Convert::raw2xml($this->RAW());
261
	}
262
263
	/**
264
	 * Returns the value to be set in the database to blank this field.
265
	 * Usually it's a choice between null, 0, and ''
266
	 *
267
	 * @return mixed
268
	 */
269
	public function nullValue() {
270
		return null;
271
	}
272
273
	/**
274
	 * Saves this field to the given data object.
275
	 */
276
	public function saveInto($dataObject) {
277
		$fieldName = $this->name;
278
		if($fieldName) {
279
			$dataObject->$fieldName = $this->value;
280
		} else {
281
			user_error("DBField::saveInto() Called on a nameless '" . get_class($this) . "' object", E_USER_ERROR);
282
		}
283
	}
284
285
	/**
286
	 * Returns a FormField instance used as a default
287
	 * for form scaffolding.
288
	 *
289
	 * Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}
290
	 *
291
	 * @param string $title Optional. Localized title of the generated instance
292
	 * @return FormField
293
	 */
294
	public function scaffoldFormField($title = null) {
295
		$field = new TextField($this->name, $title);
296
297
		return $field;
298
	}
299
300
	/**
301
	 * Returns a FormField instance used as a default
302
	 * for searchform scaffolding.
303
	 *
304
	 * Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}.
305
	 *
306
	 * @param string $title Optional. Localized title of the generated instance
307
	 * @return FormField
308
	 */
309
	public function scaffoldSearchField($title = null) {
310
		return $this->scaffoldFormField($title);
311
	}
312
313
	/**
314
	 * @todo documentation
315
	 *
316
	 * @todo figure out how we pass configuration parameters to
317
	 *       search filters (note: parameter hack now in place to pass in the required full path - using $this->name
318
	 *       won't work)
319
	 *
320
	 * @return SearchFilter
321
	 */
322
	public function defaultSearchFilter($name = false) {
323
		$name = ($name) ? $name : $this->name;
324
		$filterClass = $this->stat('default_search_filter_class');
325
		return new $filterClass($name);
326
	}
327
328
	/**
329
	 * Add the field to the underlying database.
330
	 */
331
	abstract public function requireField();
332
333
	public function debug() {
334
		return <<<DBG
335
<ul>
336
	<li><b>Name:</b>{$this->name}</li>
337
	<li><b>Table:</b>{$this->tableName}</li>
338
	<li><b>Value:</b>{$this->value}</li>
339
</ul>
340
DBG;
341
	}
342
343
	public function __toString() {
344
		return $this->forTemplate();
345
	}
346
347
    /**
348
     * Whatever this DBField only accepts scalar values.
349
     *
350
     * Composite DBField to override this method and return `false`. So they can accept arrays of values.
351
     * @return boolean
352
     */
353
	public function scalarValueOnly()
354
    {
355
        return true;
356
    }
357
}
358