1

I'm fairly new to drupal development and still trying to wrap my brain around the API. I run an athletic based website and need to be able to store race times using a mm:ss.00 format. I haven't seen any contributed modules that can do this, so I decided to create my own. I basically used an example field as my model and have gone through creating the field. When I activated the code, I can add the field to the content type. The field shows as an option when managing the display. However, the field doesn't show up when I edit the content type. I've gone through the code and compared it to others and I just can't figure out why. Below is the code for my module. Any ideas?

    /**
     * Implementation of hook_field_info().
     */
     function racetime_field_info() {
        return array(
             'racetime' => array(
                 'label' => t('Time'),
                 'description' => t('Time in format mm:ss.00'),
                 'settings' => array(),
                 'instance_settings' => array('number_decimals'=>2),
                 'default_widget' => 'racetime_default_widget',
                 'default_formatter' => 'racetime_default_formatter'
             )
         );
     }


     /**
        * Implements hook_field_instance_settings_form()
        */
     function racetime_field_instance_settings_form($field,$instance) {
         return array(
             'number_decimals' => array(
                 '#type' => 'textfield',
                 '#size' => 4,
                 '#title' => t('Number of decimals'),
                 '#default_value' => $instance['settings']['number_decimals'],
                 '#description' => t('The number of decimal places to use'),
             )
         );
     }

     /**
        * Implements hook_field_widget_info()
        */
     function racetime_field_widget_info() {
            return array(
                 'racetime_default_widget' => array(
                        'label' => t('Time Field'),
                        'field types' => array('racetime')
                 ),
            );
     }

     /**
        * Implements hook_field_is_empty()
        */
     function racetime_field_is_empty($item,$field) {
            if($item['value'] === '') {
                    return TRUE; 
            }
            return FALSE;
     }

     /**
        * Implements hook_field_widget_form()
        */
     function racetime_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
            $value = isset($items[$delta]['value']) ? $items[$delta]['value'] : '';
            $numDecimals = $instance['settings']['number_decimals'];
            $widget = $element;
            $widget['#delta'] = $delta;

            $widget += array(
                 '#type' => 'textfield',
                 '#default_value' => $value,
                 '#size' => 8,
                 '#maxlength' => 15,
                 '#number_decimals' => $numDecimals,
                 '#value_callback' => '_racetime_widget_process_callback',
            );
            if (!isset($widget['description']) || !strlen($widget['description'])) {
                $widget['#description'] = t('Add description here');
            }
            if (!isset($widget['#process'])) {
                $widget['#process'] = array();
            }
            if (!in_array('_racetime_widget_process_callback', $widget['#process'])) {
                $widget['#process'][] = '_racetime_widget_process_callback';
            }

        $element['value'] = $widget;
        echo "<!-- \$element = " . print_r($element,true) . "-->\n";
        return $element;
     }


     /**
        * Implementation of hook_field_formatter_info
        */
     function racetime_field_formatter_info() {
            return array(
                 'racetime_default_formatter' => array(
                        'label' => t('Time'),
                        'field types' => array('racetime'),
                        'settings' => array(),
                        ),
                 );
     }

     /**
        *
        */
        function racetime_field_formatter_settings_form($field, $instance, $view_mode,$form, &$form_state) {
            $display = $instance['display'][$view_mode];
            $settings = $display['settings'];

            $element = array();

            if($display['type'] == 'racetime_default_formatter') {
                $element['number_decimals'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Number of decimals'),
                    '#size' => 4,
                    '#description' => t('The number of decimals to use'),
                    '#default_value' => $settings['number_decimals'],
                    '#required' => TRUE,
                    );
            }
            return $element;
        }
     /**
        * Implements hook_help
        */
        function racetime_help($path, $arg) {
            switch ($path) {
                case "admin/help#racetime":
                    return '<p>' . t("A field for recording a race time in the format m:ss.00") . '</p>';
                    break;
            }
        }

        /**
         * Implements hook_field_formatter_view()
         */
        function racetime_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
            $element = array();

            if($display['type'] == 'racetime_default_formatter') {
                foreach($items as $delta => $item) {
                    $element[$delta]['#theme'] = 'racetime';
                    $element[$delta]['#value'] = $item['value'];
                    $element[$delta]['#number_decimals'] = $display['settings']['number_decimals'];
                }
            }

            return $element;
        }

        /**
         * Implements hook_theme()
         */
        function racetime_theme($existing, $type, $theme, $path) {
            return array(
                'racetime' => array(
                        'variables' => array('value' => '', 'number_decimals' => 2)
                )
            );
        }

        /**
         * Theme racetime
         */
         function theme_racetime($variables) {

             $classes = array();
                $html = '<span class="' . implode(' ',$classes) . '">';
                $html .= _racetime_integer_to_formatted($variables['value'],$variables['number_decimals']);
                $html .= '</span>';
                return $html;
         }
        /**
         * Function to convert a string to integer
         */
        function _racetime_string_to_int($str, $numDecimals = 2) {
            //valid formats could be 16:47.17 (minutes:seconds.hundredths)
            //or 1:53:45.35 (hours:minutes:seconds.hundredths)
            //$numDecimals is the number of decimal places to carry after the seconds

            //split the string by colons, first.
            $parts = explode(":", $str);

            $numParts = count($parts);
            $hours = 0;
            $minuts = 0;
            $seconds = 0;
            if($numParts == 3) {
                $hours = $parts[0];
                $minutes = $parts[1];
                $seconds = $parts[2];
            }
            elseif($numParts == 2) {
                $minutes = $parts[0];
                $seconds = $parts[1];
            }
            else {
                $seconds = $parts[0];
            }
            //convert hours and minutes to seconds
            $sec_hours = $hours * 3600;
            $sec_minutes = $minutes * 60;
            //add all together to get the total number of seconds
            $seconds = $sec_hours + $sec_minutes + $seconds;

            /**
             * now convert the seconds to an integer value
             * here we multiple seconds by 10 to the power of number of decimals.
             * if the user wants one decimal, we'd be expecting a value like
             * 1:54.3, in which case we'd have a seconds value of 114.3.  10^1 is 10,
             * and we'd be left with an integer of 1143.  For the default of two,
             * we would expect a value of 1:54.34, which would give us 114.34 * 10^2 or
             * 114.34 * 100 = 11434.
             */
            $seconds_int = $seconds * (10^$numDecimals);

            return $seconds;
        }
        /**
         * function to convert an integer value to a time
         */
        function _racetime_integer_to_formatted($seconds, $numDecimals=2) {
            //first convert the integer value to seconds
            $sec = $seconds / (10^$numDecimals);
            if($sec < 60) {
                return number_format($sec,$numDecimals);
            }
            else {
                $hours_str = '';
                //get number of minutes
                $minutes = floor($sec / 60);
                $seconds_str = $sec - ($minutes * 60);
                //if seconds is less then 10, then add a leading 0
                if($seconds_str < 10) { $seconds_str = 0 . number_format($seconds_str,$numDecimals); }
                //if the number of minutes is greater than 60, then convert
                //minutes to hours and minutes
                if($minutes > 60) {
                    $hours = floor($minutes / 60);
                    $minutes_str = $minutes - ($hours * 60);
                    if($minutes_str < 10) {
                        $minutes_str = 0 . $minutes_str;
                    }
                    $hours_str = $hours . ':';
                }
                else {
                        $minutes_str = $minutes;
                }
                $time_string = $hours_str . $minutes_str . ":" . $seconds_str;

                return $time_string;
            }
        }
        /**
         * Widget helper to present seconds as readable formatte string
         */
        function _racetime_widget_process_callback($element, $form_state) {
            if(!isset($element['#value'])) {
                $element['#value'] = '';
            }
            $element['#value'] = _racetime_integer_to_formatted($element['#value'],$element['#number_decimals']);
        }

EDIT It appears to have something to do with this line

 if (!in_array('_racetime_widget_process_callback', $widget['#process'])) {
     $widget['#process'][] = '_racetime_widget_process_callback';
 }

as soon as I commented it out, the form appears, even though the data doesn't get saved correctly.

4
  • Would it be possible to leverage the Date module? Times are stored in unix timestamp which goes down to the second... but you probably need those milliseconds eh?
    – emc
    Apr 10 '13 at 3:52
  • Yup, need those hundredths of a second. Competition is generally timed to the hundredths or thousandths of a second.
    – Robbert
    Apr 10 '13 at 5:00
  • There was some discussion concerning this for the HMS field module in this issue. Might want to consider a contribution to that one, although I have no idea about status of things.
    – enzipher
    Apr 10 '13 at 6:32
  • HMS is actually what I based the above on. For now, I'll use what I have. I fixed the issue by fixing a bug in the value_callback value. I was using the process_call function by mistake.
    – Robbert
    Apr 10 '13 at 16:05
-1

try to use this in the hook_field_widget_form()

'#default_value' => isset($items[$delta]) ? $items[$delta] : '',

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.