matrix.module in Matrix field 8.2
Same filename and directory in other branches
Contains matrix.module.
File
matrix.moduleView source
<?php
/**
* @file
* Contains matrix.module.
*/
use Drupal\Core\Routing\RouteMatchInterface;
include 'migrate.inc';
/**
* Implements hook_help().
*/
function matrix_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the matrix module.
case 'help.page.matrix':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Defines field type for table with textfields') . '</p>';
return $output;
default:
}
}
/**
* Implementation of hook_theme()
*/
function matrix_theme() {
$theme['matrix_preview'] = array(
'render element' => 'form',
);
$theme['matrix_table'] = array(
'render element' => 'form',
);
$theme['matrix_output'] = array(
'variables' => array(
'header' => NULL,
'rows' => NULL,
),
);
return $theme;
}
/**
* Implementation of hook_views_api()
*/
function matrix_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'matrix') . '/views',
);
}
/**
* Implements hook_field_info().
*/
function matrix_field_info() {
return array(
'matrix_text' => array(
'label' => t('Matrix (textfield)'),
'description' => t('Creates a grid of text fields.'),
'settings' => array(
'rows_count' => '',
'cols_count' => '',
'size' => '',
'spreadsheet_style' => '',
),
'default_widget' => 'matrix_grid',
'default_formatter' => 'matrix_default',
// Support hook_entity_property_info() from contrib "Entity API".
'property_type' => 'field_item_matrix',
'property_callbacks' => array(
'matrix_field_property_info_callback',
),
),
'matrix_custom' => array(
'label' => t('Matrix (custom)'),
'description' => t('Creates a grid of any field type.'),
'settings' => array(
'rows_count' => '',
'cols_count' => '',
'settings' => '',
),
'default_widget' => 'matrix_grid',
'default_formatter' => 'matrix_default',
// Support hook_entity_property_info() from contrib "Entity API".
'property_type' => 'field_item_matrix',
'property_callbacks' => array(
'matrix_field_property_info_callback',
),
),
);
}
/**
* List of all matrix field types
*/
function matrix_field_types() {
return array(
'full' => array(
'none' => t('None'),
'textfield' => t('Textfield'),
'select' => t('Select list'),
'radios' => t('Radio buttons'),
'checkboxes' => t('Check boxes'),
'calculation' => t('Calculation'),
'custom' => t('Custom'),
),
'limited' => array(
'none' => t('None'),
'calculation' => t('Calculation'),
'custom' => t('Custom'),
),
'none' => array(
'none' => t('None'),
),
);
}
/**
* Implements hook_field_settings_form().
*/
function matrix_field_settings_form($field, $instance, $has_data) {
module_load_include('inc', 'matrix', 'matrix.admin');
if ($field['type'] == 'matrix_text') {
return matrix_field_settings_form_text($field, $instance, $has_data);
}
elseif ($field['type'] == 'matrix_custom') {
return matrix_field_settings_form_custom($field, $instance, $has_data);
}
}
/**
* Implementation of hook_content_is_empty().
*/
function matrix_field_is_empty($item, $field) {
if (is_array($item) && array_key_exists('value', $item)) {
if (empty($item['value']) && (string) $item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
return TRUE;
}
/**
* Implements hook_field_widget_info().
*/
function matrix_field_widget_info() {
return array(
'matrix_text' => array(
'label' => t('Text Matrix'),
'description' => t('A grid of textfields'),
'field types' => array(
'matrix_text',
),
'settings' => array(),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_NONE,
),
),
'matrix_custom' => array(
'label' => t('Custom Matrix'),
'description' => t('A grid of form elements'),
'field types' => array(
'matrix_custom',
),
'settings' => array(),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_NONE,
),
),
);
}
/**
* Implements hook_field_widget_form().
*/
function matrix_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
$field_name = $field['field_name'];
$cols_count = $field['settings']['cols_count'];
$rows_count = $field['settings']['rows_count'];
$default_values = array();
foreach ($items as $delta => $item) {
if ($item && !empty($item['row'])) {
$default_values[$item['row']][$item['col']][] = $item['value'];
}
}
switch ($field['type']) {
case 'matrix_text':
$element['#matrix_rows'] = $rows_count;
$element['#matrix_cols'] = $cols_count;
$element['#matrix_more_rows'] = FALSE;
$element['#matrix_more_cols'] = FALSE;
$size = $field['settings']['size'];
$spreadsheet_style = $field['settings']['spreadsheet_style'];
if ($spreadsheet_style) {
for ($row = 1; $row <= $rows_count; $row++) {
$row_labels[$row] = $row;
}
for ($col = 1; $col <= $cols_count; $col++) {
$column_labels[$col] = matrix_make_letter($col);
}
}
else {
$row_labels = array();
$column_labels = array();
}
for ($row = 1; $row <= $rows_count; $row++) {
for ($col = 1; $col <= $cols_count; $col++) {
$element['grid'][$row . '-' . $col] = array(
'#type' => 'textfield',
'#default_value' => isset($default_values[$row][$col]) ? $default_values[$row][$col] : '',
'#size' => $size,
);
}
}
break;
case 'matrix_custom':
$settings = unserialize($field['settings']['settings']);
$define = $field['settings']['define'];
if ($rows_count == -1) {
if (count($default_values) > 3) {
//check to see how big the grid should be based on previously submitted data
$rows_count = count($default_values);
}
else {
$rows_count = 3;
}
if (isset($form_state['storage'][$field_name]['rows'])) {
$rows_count += $form_state['storage'][$field_name]['rows'];
}
$element['#matrix_rows'] = $rows_count;
$element['#matrix_more_rows'] = TRUE;
$row_labels = array();
}
else {
$element['#matrix_rows'] = $rows_count;
$element['#matrix_more_rows'] = FALSE;
for ($row = 1; $row <= $rows_count; $row++) {
$row_labels[$row] = isset($settings['rows'][$row]['title']) ? $settings['rows'][$row]['title'] : '';
}
}
if ($cols_count == -1) {
if (isset($default_values[1]) && count($default_values[1]) > 3) {
//check to see how big the grid should be based on previously submitted data
$cols_count = count($default_values[1]);
}
else {
$cols_count = 3;
}
if (isset($form_state['storage'][$field_name]['cols'])) {
$cols_count += $form_state['storage'][$field_name]['cols'];
}
$element['#matrix_cols'] = $cols_count;
$element['#matrix_more_cols'] = TRUE;
$column_labels = array_fill(0, $cols_count, ' ');
}
else {
$element['#matrix_cols'] = $cols_count;
$element['#matrix_more_cols'] = FALSE;
for ($col = 1; $col <= $cols_count; $col++) {
$column_labels[$col] = isset($settings['cols'][$col]['title']) ? $settings['cols'][$col]['title'] : '';
}
}
$js = '';
for ($row = 1; $row <= $rows_count; $row++) {
for ($col = 1; $col <= $cols_count; $col++) {
//determine which field type should be shown for this cell
//if define is cols then if a row is set to calculation or custom other than 'none' then it takes precidence (and visa versa)
if ($define == 'cols') {
if (isset($settings['rows'][$row]['field_type']) && in_array($settings['rows'][$row]['field_type'], array(
'calculation',
'custom',
))) {
$field_settings = isset($settings['rows'][$row]) ? $settings['rows'][$row] : array(
'field_type' => 'none',
);
$calculation_class = 'matrix-calc-col-' . $col;
}
else {
$field_settings = isset($settings['cols'][$col]) ? $settings['cols'][$col] : array(
'field_type' => 'none',
);
$calculation_class = 'matrix-calc-row-' . $row;
}
}
elseif ($define == 'rows') {
if (isset($settings['cols'][$col]['field_type']) && in_array($settings['cols'][$col]['field_type'], array(
'calculation',
'custom',
))) {
$field_settings = isset($settings['cols'][$col]) ? $settings['cols'][$col] : array(
'field_type' => 'none',
);
$calculation_class = 'matrix-calc-row-' . $row;
}
else {
$field_settings = isset($settings['rows'][$row]) ? $settings['rows'][$row] : array(
'field_type' => 'none',
);
$calculation_class = 'matrix-calc-col-' . $col;
}
}
//now render the element
$field_type = $field_settings['field_type'];
if (isset($default_values[$row][$col])) {
$default_value = $default_values[$row][$col];
}
else {
$default_value[0] = '';
}
if (isset($field_settings[$field_type]['required']) && $field_settings[$field_type]['required'] == TRUE) {
$required = TRUE;
$required_marker = _theme('form_required_marker', array());
}
else {
$required = FALSE;
$required_marker = '';
}
switch ($field_type) {
case 'none':
$element['grid'][$row . '-' . $col] = array(
'#matrix_row' => $row,
'#matrix_column' => $col,
'#field_name' => $element['#title'],
'#type' => 'markup',
'#markup' => $default_value[0],
'#attributes' => array(
'class' => array(
'matrix-col-' . $col,
'matrix-row-' . $row,
'matrix-cell-' . $row . '-' . $col,
),
),
);
break;
case 'textfield':
$element['grid'][$row . '-' . $col] = array(
'#type' => 'textfield',
'#matrix_row' => $row,
'#matrix_column' => $col,
'#field_name' => $element['#title'],
'#field_prefix' => $field_settings['textfield']['prefix'],
'#field_suffix' => $field_settings['textfield']['suffix'] . $required_marker,
'#default_value' => $default_value[0],
'#size' => $field_settings['textfield']['size'],
'#matrix_required' => $required,
'#element_validate' => array(
'matrix_required_validate',
),
'#attributes' => array(
'class' => array(
'matrix-calc-col-' . $col,
'matrix-calc-row-' . $row,
'matrix-col-' . $col,
'matrix-row-' . $row,
'matrix-cell-' . $row . '-' . $col,
),
),
);
break;
case 'select':
$element['grid'][$row . '-' . $col] = array(
'#type' => 'select',
'#matrix_row' => $row,
'#matrix_column' => $col,
'#field_name' => $element['#title'],
'#default_value' => $default_value[0],
'#matrix_required' => $required,
'#element_validate' => array(
'matrix_required_validate',
),
'#field_suffix' => $required_marker,
'#options' => matrix_allowed_values($field, $field_settings, 'select'),
'#attributes' => array(
'class' => array(
'matrix-calc-col-' . $col,
'matrix-calc-row-' . $row,
'matrix-col-' . $col,
'matrix-row-' . $row,
'matrix-cell-' . $row . '-' . $col,
),
),
);
break;
case 'radios':
$element['grid'][$row . '-' . $col] = array(
'#type' => 'radios',
'#matrix_row' => $row,
'#matrix_column' => $col,
'#field_name' => $element['#title'],
'#default_value' => $default_value[0],
'#matrix_required' => $required,
'#element_validate' => array(
'matrix_required_validate',
),
'#prefix' => $required_marker,
'#options' => matrix_allowed_values($field, $field_settings, 'radios'),
'#attributes' => array(
'class' => array(
'matrix-calc-col-' . $col,
'matrix-calc-row-' . $row,
'matrix-col-' . $col,
'matrix-row-' . $row,
'matrix-cell-' . $row . '-' . $col,
),
),
);
break;
case 'checkboxes':
$element['grid'][$row . '-' . $col] = array(
'#type' => 'checkboxes',
'#matrix_row' => $row,
'#matrix_column' => $col,
'#field_name' => $element['#title'],
'#default_value' => $default_value,
'#matrix_required' => $required,
'#element_validate' => array(
'matrix_required_validate',
),
'#prefix' => $required_marker,
'#options' => matrix_allowed_values($field, $field_settings, 'checkboxes'),
'#attributes' => array(
'class' => array(
'matrix-calc-col-' . $col,
'matrix-calc-row-' . $row,
'matrix-col-' . $col,
'matrix-row-' . $row,
'matrix-cell-' . $row . '-' . $col,
),
),
);
break;
case 'calculation':
$element['grid'][$row . '-' . $col] = array(
'#type' => 'hidden',
'#matrix_row' => $row,
'#matrix_column' => $col,
'#field_name' => $element['#title'],
'#suffix' => '<div id="matrix-result-' . $field_name . '-' . $row . '-' . $col . '"> </div>',
'#attributes' => array(
'class' => array(
'matrix-col-' . $col,
'matrix-row-' . $row,
'matrix-cell-' . $row . '-' . $col,
),
),
);
$opperation = $field_settings['calculation']['calculation'];
$prefix = $field_settings['calculation']['prefix'];
$suffix = $field_settings['calculation']['suffix'];
$rounding = $field_settings['calculation']['rounding'];
$js .= "jQuery('.{$calculation_class}').change(function(){window.matrix.{$opperation}('{$calculation_class}', '{$row}-{$col}', '{$field_name}', '{$prefix}', '{$suffix}', '{$rounding}')});\n\n window.matrix.{$opperation}('{$calculation_class}', '{$row}-{$col}', '{$field_name}', '{$prefix}', '{$suffix}', '{$rounding}');\n";
break;
case 'custom':
$callback = $field_settings['custom']['custom'];
$element['grid'][$row . '-' . $col] = array(
'#type' => 'hidden',
'#matrix_row' => $row,
'#matrix_column' => $col,
'#suffix' => '<div id="matrix-result-' . $field_name . '-' . $row . '-' . $col . '"> </div>',
'#attributes' => array(
'class' => array(
'matrix-col-' . $col,
'matrix-row-' . $row,
'matrix-cell-' . $row . '-' . $col,
),
),
);
$js .= "jQuery('.{$calculation_class}').change(function() {window.matrix.custom('{$callback}', '{$calculation_class}', '{$row}-{$col}', '{$field_name}')});\n\n window.matrix.custom('{$callback}', '{$calculation_class}', '{$row}-{$col}', '{$field_name}');\n";
break;
}
}
}
break;
}
if (!empty($js)) {
// @FIXME
// The Assets API has totally changed. CSS, JavaScript, and libraries are now
// attached directly to render arrays using the #attached property.
//
//
// @see https://www.drupal.org/node/2169605
// @see https://www.drupal.org/node/2408597
// drupal_add_js(drupal_get_path('module', 'matrix') .'/matrix.js');
// @FIXME
// The Assets API has totally changed. CSS, JavaScript, and libraries are now
// attached directly to render arrays using the #attached property.
//
//
// @see https://www.drupal.org/node/2169605
// @see https://www.drupal.org/node/2408597
// drupal_add_js('jQuery(document).ready(function () {'. $js .'});', array('type' => 'inline', 'scope' => 'footer'));
}
$element['more_rows'] = array(
'#type' => 'button',
'#value' => t('More rows'),
'#name' => 'matrix-button-' . $field_name,
'#ajax' => array(
'callback' => 'matrix_field_ajax_callback',
'wrapper' => 'matrix-field-' . $field_name,
),
'#limit_validation_errors' => array(),
);
$element['more_cols'] = array(
'#type' => 'button',
'#value' => t('More columns'),
'#name' => 'matrix-button-' . $field_name,
'#ajax' => array(
'callback' => 'matrix_field_ajax_callback',
'wrapper' => 'matrix-field-' . $field_name,
),
'#limit_validation_errors' => array(),
);
$element['#theme'] = 'matrix_table';
$element['#row_labels'] = $row_labels;
$element['#column_labels'] = $column_labels;
$element['#element_validate'] = array(
'matrix_field_widget_validate',
);
$form_state['matrix'] = $element['#field_name'];
//used to identify this element in the ajax callback.
return $element;
}
/**
* AJAX callback
* Returns the field grid after the more rows or more cols button has been pressed
*/
function matrix_field_ajax_callback($form, &$form_state) {
list($element_name, $value) = matrix_op($form_state);
if (isset($element_name)) {
return $form[$element_name];
}
}
/**
* Element validate callback; check that the entered values are valid.
*/
function matrix_allowed_values_setting_validate($element, &$form_state) {
return;
}
/**
* Submit handler for settings form
* Clears the cache which is used for this field
*/
function matrix_clear_cache_submit(&$form, &$form_state) {
$user = \Drupal::currentUser();
cache_clear_all('matrix-cache-' . $user->uid, 'cache');
//TODO run this off the form token
}
/**
* Generate the list of allowed values from a set of field settings
* This will check first if there is a function for the allowed values and if not will use the allowd_values field
*
* @param $field
* The field array
* @param $field_settings
* Array of settings for this field
* @param $element_type
* The type of element the settings are for (eg select, radios, checkboxes).
* @return
* Array of values suiteble for use in a #options form element
*/
function matrix_allowed_values($field, $field_settings, $element_type) {
if (!empty($field_settings[$element_type]['allowed_values_function']) && function_exists($field_settings[$element_type]['allowed_values_function'])) {
$values = call_user_func($field_settings[$element_type]['allowed_values_function'], $field);
}
else {
$list = explode("\n", $field_settings[$element_type]['allowed_values']);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
foreach ($list as $value) {
if (strpos($value, '|') !== FALSE) {
list($key, $value) = explode('|', $value);
$values[$key] = $value;
}
else {
$values[$value] = $value;
}
}
}
return $values;
}
/**
* Theme a set of form elements into a table
*/
function theme_matrix_table($variables) {
$form = $variables['form'];
$rows_count = $form['#matrix_rows'];
$cols_count = $form['#matrix_cols'];
$more_cols = $form['#matrix_more_cols'];
$more_rows = $form['#matrix_more_rows'];
$column_labels = $form['#column_labels'];
$row_labels = $form['#row_labels'];
$field_name = $form['#field_name'];
$table_rows = array();
for ($row = 1; $row <= $rows_count; $row++) {
for ($col = 1; $col <= $cols_count; $col++) {
$table_rows[$row - 1][$col - 1] = drupal_render($form['grid'][$row . '-' . $col]);
}
}
//lables
if (!empty($row_labels)) {
array_unshift($column_labels, '');
//The first column will contain the label
foreach ($row_labels as $id => $label) {
array_unshift($table_rows[$id - 1], $label);
}
}
//if there should be a "more rows" button, render a new row with just the button
if ($more_rows) {
$table_rows[$rows_count][1] = drupal_render($form['more_rows']);
for ($col = 2; $col <= $cols_count; $col++) {
$table_rows[$rows_count][$col] = ' ';
}
}
//if there should be a "more columns" button, render a new column with just the button
if ($more_cols) {
$column_labels[] = drupal_render($form['more_cols']);
for ($row = 1; $row <= $rows_count; $row++) {
$table_rows[$row - 1][$cols_count + 1] = ' ';
}
}
$output = '<div id="matrix-field-' . $field_name . '">';
$output .= _theme('form_element_label', array(
'element' => $form,
));
$output .= _theme('table', array(
'header' => $column_labels,
'rows' => $table_rows,
));
$output .= filter_xss_admin($form['#description']);
$output .= '</div>';
return $output;
}
/**
* Theme a set of elements into a table
*/
function theme_matrix_output($variables) {
return _theme('table', array(
'header' => $variables['header'],
'rows' => $variables['rows'],
));
}
/**
* Validate the required attribute of a cell
* standard #requied cannot be used because:
* - It should not be invoked during ajax calls
* - No message is returned to the user (error set without message or cell highlighted)
*/
function matrix_required_validate($element, &$form_state) {
$error = FALSE;
list($e, $value) = matrix_op($form_state);
if (!in_array($value, array(
t('More rows'),
t('More columns'),
))) {
if ($element['#matrix_required'] == TRUE) {
if (is_array($element['#value']) && empty($element['#value'])) {
$error = TRUE;
}
elseif ($element['#value'] == '') {
$error = TRUE;
}
if ($error) {
form_error($element, t('The cell at row %row, column %column in the %field_name is required', array(
'%row' => $element['#matrix_row'],
'%column' => $element['#matrix_column'],
'%field_name' => $element['#field_name'],
)));
}
}
}
}
/**
* Because the name attribute of the add more rows and add more columns is used
* $form_state['values']['op'] is not available. This function basically finds the op
* equivilent in $form_state
*
* @param $form_state
* The form_state array
* @return
* single array entry ofwith first element the name of the field and second element the value of the button
*/
function matrix_op(&$form_state) {
foreach ($form_state['values'] as $key => $value) {
if (is_string($value) && strpos($key, 'matrix-button-') !== FALSE) {
return array(
substr($key, 14),
$value,
);
}
}
return array(
'',
'',
);
//fallback case
}
/**
* Form element validation handler.
* Respond to ajax requests and
* Reorder the data so that it is in the correct form for the fields api to save the data
* Each record gets its own delta. For multi-valued elements each value gets its own delta.
*/
function matrix_field_widget_validate($element, &$form_state) {
list($field_name, $value) = matrix_op($form_state);
if (isset($form_state['values']['op'])) {
$rows_count = $element['#matrix_rows'];
$cols_count = $element['#matrix_cols'];
$delta = 0;
for ($row = 1; $row <= $rows_count; $row++) {
for ($col = 1; $col <= $cols_count; $col++) {
if (!isset($element['grid'][$row . '-' . $col]['#value'])) {
//if value is not set
$value = '';
}
elseif (is_array($element['grid'][$row . '-' . $col]['#value']) && empty($element['grid'][$row . '-' . $col]['#value'])) {
//if array and value not set
$value = '';
}
else {
$value = $element['grid'][$row . '-' . $col]['#value'];
//value set
}
if (is_array($value)) {
foreach ($value as $v) {
$items[$delta] = array(
'row' => $row,
'col' => $col,
'value' => $v,
);
$delta++;
}
}
else {
$items[$delta] = array(
'row' => $row,
'col' => $col,
'value' => $value,
);
$delta++;
}
}
}
$form_state
->setValueForElement($element, $items);
}
elseif ($field_name == $element['#field_name']) {
// filter to this matrix (if there is more than 1 marix per form)
if ($value == t('More columns')) {
if (isset($form_state['storage'][$field_name]['cols'])) {
$form_state['storage'][$field_name]['cols']++;
}
else {
$form_state['storage'][$field_name]['cols'] = 1;
}
}
if ($value == t('More rows')) {
if (isset($form_state['storage'][$field_name]['rows'])) {
$form_state['storage'][$field_name]['rows']++;
}
else {
$form_state['storage'][$field_name]['rows'] = 1;
}
}
}
}
/**
* Implements hook_field_formatter_info().
*/
function matrix_field_formatter_info() {
return array(
'matrix_default' => array(
'label' => t('Default'),
'field types' => array(
'matrix_text',
'matrix_custom',
),
),
);
}
/**
* Implements hook_field_formatter_view().
*/
function matrix_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $raw_items, $display) {
$element = array();
if (!$raw_items) {
//If there are no items to show (eg. no content saved for this field on this node) then hide the field
return;
}
switch ($display['type']) {
case 'matrix_default':
if (count($raw_items[0]) == 1) {
//if a single value is passed in from views
$element[0] = array(
'#markup' => field_filter_xss($raw_items[0]['value']),
);
}
//transpose the $items array into a [$row][$col] = value arangement
foreach ($raw_items as $delta => $item) {
$items[$item['row']][$item['col']][] = matrix_cell_value($item, $field);
}
//work out how many rows and columns to show, which is the number of rows with at least some data in the row.
// this count algorithm assumes the keys are in order, so make sure they are.
ksort($items);
foreach ($items as $row_id => $row) {
foreach ($row as $col_id => $value) {
if ($value != '') {
$rows_count = $row_id;
// if this row has a value, we don't need to keep looking at the rest
// of the columns.
break;
}
}
}
if ($field['settings']['cols_count'] > 0) {
$cols_count = $field['settings']['cols_count'];
}
else {
foreach ($items as $row_id => $row) {
foreach ($row as $col_id => $value) {
if (!empty($value)) {
$max_cols[$col_id] = $col_id;
}
}
}
$cols_count = max($max_cols);
}
//populate the data part of the table rows
$rows = array();
for ($row = 1; $row <= $rows_count; $row++) {
for ($col = 1; $col <= $cols_count; $col++) {
$value = array(
'',
);
if (isset($items[$row][$col])) {
$value = $items[$row][$col];
}
$rows[$row][$col] = $value;
}
}
//collapse any multi-valued results into a list
foreach ($rows as $row_id => $row) {
foreach ($row as $col_id => $values) {
if (count($values) > 1) {
$rows[$row_id][$col_id] = array(
'data' => _theme('item_list', array(
'items' => $values,
)),
'class' => 'matrix-col-' . $col_id . ' matrix-row-' . $row_id . ' matrix-cell-' . $row_id . '-' . $col_id,
);
}
else {
$rows[$row_id][$col_id] = array(
'data' => $values[0],
'class' => 'matrix-col-' . $col_id . ' matrix-row-' . $row_id . ' matrix-cell-' . $row_id . '-' . $col_id,
);
}
}
}
if ($field['type'] == 'matrix_text' && $field['settings']['spreadsheet_style'] == TRUE) {
for ($col = 1; $col <= $cols_count; $col++) {
$headers[$col] = matrix_make_letter($col);
}
array_unshift($headers, '');
//cell 0,0
for ($row = 1; $row <= $rows_count; $row++) {
$cell = array(
'data' => $row,
'class' => 'matrix-col-header',
);
array_unshift($rows[$row], $cell);
}
}
elseif ($field['type'] == 'matrix_custom') {
$headers = array();
$headers = array_fill(1, $cols_count, ' ');
//initialize the headers with spaces (in case headers have not title set)
$settings = unserialize($field['settings']['settings']);
if (isset($settings['cols'])) {
foreach ($settings['cols'] as $col_id => $col) {
$headers[$col_id] = $col['title'];
}
}
$have_row_labels = FALSE;
if (!empty($settings['rows'])) {
foreach ($settings['rows'] as $row_id => $row) {
if (!empty($row['title'])) {
$have_row_labels = TRUE;
}
$cell = array(
'data' => $row['title'],
'class' => 'matrix-col-header',
);
if (isset($rows[$row_id])) {
array_unshift($rows[$row_id], $cell);
}
}
}
if ($have_row_labels) {
//had left lables so translate the headers one to the right
array_unshift($headers, '');
//cell 0,0
}
}
else {
$headers = NULL;
}
$element[0] = array(
'#theme' => 'matrix_output',
'#header' => $headers,
'#rows' => $rows,
);
break;
}
return $element;
}
/**
* Find a value of a cell for either a string or a select list
*
* @param $item
* array representing the cell
* @param $field
* array containing the field data
* @return
* value to display
*/
function matrix_cell_value($item, $field) {
$prefix = '';
$suffix = '';
if ($field['type'] == 'matrix_text') {
//selection lists cannot apply to text fields
$value = $item['value'];
}
elseif ($field['type'] == 'matrix_custom') {
//see if the cell contains a selection list
if (isset($field['settings']['settings'])) {
$settings = unserialize($field['settings']['settings']);
}
else {
$settings = array();
}
$define = $field['settings']['define'];
//work out which settings should be used
if ($define == 'rows') {
$field_settings = $settings['rows'][$item['row']];
}
else {
$field_settings = $settings['cols'][$item['col']];
}
//determine the value to return
$field_type = $field_settings['field_type'];
if (!in_array($field_type, array(
'select',
'radios',
'checkboxes',
))) {
$value = $item['value'];
$prefix = $field_settings[$field_type]['prefix'];
$suffix = $field_settings[$field_type]['suffix'];
}
else {
$allowed_values = matrix_allowed_values($field, $field_settings, $field_type);
$value = $allowed_values[$item['value']];
}
}
return check_plain($prefix . $value . $suffix);
}
/**
* Make a letter (like with a spreadsheet A, B, C, AA, AB etc)
*
* @param $int
* The number to convert to a string
* @return string
*/
function matrix_make_letter($int) {
$string = '';
$first = chr((int) ($int / 26) + 64);
$second = chr($int % 26 + 64);
if ($first != '@') {
//@ comes before 'A'
$string .= $first;
}
$string .= $second;
return $string;
}
/**
* Menu callback for matrix custom calculations
* @return string.
*/
function matrix_custom_calculation_callback() {
$callback = $_POST['callback'];
$data = explode(",", $_POST['data']);
$functions = \Drupal::moduleHandler()
->invokeAll('matrix_functions');
//ensure the callback is allowed
if (!in_array($callback, array_keys($functions['calculation']))) {
drupal_json_output(array(
'error' => t('Calcuation callback function not available'),
));
exit;
}
//ensure the data is safe
foreach ($data as $id => $d) {
$data[$id] = check_plain($d);
}
$result = call_user_func($callback, $data);
drupal_json_output(array(
'data' => check_plain($result),
));
exit;
}
/**
* Example Implementation of hook_matrix_functions().
* Register functions that should be used with the matrix module
* These are used for the "allowed values functions" and for "custom calculation functions"
*
* @return array of allowed functions
*/
function matrix_matrix_functions() {
return array(
'allowed_values' => array(
'matrix_allowed_values_example' => t('Custom example (10\'s)'),
),
'calculation' => array(
'matrix_custom_processing_example' => t('Custom example (sum of squares)'),
),
);
}
/**
* Example function for providing a list of allowed values for a select list
*
* @param $field
* The field array
* @return
* An array of key-value pairs
*/
function matrix_allowed_values_example($field) {
return array(
10 => t('Ten'),
20 => t('Twenty'),
30 => t('Thirty'),
40 => t('Forty'),
50 => t('Fifty'),
);
}
/**
* Example function for performing a custom calculation on some data
*
* @param $data
* Array of data to process
* @return
* A string to store
*/
function matrix_custom_processing_example($data) {
return implode(',', $data);
}
/**
* Additional callback to adapt the property info of matrix fields.
*
* @see entity_metadata_field_entity_property_info()
*/
function matrix_field_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
$property =& $info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
// Define a data structure so it's possible to deal with the row, column and
// value.
$property['getter callback'] = 'entity_metadata_field_verbatim_get';
$property['setter callback'] = 'entity_metadata_field_verbatim_set';
// Auto-create the field item as soon as a property is set.
$property['auto creation'] = 'matrix_field_item_create';
$property['property info'] = matrix_field_item_property_info();
unset($property['query callback']);
}
/**
* Callback for creating a new, empty matrix field item.
*
* @see matrix_field_property_info_callback()
*/
function matrix_field_item_create() {
return array(
'row' => NULL,
'col' => NULL,
'value' => NULL,
);
}
/**
* Defines info for the properties of the matrix-field item data structure.
*/
function matrix_field_item_property_info() {
$properties['row'] = array(
'type' => 'integer',
'label' => t('The row of the item'),
'setter callback' => 'entity_property_verbatim_set',
);
$properties['col'] = array(
'type' => 'integer',
'label' => t('The column of the item.'),
'setter callback' => 'entity_property_verbatim_set',
);
$properties['value'] = array(
'type' => 'text',
'label' => t('The value of the item.'),
'setter callback' => 'entity_property_verbatim_set',
);
return $properties;
}
Functions
Name | Description |
---|---|
matrix_allowed_values | Generate the list of allowed values from a set of field settings This will check first if there is a function for the allowed values and if not will use the allowd_values field |
matrix_allowed_values_example | Example function for providing a list of allowed values for a select list |
matrix_allowed_values_setting_validate | Element validate callback; check that the entered values are valid. |
matrix_cell_value | Find a value of a cell for either a string or a select list |
matrix_clear_cache_submit | Submit handler for settings form Clears the cache which is used for this field |
matrix_custom_calculation_callback | Menu callback for matrix custom calculations |
matrix_custom_processing_example | Example function for performing a custom calculation on some data |
matrix_field_ajax_callback | AJAX callback Returns the field grid after the more rows or more cols button has been pressed |
matrix_field_formatter_info | Implements hook_field_formatter_info(). |
matrix_field_formatter_view | Implements hook_field_formatter_view(). |
matrix_field_info | Implements hook_field_info(). |
matrix_field_is_empty | Implementation of hook_content_is_empty(). |
matrix_field_item_create | Callback for creating a new, empty matrix field item. |
matrix_field_item_property_info | Defines info for the properties of the matrix-field item data structure. |
matrix_field_property_info_callback | Additional callback to adapt the property info of matrix fields. |
matrix_field_settings_form | Implements hook_field_settings_form(). |
matrix_field_types | List of all matrix field types |
matrix_field_widget_form | Implements hook_field_widget_form(). |
matrix_field_widget_info | Implements hook_field_widget_info(). |
matrix_field_widget_validate | Form element validation handler. Respond to ajax requests and Reorder the data so that it is in the correct form for the fields api to save the data Each record gets its own delta. For multi-valued elements each value gets its own delta. |
matrix_help | Implements hook_help(). |
matrix_make_letter | Make a letter (like with a spreadsheet A, B, C, AA, AB etc) |
matrix_matrix_functions | Example Implementation of hook_matrix_functions(). Register functions that should be used with the matrix module These are used for the "allowed values functions" and for "custom calculation functions" |
matrix_op | Because the name attribute of the add more rows and add more columns is used $form_state['values']['op'] is not available. This function basically finds the op equivilent in $form_state |
matrix_required_validate | Validate the required attribute of a cell standard #requied cannot be used because: |
matrix_theme | Implementation of hook_theme() |
matrix_views_api | Implementation of hook_views_api() |
theme_matrix_output | Theme a set of elements into a table |
theme_matrix_table | Theme a set of form elements into a table |