By jerrac on
I have been working on a field module in Drupal 7 Alpha 7 to learn how the Field API works. My goal is to create a custom field to store latitude and longitude.
I've run into something that has my stymied, not even sure what to search for. Basically, when I preview my content type with my custom field in it, it shows the data just fine. But when I actually save the page, it doesn't save the data.
I've been using the field_example.module and http://www.figover.com/node/16 for reference material.
Here's my code, any help?
/**
* implementation of hook_help().
*/
function fieldTesting_help($path, $arg)
{
if ($path == 'admin/help#fieldTesting')
{
$txt = 'Useless module to learn how to use fields.';
$replace = array();
return '<p>'. t($txt, $replace) .'</p>';
}
}//end _help()
/**
* Implementation of hook_menu
*/
function fieldTesting_menu() {
$items = array();
$items['fieldTesting'] = array(
'title' => 'fieldTesting',
'description' => 'fieldTesting Page.',
'page callback' => 'fieldTesting_page',
);
return $items;
}
function filedTesting_page()
{
$output = "This is the field testing page. Nothing is here.";
return $output;
}
/**
* Implements hook_permission().
*/
function fieldTesting_permission() {
return array(
'administer fieldTesting' => array(
'title' => t('administer fieldTesting'),
'description' => t('Administer fieldTesting module'),
),
);
}
/**
* Implements hook_field_info().
*
* Provides the description of the field.
*/
function fieldTesting_field_info() {
return array(
'latlng' => array(
'label' => t('Latitude and Longitude'),
'description' => t('Store the decimal value of a latitude and longitude pair'),
'default_widget' => 'latlng_text',
'default_formatter' => 'latlng_simple_text',
),
);
}
/**
* Implements hook_field_schema().
*/
function fieldTesting_field_schema($field)
{
$columns = array(
'latitude' => array(
'type' => 'float',
'not null' => FALSE,
),
'longitude' => array(
'type' => 'float',
'not null' => FALSE,
),
);
return array('columns' => $columns);
}
/**
* Implements hook_field_validate().
*/
function fieldTesting_field_validate($obj_type, $object, $field, $instance, $langcode, &$items, &$errors)
{
$regexFloatInt = '/^[-+]?([0-9]+(\.[0-9]+)?|\.[0-9]+)$/';
foreach($items as $delta => $item)
{
//$errors[$field['field_name']][$langcode][$delta][] = array();
if(isset($item['latlng']))
{
if($item['latlng']['latitude']=='' || $item['latlng']['longitude']=='')
{
$errors[$field['field_name']][$langcode][$delta][] = array(
'error' => 'latlng_invalid',
'message' => t('Latitude and Longitude must be entered as a pair, make sure you have a value in both boxes.'),
);
}
if(!preg_match($regexFloatInt, $item['latlng']['latitude']) || !preg_match($regexFloatInt, $item['latlng']['longitude']))
{
$errors[$field['field_name']][$langcode][$delta][] = array(
'error' => 'latlng_invalid',
'message' => t('Latitude\'s and Longitudes must be float or integer values.'),
);
}
else if($item['latlng']['latitude']>90 || $item['latlng']['latitude']<(-90) || $item['latlng']['longitude']>180 || $item['latlng']['longitude']<(-180))
{
$errors[$field['field_name']][$langcode][$delta][] = array(
'error' => 'latlng_invalid',
'message' => t('Latitude\'s must be between -90 and 90. Longitude\'s must be between -180 and 180.'),
);
}
}
}
}
/**
* Implements hook_field_is_empty().
*/
function fieldTesting_field_is_empty($item, $field)
{
return empty($item['latlng']);
}
/**
* Implements hook_field_formatter_info().
*/
function fieldTesting_field_formatter_info()
{
return array(
// This formatter just displays the hex value in the color indicated.
'latlng_simple_text' => array(
'label' => t('Textbox to enter latitudes and longitudes'),
'field types' => array('latlng'),
),
);
}
/**
* Implements hook_field_formatter_view().
*/
function fieldTesting_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display)
{
var_dump($field);
$element = array();
switch ($display['type']) {
// This formatter simply outputs the field as text and with a color.
case 'latlng_simple_text':
foreach ($items as $delta => $item) {
$element[$delta]['#markup'] ='';
if($item['latlng']['latitude'])
{
$element[$delta]['#markup'] .= '<p>' . t('The latitude is @code', array('@code' => $item['latlng']['latitude'])) . '</p>';
}
if($item['latlng']['longitude'])
{
$element[$delta]['#markup'] .= '<p>' . t('The longitude is @code', array('@code' => $item['latlng']['longitude'])) . '</p>';
}
}
break;
}
return $element;
}
/**
* Implements hook_field_widget_info().
*/
function fieldTesting_field_widget_info()
{
return array(
'latlng__simple_text' => array(
'label' => t('Latitude and Longitude Textbox'),
'field types' => array('latlng'),
),
);
}
/**
* Implements hook_field_widget_form().
*/
function fieldTesting_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element)
{
drupal_set_message('fieldTesting field widget form called.');
$latValue = isset($items[$delta]['latitude']) ? $items[$delta]['latitude'] : 'error';
$lngValue = isset($items[$delta]['longitude']) ? $items[$delta]['longitude'] : 'error';
//$david = var_dump($form_state);
$element += array(
'#delta' => $delta,
);
$element['latlng'] = array();
switch ($instance['widget']['type'])
{
case 'latlng__simple_text':
$element['latlng']['latitude'] = array(
'#title' => t('Latitude'),
'#type' => 'textfield',
'#default_value' => $latValue,
'#size' => 20,
'#maxlength' => 20,
);
$element['latlng']['longitude'] = array(
'#title' => t('Longitude'),
'#type' => 'textfield',
'#default_value' => $lngValue,
'#size' => 20,
'#maxlength' => 20,
);
break;
default:
break;
}
return $element;
}
/**
* Implements hook_field_widget_error().
*/
function fieldTesting_field_widget_error($element, $error, $form, &$form_state) {
switch ($error['error']) {
case 'latlng_invalid':
form_error($element, $error['message']);
break;
}
}
Comments
I should mention I get this
I should mention I get this error when viewing the saved page.
And if I fix it by removing ['latlng'] from those lines, it breaks the preview. And the saved page still won't show the data.
The bad news is
Here we meet again :c)
The bad news is that... you should remove ['latlng'] almost everywhere...
You tend to mix the field types and the column names.
Which i can understand since your example page chose the same name for both ! (The 'math_square' field type is stored in one column called... 'math_square', which could as well be called 'value'. Same for 'math_fact')
You should abandon this tutorial and read the number.module or text.module, keeping in mind all the switches and multiple key arrays are not needed in your case. The taxonomy.module is closer to your need in terms of structure, but it's much more complex overall.
Ah, ok... Could you clarify?
Ah, ok... Could you clarify? Where am I mixing the field types and column names?
I will go look at the other modules.
Examples
You should find answers in the example files.
As a general (and exagerated) approach, when defining a single field type, its name is almost never used in the source code, while most of the programming deals with column names.
Well, I was able to figure it
Well, I was able to figure it out and get it working. Thanks!
It looks like you are trying
It looks like you are trying to create a CCK content type? That's part of Drupal I never play with (I don't use CCK), so I'm by no means knowledgeable on it, but I don't see a database query in your code anywhere.
Contact me to contract me for D7 -> D10/11 migrations.
Ah, I forgot to mention I am
Ah, I forgot to mention I am working in Drupal 7 Alpha 7.
Fields API
Hi Jay,
CCK is now part of the Core in Drupal 7.
Most functions are handled by the new Field API. Check http://drupal.org/project/cck and http://drupal.org/node/707832.
The Field API takes care of all database-related interactions.
Any contributed module just has to define hook_field_info() and hook_field_schema() hooks in order to advertise the field's structure.
Solved
For anyone who is searching for the answer to the same problem, here's what I learned.
Don't treat the field columns you created as a subarray to the field. I was thinking of ['latitude'] and ['longitude'] being under ['latlng']. When I should have thought of them as just ['latitude'] and ['longitude'].
In your widget form, say something like $element['lat'] = array(); $element['lng'] = array();
Don't do: $element['latlng'] = array(); $element['latlng']['lat'] = array(); etc...
Here's my working code for reference.