Drupal development: coderen van custom (compound) fields

07 Jan 2015

Joris Snoek - Business Dev
+31 (0)20 - 261 14 99

Bron foto

In een eerdere post schreef ik over waarom 'Compound fields' in jouw Drupal installatie. Je kunt een compound field zien als een samengesteld field, dus een veld die meerdere fields bevat. Snappie :) ? 

Ter verheldering, hierbij een voorbeeld hoe je een module opbouwt waarin je een compound field definieert. Ik maak in dit voorbeeld een 'Video' field aan waarbij we volgende twee fields nodig hebben:

  • Video URL (video_url)
  • Een Drupal file id voor de preview (video_preview_fid)

Compound fields kan je maken door handmatig fields te coderen in een Drupal module. Ik ga er in dit voorbeeld van uit dat je eerder zelf modules hebt ontwikkeld, we bouwen in dit voorbeeld de module op in drie files:

  1. .info
  2. .install
  3. .module

1) De .info file

name = Custom Fields videodescription = Contains the video compound field.package = Lucius Example Packagecore = 7.x

Uiteraard kan je hierin de benodige dependencies definiëren.

2) De .install file

Daarna zul je database velden nodig hebben om de data die ingevoerd wordt in de fields op te slaan, deze velden kan je aanmaken via de .install file 

<?php/*** @file*  This file contains the schema for the video fields module.*/ /*** Implements hook_field_schema().*/function cl_fields_video_field_schema($field) {  return array(    'columns' => array(      'video_id' => array(        'description' => 'The primary identifier for a video.',        'type' => 'serial',        'unsigned' => TRUE,        'not null' => TRUE,      ),      'video_url' => array(        'type' => 'varchar',        'length' => '2048',        'not null' => FALSE,      ),      'video_preview_fid' => array(        'type' => 'int',        'size' => 'small',        'not null' => TRUE,        'default' => 0,      ),    ),    'indexes' => array(      'video_id' => array('video_id'),    ),    'foreign keys' => array(      'video_preview_fid' => array(        'table' => 'file_managed',        'columns' => array('fid' => 'video_preview_fid'),      ),    ),  );}

3) De .module file

Definieer het veld voor Drupal:

/*** Implements hook_field_info().*/function cl_fields_video_field_info() {  return array(    'cl_fields_video' => array(      'label' => t('Video'),      'description' => t("This field stores video's and their previews."),      'settings' => array('allowed_values' => array(), 'allowed_values_function' => ''),      'default_widget' => 'cl_fields_video',      'default_formatter' => 'cl_fields_video',      'property_type' => 'cl_fields_video',      'property_callbacks' => array('cl_fields_video_property_info_callback'),    ),  );}

Definieer de validatie voor de ingevoerde data:

