Now all modules are in core modules folder
This commit is contained in:
parent
5ba1cdfa0b
commit
05b6a91b0c
1907 changed files with 0 additions and 0 deletions
1960
modules/cck/includes/content.admin.inc
Normal file
1960
modules/cck/includes/content.admin.inc
Normal file
File diff suppressed because it is too large
Load diff
695
modules/cck/includes/content.crud.inc
Normal file
695
modules/cck/includes/content.crud.inc
Normal file
|
@ -0,0 +1,695 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Create/Read/Update/Delete functions for CCK-defined object types.
|
||||
*
|
||||
* The content module field API will allow $field arguments to
|
||||
* be input either in the field => widget nested array that is used
|
||||
* by the content module, or in flattened $form_values arrays, by
|
||||
* converting flattened arrays to the nested format.
|
||||
*
|
||||
* A hook_content_fieldapi() is available for each field instance action,
|
||||
* and each hook receives the nested field => widget array as an argument.
|
||||
*
|
||||
* The hook_content_fieldapi() $ops include:
|
||||
*
|
||||
* - create instance
|
||||
* - read instance
|
||||
* - update instance
|
||||
* - delete instance
|
||||
*
|
||||
* Another function, content_module_delete($module) will clean up
|
||||
* after a module that has been deleted by removing all data and
|
||||
* settings information that was created by that module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create an array of default values for a field type.
|
||||
*/
|
||||
function content_field_default_values($field_type) {
|
||||
$field_types = _content_field_types();
|
||||
$module = $field_types[$field_type]['module'];
|
||||
|
||||
$field = array(
|
||||
'module' => $module,
|
||||
'type' => $field_type,
|
||||
'active' => 0,
|
||||
);
|
||||
|
||||
if (module_exists($module)) {
|
||||
$field['active'] = 1;
|
||||
}
|
||||
|
||||
$field['columns'] = (array) module_invoke($module, 'field_settings', 'database columns', $field);
|
||||
// Ensure columns always default to NULL values.
|
||||
foreach ($field['columns'] as $column_name => $column) {
|
||||
$field['columns'][$column_name]['not null'] = FALSE;
|
||||
}
|
||||
|
||||
$field['required'] = 0;
|
||||
$field['multiple'] = 0;
|
||||
$field['db_storage'] = CONTENT_DB_STORAGE_PER_CONTENT_TYPE;
|
||||
|
||||
// Make sure field settings all have an index in the array.
|
||||
$setting_names = (array) module_invoke($module, 'field_settings', 'save', $field);
|
||||
drupal_alter('field_settings', $setting_names, 'save', $field);
|
||||
foreach ($setting_names as $setting) {
|
||||
$field[$setting] = NULL;
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array of default values for a field instance.
|
||||
*/
|
||||
function content_instance_default_values($field_name, $type_name, $widget_type) {
|
||||
$widget_types = _content_widget_types();
|
||||
$module = $widget_types[$widget_type]['module'];
|
||||
|
||||
$widget = array(
|
||||
'field_name' => $field_name,
|
||||
'type_name' => $type_name,
|
||||
'weight' => 0,
|
||||
'label' => $field_name,
|
||||
'description' => '',
|
||||
'widget_type' => $widget_type,
|
||||
'widget_module' => $module,
|
||||
'display_settings' => array(),
|
||||
'widget_settings' => array(),
|
||||
);
|
||||
|
||||
if (module_exists($module)) {
|
||||
$widget['widget_active'] = 1;
|
||||
}
|
||||
|
||||
$settings_names = array_merge(array('label'), array_keys(content_build_modes()));
|
||||
$widget['display_settings'] = array();
|
||||
foreach ($settings_names as $name) {
|
||||
$widget['display_settings'][$name]['format'] = ($name == 'label') ? 'above' : 'default';
|
||||
$widget['display_settings'][$name]['exclude'] = 0;
|
||||
}
|
||||
|
||||
// Make sure widget settings all have an index in the array.
|
||||
$settings_names = (array) module_invoke($module, 'widget_settings', 'save', $widget);
|
||||
drupal_alter('widget_settings', $settings_names, 'save', $widget);
|
||||
$widget['widget_settings'] = array();
|
||||
foreach ($settings_names as $name) {
|
||||
$widget['widget_settings'][$name] = NULL;
|
||||
}
|
||||
return $widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand field info to create field => widget info.
|
||||
*/
|
||||
function content_field_instance_expand($field) {
|
||||
if (isset($field['widget'])) {
|
||||
return $field;
|
||||
}
|
||||
$field['widget'] = !empty($field['widget_settings']) ? $field['widget_settings'] : array();
|
||||
$field['widget']['label'] = !empty($field['label']) ? $field['label'] : $field['field_name'];
|
||||
$field['widget']['weight'] = !empty($field['weight']) ? $field['weight'] : 0;
|
||||
$field['widget']['description'] = !empty($field['description']) ? $field['description'] : '';
|
||||
|
||||
if (!empty($field['widget_type'])) {
|
||||
$field['widget']['type'] = $field['widget_type'];
|
||||
$widget_types = _content_widget_types();
|
||||
$field['widget']['module'] = isset($widget_types[$field['widget_type']]['module']) ? $widget_types[$field['widget_type']]['module'] : $field['widget_module'];
|
||||
}
|
||||
elseif (!empty($field['widget_module'])) {
|
||||
$field['widget']['module'] = $field['widget_module'];
|
||||
}
|
||||
|
||||
unset($field['widget_type']);
|
||||
unset($field['weight']);
|
||||
unset($field['label']);
|
||||
unset($field['description']);
|
||||
unset($field['widget_module']);
|
||||
unset($field['widget_settings']);
|
||||
|
||||
// If content.module is handling the default value,
|
||||
// initialize $widget_settings with default values,
|
||||
if (isset($field['default_value']) && isset($field['default_value_php']) &&
|
||||
content_callback('widget', 'default value', $field) == CONTENT_CALLBACK_DEFAULT) {
|
||||
$field['widget']['default_value'] = !empty($field['default_value']) ? $field['default_value'] : NULL;
|
||||
$field['widget']['default_value_php'] = !empty($field['default_value_php']) ? $field['default_value_php'] : NULL;
|
||||
unset($field['default_value']);
|
||||
unset($field['default_value_php']);
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse field info from field => widget to flattened form values.
|
||||
*/
|
||||
function content_field_instance_collapse($field) {
|
||||
if (!isset($field['widget'])) {
|
||||
return $field;
|
||||
}
|
||||
$field['widget_settings'] = !empty($field['widget']) ? $field['widget'] : array();
|
||||
$field['widget_type'] = !empty($field['widget']['type']) ? $field['widget']['type'] : '';
|
||||
$field['weight'] = !empty($field['widget']['weight']) ? $field['widget']['weight'] : 0;
|
||||
$field['label'] = !empty($field['widget']['label']) ? $field['widget']['label'] : $field['field_name'];
|
||||
$field['description'] = !empty($field['widget']['description']) ? $field['widget']['description'] : '';
|
||||
$field['type_name'] = !empty($field['type_name']) ? $field['type_name'] : '';
|
||||
|
||||
if (!empty($field['widget']['module'])) {
|
||||
$widget_module = $field['widget']['module'];
|
||||
}
|
||||
elseif (!empty($field['widget']['type'])) {
|
||||
$widget_types = _content_widget_types();
|
||||
$widget_module = $widget_types[$field['widget']['type']]['module'];
|
||||
}
|
||||
else {
|
||||
$widget_module = '';
|
||||
}
|
||||
$field['widget_module'] = $widget_module;
|
||||
unset($field['widget_settings']['type']);
|
||||
unset($field['widget_settings']['weight']);
|
||||
unset($field['widget_settings']['label']);
|
||||
unset($field['widget_settings']['description']);
|
||||
unset($field['widget_settings']['module']);
|
||||
unset($field['widget']);
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new field instance.
|
||||
*
|
||||
* @param $field
|
||||
* An array of properties to create the field with, input either in
|
||||
* the field => widget format used by the content module or as an
|
||||
* array of form values.
|
||||
*
|
||||
* Required values:
|
||||
* - field_name, the name of the field to be created
|
||||
* - type_name, the content type of the instance to be created
|
||||
*
|
||||
* If there is no prior instance to create this from, we also need:
|
||||
* - type, the type of field to create
|
||||
* - widget_type, the type of widget to use
|
||||
* @param $rebuild
|
||||
* TRUE to clear content type caches and rebuild menu (default).
|
||||
* FALSE allows the caller to process several fields at a time quickly, but then
|
||||
* the caller is reponsible to clear content type caches and rebuild menu as soon
|
||||
* as all fields have been processed. For example:
|
||||
* @code
|
||||
* // Create several fields at a time.
|
||||
* foreach ($fields as $field) {
|
||||
* content_field_instance_create($field, FALSE);
|
||||
* }
|
||||
* // Clear caches and rebuild menu.
|
||||
* content_clear_type_cache(TRUE);
|
||||
* menu_rebuild();
|
||||
* @endcode
|
||||
* @see content_clear_type_cache()
|
||||
* @see menu_rebuild()
|
||||
*/
|
||||
function content_field_instance_create($field, $rebuild = TRUE) {
|
||||
include_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc');
|
||||
|
||||
$form_values = $field;
|
||||
$field = content_field_instance_expand($field);
|
||||
|
||||
// If there are prior instances, fill out missing values from the prior values,
|
||||
// otherwise get missing values from default values.
|
||||
$prior_instances = content_field_instance_read(array('field_name' => $field['field_name']));
|
||||
if (!empty($prior_instances) && is_array($prior_instances)) {
|
||||
$prev_field = content_field_instance_expand($prior_instances[0]);
|
||||
|
||||
// Weight, label, and description may have been forced into the $field
|
||||
// by content_field_instance_expand(). If there is a previous instance to
|
||||
// get these values from and there was no value supplied originally, use
|
||||
// the previous value.
|
||||
$field['widget']['weight'] = isset($form_values['weight']) ? $form_values['weight'] : $prev_field['widget']['weight'];
|
||||
$field['widget']['label'] = isset($form_values['label']) ? $form_values['label'] : $prev_field['widget']['label'];
|
||||
$field['widget']['description'] = isset($form_values['description']) ? $form_values['description'] : $prev_field['widget']['description'];
|
||||
}
|
||||
else {
|
||||
$prev_field = array('widget' => array());
|
||||
}
|
||||
|
||||
// If we have a field type, we can build default values for this field type.
|
||||
$default_values = array('widget' => array());
|
||||
if (isset($field['type'])) {
|
||||
$default_values = content_field_default_values($field['type']);
|
||||
$default_instance_values = content_instance_default_values($field['field_name'], $field['type_name'], $field['widget']['type']);
|
||||
$default_values = content_field_instance_expand(array_merge($default_values, $default_instance_values));
|
||||
}
|
||||
|
||||
// Merge default values, previous values, and current values to create
|
||||
// a complete field array.
|
||||
$widget = array_merge($default_values['widget'], $prev_field['widget'], $field['widget']);
|
||||
$field = array_merge($default_values, $prev_field, $field);
|
||||
$field['widget'] = $widget;
|
||||
|
||||
// Make sure we know what module to invoke for field info.
|
||||
if (empty($field['module']) && !empty($field['type'])) {
|
||||
$field_types = _content_field_types();
|
||||
$field['module'] = $field_types[$field['type']]['module'];
|
||||
}
|
||||
|
||||
// The storage type may need to be updated.
|
||||
$field['db_storage'] = content_storage_type($field);
|
||||
|
||||
// Get a fresh copy of the column information whenever a field is created.
|
||||
$field['columns'] = (array) module_invoke($field['module'], 'field_settings', 'database columns', $field);
|
||||
|
||||
if (empty($prev_field['widget']) || $prior_instances < 1) {
|
||||
// If this is the first instance, create the field.
|
||||
$field['db_storage'] = $field['multiple'] > 0 ? CONTENT_DB_STORAGE_PER_FIELD : CONTENT_DB_STORAGE_PER_CONTENT_TYPE;
|
||||
_content_field_write($field, 'create');
|
||||
}
|
||||
elseif (!empty($prev_field['widget']) && $prev_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE && count($prior_instances) > 0) {
|
||||
// If the database storage has changed, update the field and previous instances.
|
||||
$field['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD;
|
||||
|
||||
foreach ($prior_instances as $instance) {
|
||||
$new_instance = $instance;
|
||||
$new_instance['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD;
|
||||
|
||||
// Invoke hook_content_fieldapi().
|
||||
module_invoke_all('content_fieldapi', 'update instance', $new_instance);
|
||||
|
||||
content_alter_schema($instance, $new_instance);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke hook_content_fieldapi().
|
||||
module_invoke_all('content_fieldapi', 'create instance', $field);
|
||||
|
||||
// Update the field and the instance with the latest values.
|
||||
_content_field_write($field, 'update');
|
||||
_content_field_instance_write($field, 'create');
|
||||
|
||||
content_alter_schema(array(), $field);
|
||||
|
||||
if ($rebuild) {
|
||||
content_clear_type_cache(TRUE);
|
||||
menu_rebuild();
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing field instance.
|
||||
*
|
||||
* @param $field
|
||||
* An array of properties to update the field with, input either in
|
||||
* the field => widget format used by the content module or as an
|
||||
* array of form values.
|
||||
* @param $rebuild
|
||||
* TRUE to clear content type caches and rebuild menu (default).
|
||||
* FALSE allows the caller to process several fields at a time quickly, but then
|
||||
* the caller is reponsible to clear content type caches and rebuild menu as soon
|
||||
* as all fields have been processed. For example:
|
||||
* @code
|
||||
* // Update several fields at a time.
|
||||
* foreach ($fields as $field) {
|
||||
* content_field_instance_update($field, FALSE);
|
||||
* }
|
||||
* // Clear caches and rebuild menu.
|
||||
* content_clear_type_cache(TRUE);
|
||||
* menu_rebuild();
|
||||
* @endcode
|
||||
* @see content_clear_type_cache()
|
||||
* @see menu_rebuild()
|
||||
*/
|
||||
function content_field_instance_update($field, $rebuild = TRUE) {
|
||||
include_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc');
|
||||
|
||||
// Ensure the field description is in the 'expanded' form.
|
||||
$field = content_field_instance_expand($field);
|
||||
|
||||
// Get the previous value from the table.
|
||||
$previous = content_field_instance_read(array('field_name' => $field['field_name'], 'type_name' => $field['type_name']));
|
||||
$prev_field = array_pop($previous);
|
||||
|
||||
// Create a complete field array by merging the previous and current values,
|
||||
// letting the current values overwrite the previous ones.
|
||||
$widget = array_merge($prev_field['widget'], $field['widget']);
|
||||
$field = array_merge($prev_field, $field);
|
||||
$field['widget'] = $widget;
|
||||
|
||||
// Make sure we know what module to invoke for field info.
|
||||
if (empty($field['module']) && !empty($field['type'])) {
|
||||
$field_types = _content_field_types();
|
||||
$field['module'] = $field_types[$field['type']]['module'];
|
||||
}
|
||||
|
||||
// The storage type may need to be updated.
|
||||
$field['db_storage'] = content_storage_type($field);
|
||||
|
||||
// Changes in field values may affect columns, or column
|
||||
// information may have changed, get a fresh copy.
|
||||
$field['columns'] = (array) module_invoke($field['module'], 'field_settings', 'database columns', $field);
|
||||
|
||||
// If the database storage has changed, update the field and previous instances.
|
||||
$prior_instances = content_field_instance_read(array('field_name' => $field['field_name']));
|
||||
|
||||
if ($prev_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE && count($prior_instances) > 1) {
|
||||
// Update the field's data storage.
|
||||
$field['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD;
|
||||
|
||||
// Update the schema for prior instances to adapt to the change in db storage.
|
||||
foreach ($prior_instances as $instance) {
|
||||
if ($instance['type_name'] != $field['type_name']) {
|
||||
$new_instance = $instance;
|
||||
$new_instance['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD;
|
||||
|
||||
// Invoke hook_content_fieldapi().
|
||||
module_invoke_all('content_fieldapi', 'update instance', $new_instance);
|
||||
|
||||
content_alter_schema($instance, $new_instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke hook_content_fieldapi().
|
||||
module_invoke_all('content_fieldapi', 'update instance', $field);
|
||||
|
||||
// Update the field and the instance with the latest values.
|
||||
_content_field_write($field, 'update');
|
||||
_content_field_instance_write($field, 'update');
|
||||
|
||||
content_alter_schema($prev_field, $field);
|
||||
|
||||
if ($rebuild) {
|
||||
content_clear_type_cache(TRUE);
|
||||
|
||||
// The label is in the menu tree, so we need a menu rebuild
|
||||
// if the label changes.
|
||||
if ($prev_field['widget']['label'] != $field['widget']['label']) {
|
||||
menu_rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a field record.
|
||||
*
|
||||
* @param $field
|
||||
* The field array to process.
|
||||
*/
|
||||
function _content_field_write($field, $op = 'update') {
|
||||
// Rearrange the data to create the global_settings array.
|
||||
$field['global_settings'] = array();
|
||||
$setting_names = (array) module_invoke($field['module'], 'field_settings', 'save', $field);
|
||||
drupal_alter('field_settings', $setting_names, 'save', $field);
|
||||
|
||||
foreach ($setting_names as $setting) {
|
||||
// Unlike _content_field_instance_write() and 'widget_settings', 'global_settings'
|
||||
// is never preexisting, so we take no particular precautions here.
|
||||
$field['global_settings'][$setting] = isset($field[$setting]) ? $field[$setting] : '';
|
||||
unset($field[$setting]);
|
||||
}
|
||||
// 'columns' is a reserved word in MySQL4, so our column is named 'db_columns'.
|
||||
$field['db_columns'] = $field['columns'];
|
||||
|
||||
switch ($op) {
|
||||
case 'create':
|
||||
drupal_write_record(content_field_tablename(), $field);
|
||||
break;
|
||||
case 'update':
|
||||
drupal_write_record(content_field_tablename(), $field, 'field_name');
|
||||
break;
|
||||
}
|
||||
unset($field['db_columns']);
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a field instance record.
|
||||
*
|
||||
* @param $field
|
||||
* The field array to process.
|
||||
*/
|
||||
function _content_field_instance_write($field, $op = 'update') {
|
||||
// Collapse the field => widget format, so that the values to be saved by
|
||||
// drupal_write_record are on top-level.
|
||||
$field = content_field_instance_collapse($field);
|
||||
|
||||
// Rearrange the data to create the widget_settings array.
|
||||
$setting_names = (array) module_invoke($field['widget_module'], 'widget_settings', 'save', $field);
|
||||
drupal_alter('widget_settings', $setting_names, 'save', $field);
|
||||
foreach ($setting_names as $setting) {
|
||||
// In some cases (when the updated $field was originally read from
|
||||
// the db, as opposed to gathered from the values of a form), the values
|
||||
// are already in the right place, we take care to not wipe them.
|
||||
if (isset($field[$setting])) {
|
||||
$field['widget_settings'][$setting] = $field[$setting];
|
||||
unset($field[$setting]);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($op) {
|
||||
case 'create':
|
||||
drupal_write_record(content_instance_tablename(), $field);
|
||||
break;
|
||||
case 'update':
|
||||
drupal_write_record(content_instance_tablename(), $field, array('field_name', 'type_name'));
|
||||
break;
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a field instance.
|
||||
*
|
||||
* @param $param
|
||||
* An array of properties to use in selecting a field instance. Valid keys:
|
||||
* - 'type_name' - The name of the content type in which the instance exists.
|
||||
* - 'field_name' - The name of the field whose instance is to be loaded.
|
||||
* if NULL, all instances will be returned.
|
||||
* @param $include_inactive
|
||||
* TRUE will return field instances that are 'inactive', because their field
|
||||
* module or widget module is currently disabled.
|
||||
* @return
|
||||
* The field arrays.
|
||||
*/
|
||||
function content_field_instance_read($param = NULL, $include_inactive = FALSE) {
|
||||
$cond = array();
|
||||
$args = array();
|
||||
if (is_array($param)) {
|
||||
// Turn the conditions into a query.
|
||||
foreach ($param as $key => $value) {
|
||||
$cond[] = 'nfi.'. db_escape_string($key) ." = '%s'";
|
||||
$args[] = $value;
|
||||
}
|
||||
}
|
||||
if (!$include_inactive) {
|
||||
$cond[] = 'nf.active = 1';
|
||||
$cond[] = 'nfi.widget_active = 1';
|
||||
}
|
||||
$where = $cond ? ' WHERE '. implode(' AND ', $cond) : '';
|
||||
|
||||
$db_result = db_query("SELECT * FROM {". content_instance_tablename() ."} nfi ".
|
||||
" JOIN {". content_field_tablename() ."} nf ON nfi.field_name = nf.field_name ".
|
||||
"$where ORDER BY nfi.weight ASC, nfi.label ASC", $args);
|
||||
|
||||
$fields = array();
|
||||
while ($instance = db_fetch_array($db_result)) {
|
||||
// Unserialize arrays.
|
||||
foreach (array('widget_settings', 'display_settings', 'global_settings', 'db_columns') as $key) {
|
||||
$instance[$key] = (!empty($instance[$key])) ? (array) unserialize($instance[$key]) : array();
|
||||
}
|
||||
// 'columns' is a reserved word in MySQL4, so our column is named 'db_columns'.
|
||||
$instance['columns'] = $instance['db_columns'];
|
||||
unset($instance['db_columns']);
|
||||
|
||||
// Unfold 'global_settings'.
|
||||
foreach ($instance['global_settings'] as $key => $value) {
|
||||
$instance[$key] = $value;
|
||||
}
|
||||
unset($instance['global_settings']);
|
||||
|
||||
// Put the field in the $field => 'widget' structure that is used
|
||||
// all around content.module.
|
||||
$field = content_field_instance_expand($instance);
|
||||
|
||||
// Invoke hook_content_fieldapi().
|
||||
module_invoke_all('content_fieldapi', 'read instance', $field);
|
||||
$fields[] = $field;
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing field instance.
|
||||
*
|
||||
* @param $field_name
|
||||
* The field name to delete.
|
||||
* @param $type_name
|
||||
* The content type where the field instance is going to be deleted.
|
||||
* @param $rebuild
|
||||
* TRUE to clear content type caches and rebuild menu (default).
|
||||
* FALSE allows the caller to process several fields at a time quickly, but then
|
||||
* the caller is reponsible to clear content type caches and rebuild menu as soon
|
||||
* as all fields have been processed. For example:
|
||||
* @code
|
||||
* // Delete several fields at a time.
|
||||
* foreach ($fields as $field) {
|
||||
* content_field_instance_delete($field['field_name'], $type_name, FALSE);
|
||||
* }
|
||||
* // Clear caches and rebuild menu.
|
||||
* content_clear_type_cache(TRUE);
|
||||
* menu_rebuild();
|
||||
* @endcode
|
||||
* @see content_clear_type_cache()
|
||||
* @see menu_rebuild()
|
||||
*/
|
||||
function content_field_instance_delete($field_name, $type_name, $rebuild = TRUE) {
|
||||
include_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc');
|
||||
|
||||
// Get the previous field value.
|
||||
$fields = content_field_instance_read(array('field_name' => $field_name, 'type_name' => $type_name));
|
||||
$field = array_pop($fields);
|
||||
|
||||
// Invoke hook_content_fieldapi().
|
||||
module_invoke_all('content_fieldapi', 'delete instance', $field);
|
||||
|
||||
db_query("DELETE FROM {". content_instance_tablename() .
|
||||
"} WHERE field_name = '%s' AND type_name = '%s'", $field['field_name'], $field['type_name']);
|
||||
|
||||
// If no instances remain, delete the field entirely.
|
||||
$instances = content_field_instance_read(array('field_name' => $field_name));
|
||||
if (sizeof($instances) < 1) {
|
||||
db_query("DELETE FROM {". content_field_tablename() ."} WHERE field_name = '%s'", $field['field_name']);
|
||||
content_alter_schema($field, array());
|
||||
}
|
||||
// If only one instance remains, we may need to change the database
|
||||
// representation for this field.
|
||||
elseif (sizeof($instances) == 1 && !($field['multiple'])) {
|
||||
// Multiple-valued fields are always stored per-field-type.
|
||||
$instance = $instances[0];
|
||||
$new_instance = $instance;
|
||||
$new_instance['db_storage'] = CONTENT_DB_STORAGE_PER_CONTENT_TYPE;
|
||||
_content_field_write($new_instance, 'update');
|
||||
|
||||
content_alter_schema($instance, $new_instance);
|
||||
}
|
||||
|
||||
// If the deleted instance was the last field for the content type,
|
||||
// we drop the per-type table. We also consider possibly inactive fields.
|
||||
if (!content_field_instance_read(array('type_name' => $field['type_name']), TRUE)) {
|
||||
$base_tablename = _content_tablename($field['type_name'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE);
|
||||
if (db_table_exists($base_tablename)) {
|
||||
db_drop_table($ret, $base_tablename);
|
||||
}
|
||||
}
|
||||
|
||||
if ($rebuild) {
|
||||
content_clear_type_cache(TRUE);
|
||||
menu_rebuild();
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all data related to a module.
|
||||
*
|
||||
* @param string $module
|
||||
*/
|
||||
function content_module_delete($module) {
|
||||
// Delete the field data.
|
||||
// If content module has been uninstalled first, all tables
|
||||
// have already been dropped, and running that code will raise errors.
|
||||
if (db_table_exists(content_instance_tablename())) {
|
||||
$results = db_query("SELECT field_name, type_name FROM {". content_instance_tablename() ."} WHERE widget_module = '%s'", $module);
|
||||
while ($field = db_fetch_array($results)) {
|
||||
content_field_instance_delete($field['field_name'], $field['type_name'], FALSE);
|
||||
}
|
||||
// Force the caches and static arrays to update to the new info.
|
||||
content_clear_type_cache(TRUE);
|
||||
menu_rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make changes needed when a content type is created.
|
||||
*
|
||||
* @param $info
|
||||
* value supplied by hook_node_type()
|
||||
*
|
||||
* node_get_types() is still missing the new type at this point due to
|
||||
* a static caching bug. We ask it to rebuild its cache so that
|
||||
* content_clear_type_cache() can do its job properly.
|
||||
*/
|
||||
function content_type_create($info) {
|
||||
node_get_types(NULL, NULL, TRUE);
|
||||
content_clear_type_cache(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make changes needed when an existing content type is updated.
|
||||
*
|
||||
* @param $info
|
||||
* value supplied by hook_node_type()
|
||||
*/
|
||||
function content_type_update($info) {
|
||||
if (!empty($info->old_type) && $info->old_type != $info->type) {
|
||||
// Rename the content type in all fields that use changed content type.
|
||||
db_query("UPDATE {". content_instance_tablename() ."} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type));
|
||||
|
||||
// Rename the content fields table to match new content type name.
|
||||
$old_type = content_types($info->old_type);
|
||||
$old_name = _content_tablename($old_type['type'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE);
|
||||
$new_name = _content_tablename($info->type, CONTENT_DB_STORAGE_PER_CONTENT_TYPE);
|
||||
if (db_table_exists($old_name)) {
|
||||
$ret = array();
|
||||
db_rename_table($ret, $old_name, $new_name);
|
||||
watchdog('content', 'Content fields table %old_name has been renamed to %new_name and field instances have been updated.', array(
|
||||
'%old_name' => $old_name, '%new_name' => $new_name));
|
||||
}
|
||||
|
||||
// Rename the variable storing weights for non-CCK fields.
|
||||
if ($extra = variable_get('content_extra_weights_'. $info->old_type, array())) {
|
||||
variable_set('content_extra_weights_'. $info->type, $extra);
|
||||
variable_del('content_extra_weights_'. $info->old_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset all content type info.
|
||||
// Menu needs to be rebuilt as well, but node types need to be rebuilt first.
|
||||
// node_type_form_submit() takes care of this.
|
||||
content_clear_type_cache(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make changes needed when a content type is deleted.
|
||||
*
|
||||
* @param $info
|
||||
* value supplied by hook_node_type()
|
||||
*
|
||||
* TODO should we skip doing this entirely since core leaves the
|
||||
* nodes in the database as orphans and wait until the nodes are
|
||||
* deleted to respond?
|
||||
*
|
||||
*/
|
||||
function content_type_delete($info) {
|
||||
// Don't delete data for content-types defined by disabled modules.
|
||||
if (!empty($info->disabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO : What about inactive fields ?
|
||||
// Currently, content_field_instance_delete doesn't work on those...
|
||||
$fields = content_field_instance_read(array('type_name' => $info->type));
|
||||
foreach ($fields as $field) {
|
||||
content_field_instance_delete($field['field_name'], $info->type, FALSE);
|
||||
}
|
||||
$table = _content_tablename($info->type, CONTENT_DB_STORAGE_PER_CONTENT_TYPE);
|
||||
if (db_table_exists($table)) {
|
||||
$ret = array();
|
||||
db_drop_table($ret, $table);
|
||||
watchdog('content', 'The content fields table %name has been deleted.', array('%name' => $table));
|
||||
}
|
||||
// Menu needs to be rebuilt as well, but node types need to be rebuilt first.
|
||||
// node_type_form_submit() takes care of this.
|
||||
content_clear_type_cache(TRUE);
|
||||
}
|
217
modules/cck/includes/content.devel.inc
Normal file
217
modules/cck/includes/content.devel.inc
Normal file
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Functions needed for Devel module integration.
|
||||
*
|
||||
* TODO
|
||||
* This is not really working correctly yet. It is getting called once
|
||||
* for every field and then generating every field each time. But if
|
||||
* you only process one field at a time the earlier ones lose their values.
|
||||
* The current method works to create values, but is overly processor-
|
||||
* intensive and needs to be reworked in a way that each field is
|
||||
* only processed once and all values are retained.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enrich the $node that is about to be saved with arbitrary
|
||||
* information in each of its CCK fields.
|
||||
**/
|
||||
function content_generate_fields(&$node, $field) {
|
||||
$type_name = $node->type;
|
||||
$type = content_types($type_name);
|
||||
$field_types = _content_field_types();
|
||||
|
||||
if (!empty($type['fields'])) {
|
||||
foreach ($type['fields'] as $field) {
|
||||
$node_field = array();
|
||||
// If module handles own multiples, then only call its hook once.
|
||||
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_MODULE) {
|
||||
$max = 0;
|
||||
}
|
||||
else {
|
||||
switch ($field['multiple']) {
|
||||
case 0:
|
||||
$max = 0;
|
||||
break;
|
||||
case 1:
|
||||
$max = rand(0, 3); //just an arbitrary number for 'unlimited'
|
||||
break;
|
||||
default:
|
||||
$max = $field['multiple'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i <= $max; $i++) {
|
||||
$module = $field_types[$field['type']]['module'];
|
||||
$function = $module .'_content_generate';
|
||||
if (function_exists($function)) {
|
||||
$result = $function($node, $field); // $items, $teaser, $page
|
||||
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_MODULE) {
|
||||
// Fields that handle their own multiples will add their own deltas.
|
||||
$node_field = $result;
|
||||
}
|
||||
else {
|
||||
// When multiples are handled by the content module, add a delta for each result.
|
||||
$node_field[$i] = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
$node->{$field['field_name']} = $node_field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple function to return multiple values for fields that use
|
||||
* custom multiple value widgets but don't need any other special multiple
|
||||
* values handling. This will call the field generation function
|
||||
* a random number of times and compile the results into a node array.
|
||||
*/
|
||||
function content_devel_multiple($function, $node, $field) {
|
||||
$node_field = array();
|
||||
if (function_exists($function)) {
|
||||
switch ($field['multiple']) {
|
||||
case 0:
|
||||
$max = 0;
|
||||
break;
|
||||
case 1:
|
||||
$max = rand(0, 3); //just an arbitrary number for 'unlimited'
|
||||
break;
|
||||
default:
|
||||
$max = $field['multiple'];
|
||||
break;
|
||||
}
|
||||
for ($i = 0; $i <= $max; $i++) {
|
||||
$node_field[$i] = $function($node, $field);
|
||||
}
|
||||
}
|
||||
return $node_field;
|
||||
}
|
||||
|
||||
if (module_exists('text')) {
|
||||
function text_content_generate($node, $field) {
|
||||
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_MODULE) {
|
||||
return content_devel_multiple('_text_content_generate', $node, $field);
|
||||
}
|
||||
else {
|
||||
return _text_content_generate($node, $field);
|
||||
}
|
||||
}
|
||||
|
||||
function _text_content_generate($node, $field) {
|
||||
$node_field = array();
|
||||
if ($field['widget']['type'] == 'text_textarea') {
|
||||
$format = $field['text_processing'] ? rand(0, 3) : 0;
|
||||
$node_field['value'] = devel_create_content($format);
|
||||
$node_field['format'] = $format;
|
||||
}
|
||||
else {
|
||||
$allowed_values = content_allowed_values($field);
|
||||
if (!empty($allowed_values)) {
|
||||
// Just pick one of the specified allowed values.
|
||||
$node_field['value'] = array_rand($allowed_values);
|
||||
}
|
||||
else {
|
||||
// Generate a value that respects max_length.
|
||||
if (empty($field['max_length'])) {
|
||||
$field['max_length'] = 12;
|
||||
}
|
||||
$node_field['value'] = user_password($field['max_length']);
|
||||
}
|
||||
}
|
||||
return $node_field;
|
||||
}
|
||||
}
|
||||
|
||||
if (module_exists('number')) {
|
||||
function number_content_generate($node, $field) {
|
||||
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_MODULE) {
|
||||
return content_devel_multiple('_number_content_generate', $node, $field);
|
||||
}
|
||||
else {
|
||||
return _number_content_generate($node, $field);
|
||||
}
|
||||
}
|
||||
|
||||
function _number_content_generate($node, $field) {
|
||||
$node_field = array();
|
||||
$allowed_values = content_allowed_values($field);
|
||||
if (!empty($allowed_values)) {
|
||||
// Just pick one of the specified allowed values.
|
||||
$node_field['value'] = array_rand($allowed_values);
|
||||
}
|
||||
else {
|
||||
$min = is_numeric($field['min']) ? $field['min'] : 0;
|
||||
switch ($field['type']) {
|
||||
case 'number_integer':
|
||||
$max = is_numeric($field['max']) ? $field['max'] : 10000;
|
||||
$decimal = 0;
|
||||
$scale = 0;
|
||||
break;
|
||||
|
||||
case 'number_decimal':
|
||||
$precision = is_numeric($field['precision']) ? $field['precision'] : 10;
|
||||
$scale = is_numeric($field['scale']) ? $field['scale'] : 2;
|
||||
$max = is_numeric($field['max']) ? $field['max'] : pow(10, ($precision - $scale));
|
||||
$decimal = rand(0, (10 * $scale)) / 100;
|
||||
break;
|
||||
|
||||
case 'number_float':
|
||||
$precision = rand(10, 32);
|
||||
$scale = rand(0, 2);
|
||||
$decimal = rand(0, (10 * $scale)) / 100;
|
||||
$max = is_numeric($field['max']) ? $field['max'] : pow(10, ($precision - $scale));
|
||||
break;
|
||||
}
|
||||
$node_field['value'] = round((rand($min, $max) + $decimal), $scale);
|
||||
}
|
||||
return $node_field;
|
||||
}
|
||||
}
|
||||
|
||||
if (module_exists('nodereference')) {
|
||||
function nodereference_content_generate($node, $field) {
|
||||
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_MODULE) {
|
||||
return content_devel_multiple('_nodereference_content_generate', $node, $field);
|
||||
}
|
||||
else {
|
||||
return _nodereference_content_generate($node, $field);
|
||||
}
|
||||
}
|
||||
|
||||
function _nodereference_content_generate($node, $field) {
|
||||
$node_field = array();
|
||||
$allowed_values = nodereference_allowed_values($field);
|
||||
unset($allowed_values[0]);
|
||||
if (!empty($allowed_values)) {
|
||||
// Just pick one of the specified allowed values.
|
||||
$node_field['nid'] = array_rand($allowed_values);
|
||||
}
|
||||
return $node_field;
|
||||
}
|
||||
}
|
||||
|
||||
if (module_exists('userreference')) {
|
||||
function userreference_content_generate($node, $field) {
|
||||
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_MODULE) {
|
||||
return content_devel_multiple('_userreference_content_generate', $node, $field);
|
||||
}
|
||||
else {
|
||||
return _userreference_content_generate($node, $field);
|
||||
}
|
||||
}
|
||||
|
||||
function _userreference_content_generate($node, $field) {
|
||||
$node_field = array();
|
||||
$allowed_values = userreference_allowed_values($field);
|
||||
if (isset($allowed_values['none'])) {
|
||||
unset($allowed_values['none']);
|
||||
}
|
||||
if (!empty($allowed_values)) {
|
||||
// Just pick one of the specified allowed values.
|
||||
$node_field['uid'] = array_rand($allowed_values);
|
||||
}
|
||||
return $node_field;
|
||||
}
|
||||
}
|
127
modules/cck/includes/content.diff.inc
Normal file
127
modules/cck/includes/content.diff.inc
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file hook_diff() implementations for CCK (especially fields).
|
||||
*
|
||||
* These should use a field-hook so the data for the diff is
|
||||
* field-type specific.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_diff()
|
||||
*/
|
||||
function content_diff($old_node, $new_node) {
|
||||
$result = array();
|
||||
// Prevent against invalid 'nodes' built by broken 3rd party code.
|
||||
if (isset($new_node->type)) {
|
||||
$type = content_types($new_node->type);
|
||||
$field_types = _content_field_types();
|
||||
foreach ($type['fields'] as $field) {
|
||||
// Ignore fields the current user is not allowed to view.
|
||||
if (!content_access('view', $field, NULL, $new_node)) {
|
||||
continue;
|
||||
}
|
||||
$function = $field_types[$field['type']]['module'] . '_content_diff_values';
|
||||
$function = function_exists($function) ? $function : 'content_content_diff_values';
|
||||
$old_values = array();
|
||||
$new_values = array();
|
||||
if (isset($old_node->$field['field_name'])) {
|
||||
$old_values = $function($old_node, $field, $old_node->$field['field_name']);
|
||||
}
|
||||
if (isset($new_node->$field['field_name'])) {
|
||||
$new_values = $function($new_node, $field, $new_node->$field['field_name']);
|
||||
}
|
||||
if ($old_values || $new_values) {
|
||||
$result[$field['field_name']] = array(
|
||||
'#name' => $field['widget']['label'],
|
||||
'#old' => $old_values,
|
||||
'#new' => $new_values,
|
||||
'#weight' => $field['widget']['weight'],
|
||||
'#format' => array(
|
||||
'show_header' => FALSE,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default 'implementation' of hook_content_diff_values.
|
||||
*
|
||||
* Note that diff.module takes care of running check_plain on the output.
|
||||
*/
|
||||
function content_content_diff_values($node, $field, $items) {
|
||||
$return = array();
|
||||
foreach ($items as $item) {
|
||||
foreach (explode("\n", $item['value']) as $i) {
|
||||
$return[] = $i;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
if (module_exists('userreference')) {
|
||||
/**
|
||||
* Implementation of hook_content_diff_values.
|
||||
*/
|
||||
function userreference_content_diff_values($node, $field, $items) {
|
||||
static $titles = array();
|
||||
// Gather ids.
|
||||
$ids = array();
|
||||
foreach ($items as $item) {
|
||||
if ($item['uid'] && is_numeric($item['uid'])) {
|
||||
$ids[] = $item['uid'];
|
||||
}
|
||||
}
|
||||
// Fetch titles we don't know yet.
|
||||
$queried_ids = array_diff($ids, array_keys($titles));
|
||||
if ($queried_ids) {
|
||||
$result = db_query('SELECT uid, name FROM {users} WHERE uid IN ('. db_placeholders($queried_ids) .')', $queried_ids);
|
||||
while ($row = db_fetch_array($result)) {
|
||||
$titles[$row['uid']] = $row['name'];
|
||||
}
|
||||
}
|
||||
// Return result.
|
||||
$return = array();
|
||||
foreach ($items as $item) {
|
||||
if ($item['uid'] && isset($titles[$item['uid']])) {
|
||||
$return[] = $titles[$item['uid']];
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
if (module_exists('nodereference')) {
|
||||
/**
|
||||
* Implementation of hook_content_diff_values.
|
||||
*/
|
||||
function nodereference_content_diff_values($node, $field, $items) {
|
||||
static $titles = array();
|
||||
// Gather ids.
|
||||
$ids = array();
|
||||
foreach ($items as $item) {
|
||||
if ($item['nid'] && is_numeric($item['nid'])) {
|
||||
$ids[] = $item['nid'];
|
||||
}
|
||||
}
|
||||
// Fetch titles we don't know yet.
|
||||
$queried_ids = array_diff($ids, array_keys($titles));
|
||||
if ($queried_ids) {
|
||||
$result = db_query('SELECT nid, title FROM {node} WHERE nid IN ('. db_placeholders($queried_ids) .')', $queried_ids);
|
||||
while ($row = db_fetch_array($result)) {
|
||||
$titles[$row['nid']] = $row['title'];
|
||||
}
|
||||
}
|
||||
// Return result.
|
||||
$return = array();
|
||||
foreach ($items as $item) {
|
||||
if ($item['nid'] && isset($titles[$item['nid']])) {
|
||||
$return[] = $titles[$item['nid']];
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
}
|
520
modules/cck/includes/content.node_form.inc
Normal file
520
modules/cck/includes/content.node_form.inc
Normal file
|
@ -0,0 +1,520 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Create fields' form for a content type.
|
||||
*
|
||||
* Each field defines its own component of the content entry form, via its
|
||||
* chosen widget.
|
||||
*/
|
||||
function content_form(&$form, &$form_state) {
|
||||
$type = content_types($form['type']['#value']);
|
||||
foreach ($type['fields'] as $field_name => $field) {
|
||||
$form['#field_info'][$field['field_name']] = $field;
|
||||
$form += (array) content_field_form($form, $form_state, $field);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a separate form element for each field.
|
||||
*
|
||||
* // TODO: $count param ? not used anymore ?
|
||||
* Hook_widget() picks up two new values, $count and $delta, to help
|
||||
* widgets know what information to return since multiple values are
|
||||
* sometimes controlled by the content module.
|
||||
*
|
||||
* @param $form
|
||||
* the form to add this field element to
|
||||
* @param $form_state
|
||||
* the form_state for the above form
|
||||
* @param $field
|
||||
* the field array to use to create the form element
|
||||
* @param $get_delta
|
||||
* use to get only a specific delta value of a multiple value field, otherwise
|
||||
* function will return the entire $field form element.
|
||||
*/
|
||||
function content_field_form(&$form, &$form_state, $field, $get_delta = NULL) {
|
||||
$form['#cache'] = FALSE;
|
||||
$node = $form['#node'];
|
||||
$addition = array();
|
||||
$form_element = array();
|
||||
$field_name = $field['field_name'];
|
||||
|
||||
$items = array();
|
||||
|
||||
// TODO: is the "if (function_exists($function)) {" needed ?
|
||||
// defining the $function here makes it unclear where it is actually called
|
||||
$function = $field['widget']['module'] .'_widget';
|
||||
if (function_exists($function)) {
|
||||
// Prepare the values to be filled in the widget.
|
||||
// We look in the following places:
|
||||
// - Form submitted values
|
||||
// - Node values (when editing an existing node), or pre-filled values (when
|
||||
// creating a new node translation)
|
||||
// - Default values set for the field (when creating a new node).
|
||||
if (!empty($form_state['values'][$field['field_name']])) {
|
||||
$items = $form_state['values'][$field['field_name']];
|
||||
// If there was an AHAH add more button in this field, don't save it.
|
||||
unset($items[$field['field_name'] .'_add_more']);
|
||||
}
|
||||
elseif (!empty($node->$field['field_name'])) {
|
||||
$items = $node->$field['field_name'];
|
||||
}
|
||||
elseif (empty($node->nid)) {
|
||||
if (content_callback('widget', 'default value', $field) != CONTENT_CALLBACK_NONE) {
|
||||
// If a module wants to insert custom default values here,
|
||||
// it should provide a hook_default_value() function to call,
|
||||
// otherwise the content module's content_default_value() function
|
||||
// will be used.
|
||||
$callback = content_callback('widget', 'default value', $field) == CONTENT_CALLBACK_CUSTOM ? $field['widget']['module'] .'_default_value' : 'content_default_value';
|
||||
if (function_exists($callback)) {
|
||||
$items = $callback($form, $form_state, $field, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See if access to this form element is restricted,
|
||||
// if so, skip widget processing and just set the value.
|
||||
$access = content_access('edit', $field, NULL, $node);
|
||||
if (!$access) {
|
||||
$addition[$field_name] = array(
|
||||
'#access' => $access,
|
||||
'#type' => 'value',
|
||||
'#value' => $items,
|
||||
);
|
||||
return $addition;
|
||||
}
|
||||
|
||||
// If content module handles multiple values for this form element,
|
||||
// and not selecting an individual $delta, process the multiple value form.
|
||||
if (!isset($get_delta) && content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
|
||||
$form_element = content_multiple_value_form($form, $form_state, $field, $items);
|
||||
}
|
||||
// If the widget is handling multiple values (e.g optionwidgets),
|
||||
// or selecting an individual element, just get a single form
|
||||
// element and make it the $delta value.
|
||||
else {
|
||||
$delta = isset($get_delta) ? $get_delta : 0;
|
||||
if ($element = $function($form, $form_state, $field, $items, $delta)) {
|
||||
$title = check_plain(t($field['widget']['label']));
|
||||
$description = content_filter_xss(t($field['widget']['description']));
|
||||
$defaults = array(
|
||||
'#required' => $get_delta > 0 ? FALSE : $field['required'],
|
||||
'#columns' => array_keys($field['columns']),
|
||||
'#title' => $title,
|
||||
'#description' => $description,
|
||||
'#delta' => $delta,
|
||||
'#field_name' => $field['field_name'],
|
||||
'#type_name' => $field['type_name'],
|
||||
);
|
||||
// If we're processing a specific delta value for a field where the
|
||||
// content module handles multiples, set the delta in the result.
|
||||
// For fields that handle their own processing, we can't make assumptions
|
||||
// about how the field is structured, just merge in the returned value.
|
||||
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
|
||||
$form_element[$delta] = array_merge($element, $defaults);
|
||||
}
|
||||
else {
|
||||
$form_element = array_merge($element, $defaults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Field name is needed at top level as well as the individual elements
|
||||
// so the multiple values or other field level theme or processing can find it.
|
||||
if ($form_element) {
|
||||
$defaults = array(
|
||||
'#field_name' => $field['field_name'],
|
||||
'#tree' => TRUE,
|
||||
'#weight' => $field['widget']['weight'],
|
||||
'#access' => $access,
|
||||
// TODO: what's the need for #count ? does not seem to be used anywhere ?
|
||||
'#count' => count($form_element),
|
||||
);
|
||||
$addition[$field['field_name']] = array_merge($form_element, $defaults);
|
||||
}
|
||||
}
|
||||
return $addition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Special handling to create form elements for multiple values.
|
||||
*
|
||||
* Handles generic features for multiple fields:
|
||||
* - number of widgets
|
||||
* - AHAH-'add more' button
|
||||
* - drag-n-drop value reordering
|
||||
*/
|
||||
function content_multiple_value_form(&$form, &$form_state, $field, $items) {
|
||||
$field_name = $field['field_name'];
|
||||
|
||||
switch ($field['multiple']) {
|
||||
case 0:
|
||||
$deltas = array(0);
|
||||
$max = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$deltas = array_keys($items);
|
||||
$current_item_count = max(1, (isset($form_state['item_count'][$field_name]) ? $form_state['item_count'][$field_name] : count($deltas)));
|
||||
$max = (!empty($deltas) ? max($deltas) : -1);
|
||||
while (count($deltas) < $current_item_count) {
|
||||
$max++;
|
||||
$deltas[] = $max;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$max = $field['multiple'] - 1;
|
||||
$deltas = range(0, $max);
|
||||
break;
|
||||
}
|
||||
|
||||
$title = check_plain(t($field['widget']['label']));
|
||||
$description = content_filter_xss(t($field['widget']['description']));
|
||||
|
||||
$form_element = array(
|
||||
'#theme' => 'content_multiple_values',
|
||||
'#title' => $title,
|
||||
'#required' => $field['required'],
|
||||
'#description' => $description,
|
||||
);
|
||||
$function = $field['widget']['module'] .'_widget';
|
||||
|
||||
foreach ($deltas as $delta) {
|
||||
if ($element = $function($form, $form_state, $field, $items, $delta)) {
|
||||
$defaults = array(
|
||||
'#title' => ($field['multiple'] >= 1) ? '' : $title,
|
||||
'#description' => ($field['multiple'] >= 1) ? '' : $description,
|
||||
'#required' => ($field['multiple'] == 0 ? $field['required'] : FALSE),
|
||||
'#weight' => $delta,
|
||||
'#delta' => $delta,
|
||||
'#columns' => array_keys($field['columns']),
|
||||
'#field_name' => $field_name,
|
||||
'#type_name' => $field['type_name'],
|
||||
);
|
||||
|
||||
// Add an input field for the delta (drag-n-drop reordering), which will
|
||||
// be hidden by tabledrag js behavior.
|
||||
if ($field['multiple'] >= 1) {
|
||||
// We name the element '_weight' to avoid clashing with column names
|
||||
// defined by field modules.
|
||||
$element['_weight'] = array(
|
||||
'#type' => 'weight',
|
||||
'#delta' => $max, // this 'delta' is the 'weight' element's property
|
||||
'#default_value' => isset($items[$delta]['_weight']) ? $items[$delta]['_weight'] : $delta,
|
||||
'#weight' => 100,
|
||||
);
|
||||
}
|
||||
|
||||
// Add a checkbox to allow users remove a single delta item.
|
||||
// See content_set_empty() and theme_content_multiple_values().
|
||||
if ($field['multiple'] == 1) {
|
||||
// We name the element '_remove' to avoid clashing with column names
|
||||
// defined by field modules.
|
||||
$element['_remove'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#attributes' => array('class' => 'content-multiple-remove-checkbox'),
|
||||
'#default_value' => isset($items[$delta]['_remove']) ? $items[$delta]['_remove'] : 0,
|
||||
);
|
||||
}
|
||||
|
||||
$form_element[$delta] = array_merge($element, $defaults);
|
||||
}
|
||||
}
|
||||
|
||||
// Add an #after_build callback to prevent validation of fields that are
|
||||
// flagged for removal and enforce field requirement settings.
|
||||
if ($field['multiple'] >= 1) {
|
||||
$form_element['#after_build'] = array('content_multiple_value_after_build_proxy');
|
||||
}
|
||||
|
||||
// Add AHAH add more button, if not working with a programmed form.
|
||||
if ($field['multiple'] == 1 && empty($form['#programmed'])) {
|
||||
// Make sure the form is cached so ahah can work.
|
||||
$form['#cache'] = TRUE;
|
||||
$content_type = content_types($field['type_name']);
|
||||
$field_name_css = str_replace('_', '-', $field_name);
|
||||
|
||||
$form_element[$field_name .'_add_more'] = array(
|
||||
'#type' => 'submit',
|
||||
'#name' => $field_name .'_add_more',
|
||||
'#value' => t('Add another item'),
|
||||
'#weight' => $field['widget']['weight'] + $max + 1,
|
||||
// Submit callback for disabled JavaScript. drupal_get_form() might get
|
||||
// the form from the cache, so we can't rely on content_form_alter()
|
||||
// including this file. Therefore, call a proxy function to do this.
|
||||
'#submit' => array('content_add_more_submit_proxy'),
|
||||
'#ahah' => array(
|
||||
'path' => 'content/js_add_more/'. $content_type['url_str'] .'/'. $field_name,
|
||||
'wrapper' => $field_name_css .'-items',
|
||||
'method' => 'replace',
|
||||
'effect' => 'fade',
|
||||
),
|
||||
// When JS is disabled, the content_add_more_submit handler will find
|
||||
// the relevant field using these entries.
|
||||
'#field_name' => $field_name,
|
||||
'#type_name' => $field['type_name'],
|
||||
);
|
||||
|
||||
// Add wrappers for the fields and 'more' button.
|
||||
$form_element['#prefix'] = '<div id="'. $field_name_css .'-items">';
|
||||
$form_element['#suffix'] = '</div>';
|
||||
$form_element[$field_name .'_add_more']['#prefix'] = '<div class="content-add-more clear-block">';
|
||||
$form_element[$field_name .'_add_more']['#suffix'] = '</div>';
|
||||
}
|
||||
|
||||
return $form_element;
|
||||
}
|
||||
|
||||
/**
|
||||
* After build callback for multiple value fields.
|
||||
*/
|
||||
function content_multiple_value_after_build($elements, &$form_state) {
|
||||
$items_map = array();
|
||||
|
||||
foreach (element_children($elements) as $delta) {
|
||||
// Find delta items for this field when the form if being processed for validation.
|
||||
if (isset($elements[$delta]) && $elements[$delta] && is_numeric($delta) && !empty($elements[$delta]['#needs_validation'])) {
|
||||
|
||||
// Find items that have been flagged for removal.
|
||||
if (isset($elements[$delta]['_remove']) && !empty($elements[$delta]['_remove']['#value'])) {
|
||||
|
||||
// Update the value in the #post attribute of the elements.
|
||||
$post = &$elements[$delta]['#post'];
|
||||
foreach ($elements[$delta]['#parents'] as $name) {
|
||||
$post = &$post[$name];
|
||||
}
|
||||
$post = array('_weight' => $elements[$delta]['_weight']['#value'], '_remove' => 1);
|
||||
|
||||
// Alter the value of this element and children recursively.
|
||||
content_multiple_value_after_build_recursive($elements[$delta], $elements[$delta]['#post']);
|
||||
|
||||
$items_map[$delta] = TRUE;
|
||||
}
|
||||
else {
|
||||
$items_map[$delta] = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the multiple values field is required, then make sure there's at
|
||||
// least one item not flagged for removal. This is necessary to point
|
||||
// the user to the correct form element when the validation error is
|
||||
// issued from content_multiple_value_nodeapi_validate().
|
||||
$items_count = count($items_map);
|
||||
if (!empty($elements['#required']) && $items_count > 0) {
|
||||
// If the number of removed items is equal to the total number of
|
||||
// items, then we'll reset the '_remove' flag of the first item, and
|
||||
// that will be used to point the user when the required field error
|
||||
// is issued by content_multiple_value_nodeapi_validate().
|
||||
if ($items_count == count(array_filter($items_map))) {
|
||||
$delta = key($items_map);
|
||||
if (isset($elements[$delta]['_remove'])) {
|
||||
$elements[$delta]['_remove']['#value'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to deal with items flagged for removal recursively.
|
||||
*/
|
||||
function content_multiple_value_after_build_recursive(&$elements, $post) {
|
||||
foreach (element_children($elements) as $key) {
|
||||
if (isset($elements[$key]) && $elements[$key] && !in_array($key, array('_weight', '_remove', '_error_element'))) {
|
||||
// Recurse through all children elements.
|
||||
content_multiple_value_after_build_recursive($elements[$key], $post);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove values for items flagged for removal.
|
||||
if (isset($elements['#value'])) {
|
||||
$elements['#value'] = NULL;
|
||||
form_set_value($elements, NULL, $form_state);
|
||||
$elements['#post'] = $post;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of nodeapi('validate') for multiple value fields
|
||||
* managed by content module itself.
|
||||
*/
|
||||
function content_multiple_value_nodeapi_validate(&$node, $field, &$items, $form) {
|
||||
$field_name = $field['field_name'];
|
||||
|
||||
// Getting the field structure from the form allows other modules alter
|
||||
// field properties such as the required attribute.
|
||||
$field = $form['#field_info'][$field_name];
|
||||
|
||||
// Get rid of the add more items element.
|
||||
unset($items[$field_name .'_add_more']);
|
||||
|
||||
// Reorder items to account for drag-n-drop reordering.
|
||||
$items = _content_sort_items($field, $items);
|
||||
|
||||
// Create a copy of the items before filtering those that are flagged
|
||||
// for removal. We need this copy later to obtain the error element.
|
||||
$items_copy = $items;
|
||||
|
||||
// Filter out items flagged for removal.
|
||||
$items = content_set_empty($field, $items);
|
||||
|
||||
// Enforce field requirement settings.
|
||||
if ($field['required'] && empty($node->_content_ignore_required_fields[$field_name]) && content_access('edit', $field, NULL, $node)) {
|
||||
// Count non-empty items.
|
||||
$count = 0;
|
||||
$function = $field['module'] .'_content_is_empty';
|
||||
foreach ($items as $item) {
|
||||
if (!$function($item, $field)) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
// The field is required so we expect at least one non-empty item.
|
||||
if ($count == 0) {
|
||||
// Try to guess the element path in the form from the first item that
|
||||
// is not flagged for removal. Defaults to first item.
|
||||
$error_element_index = 0;
|
||||
foreach ($items_copy as $index => $item) {
|
||||
if (empty($item['_remove'])) {
|
||||
$error_element_index = $index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$error_element = isset($items_copy[$error_element_index]) && is_array($items_copy[$error_element_index]) && isset($items_copy[$error_element_index]['_error_element']) ? $items_copy[$error_element_index]['_error_element'] : '';
|
||||
form_set_error($error_element, t('%name field is required.', array('%name' => t($field['widget']['label']))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler to add more choices to a content form. This handler is used when
|
||||
* JavaScript is not available. It makes changes to the form state and the
|
||||
* entire form is rebuilt during the page reload.
|
||||
*/
|
||||
function content_add_more_submit($form, &$form_state) {
|
||||
// Set the form to rebuild and run submit handlers.
|
||||
node_form_submit_build_node($form, $form_state);
|
||||
$field_name = $form_state['clicked_button']['#field_name'];
|
||||
$type_name = $form_state['clicked_button']['#type_name'];
|
||||
|
||||
// Make the changes we want to the form state.
|
||||
if ($form_state['values'][$field_name][$field_name .'_add_more']) {
|
||||
$form_state['item_count'][$field_name] = count($form_state['values'][$field_name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback for AHAH addition of new empty widgets.
|
||||
*/
|
||||
function content_add_more_js($type_name_url, $field_name) {
|
||||
$content_type = content_types($type_name_url);
|
||||
$type = content_types($type_name_url);
|
||||
$field = content_fields($field_name, $type['type']);
|
||||
|
||||
if (($field['multiple'] != 1) || empty($_POST['form_build_id'])) {
|
||||
// Invalid request.
|
||||
drupal_json(array('data' => ''));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Retrieve the cached form.
|
||||
$form_state = array('submitted' => FALSE);
|
||||
$form_build_id = $_POST['form_build_id'];
|
||||
$form = form_get_cache($form_build_id, $form_state);
|
||||
if (!$form) {
|
||||
// Invalid form_build_id.
|
||||
drupal_json(array('data' => ''));
|
||||
exit;
|
||||
}
|
||||
|
||||
// We don't simply return a new empty widget to append to existing ones, because
|
||||
// - ahah.js won't simply let us add a new row to a table
|
||||
// - attaching the 'draggable' behavior won't be easy
|
||||
// So we resort to rebuilding the whole table of widgets including the existing ones,
|
||||
// which makes us jump through a few hoops.
|
||||
|
||||
// The form that we get from the cache is unbuilt. We need to build it so that
|
||||
// _value callbacks can be executed and $form_state['values'] populated.
|
||||
// We only want to affect $form_state['values'], not the $form itself
|
||||
// (built forms aren't supposed to enter the cache) nor the rest of $form_data,
|
||||
// so we use copies of $form and $form_data.
|
||||
$form_copy = $form;
|
||||
$form_state_copy = $form_state;
|
||||
$form_copy['#post'] = array();
|
||||
form_builder($_POST['form_id'], $form_copy, $form_state_copy);
|
||||
// Just grab the data we need.
|
||||
$form_state['values'] = $form_state_copy['values'];
|
||||
// Reset cached ids, so that they don't affect the actual form we output.
|
||||
form_clean_id(NULL, TRUE);
|
||||
|
||||
// Sort the $form_state['values'] we just built *and* the incoming $_POST data
|
||||
// according to d-n-d reordering.
|
||||
unset($form_state['values'][$field_name][$field['field_name'] .'_add_more']);
|
||||
foreach ($_POST[$field_name] as $delta => $item) {
|
||||
$form_state['values'][$field_name][$delta]['_weight'] = $item['_weight'];
|
||||
$form_state['values'][$field_name][$delta]['_remove'] = isset($item['_remove']) ? $item['_remove'] : 0;
|
||||
}
|
||||
$form_state['values'][$field_name] = _content_sort_items($field, $form_state['values'][$field_name]);
|
||||
$_POST[$field_name] = _content_sort_items($field, $_POST[$field_name]);
|
||||
|
||||
// Build our new form element for the whole field, asking for one more element.
|
||||
$delta = max(array_keys($_POST[$field_name])) + 1;
|
||||
$form_state['item_count'] = array($field_name => count($_POST[$field_name]) + 1);
|
||||
$form_element = content_field_form($form, $form_state, $field);
|
||||
// Let other modules alter it.
|
||||
// We pass an empty array as hook_form_alter's usual 'form_state' parameter,
|
||||
// instead of $form_atate (for reasons we may never remember).
|
||||
// However, this argument is still expected to be passed by-reference
|
||||
// (and PHP5.3 will throw an error if it isn't.) This leads to:
|
||||
$data = &$form_element;
|
||||
$empty_form_state = array();
|
||||
$data['__drupal_alter_by_ref'] = array(&$empty_form_state);
|
||||
drupal_alter('form', $data, 'content_add_more_js');
|
||||
|
||||
// Add the new element at the right place in the (original, unbuilt) form.
|
||||
$success = content_set_nested_elements($form, $field_name, $form_element[$field_name]);
|
||||
|
||||
// Save the new definition of the form.
|
||||
$form_state['values'] = array();
|
||||
form_set_cache($form_build_id, $form, $form_state);
|
||||
|
||||
// Build the new form against the incoming $_POST values so that we can
|
||||
// render the new element.
|
||||
$_POST[$field_name][$delta]['_weight'] = $delta;
|
||||
$form_state = array('submitted' => FALSE);
|
||||
$form += array(
|
||||
'#post' => $_POST,
|
||||
'#programmed' => FALSE,
|
||||
);
|
||||
$form = form_builder($_POST['form_id'], $form, $form_state);
|
||||
|
||||
// Render the new output.
|
||||
$field_form = array_shift(content_get_nested_elements($form, $field_name));
|
||||
|
||||
// We add a div around the new content to receive the ahah effect.
|
||||
$field_form[$delta]['#prefix'] = '<div class="ahah-new-content">'. (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : '');
|
||||
$field_form[$delta]['#suffix'] = (isset($field_form[$delta]['#suffix']) ? $field_form[$delta]['#suffix'] : '') .'</div>';
|
||||
// Prevent duplicate wrapper.
|
||||
unset($field_form['#prefix'], $field_form['#suffix']);
|
||||
|
||||
// If a newly inserted widget contains AHAH behaviors, they normally won't
|
||||
// work because AHAH doesn't know about those - it just attaches to the exact
|
||||
// form elements that were initially specified in the Drupal.settings object.
|
||||
// The new ones didn't exist then, so we need to update Drupal.settings
|
||||
// by ourselves in order to let AHAH know about those new form elements.
|
||||
$javascript = drupal_add_js(NULL, NULL);
|
||||
$output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, '. drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) .');</script>' : '';
|
||||
|
||||
$output = theme('status_messages') . drupal_render($field_form) . $output_js;
|
||||
|
||||
// Using drupal_json() breaks filefield's file upload, because the jQuery
|
||||
// Form plugin handles file uploads in a way that is not compatible with
|
||||
// 'text/javascript' response type.
|
||||
$GLOBALS['devel_shutdown'] = FALSE;
|
||||
print drupal_to_js(array('status' => TRUE, 'data' => $output));
|
||||
exit;
|
||||
}
|
347
modules/cck/includes/content.rules.inc
Normal file
347
modules/cck/includes/content.rules.inc
Normal file
|
@ -0,0 +1,347 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides basic rules module support.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_rules_action_info().
|
||||
*/
|
||||
function content_rules_action_info() {
|
||||
$info = array();
|
||||
$info['content_rules_action_populate_field'] = array(
|
||||
'label' => t('Populate a field'),
|
||||
'arguments' => array(
|
||||
'node' => array(
|
||||
'type' => 'node',
|
||||
'label' => t('Content'),
|
||||
),
|
||||
),
|
||||
'eval input' => array('code'),
|
||||
'help' => t('You should make sure that the used field exists in the given content type.'),
|
||||
'module' => 'CCK',
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action: populate a field.
|
||||
*/
|
||||
function content_rules_action_populate_field($node, $settings, $element, &$state) {
|
||||
// Get information about the field.
|
||||
$field = content_fields($settings['field_name'], $node->type);
|
||||
$value = _content_rules_get_field_value($settings, $state);
|
||||
|
||||
if (!empty($field) && is_array($value)) {
|
||||
$node->$settings['field_name'] = $value;
|
||||
return array('node' => $node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Action "populate a field" configuration form.
|
||||
* This is a multistep form!
|
||||
*/
|
||||
function content_rules_action_populate_field_form($settings, &$form, &$form_state) {
|
||||
$settings += array('field_name' => '', 'code' => '', 'value' => NULL);
|
||||
if (empty($settings['field_name'])) {
|
||||
$form['settings']['field_name'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Field'),
|
||||
'#options' => content_rules_get_field_names_by_type(),
|
||||
'#default_value' => $settings['field_name'],
|
||||
'#description' => t('Select the machine-name of the field.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
// Hide some form elements in the first step.
|
||||
$form['negate']['#access'] = FALSE;
|
||||
$form['input_help']['#access'] = FALSE;
|
||||
$form['weight']['#access'] = FALSE;
|
||||
|
||||
// Replace the usual submit handlers with a own handler.
|
||||
$form['submit']['#submit'] = array('content_rules_action_populate_field_form_step_submit');
|
||||
$form['submit']['#value'] = t('Continue');
|
||||
}
|
||||
else {
|
||||
// Show the fields form here.
|
||||
module_load_include('inc', 'content', 'includes/content.node_form');
|
||||
$field = content_fields($settings['field_name']);
|
||||
|
||||
$form['#node'] = (object)array('type' => '', $settings['field_name'] => $settings['value']);
|
||||
$form['#field_info'][$field['field_name']] = $field;
|
||||
// We can't put it into $form['settings'] as this would break AHAH callbacks
|
||||
$form += (array) content_field_form($form, $form_state, $field);
|
||||
$form[ $settings['field_name'] ]['#weight'] = 4;
|
||||
|
||||
unset($form['#cache']);
|
||||
|
||||
// Advanced: PHP code.
|
||||
$form['advanced_options'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Advanced: Specify the fields value with PHP code'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => empty($settings['code']),
|
||||
'#weight' => 5,
|
||||
);
|
||||
|
||||
$db_info = content_database_info($field);
|
||||
$columns = array_keys($db_info['columns']);
|
||||
foreach ($columns as $key => $column) {
|
||||
$columns[$key] = t("'@column' => value for @column", array('@column' => $column));
|
||||
}
|
||||
$sample = t("return array(\n 0 => array(@columns),\n // You'll usually want to stop here. Provide more values\n // if you want your 'default value' to be multi-valued:\n 1 => array(@columns),\n 2 => ...\n);", array('@columns' => implode(', ', $columns)));
|
||||
|
||||
$form['advanced_options']['code'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Code'),
|
||||
'#default_value' => $settings['code'],
|
||||
'#rows' => 6,
|
||||
'#description' => t('Advanced usage only: PHP code that returns the value to set. Should not include <?php ?> delimiters. If this field is filled out, the value returned by this code will override any value specified above. Expected format: <pre>!sample</pre>Using <a href="@link_devel">devel.module\'s</a> \'devel load\' tab on a content page might help you figure out the expected format.', array(
|
||||
'!sample' => $sample,
|
||||
'@link_devel' => 'http://www.drupal.org/project/devel',
|
||||
)),
|
||||
);
|
||||
|
||||
// Add this file to be included when the form is built by rules
|
||||
// as it's needed by CCKs add more button.
|
||||
// See rules_after_build_include_files().
|
||||
$form['#includes'][] = './'. drupal_get_path('module', 'node') .'/node.pages.inc';
|
||||
}
|
||||
}
|
||||
|
||||
function content_rules_action_populate_field_form_step_submit($form, &$form_state) {
|
||||
$form_state['element']['#settings']['field_name'] = $form_state['values']['settings']['field_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the chosen value or php code.
|
||||
*/
|
||||
function content_rules_action_populate_field_validate($form, &$form_state) {
|
||||
if (!isset($form_state['element']['#settings']['field_name'])) {
|
||||
//Just validate the last step.
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($form_state['values']['code']) && ($php = $form_state['values']['code'])) {
|
||||
if (strpos($php, 'return') === FALSE) {
|
||||
form_set_error('code', t('You have to return the default value in the expected format.'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Validate the field.
|
||||
$settings = $form_state['element']['#settings'];
|
||||
$field = content_fields($settings['field_name']);
|
||||
$field_types = _content_field_types();
|
||||
$function = $field_types[$field['type']]['module'] .'_field';
|
||||
if (function_exists($function)) {
|
||||
$form['#node'] = (object)array('type' => '', $settings['field_name'] => $form_state['values'][$settings['field_name']]);
|
||||
$items = isset($form['#node']->$field['field_name']) ? $form['#node']->$field['field_name'] : array();
|
||||
|
||||
//Make sure AHAH 'add more' button isn't sent to the fields
|
||||
// for processing.
|
||||
unset($items[$field['field_name'] .'_add_more']);
|
||||
|
||||
$function('validate', $form['#node'], $field, $items, $form, NULL);
|
||||
content_field('validate', $form['#node'], $field, $items, $form, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function content_rules_action_populate_field_submit(&$settings, $form, &$form_state) {
|
||||
// Take over field values and filter out private properties added by CCK
|
||||
$settings['value'] = array_filter($form_state['values'][$settings['field_name']], 'is_array');
|
||||
|
||||
foreach ($settings['value'] as $key => $data) {
|
||||
foreach (array_filter(array_keys($data)) as $col) {
|
||||
if ($col[0] == '_') {
|
||||
unset($settings['value'][$key][$col]);
|
||||
}
|
||||
}
|
||||
if ($key && count(array_filter($settings['value'][$key])) == 0) {
|
||||
// For multi-valued fields don't check for any additional empty values.
|
||||
unset($settings['value'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$settings['code'] = $form_state['values']['code'];
|
||||
|
||||
if (function_exists('rules_action_custom_php_submit')) {
|
||||
// Support adding variables to the php code, if php module is present.
|
||||
rules_action_custom_php_submit($settings, $form, $form_state);
|
||||
}
|
||||
|
||||
// Add all values to the input evaluator, so that textfields / textares can
|
||||
// make use of it.
|
||||
$names = array('code');
|
||||
|
||||
foreach ($settings['value'] as $key => $data) {
|
||||
foreach (array_filter($data, 'is_string') as $col => $value) {
|
||||
$names[] = "value|$key|$col";
|
||||
}
|
||||
}
|
||||
$form_state['element']['#info']['eval input'] = $names;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Label callback: Improve the label of the action.
|
||||
*/
|
||||
function content_rules_action_populate_field_label($settings, $argument_labels) {
|
||||
return t("Populate @node's field '@field'", array('@field' => $settings['field_name']) + $argument_labels);
|
||||
}
|
||||
|
||||
function workflow_ng_action_populate_field_upgrade(&$element) {
|
||||
$element['#name'] = 'content_rules_action_populate_field';
|
||||
$element['#settings']['code'] = $element['#settings']['default_value_php'];
|
||||
$element['#settings'][$element['#settings']['field_name']] = array();
|
||||
unset($element['#settings']['default_value_php']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hook_rules_condition_info().
|
||||
*/
|
||||
function content_rules_condition_info() {
|
||||
$info = array();
|
||||
$info['content_rules_field_has_value'] = array(
|
||||
'label' => t('Field has value'),
|
||||
'arguments' => array(
|
||||
'node' => array('type' => 'node', 'label' => t('Content')),
|
||||
),
|
||||
'eval input' => array('code'),
|
||||
'help' => t('You should make sure that the used field exists in the given content type. The condition returns TRUE, if the selected field has the given value.'),
|
||||
'module' => 'CCK',
|
||||
);
|
||||
$info['content_rules_field_changed'] = array(
|
||||
'label' => t('Field has changed'),
|
||||
'arguments' => array(
|
||||
'node' => array('type' => 'node', 'label' => t('Content containing changes')),
|
||||
'node_unchanged' => array('type' => 'node', 'label' => t('Content not containing changes')),
|
||||
),
|
||||
'help' => t('You should make sure that the used field exists in the given content type.'),
|
||||
'module' => 'CCK',
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition: Check the value of a field.
|
||||
*/
|
||||
function content_rules_field_has_value($node, $settings) {
|
||||
// Get information about the field.
|
||||
$field = content_fields($settings['field_name'], $node->type);
|
||||
$value = _content_rules_get_field_value($settings, $state);
|
||||
|
||||
if (empty($field) || !is_array($value)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _content_rules_field_has_value($node->$settings['field_name'], $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the same configuration form as the "populate field" action.
|
||||
*/
|
||||
function content_rules_field_has_value_form($settings, &$form, &$form_state) {
|
||||
content_rules_action_populate_field_form($settings, $form, $form_state);
|
||||
}
|
||||
function content_rules_field_has_value_validate($form, &$form_state) {
|
||||
content_rules_action_populate_field_validate($form, $form_state);
|
||||
}
|
||||
function content_rules_field_has_value_submit(&$settings, $form, &$form_state) {
|
||||
content_rules_action_populate_field_submit($settings, $form, $form_state);
|
||||
}
|
||||
|
||||
function content_rules_field_has_value_label($settings, $argument_labels) {
|
||||
return t("@node's field '@field' has value", array('@field' => $settings['field_name']) + $argument_labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition: Check if the field has changed.
|
||||
*/
|
||||
function content_rules_field_changed($node1, $node2, $settings) {
|
||||
// Get information about the field.
|
||||
$field = content_fields($settings['field_name'], $node1->type);
|
||||
|
||||
return !empty($field) && !_content_rules_field_has_value($node1->$settings['field_name'], $node2->$settings['field_name']);
|
||||
}
|
||||
|
||||
function content_rules_field_changed_form($settings, &$form, &$form_state) {
|
||||
$settings += array('field_name' => '');
|
||||
$form['settings']['field_name'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Field'),
|
||||
'#options' => content_rules_get_field_names_by_type(),
|
||||
'#default_value' => $settings['field_name'],
|
||||
'#description' => t('Select the machine-name of the field to look at.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
function content_rules_field_changed_label($settings, $argument_labels) {
|
||||
return t("@node's field '@field' has been changed", array('@field' => $settings['field_name']) + $argument_labels);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the fields of a given field type only.
|
||||
* Suitable for using it with #options.
|
||||
*/
|
||||
function content_rules_get_field_names_by_type($type = NULL) {
|
||||
$fields = array();
|
||||
foreach (content_fields() as $field) {
|
||||
if (!isset($type) || $field['type'] == $type) {
|
||||
$fields[$field['field_name']] = $field['field_name'];
|
||||
}
|
||||
}
|
||||
asort($fields);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function _content_rules_get_field_value($settings, &$state) {
|
||||
if ($settings['code']) {
|
||||
if (function_exists('rules_input_evaluator_php_apply')) {
|
||||
// Support adding variables to the php code, if php module is present.
|
||||
$value = rules_input_evaluator_php_apply($settings['code'], $settings['vars'], $state, FALSE);
|
||||
}
|
||||
else {
|
||||
ob_start();
|
||||
$value = eval($settings['code']);
|
||||
ob_end_clean();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$value = $settings['value'];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether both field values match in a robust way.
|
||||
*
|
||||
* It returns TRUE, only if the number of multiple values matches and
|
||||
* each property of the cck field's value is the same in the node.
|
||||
*
|
||||
* @param $node_value The value present in the node.
|
||||
* @param $value The value to check for.
|
||||
*/
|
||||
function _content_rules_field_has_value($node_value, $value) {
|
||||
if (count($value) != count($node_value)) {
|
||||
return FALSE;
|
||||
}
|
||||
// Loop over multiple fields
|
||||
foreach ($value as $delta => $sub_value) {
|
||||
// Check if all properties of the value are there in the node value too
|
||||
if (is_array($sub_value) && is_array($node_value[$delta])) {
|
||||
if (count(array_diff_assoc($sub_value, $node_value[$delta])) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
elseif ($sub_value !== $node_value[$delta]) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
76
modules/cck/includes/content.token.inc
Normal file
76
modules/cck/includes/content.token.inc
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementation of hook_content_build_modes
|
||||
* (on behalf of token.module)
|
||||
*/
|
||||
function token_content_build_modes() {
|
||||
return array(
|
||||
'token' => array(
|
||||
'title' => t('Token'),
|
||||
'build modes' => array(
|
||||
'token' => array(
|
||||
'title' => t('Token'),
|
||||
'views style' => FALSE,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Two helper functions that generate appropriate tokens for CCK-added fields.
|
||||
function content_token_values($type, $object = NULL, $options = array()) {
|
||||
$tokens = array();
|
||||
if ($type == 'node') {
|
||||
// Prevent against invalid 'nodes' built by broken 3rd party code.
|
||||
if (isset($object->type)) {
|
||||
// Let PHP free the $node object when we are done. Working directly on the
|
||||
// incoming $object causes memory leak issues on long-running scripts such
|
||||
// as migrations. See http://drupal.org/node/736440.
|
||||
$node = drupal_clone($object);
|
||||
$content_type = content_types($node->type);
|
||||
$node->build_mode = 'token';
|
||||
$node->content = array();
|
||||
content_view($node);
|
||||
// The formatted values will only be known after the content has been rendered.
|
||||
drupal_render($node->content);
|
||||
content_alter($node);
|
||||
|
||||
$field_types = _content_field_types();
|
||||
foreach ($content_type['fields'] as $field_name => $field) {
|
||||
$items = isset($node->{$field_name}) ? $node->{$field_name} : array();
|
||||
$function = $field_types[$field['type']]['module'] . '_token_values';
|
||||
if (!empty($items) && function_exists($function)) {
|
||||
$token_values = (array) $function('field', $items, $options);
|
||||
foreach ($token_values as $token => $value) {
|
||||
$tokens[$field_name .'-'. $token] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
function content_token_list($type = 'all') {
|
||||
if ($type == 'node' || $type == 'all') {
|
||||
$list = array();
|
||||
$field_types = _content_field_types();
|
||||
|
||||
foreach (content_fields() as $field) {
|
||||
$sub_list = array();
|
||||
$function = $field_types[$field['type']]['module'] . '_token_list';
|
||||
if (function_exists($function)) {
|
||||
$sub_list = $function('field');
|
||||
foreach ($sub_list as $category => $token_list) {
|
||||
foreach ($token_list as $token => $description) {
|
||||
$list['CCK '. $category][$field['field_name'] .'-'. $token] = $description;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
214
modules/cck/includes/panels/content_types/content_field.inc
Normal file
214
modules/cck/includes/panels/content_types/content_field.inc
Normal file
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file provides a CTools content type for fields.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback function to supply a list of content types.
|
||||
*/
|
||||
function content_content_field_ctools_content_types() {
|
||||
return array(
|
||||
'title' => t('Content field'),
|
||||
'defaults' => array('label' => '', 'formatter' => ''),
|
||||
'content type' => 'content_content_field_content_type_content_type',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all field content types available.
|
||||
*/
|
||||
function content_content_field_content_type_content_types() {
|
||||
// This will hold all the individual field content types.
|
||||
$types = array();
|
||||
|
||||
// Get all fields on the site.
|
||||
$field_types = _content_field_types();
|
||||
|
||||
foreach (content_types() as $type_name => $type) {
|
||||
foreach ($type['fields'] as $field_name => $field) {
|
||||
if (!isset($types[$field_name])) {
|
||||
$types[$field_name] = array(
|
||||
'category' => t('Node'),
|
||||
'icon' => 'icon_cck_field.png',
|
||||
'title' => t('Field: @widget_label (@field_name) - @field_type', array(
|
||||
'@widget_label' => t($field['widget']['label']),
|
||||
'@field_name' => $field_name,
|
||||
'@field_type' => t($field_types[$field['type']]['label']),
|
||||
)),
|
||||
'description' => t('Field on the referenced node.'),
|
||||
'types' => array(),
|
||||
);
|
||||
if (isset($field_types[$field['type']]['content_icon'])) {
|
||||
$types[$field_name]['icon'] = $field_types[$field['type']]['content_icon'];
|
||||
}
|
||||
}
|
||||
$types[$field_name]['types'][$type_name] = $type['name'];
|
||||
}
|
||||
}
|
||||
|
||||
// Create the required context for each field related to the content types.
|
||||
foreach ($types as $field_name => $field_content_type) {
|
||||
$types[$field_name]['required context'] = new ctools_context_required(t('Node'), 'node', array(
|
||||
'type' => array_keys($types[$field_name]['types']),
|
||||
));
|
||||
unset($types[$field_name]['types']);
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just one subtype.
|
||||
*
|
||||
* Ordinarily this function is meant to get just one subtype. However, we are
|
||||
* using it to deal with the fact that we have changed the subtype names. This
|
||||
* lets us translate the name properly.
|
||||
*/
|
||||
function content_content_field_content_type_content_type($subtype) {
|
||||
// Previous versions of CCK included the content type as part of the subtype.
|
||||
// This allows those to continue to sort of work, at least during render.
|
||||
if (strpos($subtype, ':') !== FALSE) {
|
||||
list($content_type, $subtype) = explode(':', $subtype, 2);
|
||||
}
|
||||
|
||||
$types = content_content_field_content_type_content_types();
|
||||
if (isset($types[$subtype])) {
|
||||
return $types[$subtype];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output function for the 'field' content type.
|
||||
*/
|
||||
function content_content_field_content_type_render($subtype, $conf, $panel_args, $context) {
|
||||
// Previous versions of CCK included the content type as part of the subtype.
|
||||
// This allows those to continue to sort of work, at least during render.
|
||||
if (strpos($subtype, ':') !== FALSE) {
|
||||
list($content_type, $subtype) = explode(':', $subtype, 2);
|
||||
}
|
||||
|
||||
if (is_array($context)) {
|
||||
$context = array_pop($context);
|
||||
}
|
||||
// If we do not have a node, then we cannot generate output.
|
||||
if (!isset($context->data)) {
|
||||
return;
|
||||
}
|
||||
$node = drupal_clone($context->data);
|
||||
|
||||
// Extract the node type from the node in context, the field name from the
|
||||
// panels content type subtype, and get the content field structure.
|
||||
$field_name = $subtype;
|
||||
$field = content_fields($field_name, $node->type);
|
||||
|
||||
// Get the formatter that was selected in the settings dialog.
|
||||
$formatter = $conf['formatter'];
|
||||
|
||||
// Check view access to the field.
|
||||
if (!content_access('view', $field, NULL, $node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Force panel settings into the field's display settings.
|
||||
$field['display_settings']['label']['format'] = $conf['label'] == 'normal' || !empty($conf['override_title']) ? 'hidden' : $conf['label'];
|
||||
$field['display_settings']['full']['format'] = $formatter;
|
||||
$node->build_mode = NODE_BUILD_NORMAL;
|
||||
// TODO : allow panel-specific template suggestions for content-field.tpl.php ?
|
||||
|
||||
$output = content_view_field($field, $node);
|
||||
|
||||
$block = new stdClass();
|
||||
$block->module = 'content';
|
||||
$block->delta = $field_name;
|
||||
if ($conf['label'] == 'normal') {
|
||||
$block->title = t($field['widget']['label']);
|
||||
}
|
||||
$block->content = $output;
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a settings form for the custom type.
|
||||
*/
|
||||
function content_content_field_content_type_edit_form(&$form, &$form_state) {
|
||||
$conf = $form_state['conf'];
|
||||
|
||||
$form['label'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Field label'),
|
||||
'#default_value' => isset($conf['label']) ? $conf['label'] : '',
|
||||
'#options' => array(
|
||||
'normal' => t('Block title'),
|
||||
'above' => t('Above'),
|
||||
'inline' => t('Inline'),
|
||||
),
|
||||
'#description' => t('Configure how the label is going to be displayed. This option takes no effect when "Override title" option is enabled, the specified block title is displayed instead.'),
|
||||
);
|
||||
|
||||
// Extract the field name from the panels content type subtype.
|
||||
$field_name = $form_state['subtype_name'];
|
||||
|
||||
// Previous versions of CCK included the content type as part of the subtype.
|
||||
// This allows those to continue to sort of work.
|
||||
if (strpos($field_name, ':') !== FALSE) {
|
||||
list($content_type, $field_name) = explode(':', $field_name, 2);
|
||||
}
|
||||
|
||||
// Get all the information about our field.
|
||||
$field = content_fields($field_name);
|
||||
|
||||
// Get information about all the field types on the site.
|
||||
$field_types = _content_field_types();
|
||||
|
||||
// Get the information about the type that our field is.
|
||||
$type_info = $field_types[$field['type']];
|
||||
|
||||
// Put the possible formatters for our type into an array.
|
||||
$options = array();
|
||||
foreach ($type_info['formatters'] as $formatter_name => $formatter) {
|
||||
$options[$formatter_name] = $formatter['label'];
|
||||
}
|
||||
|
||||
$form['formatter'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Field formatter'),
|
||||
'#default_value' => isset($conf['formatter']) ? $conf['formatter'] : 'default',
|
||||
'#options' => $options,
|
||||
'#description' => t('Select a formatter.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
function content_content_field_content_type_edit_form_submit(&$form, &$form_state) {
|
||||
// Copy everything from our defaults.
|
||||
foreach (array_keys($form_state['plugin']['defaults']) as $key) {
|
||||
$form_state['conf'][$key] = $form_state['values'][$key];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin title for field content type.
|
||||
*/
|
||||
function content_content_field_content_type_admin_title($subtype, $conf, $context) {
|
||||
// Previous versions of CCK included the content type as part of the subtype.
|
||||
// This allows those to continue to sort of work, at least during render.
|
||||
if (strpos($subtype, ':') !== FALSE) {
|
||||
list($content_type, $subtype) = explode(':', $subtype, 2);
|
||||
}
|
||||
|
||||
// Get all fields on the site.
|
||||
$field_types = _content_field_types();
|
||||
|
||||
// Get all the information about our field.
|
||||
$field = content_fields($subtype);
|
||||
|
||||
return t('"@s" field: @widget_label (@field_name) - @field_type', array(
|
||||
'@s' => $context->identifier,
|
||||
'@widget_label' => t($field['widget']['label']),
|
||||
'@field_name' => $subtype,
|
||||
'@field_type' => t($field_types[$field['type']]['label']),
|
||||
));
|
||||
}
|
BIN
modules/cck/includes/panels/content_types/icon_cck_field.png
Normal file
BIN
modules/cck/includes/panels/content_types/icon_cck_field.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 989 B |
374
modules/cck/includes/views/content.views.inc
Normal file
374
modules/cck/includes/views/content.views.inc
Normal file
|
@ -0,0 +1,374 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Interface between content.module and views.module.
|
||||
*/
|
||||
|
||||
// Include the files defining the classes we extend.
|
||||
// This is needed in case the /cck folder lives in the main
|
||||
// /modules folder (views_module_include() will then load
|
||||
// content.views.inc before node.views.inc)
|
||||
module_load_include('inc', 'views', 'modules/node.views');
|
||||
|
||||
/**
|
||||
* Implementation of hook_views_handlers().
|
||||
*/
|
||||
function content_views_handlers() {
|
||||
return array(
|
||||
'info' => array(
|
||||
'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
|
||||
),
|
||||
'handlers' => array(
|
||||
|
||||
// argument handlers
|
||||
'content_handler_argument' => array(
|
||||
'parent' => 'views_handler_argument',
|
||||
),
|
||||
'content_handler_argument_string' => array(
|
||||
'parent' => 'views_handler_argument_string',
|
||||
),
|
||||
'content_handler_argument_numeric' => array(
|
||||
'parent' => 'views_handler_argument_numeric',
|
||||
),
|
||||
'content_handler_argument_reference' => array(
|
||||
'parent' => 'content_handler_argument_numeric',
|
||||
),
|
||||
'content_handler_argument_many_to_one' => array(
|
||||
'parent' => 'views_handler_argument_many_to_one',
|
||||
),
|
||||
|
||||
// field handlers
|
||||
'content_handler_field' => array(
|
||||
'parent' => 'views_handler_field_node',
|
||||
),
|
||||
'content_handler_field_multiple' => array(
|
||||
'parent' => 'content_handler_field',
|
||||
),
|
||||
|
||||
// filter handlers
|
||||
'content_handler_filter_string' => array(
|
||||
'parent' => 'views_handler_filter_string',
|
||||
),
|
||||
'content_handler_filter_numeric' => array(
|
||||
'parent' => 'views_handler_filter_numeric',
|
||||
),
|
||||
'content_handler_filter_float' => array(
|
||||
'parent' => 'views_handler_filter_float',
|
||||
),
|
||||
'content_handler_filter_many_to_one' => array(
|
||||
'parent' => 'views_handler_filter_many_to_one',
|
||||
),
|
||||
|
||||
// relationship handlers
|
||||
'content_handler_relationship' => array(
|
||||
'parent' => 'views_handler_relationship',
|
||||
),
|
||||
|
||||
// sort handlers
|
||||
'content_handler_sort' => array(
|
||||
'parent' => 'views_handler_sort',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_views_plugins.
|
||||
*
|
||||
* Defines some plugins used by the Views modes for
|
||||
* nodereference and userreference.
|
||||
*/
|
||||
function content_views_plugins() {
|
||||
$plugins = array(
|
||||
'module' => 'content', // This just tells our themes are elsewhere.
|
||||
'display' => array(
|
||||
'content_simple' => array(
|
||||
'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
|
||||
// Those strings are not translated for now.
|
||||
// We'll need to change that if / when we remove 'no ui'
|
||||
'title' => 'Simple', // TODO: better name ? (currently not displayed anyway)
|
||||
'help' => 'Destination-agnostic display. Mostly useful for programmatic views.',
|
||||
'handler' => 'content_plugin_display_simple',
|
||||
'no ui' => TRUE, // Programmatic use only.
|
||||
'uses hook menu' => FALSE,
|
||||
'use ajax' => FALSE,
|
||||
'use pager' => FALSE,
|
||||
'accept attachments' => FALSE,
|
||||
),
|
||||
'content_references' => array(
|
||||
'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
|
||||
// Those strings are not translated for now.
|
||||
// We'll need to change that if / when we remove 'no ui'
|
||||
'title' => 'Simple - for reference fields', // TODO: better name ? (currently not displayed anyway)
|
||||
'help' => 'Destination-agnostic display. Mostly useful for programmatic views.',
|
||||
'parent' => 'content_simple',
|
||||
'handler' => 'content_plugin_display_references',
|
||||
'no ui' => TRUE, // Programmatic use only.
|
||||
'uses hook menu' => FALSE,
|
||||
'use ajax' => FALSE,
|
||||
'use pager' => FALSE,
|
||||
'accept attachments' => FALSE,
|
||||
),
|
||||
),
|
||||
'style' => array(
|
||||
'content_php_array_autocomplete' => array(
|
||||
'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
|
||||
// Those strings are not translated for now.
|
||||
// We'll need to change that if / when we remove 'no ui'
|
||||
'title' => 'Results array (with title)',
|
||||
'help' => 'Returns the view as a PHP array of names + rendered rows.',
|
||||
'handler' => 'content_plugin_style_php_array_ac',
|
||||
'no ui' => TRUE, // Programmatic use only.
|
||||
'uses row plugin' => TRUE,
|
||||
'uses fields' => TRUE,
|
||||
'type' => 'content_simple',
|
||||
'even empty' => TRUE,
|
||||
),
|
||||
),
|
||||
);
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_views_data().
|
||||
*
|
||||
* Exposes all fields to the views system.
|
||||
*/
|
||||
function content_views_data() {
|
||||
$data = array();
|
||||
foreach (content_fields() as $field) {
|
||||
$module = $field['module'];
|
||||
$result = (array) module_invoke($module, 'field_settings', 'views data', $field);
|
||||
drupal_alter('field_settings', $result, 'views data', $field);
|
||||
if (empty($result)) {
|
||||
$result = content_views_field_views_data($field);
|
||||
}
|
||||
if (is_array($result)) {
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
function content_views_field_views_data($field) {
|
||||
$field_types = _content_field_types();
|
||||
|
||||
// Check the field module is available.
|
||||
// TODO: is this really how we should do it ?
|
||||
if (isset($field_types[$field['type']])) {
|
||||
$db_info = content_database_info($field);
|
||||
|
||||
// Field modules that do not store data in the database
|
||||
// should not create views data tables.
|
||||
if (empty($db_info['columns'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table_alias = content_views_tablename($field);
|
||||
|
||||
$types = array();
|
||||
foreach (content_types() as $type) {
|
||||
if (isset($type['fields'][$field['field_name']])) {
|
||||
// TODO : run check_plain here instead of on the imploded string below ?
|
||||
$types[] = $type['name'];
|
||||
}
|
||||
}
|
||||
|
||||
$data = array();
|
||||
$data['table']['group'] = t('Content');
|
||||
$data['table']['join']['node'] = array(
|
||||
'table' => $db_info['table'],
|
||||
'left_field' => 'vid',
|
||||
'field' => 'vid',
|
||||
);
|
||||
$data['table']['join']['node_revisions'] = array(
|
||||
'table' => $db_info['table'],
|
||||
'left_field' => 'vid',
|
||||
'field' => 'vid',
|
||||
);
|
||||
|
||||
// Build the list of columns enabled for default views integration.
|
||||
$db_columns = array();
|
||||
$additional_fields = array();
|
||||
foreach ($db_info['columns'] as $column => $attributes) {
|
||||
// Select explicitly enabled field columns.
|
||||
if (!empty($attributes['views'])) {
|
||||
$db_columns[$column] = $attributes;
|
||||
}
|
||||
// Ensure all columns are retrieved.
|
||||
$additional_fields[$attributes['column']] = $attributes['column'];
|
||||
}
|
||||
// Pick up the first column when none has been explicitly enabled
|
||||
// (pre CCK 2.2 backwards compatibility).
|
||||
if (empty($db_columns)) {
|
||||
// Can't use array_slice(), it won't work in PHP4 for assoc array.
|
||||
foreach ($db_info['columns'] as $column => $attributes) {
|
||||
$db_columns[$column] = $attributes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$columns = array();
|
||||
$db_fields = array();
|
||||
$arguments = array();
|
||||
$filters = array();
|
||||
foreach ($db_columns as $column => $attributes) {
|
||||
$columns[] = $column;
|
||||
$db_fields[] = $attributes['column'];
|
||||
$sorts[] = !empty($attributes['sortable']) ? TRUE : FALSE;
|
||||
|
||||
// Identify likely filters and arguments for each column based on field type.
|
||||
switch ($attributes['type']) {
|
||||
case 'int':
|
||||
case 'mediumint':
|
||||
case 'tinyint':
|
||||
case 'bigint':
|
||||
case 'serial':
|
||||
$filters[] = 'content_handler_filter_numeric';
|
||||
$arguments[] = 'content_handler_argument_numeric';
|
||||
break;
|
||||
case 'numeric':
|
||||
case 'float':
|
||||
$filters[] = 'content_handler_filter_float';
|
||||
$arguments[] = 'content_handler_argument_numeric';
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
case 'blob':
|
||||
// TODO add markup handlers for these types
|
||||
default:
|
||||
$filters[] = 'content_handler_filter_string';
|
||||
$arguments[] = 'content_handler_argument_string';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Provide automatic filters, sorts, and arguments for each column, not just the first.
|
||||
$db_fields_count = count($db_fields);
|
||||
foreach ($db_fields as $i => $db_field) {
|
||||
$label_truncated = truncate_utf8(t($field['widget']['label']), 10, TRUE);
|
||||
if ($db_fields_count == 1) {
|
||||
$title = t('@label (!name)', array('@label' => t($field['widget']['label']), '!name' => $field['field_name']));
|
||||
$title_short = check_plain($label_truncated);
|
||||
}
|
||||
else {
|
||||
$title = t('@label (!name) - !column', array('@label' => t($field['widget']['label']), '!name' => $field['field_name'], '!column' => $columns[$i]));
|
||||
$title_short = t('@label-truncated - !column', array('@label-truncated' => $label_truncated, '!column' => $columns[$i]));
|
||||
}
|
||||
|
||||
$data[$db_field] = array(
|
||||
'group' => t('Content'),
|
||||
'title' => $title,
|
||||
'title short' => $title_short,
|
||||
'help' => t($field_types[$field['type']]['label']) .' - '. t('Appears in: @types', array('@types' => implode(', ', $types))),
|
||||
);
|
||||
if ($i == 0) {
|
||||
$data[$db_field]['field'] = array(
|
||||
'title' => t('@label (!name)', array('@label' => t($field['widget']['label']), '!name' => $field['field_name'])),
|
||||
'title short' => check_plain($label_truncated),
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => 'content_handler_field_multiple',
|
||||
'click sortable' => $sorts[$i],
|
||||
'additional fields' => $additional_fields,
|
||||
'content_field_name' => $field['field_name'],
|
||||
'access callback' => 'content_access',
|
||||
'access arguments' => array('view', $field),
|
||||
);
|
||||
}
|
||||
$data[$db_field]['argument'] = array(
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => $arguments[$i],
|
||||
'additional fields' => $additional_fields,
|
||||
'content_field_name' => $field['field_name'],
|
||||
'empty field name' => t('<No value>'),
|
||||
);
|
||||
$data[$db_field]['filter'] = array(
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => $filters[$i],
|
||||
'additional fields' => $additional_fields,
|
||||
'content_field_name' => $field['field_name'],
|
||||
'allow empty' => TRUE,
|
||||
);
|
||||
if (!empty($sorts[$i])) {
|
||||
$data[$db_field]['sort'] = array(
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => 'content_handler_sort',
|
||||
'additional fields' => $additional_fields,
|
||||
'content_field_name' => $field['field_name'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Expose additional delta column for multiple value fields.
|
||||
if ($field['multiple']) {
|
||||
$title = t('@label (!name) - delta', array('@label' => t($field['widget']['label']), '!name' => $field['field_name']));
|
||||
$title_short = t('@label-truncated - delta', array('@label-truncated' => $label_truncated));
|
||||
|
||||
$db_field = 'delta';
|
||||
$data[$db_field] = array(
|
||||
'group' => t('Content'),
|
||||
'title' => $title,
|
||||
'title short' => $title_short,
|
||||
'help' => t('Delta - Appears in: @types', array('@types' => implode(', ', $types))),
|
||||
);
|
||||
$data[$db_field]['field'] = array(
|
||||
'title' => $title,
|
||||
'title short' => $title_short,
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => 'views_handler_field_numeric',
|
||||
'click sortable' => TRUE,
|
||||
'additional fields' => $additional_fields,
|
||||
'access callback' => 'content_access',
|
||||
'access arguments' => array('view', $field),
|
||||
);
|
||||
$data[$db_field]['argument'] = array(
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => 'views_handler_argument_numeric',
|
||||
'additional fields' => $additional_fields,
|
||||
'empty field name' => t('<No value>'),
|
||||
);
|
||||
$data[$db_field]['filter'] = array(
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => 'views_handler_filter_numeric',
|
||||
'additional fields' => $additional_fields,
|
||||
'allow empty' => TRUE,
|
||||
);
|
||||
$data[$db_field]['sort'] = array(
|
||||
'field' => $db_field,
|
||||
'table' => $db_info['table'],
|
||||
'handler' => 'views_handler_sort',
|
||||
'additional fields' => $additional_fields,
|
||||
);
|
||||
}
|
||||
|
||||
return array($table_alias => $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function so it is possible to change the Views tablename
|
||||
* in the future without re-writing code.
|
||||
*/
|
||||
function content_views_tablename($field) {
|
||||
return 'node_data_'. $field['field_name'];
|
||||
}
|
||||
|
||||
function theme_content_view_multiple_field($items, $field, $values) {
|
||||
$output = '';
|
||||
$i = 0;
|
||||
foreach ($items as $item) {
|
||||
if (!empty($item) || $item == '0') {
|
||||
$output .= '<div class="field-item field-item-'. $i .'">'. $item .'</div>';
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
71
modules/cck/includes/views/content.views_convert.inc
Normal file
71
modules/cck/includes/views/content.views_convert.inc
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Field conversion for fields handled by this module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_views_convert().
|
||||
*
|
||||
* Intervene to convert field values from the Views 1 format to the
|
||||
* Views 2 format. Intervene only if $view->add_item() won't produce
|
||||
* the right results, usually needed to set field options or values.
|
||||
*/
|
||||
function content_views_convert($display, $type, &$view, $views_field) {
|
||||
static $views_fields;
|
||||
|
||||
if (empty($views_fields)) {
|
||||
$views_fields = array();
|
||||
$types = content_types();
|
||||
foreach ($types as $ctype) {
|
||||
foreach ($ctype['fields'] as $field) {
|
||||
$module = $field['module'];
|
||||
$result = (array) module_invoke($module, 'field_settings', 'views data', $field);
|
||||
drupal_alter('field_settings', $result, 'views data', $field);
|
||||
if (empty($result)) {
|
||||
// The views field name had the column name appended,
|
||||
// like field_name_value or field_username_uid.
|
||||
$column = array_shift(array_keys($field['columns']));
|
||||
$views_fields[$field['field_name'] .'_'. $column] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is this a field that CCK should handle? If not, return.
|
||||
if (!in_array($views_field['field'], array_keys($views_fields))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now update values, options, etc. to those selected in the imported view.
|
||||
switch ($type) {
|
||||
case 'field':
|
||||
$view->display[$display]->display_options['fields'][$views_field['field']]['format'] = $views_field['options'];
|
||||
if ($views_field['handler'] == 'content_views_field_handler_group') {
|
||||
$view->display[$display]->display_options['fields'][$views_field['field']]['multiple']['group'] = 1;
|
||||
}
|
||||
else {
|
||||
$view->display[$display]->display_options['fields'][$views_field['field']]['multiple']['group'] = 0;
|
||||
}
|
||||
return;
|
||||
|
||||
case 'filter':
|
||||
// TODO
|
||||
return;
|
||||
|
||||
case 'exposed_filter':
|
||||
// TODO
|
||||
return;
|
||||
|
||||
case 'argument':
|
||||
// TODO
|
||||
return;
|
||||
|
||||
case 'sort':
|
||||
// TODO
|
||||
break;
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass simply adds properties,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*/
|
||||
class content_handler_argument extends views_handler_argument {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Handler for 'content_handler_argument_many_to_one' style.
|
||||
*/
|
||||
class content_handler_argument_many_to_one extends views_handler_argument_many_to_one {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
|
||||
function summary_name($data) {
|
||||
$options = $this->allowed_values();
|
||||
$value = $data->{$this->name_alias};
|
||||
if (isset($options[$value])) {
|
||||
$value = $options[$value];
|
||||
}
|
||||
else {
|
||||
$value = parent::summary_name($data);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
function title_query() {
|
||||
$options = $this->allowed_values();
|
||||
$values = $this->value;
|
||||
foreach ($values as $key => $value) {
|
||||
if (isset($options[$value])) {
|
||||
$values[$key] = $options[$value];
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
function allowed_values() {
|
||||
$field = $this->content_field;
|
||||
$function = $field['module'] .'_allowed_values';
|
||||
$options = function_exists($function) ? $function($field) : content_allowed_values($field);
|
||||
return (array) $options;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass simply adds properties,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*/
|
||||
class content_handler_argument_numeric extends views_handler_argument_numeric {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provide handler to replace reference with title.
|
||||
*/
|
||||
class content_handler_argument_reference extends content_handler_argument_numeric {
|
||||
/**
|
||||
* Override the behavior of title().
|
||||
*/
|
||||
function title_query() {
|
||||
$titles = array();
|
||||
$placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
|
||||
|
||||
$table_data = views_fetch_data($this->name_table);
|
||||
$table = array_shift($table_data['table']['join']);
|
||||
|
||||
$result = db_query("SELECT $this->name_field AS title FROM {". $table['table'] ."} WHERE ". $table['field'] ." IN ($placeholders)", $this->value);
|
||||
while ($row = db_fetch_object($result)) {
|
||||
$titles[] = check_plain($row->title);
|
||||
}
|
||||
return $titles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass simply adds properties,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*/
|
||||
class content_handler_argument_string extends views_handler_argument_string {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
}
|
228
modules/cck/includes/views/handlers/content_handler_field.inc
Normal file
228
modules/cck/includes/views/handlers/content_handler_field.inc
Normal file
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass adds basic field and formatter info,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*
|
||||
* Fields could extend this class if they want field and formatter handling
|
||||
* but don't want the multiple value grouping options created by
|
||||
* content_handler_field_multiple.
|
||||
*/
|
||||
class content_handler_field extends views_handler_field_node {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
}
|
||||
|
||||
function init(&$view, $options) {
|
||||
$field = $this->content_field;
|
||||
parent::init($view, $options);
|
||||
if ($field['multiple']) {
|
||||
$this->additional_fields['delta'] = 'delta';
|
||||
}
|
||||
// Make sure we grab enough information to build a pseudo-node with enough
|
||||
// credentials at render-time.
|
||||
$this->additional_fields['type'] = array('table' => 'node', 'field' => 'type');
|
||||
$this->additional_fields['nid'] = array('table' => 'node', 'field' => 'nid');
|
||||
$this->additional_fields['vid'] = array('table' => 'node', 'field' => 'vid');
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$field = $this->content_field;
|
||||
|
||||
// Override views_handler_field_node's default label
|
||||
$options['label'] = array('default' => '', 'translatable' => TRUE);
|
||||
$options['label_type'] = array('default' => 'widget');
|
||||
$options['format'] = array('default' => 'default');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide formatter option.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
// TODO: do we want the 'link to node' checkbox ?
|
||||
// That's usually formatters business...
|
||||
|
||||
$field = $this->content_field;
|
||||
$options = $this->options;
|
||||
|
||||
$form['label_type'] = array(
|
||||
'#title' => t('Label'),
|
||||
'#type' => 'radios',
|
||||
'#options' => array(
|
||||
'none' => t('None'),
|
||||
'widget' => t('Widget label (@label)', array('@label' => $field['widget']['label'])),
|
||||
'custom' => t('Custom'),
|
||||
),
|
||||
'#default_value' => $options['label_type'],
|
||||
'#weight' => 2,
|
||||
);
|
||||
$form['label'] = array(
|
||||
'#title' => t('Custom label'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $options['label'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('radio:options[label_type]' => array('custom')),
|
||||
'#weight' => 3,
|
||||
);
|
||||
|
||||
$field_types = _content_field_types();
|
||||
$formatters = array();
|
||||
if (is_array($field_types[$field['type']]['formatters'])) {
|
||||
foreach ($field_types[$field['type']]['formatters'] as $name => $info) {
|
||||
$formatters[$name] = $info['label'];
|
||||
}
|
||||
}
|
||||
$form['format'] = array(
|
||||
'#title' => t('Format'),
|
||||
'#type' => 'select',
|
||||
'#options' => $formatters,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $options['format'],
|
||||
'#weight' => 4,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure some value is stored as a label.
|
||||
*
|
||||
* Don't use t(), since Views' views_handler_field already has
|
||||
* $this->options['label'] marked as a translatable field.
|
||||
*
|
||||
* @see http://drupal.org/node/285470
|
||||
*/
|
||||
function options_submit($form, &$form_state) {
|
||||
switch ($form_state['values']['options']['label_type']) {
|
||||
case 'none':
|
||||
$form_state['values']['options']['label'] = '';
|
||||
break;
|
||||
case 'widget':
|
||||
$form_state['values']['options']['label'] = $this->content_field['widget']['label'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* Now that we save the label in the submit process above we could
|
||||
* get rid of this function. Leave it here for now to be sure the
|
||||
* label works for fields that haven't been updated since this
|
||||
* change was made, since $this->options['label'] will be missing a
|
||||
* value until it is updated in the view.
|
||||
*
|
||||
* Don't use t(), since Views' views_handler_field already has
|
||||
* $this->options['label'] marked as a translatable field.
|
||||
*/
|
||||
function label() {
|
||||
$field = $this->content_field;
|
||||
switch ($this->options['label_type']) {
|
||||
case 'none':
|
||||
return '';
|
||||
case 'widget':
|
||||
return $field['widget']['label'];
|
||||
default:
|
||||
return $this->options['label'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DIV or SPAN based upon the field's element type.
|
||||
*/
|
||||
function element_type($none_supported = FALSE, $default_empty = FALSE) {
|
||||
// The 'element_type' property denotes Views 3.x ('semantic views'
|
||||
// functionnality). If the property is set, and not set to '' ("default"),
|
||||
// let the generic method handle the output.
|
||||
if (isset($this->options['element_type']) && $this->options['element_type'] !== '') {
|
||||
return parent::element_type($none_supported, $default_empty);
|
||||
}
|
||||
|
||||
if ($default_empty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (isset($this->definition['element type'])) {
|
||||
return $this->definition['element type'];
|
||||
}
|
||||
|
||||
// TODO Figure out exactly when to return a div or a <span>. Any field
|
||||
// that ever needs to be shown inline in Views UI. It needs to return
|
||||
// a div for textareas to prevent wrapping a <span> around a <p>.
|
||||
// Earl says we need to be sure that other fields we don't know
|
||||
// about won't end up wrapping a span around a block-level element.
|
||||
if ($this->content_field['widget']['type'] == 'text_textarea') {
|
||||
return 'div';
|
||||
}
|
||||
else {
|
||||
return 'span';
|
||||
}
|
||||
}
|
||||
|
||||
function options_validate($form, &$form_state) { }
|
||||
|
||||
/**
|
||||
* Provide text for the administrative summary
|
||||
*/
|
||||
function admin_summary() {
|
||||
// Display the formatter name.
|
||||
$field = $this->content_field;
|
||||
$field_types = _content_field_types();
|
||||
if (isset($field_types[$field['type']]['formatters'][$this->options['format']])) {
|
||||
return t($field_types[$field['type']]['formatters'][$this->options['format']]['label']);
|
||||
}
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
// We're down to a single node here, so we can retrieve the actual field
|
||||
// definition for the node type being considered.
|
||||
$field = content_fields($this->content_field['field_name'], $values->{$this->aliases['type']});
|
||||
|
||||
// If the field does not appear in the node type, then we have no value
|
||||
// to display, and can just return.
|
||||
if (empty($field)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$options = $this->options;
|
||||
$db_info = content_database_info($field);
|
||||
|
||||
// Build a pseudo-node from the retrieved values.
|
||||
$node = drupal_clone($values);
|
||||
$node->type = $values->{$this->aliases['type']};
|
||||
$node->nid = $values->{$this->aliases['nid']};
|
||||
$node->vid = $values->{$this->aliases['vid']};
|
||||
// Some formatters need to behave differently depending on the build_mode
|
||||
// (for instance: preview), so we provide one.
|
||||
$node->build_mode = NODE_BUILD_NORMAL;
|
||||
|
||||
$item = array();
|
||||
foreach ($db_info['columns'] as $column => $attributes) {
|
||||
$item[$column] = $values->{$this->aliases[$attributes['column']]};
|
||||
}
|
||||
|
||||
$item['#delta'] = $field['multiple'] ? $values->{$this->aliases['delta']} : 0;
|
||||
|
||||
// Render items.
|
||||
$formatter_name = $options['format'];
|
||||
if ($formatter = _content_get_formatter($formatter_name, $field['type'])) {
|
||||
if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
|
||||
// Single-value formatter.
|
||||
$output = content_format($field, $item, $formatter_name, $node);
|
||||
}
|
||||
else {
|
||||
// Multiple values formatter - we actually have only one value to display.
|
||||
$output = content_format($field, array($item), $formatter_name, $node);
|
||||
}
|
||||
return $this->render_link($output, $values);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* An extended subclass for field handling that adds multiple field grouping.
|
||||
*
|
||||
* Fields that want multiple value grouping options in addition to basic
|
||||
* field and formatter handling can extend this class.
|
||||
*/
|
||||
class content_handler_field_multiple extends content_handler_field {
|
||||
var $defer_query;
|
||||
|
||||
function init(&$view, $options) {
|
||||
$field = $this->content_field;
|
||||
parent::init($view, $options);
|
||||
|
||||
$this->defer_query = !empty($options['multiple']['group']) && $field['multiple'];
|
||||
|
||||
if ($this->defer_query) {
|
||||
// Grouped field: ditch the existing additional_fields (field columns + delta).
|
||||
// In the main query we'll only need:
|
||||
// - vid, which will be used to retrieve the actual values in pre_render,
|
||||
// - node type and nid, which wil be used in the pseudo-node used when
|
||||
// rendering.
|
||||
$this->additional_fields = array(
|
||||
'type' => array('table' => 'node', 'field' => 'type'),
|
||||
'nid' => array('table' => 'node', 'field' => 'nid'),
|
||||
);
|
||||
if ($view->base_table == 'node_revisions') {
|
||||
$this->additional_fields['vid'] = array('table' => 'node_revisions', 'field' => 'vid');
|
||||
}
|
||||
else {
|
||||
$this->additional_fields['vid'] = array('table' => 'node', 'field' => 'vid');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['multiple'] = array(
|
||||
'contains' => array(
|
||||
'group' => array('default' => TRUE),
|
||||
'multiple_number' => array('default' => ''),
|
||||
'multiple_from' => array('default' => ''),
|
||||
'multiple_reversed' => array('default' => FALSE),
|
||||
),
|
||||
);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide 'group multiple values' option.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
$field = $this->content_field;
|
||||
$options = $this->options;
|
||||
|
||||
$form['multiple'] = array(
|
||||
'#access' => $field['multiple'],
|
||||
'#weight' => 1,
|
||||
);
|
||||
$form['multiple']['group'] = array(
|
||||
'#title' => t('Group multiple values'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $options['multiple']['group'],
|
||||
'#description' => t('If unchecked, each item in the field will create a new row, which may appear to cause duplicates. This setting is not compatible with click-sorting in table displays.'),
|
||||
);
|
||||
// Make the string translatable by keeping it as a whole rather than
|
||||
// translating prefix and suffix separately.
|
||||
list($prefix, $suffix) = explode('@count', t('Show @count value(s)'));
|
||||
$form['multiple']['multiple_number'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 5,
|
||||
'#field_prefix' => $prefix,
|
||||
'#field_suffix' => $suffix,
|
||||
'#default_value' => $options['multiple']['multiple_number'],
|
||||
'#prefix' => '<div class="container-inline">',
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-multiple-group' => array(TRUE)),
|
||||
);
|
||||
list($prefix, $suffix) = explode('@count', t('starting from @count'));
|
||||
$form['multiple']['multiple_from'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 5,
|
||||
'#field_prefix' => $prefix,
|
||||
'#field_suffix' => $suffix,
|
||||
'#default_value' => $options['multiple']['multiple_from'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-multiple-group' => array(TRUE)),
|
||||
'#description' => t('(first item is 0)'),
|
||||
);
|
||||
$form['multiple']['multiple_reversed'] = array(
|
||||
'#title' => t('Reversed'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $options['multiple']['multiple_reversed'],
|
||||
'#suffix' => '</div>',
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-multiple-group' => array(TRUE)),
|
||||
'#description' => t('(start from last values)'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this field is click sortable.
|
||||
*/
|
||||
function click_sortable() {
|
||||
$field = $this->content_field;
|
||||
$options = $this->options;
|
||||
|
||||
// Grouped fields are not click-sortable.
|
||||
return !empty($this->definition['click sortable']) && !$this->defer_query;
|
||||
}
|
||||
|
||||
function query() {
|
||||
// If this is not a grouped field, use the generic query().
|
||||
if (!$this->defer_query) {
|
||||
return parent::query();
|
||||
}
|
||||
|
||||
// Grouped field: do NOT call ensure_my_table, only add additional fields.
|
||||
$this->add_additional_fields();
|
||||
$this->field_alias = $this->aliases['vid'];
|
||||
}
|
||||
|
||||
function pre_render($values) {
|
||||
// If there are no values to render (displaying a summary, or query returned no results),
|
||||
// or if this is not a grouped field, do nothing specific.
|
||||
if (isset($this->view->build_info['summary']) || empty($values) || !$this->defer_query) {
|
||||
return parent::pre_render($values);
|
||||
}
|
||||
|
||||
$field = $this->content_field;
|
||||
$db_info = content_database_info($field);
|
||||
$options = $this->options;
|
||||
|
||||
// Build the list of vids to retrieve.
|
||||
// TODO: try fetching from cache_content first ??
|
||||
$vids = array();
|
||||
$this->field_values = array();
|
||||
foreach ($values as $result) {
|
||||
if (isset($result->{$this->field_alias})) {
|
||||
$vids[] = $result->{$this->field_alias};
|
||||
}
|
||||
}
|
||||
|
||||
// It may happend that the multiple values field is related to a non
|
||||
// required relation for which no node data related to the field being
|
||||
// processed here is available.
|
||||
if (empty($vids)) {
|
||||
return parent::pre_render($values);
|
||||
}
|
||||
|
||||
// List columns to retrieve.
|
||||
$alias = content_views_tablename($field);
|
||||
// Prefix aliases with '_' to avoid clashing with field columns names.
|
||||
$query_columns = array(
|
||||
'vid AS _vid',
|
||||
"delta as _delta",
|
||||
// nid is needed to generate the links for 'link to node' option.
|
||||
'nid AS _nid',
|
||||
);
|
||||
// The actual field columns.
|
||||
foreach ($db_info['columns'] as $column => $attributes) {
|
||||
$query_columns[] = "$attributes[column] AS $column";
|
||||
}
|
||||
$query = 'SELECT '. implode(', ', $query_columns) .
|
||||
' FROM {'. $db_info['table'] ."}".
|
||||
" WHERE vid IN (". implode(',', $vids) .')'.
|
||||
" ORDER BY _nid ASC, _delta ". ($options['multiple']['multiple_reversed'] ? 'DESC' : 'ASC');
|
||||
$result = db_query($query);
|
||||
|
||||
while ($item = db_fetch_array($result)) {
|
||||
// Clean up the $item from vid and delta. We keep nid for now.
|
||||
$vid = $item['_vid'];
|
||||
unset($item['_vid']);
|
||||
$delta = !empty($item['_delta']) ? $item['_delta'] : 0;
|
||||
$item['#delta'] = $item['_delta'];
|
||||
unset($item['_delta']);
|
||||
$this->field_values[$vid][$delta] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DIV or SPAN based upon the field's element type.
|
||||
*
|
||||
* Fields rendered with the 'group multiple' option use <div> markers,
|
||||
* and thus shouldn't be wrapped in a <span>.
|
||||
*/
|
||||
function element_type($none_supported = FALSE, $default_empty = FALSE) {
|
||||
// If this is not a grouped field, use the parent method.
|
||||
if (!$this->defer_query) {
|
||||
return parent::element_type($none_supported, $default_empty);
|
||||
}
|
||||
|
||||
// The 'element_type' property denotes Views 3.x ('semantic views'
|
||||
// functionnality). If the property is set, and not set to '' ("default"),
|
||||
// let the generic method handle the output.
|
||||
if (isset($this->options['element_type']) && $this->options['element_type'] !== '') {
|
||||
return parent::element_type($none_supported, $default_empty);
|
||||
}
|
||||
|
||||
if ($default_empty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (isset($this->definition['element type'])) {
|
||||
return $this->definition['element type'];
|
||||
}
|
||||
|
||||
return 'div';
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
// If this is not a grouped field, use content_handler_field::render().
|
||||
if (!$this->defer_query) {
|
||||
return parent::render($values);
|
||||
}
|
||||
|
||||
// We're down to a single node here, so we can retrieve the actual field
|
||||
// definition for the node type being considered.
|
||||
$field = content_fields($this->content_field['field_name'], $values->{$this->aliases['type']});
|
||||
|
||||
// If the field does not appear in the node type, then we have no value
|
||||
// to display, and can just return.
|
||||
if (empty($field)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$options = $this->options;
|
||||
|
||||
$vid = $values->{$this->field_alias};
|
||||
if (isset($this->field_values[$vid])) {
|
||||
// Gather items, respecting the 'Display n values starting from m' settings.
|
||||
$count_skipped = 0;
|
||||
$items = array();
|
||||
foreach ($this->field_values[$vid] as $item) {
|
||||
if (empty($options['multiple']['multiple_from']) || ($count_skipped >= $options['multiple']['multiple_from'])) {
|
||||
if (empty($options['multiple']['multiple_number']) || (count($items) < $options['multiple']['multiple_number'])) {
|
||||
// Grab the nid - needed for render_link().
|
||||
$nid = $item['_nid'];
|
||||
unset($item['_nid']);
|
||||
$items[] = $item;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$count_skipped++;
|
||||
}
|
||||
|
||||
// Build a pseudo-node from the retrieved values.
|
||||
$node = drupal_clone($values);
|
||||
// content_format and formatters will need a 'type'.
|
||||
$node->type = $values->{$this->aliases['type']};
|
||||
$node->nid = $values->{$this->aliases['nid']};
|
||||
$node->vid = $values->{$this->aliases['vid']};
|
||||
|
||||
// Some formatters need to behave differently depending on the build_mode
|
||||
// (for instance: preview), so we provide one.
|
||||
$node->build_mode = NODE_BUILD_NORMAL;
|
||||
|
||||
// Render items.
|
||||
$formatter_name = $options['format'];
|
||||
if ($items && ($formatter = _content_get_formatter($formatter_name, $field['type']))) {
|
||||
$rendered = array();
|
||||
if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
|
||||
// Single-value formatter.
|
||||
foreach ($items as $item) {
|
||||
$output = content_format($field, $item, $formatter_name, $node);
|
||||
if (!empty($output)) {
|
||||
$rendered[] = $this->render_link($output, (object) array('nid' => $nid));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Multiple values formatter.
|
||||
$output = content_format($field, $items, $formatter_name, $values);
|
||||
if (!empty($output)) {
|
||||
$rendered[] = $this->render_link($output, (object) array('nid' => $nid));
|
||||
}
|
||||
}
|
||||
|
||||
if (count($rendered) > 1) {
|
||||
// TODO: could we use generic field display ?
|
||||
return theme('content_view_multiple_field', $rendered, $field, $values);
|
||||
}
|
||||
elseif ($rendered) {
|
||||
return $rendered[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function render_link($data, $values) {
|
||||
if (!$this->defer_query) {
|
||||
return parent::render_link($data, $values);
|
||||
}
|
||||
|
||||
if (!empty($this->options['link_to_node']) && $data !== NULL && $data !== '') {
|
||||
if (method_exists('render_as_link', 'views_handler_field')) {
|
||||
// Views 2.3+
|
||||
$this->options['alter']['make_link'] = TRUE;
|
||||
$this->options['alter']['path'] = "node/" . $values->{$this->aliases['nid']};
|
||||
}
|
||||
else {
|
||||
// Views up to 2.2
|
||||
return l($data, "node/" . $values->nid, array('html' => TRUE));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass simply adds properties,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*/
|
||||
|
||||
// Ensure compatibility with Views pre 2.4, where the
|
||||
// views_handler_filter_float class lived in views_handler_filter_numeric.inc.
|
||||
if (!class_exists('views_handler_filter_float')) {
|
||||
// Manually include the parent class.
|
||||
$definition = views_fetch_handler_data('views_handler_filter_numeric');
|
||||
views_include_handler($definition, 'handler');
|
||||
}
|
||||
|
||||
class content_handler_filter_float extends views_handler_filter_float {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass simply adds properties,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*/
|
||||
class content_handler_filter_many_to_one extends views_handler_filter_many_to_one {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
$field = $this->content_field;
|
||||
$this->value_title = $field['widget']['label'];
|
||||
}
|
||||
|
||||
function get_value_options() {
|
||||
$this->value_options = $this->allowed_values();
|
||||
}
|
||||
|
||||
// Get allowed values from hook_allowed_values(), if any,
|
||||
// or from content_allowed_values();
|
||||
function allowed_values() {
|
||||
$field = $this->content_field;
|
||||
$function = $field['module'] .'_allowed_values';
|
||||
if ($this->value_form_type == 'select') {
|
||||
// Select elements accept multidimensional arrays to support optgroups.
|
||||
$options = function_exists($function) ? $function($field) : content_allowed_values($field, FALSE);
|
||||
// For selects, HTML should be filtered out and entities left unencoded.
|
||||
// See content_allowed_values / content_filter_xss / filter_xss.
|
||||
content_allowed_values_filter_html($options);
|
||||
}
|
||||
else {
|
||||
$options = function_exists($function) ? $function($field) : content_allowed_values($field);
|
||||
}
|
||||
return (array) $options;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass simply adds properties,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*/
|
||||
class content_handler_filter_numeric extends views_handler_filter_numeric {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The subclass simply adds properties,
|
||||
* for field-specific subclasses to use if they need to.
|
||||
*/
|
||||
class content_handler_filter_string extends views_handler_filter_string {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Handles content relationships and deals properly with multiple
|
||||
* values by allowing the views administrator to select deltas.
|
||||
*/
|
||||
class content_handler_relationship extends views_handler_relationship {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['delta'] = array('default' => -1);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a delta selector for multiple fields.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
$field = $this->content_field;
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
// Only add the form gadget if the field is multiple.
|
||||
if ($field['multiple']) {
|
||||
$max_delta = $field['multiple'];
|
||||
// 1 means unlimited.
|
||||
if ($max_delta == 1) {
|
||||
$max_delta = 10;
|
||||
}
|
||||
|
||||
$options = array('-1' => t('All'));
|
||||
for ($i = 0; $i < $max_delta; $i++) {
|
||||
$options[$i] = $i + 1;
|
||||
}
|
||||
$form['delta'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
'#default_value' => $this->options['delta'],
|
||||
'#title' => t('Delta'),
|
||||
'#description' => t('The delta allows you to select which item in a multiple value field to key the relationship off of. Select "1" to use the first item, "2" for the second item, and so on. If you select "All", each item in the field will create a new row, which may appear to cause duplicates.'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function ensure_my_table() {
|
||||
if (!isset($this->table_alias)) {
|
||||
$join = $this->get_join();
|
||||
if (!isset($join->extra)) {
|
||||
$join->extra = array();
|
||||
}
|
||||
$delta = isset($this->options['delta']) ? $this->options['delta'] : -1;
|
||||
if ($delta != -1) {
|
||||
$join->extra[] = array(
|
||||
'field' => 'delta',
|
||||
'value' => $delta,
|
||||
'numeric' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
$this->table_alias = $this->query->add_table($this->table, $this->relationship, $join);
|
||||
}
|
||||
return $this->table_alias;
|
||||
}
|
||||
}
|
73
modules/cck/includes/views/handlers/content_handler_sort.inc
Normal file
73
modules/cck/includes/views/handlers/content_handler_sort.inc
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Handles sorts and deals properly with multiple
|
||||
* values by allowing the views administrator to select deltas.
|
||||
*/
|
||||
class content_handler_sort extends views_handler_sort {
|
||||
var $content_field;
|
||||
|
||||
function construct() {
|
||||
parent::construct();
|
||||
|
||||
$this->content_field = content_fields($this->definition['content_field_name']);
|
||||
$this->additional_fields = $this->definition['additional fields'];
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['delta'] = array('default' => -1);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a delta selector for multiple fields.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
$field = $this->content_field;
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
// Only add the form gadget if the field is multiple.
|
||||
if ($field['multiple']) {
|
||||
$max_delta = $field['multiple'];
|
||||
// 1 means unlimited.
|
||||
if ($max_delta == 1) {
|
||||
$max_delta = 10;
|
||||
}
|
||||
|
||||
$options = array('-1' => t('All'));
|
||||
for ($i = 0; $i < $max_delta; $i++) {
|
||||
$options[$i] = $i + 1;
|
||||
}
|
||||
$form['delta'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
'#default_value' => $this->options['delta'],
|
||||
'#title' => t('Delta'),
|
||||
'#description' => t('The delta allows you to select which item in a multiple value field will be used for sorting. Select "1" to use the first item, "2" for the second item, and so on. If you select "All", each item in the field will create a new row, which may appear to cause duplicates.'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function ensure_my_table() {
|
||||
if (!isset($this->table_alias)) {
|
||||
$join = $this->get_join();
|
||||
if (!isset($join->extra)) {
|
||||
$join->extra = array();
|
||||
}
|
||||
$delta = isset($this->options['delta']) ? $this->options['delta'] : -1;
|
||||
if ($delta != -1) {
|
||||
$join->extra[] = array(
|
||||
'field' => 'delta',
|
||||
'value' => $delta,
|
||||
'numeric' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
$this->table_alias = $this->query->ensure_table($this->table, $this->relationship, $join);
|
||||
}
|
||||
return $this->table_alias;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Handler for 'content_simple' display.
|
||||
*/
|
||||
class content_plugin_display_simple extends views_plugin_display {
|
||||
function execute() {
|
||||
return $this->view->render($this->display->id);
|
||||
}
|
||||
|
||||
function render() {
|
||||
return !empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty']) ? $this->view->style_plugin->render($this->view->result) : '';
|
||||
}
|
||||
|
||||
function uses_exposed() {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
class content_plugin_display_references extends content_plugin_display_simple {
|
||||
function query() {
|
||||
$options = $this->get_option('content_options');
|
||||
|
||||
if ($options['string'] !== '') {
|
||||
$like = $GLOBALS["db_type"] == 'pgsql' ? "ILIKE" : "LIKE";
|
||||
$match_clauses = array(
|
||||
'contains' => "$like '%%%s%%'",
|
||||
'equals' => "= '%s'",
|
||||
'starts_with' => "$like '%s%%'",
|
||||
);
|
||||
$clause = isset($match_clauses[$options['match']]) ? $match_clauses[$options['match']] : $match_clauses['contains'];
|
||||
$alias = $this->view->query->ensure_table($options['table']);
|
||||
$this->view->query->add_where(NULL, "$alias.$options[field_string] $clause", $options['string']);
|
||||
}
|
||||
elseif ($options['ids']) {
|
||||
$alias = $this->view->query->ensure_table($options['table']);
|
||||
$this->view->query->add_where(NULL, "$alias.$options[field_id] IN (" . db_placeholders($options['ids']) . ')', $options['ids']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Handler for 'content_php_array_autocomplete' style.
|
||||
*/
|
||||
class content_plugin_style_php_array_ac extends views_plugin_style {
|
||||
function render() {
|
||||
$results = array();
|
||||
|
||||
// Group the rows according to the grouping field, if specified.
|
||||
$sets = $this->render_grouping($this->view->result, $this->options['grouping']);
|
||||
|
||||
$base_field = $this->view->base_field;
|
||||
$title_field = $this->display->display_options['content_title_field'];
|
||||
$title_field_alias = $this->view->field[$title_field]->field_alias;
|
||||
|
||||
// TODO : We don't display grouping info for now.
|
||||
// Could be useful for select widget, though.
|
||||
$this->view->row_index = 0;
|
||||
foreach ($sets as $title => $records) {
|
||||
foreach ($records as $label => $row) {
|
||||
$results[$row->{$base_field}] = array(
|
||||
'title' => $row->{$title_field_alias},
|
||||
'rendered' => $this->row_plugin->render($row),
|
||||
);
|
||||
$this->view->row_index++;
|
||||
}
|
||||
}
|
||||
unset($this->view->row_index);
|
||||
return $results;
|
||||
}
|
||||
}
|
Reference in a new issue