Simpletest Coverage - modules/field/modules/number/number.module

1 <?php
2 // $Id: number.module,v 1.11 2009/08/01 06:03:12 dries Exp $
3
4 /**
5 * @file
6 * Defines numeric field types.
7 */
8
9 /**
10 * Implement hook_theme().
11 */
12 function number_theme() {
13 return array(
14 'number' => array('arguments' => array('element' => NULL)),
15 'field_formatter_number_integer' => array('arguments' => array('element' => NULL), 'function' => 'theme_field_formatter_number'),
16 'field_formatter_number_decimal' => array('arguments' => array('element' => NULL), 'function' => 'theme_field_formatter_number'),
17 'field_formatter_number_unformatted' => array('arguments' => array('element' => NULL)),
18 );
19 }
20
21 /**
22 * Implement hook_field_info().
23 */
24 function number_field_info() {
25 return array(
26 'number_integer' => array(
27 'label' => t('Integer'),
28 'description' => t('This field stores a number in the database as an integer.'),
29 'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
30 'default_widget' => 'number',
31 'default_formatter' => 'number_integer',
32 ),
33 'number_decimal' => array(
34 'label' => t('Decimal'),
35 'description' => t('This field stores a number in the database in a fixed decimal format.'),
36 'settings' => array('precision' => 10, 'scale' => 2, 'decimal' => ' .'),
37 'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
38 'default_widget' => 'number',
39 'default_formatter' => 'number_integer',
40 ),
41 'number_float' => array(
42 'label' => t('Float'),
43 'description' => t('This field stores a number in the database in a floating point format.'),
44 'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
45 'default_widget' => 'number',
46 'default_formatter' => 'number_integer',
47 ),
48 );
49 }
50
51 /**
52 * Implement hook_field_schema().
53 */
54 function number_field_schema($field) {
55 switch ($field['type']) {
56 case 'number_integer' :
57 $columns = array(
58 'value' => array(
59 'type' => 'int',
60 'not null' => FALSE
61 ),
62 );
63 break;
64
65 case 'number_float' :
66 $columns = array(
67 'value' => array(
68 'type' => 'float',
69 'not null' => FALSE
70 ),
71 );
72 break;
73
74 case 'number_decimal' :
75 $columns = array(
76 'value' => array(
77 'type' => 'numeric',
78 'precision' => $field['settings']['precision'],
79 'scale' => $field['settings']['scale'],
80 'not null' => FALSE
81 ),
82 );
83 break;
84 }
85 return array(
86 'columns' => $columns,
87 );
88 }
89
90 /**
91 * Implement hook_field_validate().
92 *
93 * Possible error codes:
94 * - 'number_min': The value is smaller than the allowed minimum value.
95 * - 'number_max': The value is larger than the allowed maximum value.
96 */
97 function number_field_validate($obj_type, $node, $field, $instance, $items, &$errors) {
98 foreach ($items as $delta => $item) {
99 if ($item['value'] != '') {
100 if (is_numeric($instance['settings']['min']) && $item['value'] < $instance['settings']['min']) {
101 $errors[$field['field_name']][$delta][] = array(
102 'error' => 'number_min',
103 'message' => t('%name: the value may be no smaller than %min.', array('%name' => t($instance['label']), '%min' => $instance['settings']['min'])),
104 );
105 }
106 if (is_numeric($instance['settings']['max']) && $item['value'] > $instance['settings']['max']) {
107 $errors[$field['field_name']][$delta][] = array(
108 'error' => 'number_max',
109 'message' => t('%name: the value may be no larger than %max.', array('%name' => t($instance['label']), '%max' => $instance['settings']['max'])),
110 );
111 }
112 }
113 }
114 }
115
116 /**
117 * Implement hook_content_is_empty().
118 */
119 function number_field_is_empty($item, $field) {
120 if (empty($item['value']) && (string)$item['value'] !== '0') {
121 return TRUE;
122 }
123 return FALSE;
124 }
125
126 /**
127 * Implement hook_field_formatter_info().
128 */
129 function number_field_formatter_info() {
130 return array(
131 'number_integer' => array(
132 'label' => t('default'),
133 'field types' => array('number_integer'),
134 'settings' => array(
135 'thousand_separator' => ' ',
136 'decimal_separator' => '.',
137 'scale' => 0,
138 'prefix_suffix' => TRUE,
139 ),
140 ),
141 'number_decimal' => array(
142 'label' => t('default'),
143 'field types' => array('number_decimal', 'number_float'),
144 'settings' => array(
145 'thousand_separator' => ' ',
146 'decimal_separator' => '.',
147 'scale' => 2,
148 'prefix_suffix' => TRUE,
149 ),
150 ),
151 'number_unformatted' => array(
152 'label' => t('unformatted'),
153 'field types' => array('number_integer', 'number_decimal', 'number_float'),
154 ),
155 );
156 }
157
158 /**
159 * Theme function for 'unformatted' number field formatter.
160 */
161 function theme_field_formatter_number_unformatted($element) {
162 return $element['#item']['value'];
163 }
164
165 /**
166 * Proxy theme function for number field formatters.
167 */
168 function theme_field_formatter_number($element) {
169 $field = field_info_field($element['#field_name']);
170 $instance = field_info_instance($element['#field_name'], $element['#bundle']);
171 $value = $element['#item']['value'];
172 $settings = $element['#settings'];
173 $formatter_type = $element['#formatter'];
174
175 if (empty($value) && $value !== '0') {
176 return '';
177 }
178
179 $output = number_format($value, $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
180
181 if ($settings['prefix_suffix']) {
182 $prefixes = isset($instance['settings']['prefix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['prefix'])) : array('');
183 $suffixes = isset($instance['settings']['suffix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['suffix'])) : array('');
184 $prefix = (count($prefixes) > 1) ? format_plural($value, $prefixes[0], $prefixes[1]) : $prefixes[0];
185 $suffix = (count($suffixes) > 1) ? format_plural($value, $suffixes[0], $suffixes[1]) : $suffixes[0];
186 $output = $prefix . $output . $suffix;
187 }
188
189 return $output;
190 }
191
192 /**
193 * Implement hook_field_widget_info().
194 *
195 * Here we indicate that the Field module will handle
196 * multiple values for these widgets.
197 *
198 * Callbacks can be omitted if default handing is used.
199 * They're included here just so this module can be used
200 * as an example for custom modules that might do things
201 * differently.
202 */
203 function number_field_widget_info() {
204 return array(
205 'number' => array(
206 'label' => t('Text field'),
207 'field types' => array('number_integer', 'number_decimal', 'number_float'),
208 ),
209 );
210 }
211
212 /**
213 * Implement FAPI hook_elements().
214 *
215 * Any FAPI callbacks needed for individual widgets can be declared here,
216 * and the element will be passed to those callbacks for processing.
217 *
218 * Drupal will automatically theme the element using a theme with
219 * the same name as the hook_elements key.
220 *
221 * Includes a regex to check for valid values as an additional parameter
222 * the validator can use. The regex can be overridden if necessary.
223 */
224 function number_elements() {
225 return array(
226 'number' => array(
227 '#input' => TRUE,
228 '#columns' => array('value'), '#delta' => 0,
229 '#process' => array('number_elements_process'),
230 ),
231 );
232 }
233
234 /**
235 * Implement hook_field_widget().
236 *
237 * Attach a single form element to the form. It will be built out and
238 * validated in the callback(s) listed in hook_elements. We build it
239 * out in the callbacks rather than here in hook_widget so it can be
240 * plugged into any module that can provide it with valid
241 * $field information.
242 *
243 * Field module will set the weight, field name and delta values
244 * for each form element.
245 *
246 * If there are multiple values for this field, the Field module will
247 * call this function as many times as needed.
248 *
249 * @param $form
250 * the entire form array, $form['#node'] holds node information
251 * @param $form_state
252 * the form_state, $form_state['values'] holds the form values.
253 * @param $field
254 * The field structure.
255 * @param $instance
256 * the field instance array
257 * @param $delta
258 * the order of this item in the array of subelements (0, 1, 2, etc)
259 *
260 * @return
261 * the form item for a single element for this field
262 */
263 function number_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) {
264 $element = array(
265 '#type' => $instance['widget']['type'],
266 '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
267 );
268 return $element;
269 }
270
271 /**
272 * Implement hook_field_widget_error().
273 */
274 function number_field_widget_error($element, $error) {
275 form_error($element['value'], $error['message']);
276 }
277
278 /**
279 * Process an individual element.
280 *
281 * Build the form element. When creating a form using FAPI #process,
282 * note that $element['#value'] is already set.
283 *
284 * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
285 */
286 function number_elements_process($element, $form_state, $form) {
287 $field_name = $element['#field_name'];
288 $field = field_info_field($element['#field_name']);
289 $instance = field_info_instance($element['#field_name'], $element['#bundle']);
290 $field_key = $element['#columns'][0];
291
292 $value = isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : '';
293 if ($field['type'] == 'number_decimal') {
294 $value = str_replace('.', $field['settings']['decimal'], $value);
295 }
296
297 $element[$field_key] = array(
298 '#type' => 'textfield',
299 '#default_value' => $value,
300 // Need to allow a slightly larger size that the field length to allow
301 // for some configurations where all characters won't fit in input field.
302 '#size' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 2 : 12,
303 '#maxlength' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] : 10,
304 '#attributes' => array('class' => 'number'),
305 // The following values were set by the Field module and need
306 // to be passed down to the nested element.
307 '#title' => $element['#title'],
308 '#description' => $element['#description'],
309 '#required' => $element['#required'],
310 '#field_name' => $element['#field_name'],
311 '#bundle' => $element['#bundle'],
312 '#delta' => $element['#delta'],
313 '#columns' => $element['#columns'],
314 );
315
316 if (!empty($instance['settings']['prefix'])) {
317 $prefixes = explode('|', $instance['settings']['prefix']);
318 $element[$field_key]['#field_prefix'] = field_filter_xss(array_pop($prefixes));
319 }
320 if (!empty($instance['settings']['suffix'])) {
321 $suffixes = explode('|', $instance['settings']['suffix']);
322 $element[$field_key]['#field_suffix'] = field_filter_xss(array_pop($suffixes));
323 }
324
325 // Make sure we don't wipe out element validation added elsewhere.
326 if (empty($element['#element_validate'])) {
327 $element['#element_validate'] = array();
328 }
329 switch ($field['type']) {
330 case 'number_float':
331 $element['#element_validate'][] = 'number_float_validate';
332 break;
333 case 'number_integer':
334 $element['#element_validate'][] = 'number_integer_validate';
335 break;
336 case 'number_decimal':
337 $element['#element_validate'][] = 'number_decimal_validate';
338 break;
339 }
340
341 return $element;
342 }
343
344 /**
345 * FAPI validation of an individual float element.
346 */
347 function number_float_validate($element, &$form_state) {
348 $field = field_info_field($element['#field_name']);
349 $instance = field_info_instance($element['#field_name'], $element['#bundle']);
350 $field_key = $element['#columns'][0];
351 $value = $element['#value'][$field_key];
352
353 if (($element[$field_key]['#required'] || !empty($value))) {
354 $start = $value;
355 $value = preg_replace('@[^-0-9\.]@', '', $value);
356 if ($start != $value) {
357 $error_field = implode('][', $element['#parents']) . '][' . $field_key;
358 form_set_error($error_field, t('Only numbers and decimals are allowed in %field.', array('%field' => t($instance['label']))));
359 }
360 else {
361 form_set_value($element[$field_key], $value, $form_state);
362 }
363 }
364 }
365
366 /**
367 * FAPI validation of an individual integer element.
368 */
369 function number_integer_validate($element, &$form_state) {
370 $field = field_info_field($element['#field_name']);
371 $instance = field_info_instance($element['#field_name'], $element['#bundle']);
372 $field_key = $element['#columns'][0];
373 $value = $element['#value'][$field_key];
374
375 if (($element[$field_key]['#required'] || !empty($value))) {
376 $start = $value;
377 $value = preg_replace('@[^-0-9]@', '', $value);
378 if ($start != $value) {
379 $error_field = implode('][', $element['#parents']) . '][' . $field_key;
380 form_set_error($error_field, t('Only numbers are allowed in %field.', array('%field' => t($instance['label']))));
381 }
382 else {
383 form_set_value($element[$field_key], $value, $form_state);
384 }
385 }
386 }
387
388 /**
389 * FAPI validation of an individual decimal element.
390 */
391 function number_decimal_validate($element, &$form_state) {
392 $field = field_info_field($element['#field_name']);
393 $instance = field_info_instance($element['#field_name'], $element['#bundle']);
394 $field_key = $element['#columns'][0];
395 $value = $element['#value'][$field_key];
396
397 if (($element[$field_key]['#required'] || !empty($value))) {
398 $start = $value;
399 $value = preg_replace('@[^-0-9\\' . $field['settings']['decimal'] . ']@', '', $value);
400 if ($start != $value) {
401 $error_field = implode('][', $element['#parents']) . '][' . $field_key;
402 form_set_error($error_field, t('Only numbers and the decimal character (%decimal) are allowed in %field.', array('%decimal' => $field['settings']['decimal'], '%field' => t($instance['label']))));
403 }
404 else {
405 $value = str_replace($field['settings']['decimal'], ' .', $value);
406 $value = round($value, $field['settings']['scale']);
407 form_set_value($element[$field_key], $value, $form_state);
408 }
409 }
410 }
411
412 /**
413 * FAPI theme for an individual number element.
414 *
415 * The textfield is already rendered by the textfield
416 * theme and the HTML output lives in $element['#children'].
417 * Override this theme to make custom changes to the output.
418 *
419 * $element['#field_name'] contains the field name
420 * $element['#delta] is the position of this element in the group
421 */
422 function theme_number($element) {
423 return $element['#children'];
424 }

Legend

Missed
lines code that were not excersized during program execution.
Covered
lines code were excersized during program execution.
Comment/non executable
Comment or non-executable line of code.
Dead
lines of code that according to xdebug could not be executed. This is counted as coverage code because in almost all cases it is code that runnable.