1 <?php
2 /**
3 * Single field in the database.
4 * Every field from the database is represented as a sub-class of DBField.
5 *
6 * <h2>Multi-value DBField objects</h2>
7 * Sometimes you will want to make DBField classes that don't have a 1-1 match to database fields. To do this, there are a
8 * number of fields for you to overload.
9 * - Overload {@link writeToManipulation} to add the appropriate references to the INSERT or UPDATE command
10 * - Overload {@link addToQuery} to add the appropriate items to a SELECT query's field list
11 * - Add appropriate accessor methods
12 *
13 * @package sapphire
14 * @subpackage model
15 */
16 abstract class DBField extends ViewableData {
17
18 protected $value;
19
20 protected $tableName;
21
22 protected $name;
23
24 protected $arrayValue;
25
26 /**
27 * The escape type for this field when inserted into a template - either "xml" or "raw".
28 *
29 * @var string
30 */
31 public static $escape_type = 'raw';
32
33 /**
34 * Subclass of {@link SearchFilter} for usage in {@link defaultSearchFilter()}.
35 *
36 * @var string
37 */
38 public static $default_search_filter_class = 'PartialMatchFilter';
39
40 /**
41 * @var $default mixed Default-value in the database.
42 * Might be overridden on DataObject-level, but still useful for setting defaults on
43 * already existing records after a db-build.
44 */
45 protected $defaultVal;
46
47 function __construct($name = null) {
48 $this->name = $name;
49
50 parent::__construct();
51 }
52
53 /**
54 * Create a DBField object that's not bound to any particular field.
55 * Useful for accessing the classes behaviour for other parts of your code.
56 */
57 static function create($className, $value, $name = null, $object = null) {
58 $dbField = Object::create($className, $name, $object);
59 $dbField->setValue($value, null, false);
60 return $dbField;
61 }
62
63 /**
64 * Set the name of this field.
65 * The name should never be altered, but it if was never given a name in the first place you can set a name.
66 * If you try an alter the name a warning will be thrown.
67 */
68 function setName($name) {
69 if($this->name) {
70 user_error("DBField::setName() shouldn't be called once a DBField already has a name. It's partially immutable - it shouldn't be altered after it's given a value.", E_USER_WARNING);
71 }
72 $this->name = $name;
73 }
74
75 /**
76 * Returns the name of this field.
77 * @return string
78 */
79 function getName() {
80 return $this->name;
81 }
82
83 /**
84 * Returns the value of this field.
85 * @return mixed
86 */
87 function getValue() {
88 return $this->value;
89 }
90
91 /**
92 * Set the value on the field.
93 * Optionally takes the whole record as an argument,
94 * to pick other values.
95 *
96 * @param mixed $value
97 * @param array $record
98 */
99 function setValue($value, $record = null) {
100 $this->value = $value;
101 }
102
103 /**
104 * Determines if the field has a value which
105 * is not considered to be 'null' in
106 * a database context.
107 *
108 * @return boolean
109 */
110 function hasValue() {
111 return ($this->value);
112 }
113
114 /**
115 * @return bool
116 */
117 public function exists() {
118 return $this->hasValue();
119 }
120
121 /**
122 * Return an encoding of the given value suitable
123 * for inclusion in a SQL statement. If necessary,
124 * this should include quotes.
125 *
126 * @param $value mixed The value to check
127 * @return string The encoded value
128 */
129 function prepValueForDB($value) {
130 if($value === null || $value === "" || $value === false) {
131 return "null";
132 } else {
133 return "'" . Convert::raw2sql($value) . "'";
134 }
135 }
136
137 /**
138 * Prepare the current field for usage in a
139 * database-manipulation (works on a manipulation reference).
140 *
141 * Make value safe for insertion into
142 * a SQL SET statement by applying addslashes() -
143 * can also be used to apply special SQL-commands
144 * to the raw value (e.g. for GIS functionality).
145 * {@see prepValueForDB}
146 *
147 * @param array $manipulation
148 */
149 function writeToManipulation(&$manipulation) {
150 $manipulation['fields'][$this->name] = $this->hasValue() ? $this->prepValueForDB($this->value) : $this->nullValue();
151 }
152
153 /**
154 * Add custom query parameters for this field,
155 * mostly SELECT statements for multi-value fields.
156 *
157 * By default, the ORM layer does a
158 * SELECT <tablename>.* which
159 * gets you the default representations
160 * of all columns.
161 *
162 * @param SS_Query $query
163 */
164 function addToQuery(&$query) {
165
166 }
167
168 function setTable($tableName) {
169 $this->tableName = $tableName;
170 }
171
172 /**
173 * @return string
174 */
175 public function forTemplate() {
176 return $this->XML();
177 }
178
179 function HTMLATT() {
180 return Convert::raw2htmlatt($this->value);
181 }
182 function URLATT() {
183 return urlencode($this->value);
184 }
185 function RAWURLATT() {
186 return rawurlencode($this->value);
187 }
188 function ATT() {
189 return Convert::raw2att($this->value);
190 }
191
192 function RAW() {
193 return $this->value;
194 }
195
196 function JS() {
197 return Convert::raw2js($this->value);
198 }
199
200 function HTML(){
201 return Convert::raw2xml($this->value);
202 }
203
204 function XML(){
205 return Convert::raw2xml($this->value);
206 }
207
208 /**
209 * Converts the current value for this Enum DBField to lowercase.
210 * @return string
211 */
212 function LowerCase() {
213 return Convert::raw2xml(strtolower($this->value));
214 }
215
216 /**
217 * Converts the current value for this Enum DBField to uppercase.
218 * @return string
219 */
220 function UpperCase() {
221 return Convert::raw2xml(strtoupper($this->value));
222 }
223
224
225 /**
226 * Returns the value to be set in the database to blank this field.
227 * Usually it's a choice between null, 0, and ''
228 */
229 function nullValue() {
230 return "null";
231 }
232
233 /**
234 * Saves this field to the given data object.
235 */
236 function saveInto($dataObject) {
237 $fieldName = $this->name;
238 if($fieldName) {
239 $dataObject->$fieldName = $this->value;
240 } else {
241 user_error("DBField::saveInto() Called on a nameless '" . get_class($this) . "' object", E_USER_ERROR);
242 }
243 }
244
245 /**
246 * Returns a FormField instance used as a default
247 * for form scaffolding.
248 *
249 * Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}
250 *
251 * @param string $title Optional. Localized title of the generated instance
252 * @return FormField
253 */
254 public function scaffoldFormField($title = null) {
255 $field = new TextField($this->name, $title);
256
257 return $field;
258 }
259
260 /**
261 * Returns a FormField instance used as a default
262 * for searchform scaffolding.
263 *
264 * Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}.
265 *
266 * @param string $title Optional. Localized title of the generated instance
267 * @return FormField
268 */
269 public function scaffoldSearchField($title = null) {
270 return $this->scaffoldFormField($title);
271 }
272
273 /**
274 * @todo documentation
275 *
276 * @todo figure out how we pass configuration parameters to
277 * search filters (note: parameter hack now in place to pass in the required full path - using $this->name won't work)
278 *
279 * @return SearchFilter
280 */
281 public function defaultSearchFilter($name = false) {
282 $name = ($name) ? $name : $this->name;
283 $filterClass = $this->stat('default_search_filter_class');
284 return new $filterClass($name);
285 }
286
287 /**
288 * Add the field to the underlying database.
289 */
290 abstract function requireField();
291
292 function debug() {
293 return <<<DBG
294 <ul>
295 <li><b>Name:</b>{$this->name}</li>
296 <li><b>Table:</b>{$this->tableName}</li>
297 <li><b>Value:</b>{$this->value}</li>
298 </ul>
299 DBG;
300 }
301
302 }
303 ?>