/*** Implements hook_field_validate().*/function cl_fields_video_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {  global $user;  if ($field['type'] == 'cl_fields_video') {    foreach ($items as $delta => $item) {      // Check if we have an image, if we do make it permanent.      if (!empty($item['video_preview_fid'])) {        $file = file_load($item['video_preview_fid']);        // Change status to permanent.        $file->status = FILE_STATUS_PERMANENT;        // Save.        file_save($file);        // Record that the module is using the file.        file_usage_add($file, 'cl_fields_video', 'general', $user->uid);      }    }  }} 

Definieer hook_field_is_empty()

Hiermee bepaal je of het veld leeg mag zijn.

Sommige fields zijn optioneel zijn. Of, wat ook mogelijk is, óf het ene veld óf een ander veld moet ingevuld zijn.
Als deze functie true returned dan wordt het veld niet opgeslagen.
 
/*** Implements hook_field_is_empty().*/function cl_fields_video_field_is_empty($item, $field) {  if ($field['type'] == 'cl_fields_video') {    return empty($item['video_url']);  }}

 

Definieer de Drupal widget informatie:

/*** Implements hook_field_widget_info().*/function cl_fields_video_field_widget_info() {  return array(    'cl_fields_video' => array(      'label' => t('Video and preview field'),      'field types' => array('cl_fields_video'),    ),  );}

Definieer de velden:

/*** Implements hook_field_widget_form().*/function cl_fields_video_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {  switch ($instance['widget']['type']) {     // Compound field for video urls and their preview.    case 'cl_fields_video':       // The fields to be rendered.      $fields = array(        'video_url' => t('Video url'),        'video_preview_fid' => t('Video preview image'),      );       // Loop through each field and create the appropriate widget.      foreach ($fields as $key => $label) {        switch($key) {          case 'video_url':            $element[$key] = array(              '#type' => 'textfield',              '#title' => $label,              '#default_value' => isset($items[$delta][$key]) ? $items[$delta][$key] : '',            );            break;          case 'video_preview_fid':            $element[$key] = array(              '#type' => 'managed_file',              '#upload_location' => 'public://video_previews',              '#progress_indicator' => "bar",              '#title' => $label,              '#default_value' => isset($items[$delta][$key]) ? $items[$delta][$key] : 0,            );             // Add the validators            $supported_extensions = array('png', 'gif', 'jpg', 'jpeg');            $element[$key]['#upload_validators']['file_validate_extensions'][0] = implode(' ', $supported_extensions);            break;          default:            break;        }      }    break;  }   return $element;} 

Definieer hook_field_formatter_info()

Hiermee meld je als het ware de frontend weergave van je compound field aan. In dit geval het type cl_fields_video. Vervolgens geef je de echte vorm met hook_field_formatter_view()

Vergelijkbaar met hook_block_info() voor het aanmelden en hook_block_view voor de weergave.
 
/*** Implements hook_field_formatter_info().*/function cl_fields_video_field_formatter_info() {  return array(    'cl_fields_video' => array(      'label' => t('Video'),      'field types' => array('cl_fields_video'),    ),  );}

 

Definieer hook_field_formatter_view()

/*** Implements hook_field_formatter_view().*/function cl_fields_video_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {  $element = array();  $node = menu_get_object();   if (!empty($node)) {    switch ($display['type']) {      case 'cl_fields_video':         // Theme items.        foreach ($items as $key => $item) {          $video = array(            'video_title' => $node->title . ' ' . t('video') . ' ' . ($key + 1),            'video_url' => $item['video_url'],          );           // Add preview if available.          if (!empty($item['video_preview_fid'])) {            $video['video_preview'] = cl_helpers_get_full_path($item['video_preview_fid']);          }           $element[$key] = array('#markup' => theme('cl_metadata_video', $video));        }        break;    }  }   return $element;}

Definieer de Meta data

Wanneer je met compound fields aan de slag gaat en verder je systeem gaat coderen, zal er waarschijnlijk een moment komen waarin je gebruik gaat maken van de meta data wrapper functie om CRUD acties uit te halen met data in de velden.

Deze functie zorgt ervoor dat jouw custom compound field daarin beschikbaar is:

/*** Custom callback function for metadata.** @param $info* @param $entity_type* @param $field* @param $instance* @param $field_type*/function cl_fields_video_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];   $property['getter callback'] = 'entity_metadata_field_verbatim_get';  $property['setter callback'] = 'entity_metadata_field_verbatim_set';   unset($property['query callback']);   $property['property info']['video_url'] = array(    'type' => 'text',    'label' => t('Video url'),    'setter callback' => 'entity_property_verbatim_set',  );  $property['property info']['video_preview_fid'] = array(    'type' => 'text',    'label' => t('Video preview fid'),    'setter callback' => 'entity_property_verbatim_set',  );}

Download voorbeeld code

Wil je een voorbeeld downloaden? Dat kan hier.

Wrap up

Ok, that's it for now. Laat het me maar even weten als je feedback of vragen hebt.

-- Cheers

Comments

Nóg meer
kennis nodig?

Check ons ons blog archief >