Completed
Push — 3.7 ( 11b87a...bb5701 )
by
unknown
09:09 queued 01:14
created

DBField::scalarValueOnly()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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