class FlexiformElementField in Flexiform 7
Class for Field API elements.
Hierarchy
- class \FlexiformElement implements FlexiformElementInterface
- class \FlexiformElementField implements FlexiformElementFieldAPIInterface
Expanded class hierarchy of FlexiformElementField
2 string references to 'FlexiformElementField'
- flexiform_flexiform_element_info in ./
flexiform.flexiform.inc - Implements hook_flexiform_element_info().
- hook_flexiform_element_info in ./
flexiform.api.php - Define elements for use in flexiforms.
File
- includes/
element/ field.element.inc, line 10 - Contains FlexiformElementField class.
View source
class FlexiformElementField extends FlexiformElement implements FlexiformElementFieldAPIInterface {
/**
* The field name of the field.
*/
protected $field_name;
/**
* The instance settings for the field
*/
protected $instance;
/**
* The field settings for the field.
*/
protected $field;
/**
* Overrides FlexiformElement::__construct().
*/
public function __construct($flexiform, $settings, $element_namespace = '') {
parent::__construct($flexiform, $settings, $element_namespace);
$this->field_name = $this->element_info['field_name'];
// Build the fake instance for this form (incase the widget has changed -
// we would normally have to be careful of default_value but that doesn't
// figure here, so we should be fine.
$this->instance = !empty($settings['instance']) ? $settings['instance'] : array();
$this->field = !empty($settings['field']) ? $settings['field'] : array();
// Get the initial weight.
$instance = $this
->getInstance();
$this->weight = isset($settings['weight']) ? $settings['weight'] : $instance['widget']['weight'];
}
/**
* Overrides FlexiformElement::label().
*
* @return string
* The field label.
*/
public function label() {
$instance = $this
->getInstance();
return check_plain($instance['label']);
}
/**
* Overrides FlexiformElement::setLabel().
*/
public function setLabel($label) {
$this->instance['label'] = $label;
}
/**
* Return the type.
*/
public function type() {
return 'Field';
}
/**
* Get the widget type from the instance settings.
*
* @return string
* Machine name of the field widget in use.
*/
public function getWidgetType() {
$instance = $this
->getInstance();
return $instance['widget']['type'];
}
/**
* Get the widget label from the instance settings.
*
* @return string
* Human readable name of the field widget.
*/
public function getWidgetLabel() {
$widget_types = field_info_widget_types();
return $widget_types[$this
->getWidgetType()]['label'];
}
/**
* Get the instance array.
*
* At this point we merge the instance settings for the form into the normal
* field instance settings.
*/
public function getInstance() {
if (empty($this->full_instance)) {
$field_instance = field_info_instance($this->entity_type, $this->field_name, $this->bundle);
$this->full_instance = array_replace_recursive($field_instance, $this->instance);
// Default value might be a numerically indexed array, so we'll overwrite
if (isset($this->instance['default_value'])) {
$this->full_instance['default_value'] = $this->instance['default_value'];
}
// Here we check if a default value function is used.
if (isset($this->instance['use_default_value_function'])) {
if (empty($this->instance['use_default_value_function'])) {
unset($this->full_instance['default_value_function']);
}
else {
unset($this->full_instance['default_value']);
}
}
}
return $this->full_instance;
}
/**
* {@inheritdoc}
*/
public function setWeight($weight) {
parent::setWeight($weight);
$this->instance['widget']['weight'] = $weight;
}
/**
* Check widget behavior.
*
* @param array $instance
* (optional) The instance array to check the widget behavior of. Defaults
* to the result of getInstance().
* @param string $op
* (optional) The $op to check the behavior of, either 'default value' (default) or 'multiple values'.
* @param $behavior
* (optional) The behavior.
*
* @see field_behaviors_widget()
*/
public function checkWidgetBehavior($instance = array(), $op = 'default value', $behavior = FIELD_BEHAVIOR_DEFAULT) {
if (empty($instance)) {
$instance = $this
->getInstance();
}
return field_behaviors_widget($op, $instance) == $behavior;
}
/**
* Get the Difference of two settings arrays.
*
* @see http://uk1.php.net/manual/en/function.array-diff-assoc.php#111675
*
* @todo: Build in special casing for default values.
*/
public function diffArrays($array, $original_array) {
$difference = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
if (!isset($original_array[$key]) || !is_array($original_array[$key])) {
$difference[$key] = $value;
}
else {
$new_diff = $this
->diffArrays($value, $original_array[$key]);
if (!empty($new_diff)) {
$difference[$key] = $new_diff;
}
}
}
elseif (!array_key_exists($key, $original_array) || $original_array[$key] !== $value) {
$difference[$key] = $value;
}
}
return $difference;
}
/**
* Get the field array.
*
* At this point we merge the field settings for the form into the normal
* field settings.
*/
public function getField() {
if (empty($this->full_field)) {
$field = field_info_field($this->field_name);
$this->full_field = array_replace_recursive($field, $this->field);
}
return $this->full_field;
}
/**
* Add the Field Settings section to the config form.
*
* We add this method separately as it allows us to pass our overridden field
* settings to the form, whereas field_ui_field_edit_form assumes
* field_info_field will provide the correct values.
*
* @param array $element
* The Field Settings section of the form.
* @param array &$form_state
* The form state.
* @param array $instance
* Instance settings.
* @param array $field
* The field settings.
*
* @return array
* The form element for the field settings.
*/
public function configureFieldSettingsForm($element, $form_state, $field, $instance) {
$has_data = field_has_data($field);
// Create a form structure for the field values.
$element = array(
'#type' => 'fieldset',
'#title' => t('Field Settings'),
'#description' => t('These settings will override default Field API settings for this field. Overrides will only apply to this flexiform. <strong>Handle with care: Altering these settings can cause unexpected results.</strong>'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
);
// Build the configurable field values.
$description = t('Maximum number of values users can enter for this field.');
if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
$description .= '<br/>' . t("'Unlimited' will provide an 'Add more' button so the users can add as many values as they like.");
}
$element['cardinality'] = array(
'#type' => 'select',
'#title' => t('Number of values'),
'#options' => array(
FIELD_CARDINALITY_UNLIMITED => t('Unlimited'),
) + drupal_map_assoc(range(1, 10)),
'#default_value' => $field['cardinality'],
'#description' => $description,
);
// Add additional field type settings. The field type module is
// responsible for not returning settings that cannot be changed if
// the field already has data.
$additions = module_invoke($field['module'], 'field_settings_form', $field, $instance, $has_data);
if (is_array($additions)) {
$element['settings'] = $additions;
}
return $element;
}
/**
* Overrides FlexiformElement::configureForm().
*/
public function configureForm($form, &$form_state, $flexiform) {
form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin');
$instance = $this
->getInstance();
$field = $this
->getField();
$form = field_ui_field_edit_form($form, $form_state, $instance);
// Invoke hook_form_alter() and hook_form_field_ui_field_edit_form_alter()
/*$hooks = array('form');
$hooks[] = 'form_field_ui_field_edit_form';
$fake_form_id = 'field_ui_field_edit_form';
drupal_alter($hooks, $form, $form_state, $fake_form_id);*/
// If the default value behaviour is default, expose our better default
// value form.
if ($this
->checkWidgetBehavior()) {
// Allow changes to the default values regardless of anything else thats
// going on.
$form['instance']['use_default_value_function'] = array(
'#type' => 'checkbox',
'#title' => t('Use a Default Value Function'),
'#default_value' => !empty($instance['default_value_function']),
);
$form['instance']['default_value_function'] = array(
'#type' => 'textfield',
'#title' => t('Default Value Function'),
'#description' => t('If you wish to use a custom default value function, enter the name of it here. Reccommended for advanced users only.'),
'#default_value' => isset($instance['default_value_function']) ? $instance['default_value_function'] : NULL,
'#states' => array(
'invisible' => array(
':input[name="instance[use_default_value_function]"]' => array(
'checked' => FALSE,
),
),
),
);
$form['instance']['default_value_widget'] = field_ui_default_value_widget($this
->getField(), $instance, $form, $form_state);
$form['instance']['default_value_widget']['#states'] = array(
'visible' => array(
':input[name="instance[use_default_value_function]"]' => array(
'checked' => FALSE,
),
),
);
$form['instance']['use_default_value_tokens'] = array(
'#type' => 'checkbox',
'#title' => t('Use Tokens in Default Value'),
'#default_value' => !empty($instance['use_default_value_tokens']),
'#states' => array(
'visible' => array(
':input[name="instance[use_default_value_function]"]' => array(
'checked' => FALSE,
),
),
),
);
$form['instance']['contexts'] = array(
'#title' => t('Substitutions'),
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#status' => array(
'visible' => array(
':input[name="instance[use_default_value_tokens]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['instance']['contexts']['contexts'] = $this
->getCtoolsSubstitutionsList();
}
// Rename the boxes and discourage use of field settings.
$form['instance']['#title'] = t('Form Settings');
$form['instance']['#description'] = t('These settings will override default Field API settings for this field instance. Overrides will only apply to this flexiform.');
$form['field'] = $this
->configureFieldSettingsForm($form, $form_state, $field, $instance);
// Delete the 'Save Settings' button added by FieldUI.
unset($form['actions']);
$form = parent::configureForm($form, $form_state, $flexiform);
// Unset the label field added by FlexiformElementBase.
unset($form['label']);
// Allow the field label to be longer.
$form['instance']['label']['#maxlength'] = NULL;
return $form;
}
/**
* Overrides FlexiformElement::configureFormValidate().
*/
public function configureFormValidate($form, &$form_state, $flexiform) {
if ($this
->checkWidgetBehavior() && $form_state['values']['instance']['use_default_value_function']) {
unset($form['instance']['default_value_widget']);
}
field_ui_field_edit_form_validate($form, $form_state);
}
/**
* Overrides FlexiformElement::configureFormSubmit().
*/
public function configureFormSubmit($form, &$form_state, $flexiform) {
$instance = $form_state['values']['instance'];
$field = $form_state['values']['field'];
// Update any field settings that have changed.
$element_field = $this
->getField();
$field = array_merge($element_field, $field);
$original_field = field_info_field($instance['field_name']);
$this->field = $this
->diffArrays($field, $original_field);
// Work out element instance settings. This gets a little complicated as
// we want to make sure the default value settings work.
$element_instance = $this
->getInstance();
$instance = array_merge($element_instance, $instance);
$original_instance = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
if ($this
->checkWidgetBehavior()) {
if (!$instance['use_default_value_function']) {
$element = $form['instance']['default_value_widget'];
// Extract field values.
$items = array();
field_default_extract_form_values(NULL, NULL, $element_field, $element_instance, LANGUAGE_NONE, $items, $element, $form_state);
field_default_submit(NULL, NULL, $element_field, $element_instance, LANGUAGE_NONE, $items, $element, $form_state);
$instance['default_value'] = $items ? $items : NULL;
}
else {
unset($instance['default_value']);
}
}
// Cast Required to a boolean so it doesn't get erroneously stored.
$instance['required'] = (bool) $instance['required'];
$this->instance = $this
->diffArrays($instance, $original_instance);
parent::configureFormSubmit($form, $form_state, $flexiform);
}
/**
* Return the form element for this FlexiformElement.
*/
public function form($form, &$form_state, $entity, $language = LANGUAGE_NONE) {
$items = field_get_items($this->entity_type, $entity, $this->field_name, $language);
// field_default_form expects $items to be an array or NULL but
// field_get_items returns FALSE when there are none. If $items is FALSE
// turn it into an empty array to prevent errors later on.
if (!$items) {
$items = array();
}
if (!field_info_field($this->field_name) || !field_info_instance($this->entity_type, $this->field_name, $this->bundle)) {
debug("Error in " . __CLASS__ . "::" . __METHOD__ . ": Field <em>{$this->field_name}</em> does not exist or does not have an instance on {$this->entity_type}:{$this->bundle}.", "error");
return $form;
}
$instance = $this
->getInstance();
// Deal with default value tokens.
if ($this
->checkWidgetBehavior() && !empty($instance['use_default_value_tokens'])) {
$defaults =& $instance['default_value'];
foreach ($defaults as $delta => &$item) {
foreach ($item as &$value) {
if (is_string($value)) {
$value = $this
->replaceCtoolsSubstitutions($value, $form['#flexiform_entities']);
}
}
}
}
$form_fields = field_default_form($this->entity_type, $entity, $this
->getField(), $instance, $language, $items, $form, $form_state);
foreach ($form_fields as $form_key => $form_field) {
// Make sure the parents stuff is always correct.
$form_field['#parents'] = $form['#parents'];
array_push($form_field['#parents'], $this->field_name);
if (!empty($instance['remove_none'])) {
unset($form_field[$language]['#options']['']);
unset($form_field[$language]['#options']['_none']);
}
if (isset($instance['attributes']) && is_array($instance['attributes'])) {
if (isset($form_field['#attributes'])) {
$form_field['#attributes'] = array_replace_recursive($form_field['#attributes'], $instance['attributes']);
}
else {
$form_field['#attributes'] = $instance['attributes'];
}
}
// Honour the hide title settings.
if (!empty($this->settings['display_options']['hide_label'])) {
$form_field[LANGUAGE_NONE]['#title_display'] = 'invisible';
}
$form[$this->element_namespace] = $form_field;
}
$form = parent::form($form, $form_state, $entity);
return $form;
}
/**
* Validate this element.
*
* This is effectively the same as field_attach_form_validate passed with the
* field_name options, except that we have replaced _field_invoke and
* _field_invoke_default with our own methods to make sure the correct field
* settings get used.
*
* @see field_attach_validate()
* @see field_attach_form_validate()
*/
public function formValidate($form, &$form_state, $entity, $language = LANGUAGE_NONE) {
$entity = clone $entity;
$form_elements = $this
->extractFormElements($form);
$this
->fieldInvokeDefault('extract_form_values', $entity, $form_elements, $form_state);
try {
$errors = array();
$null = NULL;
$this
->fieldInvokeDefault('validate', $entity, $errors, $null);
$this
->fieldInvoke('validate', $entity, $errors, $null);
// Let other modules validate the entity.
foreach (module_implements('field_attach_validate') as $module) {
$function = $module . '_field_attach_validate';
$function($this
->getEntityType(), $entity, $errors);
}
if ($errors) {
throw new FieldValidationException($errors);
}
} catch (FieldValidationException $e) {
// Pass field-level validation errors back to widgets for accurate error
// flagging.
foreach ($e->errors as $field_name => $field_errors) {
foreach ($field_errors as $langcode => $errors) {
$field_state = field_form_get_state($form_elements['#parents'], $field_name, $langcode, $form_state);
$field_state['errors'] = $errors;
field_form_set_state($form_elements['#parents'], $field_name, $langcode, $form_state, $field_state);
}
}
$this
->fieldInvokeDefault('form_errors', $entity, $form_elements, $form_state);
}
}
/**
* Invoke default field hooks on this element.
*
* @see _field_invoke_default()
*/
protected function fieldInvokeDefault($op, $entity, &$a = NULL, &$b = NULL, $options = array()) {
$options['default'] = TRUE;
return $this
->fieldInvoke($op, $entity, $a, $b, $options);
}
/**
* Invoke field hooks on a specific field.
*
* This method is the equivelant of _field_invoke. For a specific field in flexiform.
*
* @see _field_invoke()
*/
protected function fieldInvoke($op, $entity, &$a = NULL, &$b = NULL, $options = array()) {
$entity_type = $this
->getEntityType();
$bundle = $this->bundle;
$default_options = array(
'default' => FALSE,
'deleted' => FALSE,
'language' => NULL,
);
$options += $default_options;
$return = array();
$instance = $this
->getInstance();
$field = $this
->getField();
$field_name = $field['field_name'];
$function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
if (function_exists($function)) {
// Determine the list of languages to iterate on.
$available_languages = field_available_languages($entity_type, $field);
$languages = _field_language_suggestion($available_languages, $options['language'], $field_name);
foreach ($languages as $langcode) {
$items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
$result = $function($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b);
if (isset($result)) {
// For hooks with array results, we merge results together.
// For hooks with scalar results, we collect results in an array.
if (is_array($result)) {
$return = array_merge($return, $result);
}
else {
$return[] = $result;
}
}
// Populate $items back in the field values, but avoid replacing missing
// fields with an empty array (those are not equivalent on update).
if ($items !== array() || isset($entity->{$field_name}[$langcode])) {
$entity->{$field_name}[$langcode] = $items;
}
}
}
return $return;
}
/**
* Submit callback for this form.
*/
function formSubmit($form, &$form_state, $entity, $language = LANGUAGE_NONE) {
$form_elements = $this
->extractFormElements($form);
field_attach_submit($this
->getEntityType(), $entity, $form_elements, $form_state, array(
'field_name' => $this->field_name,
));
}
/**
* Overrides FlexiformElement::formIsEmpty().
*/
function formIsEmpty($form, &$form_state, $entity, $language = LANGUAGE_NONE) {
$items = $this
->formExtractValues($form, $form_state, $entity, $language);
$items = _field_filter_items($this
->getField(), $items);
if (empty($items)) {
return TRUE;
}
}
/**
* Overrides FlexiformElement::formExtractValues().
*/
function formExtractValues($form, &$form_state, $entity, $language = LANGUAGE_NONE) {
// Extract form values.
$form_elements = $this
->extractFormElements($form);
$items = array();
field_default_extract_form_values($this
->getEntityType(), $entity, $this
->getField(), $this
->getInstance(), $language, $items, $form_elements, $form_state);
return $items;
}
/**
* Extract the form element from $form and give it the correct key.
*/
function extractFormElements($form) {
$form_element = $form[$this
->getElementNamespace()];
return array(
'#parents' => array_merge($form['#parents'], array(
$this
->getEntityNamespace(),
)),
$this->field_name => $form_element,
);
}
/**
* Overrides FlexifromElement::toSettingsArray();
*/
public function toSettingsArray() {
$settings = parent::toSettingsArray();
$settings['type'] = 'field';
$settings['field_name'] = $this->field_name;
$settings['instance'] = $this->instance;
$settings['field'] = $this->field;
return $settings;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
FlexiformElement:: |
protected | property | The bundle this is on. | |
FlexiformElement:: |
protected | property | The namespace of this element. | |
FlexiformElement:: |
protected | property | The entity namespace of the entity this element is acting on. | |
FlexiformElement:: |
protected | property | The entity type this field is on. | |
FlexiformElement:: |
protected | property | The flexiform entity this element is one. | |
FlexiformElement:: |
protected | property | The settings for this element. | |
FlexiformElement:: |
protected | property | The weight of this element. | |
FlexiformElement:: |
public static | function | Create an element object. | |
FlexiformElement:: |
public | function | Get an array of ctools context for the flexiform. | |
FlexiformElement:: |
public | function | Build a list of possible ctools substitutions. | |
FlexiformElement:: |
public static | function | Get an element object. | |
FlexiformElement:: |
public | function | Get the element namespace for this form element. | |
FlexiformElement:: |
public | function | Get the entity namespace for this form element. | |
FlexiformElement:: |
public | function | Get the entity type for this element. | |
FlexiformElement:: |
public | function | Get the settings. | |
FlexiformElement:: |
public | function | Get the weight of this form element. | |
FlexiformElement:: |
public | function | Make namespace for the element. | 1 |
FlexiformElement:: |
public | function | Get the name for this form element. | |
FlexiformElement:: |
public | function | Build the remove form for the element. | |
FlexiformElement:: |
public | function | Submit the remove form for the element. | |
FlexiformElement:: |
public | function | Validate the remove form for the element. | |
FlexiformElement:: |
public | function | Replace ctools substitutions with their values. | |
FlexiformElementField:: |
protected | property | The field settings for the field. | |
FlexiformElementField:: |
protected | property | The field name of the field. | |
FlexiformElementField:: |
protected | property | The instance settings for the field | |
FlexiformElementField:: |
public | function | Check widget behavior. | |
FlexiformElementField:: |
public | function | Add the Field Settings section to the config form. | |
FlexiformElementField:: |
public | function |
Overrides FlexiformElement::configureForm(). Overrides FlexiformElement:: |
1 |
FlexiformElementField:: |
public | function |
Overrides FlexiformElement::configureFormSubmit(). Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function |
Overrides FlexiformElement::configureFormValidate(). Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function | Get the Difference of two settings arrays. | |
FlexiformElementField:: |
function | Extract the form element from $form and give it the correct key. | ||
FlexiformElementField:: |
protected | function | Invoke field hooks on a specific field. | |
FlexiformElementField:: |
protected | function | Invoke default field hooks on this element. | |
FlexiformElementField:: |
public | function |
Return the form element for this FlexiformElement. Overrides FlexiformElement:: |
2 |
FlexiformElementField:: |
function |
Overrides FlexiformElement::formExtractValues(). Overrides FlexiformElement:: |
||
FlexiformElementField:: |
function |
Overrides FlexiformElement::formIsEmpty(). Overrides FlexiformElement:: |
||
FlexiformElementField:: |
function |
Submit callback for this form. Overrides FlexiformElement:: |
1 | |
FlexiformElementField:: |
public | function |
Validate this element. Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function |
Get the field array. Overrides FlexiformElementFieldAPIInterface:: |
|
FlexiformElementField:: |
public | function |
Get the instance array. Overrides FlexiformElementFieldAPIInterface:: |
|
FlexiformElementField:: |
public | function | Get the widget label from the instance settings. | |
FlexiformElementField:: |
public | function | Get the widget type from the instance settings. | |
FlexiformElementField:: |
public | function |
Overrides FlexiformElement::label(). Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function |
Overrides FlexiformElement::setLabel(). Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function |
Set the weight of this form element. Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function |
Overrides FlexifromElement::toSettingsArray(); Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function |
Return the type. Overrides FlexiformElement:: |
|
FlexiformElementField:: |
public | function |
Overrides FlexiformElement::__construct(). Overrides FlexiformElement:: |