Issue #1230398 fillowup by andypost: Fixed unset var *after* using it
[project/cck.git] / cck.module
CommitLineData
c573bbbd 1<?php
c573bbbd
KS
2/**
3 * @file
2d9c2350
KS
4 * Allows administrators to use php code snippets to
5 * define allowed values or default values. The snippets
6 * are stored in a database table and retrieved in
7 * callback functions.
c573bbbd
KS
8 */
9
10/**
c573bbbd
KS
11 * Implementation of hook_perm().
12 */
68d24e95 13function cck_permission() {
ecc284c7
YC
14 return array(
15 // TODO : simplify machine name and update existing perms ?
16 'Use PHP input for field settings (dangerous - grant with care)' => array(
17 'title' => t('Use PHP input for field settings'),
18 'description' => t('Enter PHP code in the field for the field settings that allow it. Warning: Give to trusted roles only; this permission has security implications.'),
19 ),
20 );
c573bbbd
KS
21}
22
23/**
78cc2178
KS
24 * Add fields to allowed values form to allow
25 * users to input a function or a PHP snippet
26 * that will return the allowed values.
c573bbbd 27 */
78cc2178
KS
28function cck_form_alter(&$form, $form_state, $form_id) {
29 switch ($form_id) {
30 case 'field_ui_field_settings_form':
31 $field = field_info_field($form['field']['field_name']['#value']);
32 if ($field['module'] == 'list') {
41d887a5
YC
33 // @todo : core should put that for us.
34 $form['#field'] = $field;
78cc2178 35 cck_allowed_values_form($form, $form_state, $field);
2d9c2350 36 $form['#validate'][] = 'cck_allowed_values_validate';
78cc2178
KS
37 }
38 break;
39 case 'field_ui_field_edit_form':
40 $field = $form['#field'];
41 if ($field['module'] == 'list') {
2d9c2350 42 cck_default_value_form($form, $form_state, $field);
78cc2178 43 cck_allowed_values_form($form, $form_state, $field);
2d9c2350
KS
44 $form['#validate'][] = 'cck_allowed_values_validate';
45 $form['#validate'][] = 'cck_default_value_validate';
78cc2178
KS
46 }
47 break;
48 }
c573bbbd
KS
49}
50
41e5083c
KS
51/**
52 * Add fields to allowed values form to allow
53 * users to input a function or a PHP snippet
54 * that will return the allowed values.
55 */
d5d3500b 56function cck_allowed_values_form(&$form, $form_state, $field) {
41e5083c
KS
57 $php_code = cck_field_get_setting('allowed_values_php', 'field', $field);
58 $allowed_values_function = $form['field']['settings']['allowed_values_function']['#value'];
59 if (!empty($php_code)) {
60 $allowed_values_function = 'cck_allowed_values_php';
61 }
d5d3500b 62
41e5083c
KS
63 // Add a field where users can specify some PHP
64 // code that will return the allowed values list.
41e5083c
KS
65 $form['field']['settings']['allowed_values_php'] = array(
66 '#access' => user_access('Use PHP input for field settings (dangerous - grant with care)'),
67 '#type' => 'textarea',
68 '#title' => t('Allowed values PHP code'),
69 '#default_value' => $php_code,
41d887a5
YC
70 '#description' => t('Advanced usage only: PHP code that returns an array of allowed values. Should not include &lt;?php ?&gt; delimiters. If this field is filled out, the value returned by this code will be used as the response to the function <strong>cck_allowed_values_php</strong> and will override any other allowed values list or function specified above. Expected format: <pre>!sample</pre>', array(
71 '!sample' => t("return array(\n value_1 => label_1,\n value_2 => label_2\n ...\n);"),
41e5083c 72 )),
41d887a5 73 '#weight' => 5,
41e5083c 74 );
d5d3500b 75
41d887a5
YC
76 // Add a field where users can specify a function
77 // to return the allowed values list.
78 $form['field']['settings']['allowed_values_function'] = array(
79 '#type' => 'textfield',
80 '#title' => t('Allowed values function'),
81 '#default_value' => $allowed_values_function,
82 '#description' => t('The name of a function that will return the allowed values list.'),
83 '#weight' => 6,
84 '#states' => array(
85 'visible' => array(
86 ':input[name="field[settings][allowed_values_php]"]' => array('empty' => TRUE),
87 ),
88 )
89 );
41e5083c
KS
90}
91
2d9c2350
KS
92/**
93 * Add fields to default value form to allow
94 * users to input a function or a PHP snippet
95 * that will return the default values.
96 */
d5d3500b 97function cck_default_value_form(&$form, $form_state, $field) {
2d9c2350 98 $instance = field_info_instance($form['instance']['entity_type']['#value'], $field['field_name'], $form['instance']['bundle']['#value']);
41d887a5
YC
99 $default_value_function = !empty($instance['default_value_function']) ? $instance['default_value_function'] : '';
100 $php_code = cck_field_get_setting('default_value_php', 'instance', $field, $instance);
2d9c2350
KS
101 if (!empty($php_code)) {
102 $default_value_function = 'cck_default_value_php';
103 }
d5d3500b 104
2d9c2350
KS
105 // Add a field where users can specify some PHP
106 // code that will return the default value.
01e7cc15 107 module_load_include('install', $field['module']);
d5d3500b
YC
108 $schema = module_invoke($field['module'], 'field_schema', $field);
109 $columns = array_keys($schema['columns']);
2d9c2350 110 $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)));
d5d3500b 111
2d9c2350
KS
112 $form['instance']['default_value_widget']['default_value_php'] = array(
113 '#access' => user_access('Use PHP input for field settings (dangerous - grant with care)'),
114 '#type' => 'textarea',
115 '#title' => t('Default value PHP code'),
116 '#default_value' => $php_code,
117 '#description' => t('Advanced usage only: PHP code that returns a default value. Should not include &lt;?php ?&gt; delimiters. If this field is filled out, the value returned by this code will be used as the response to the function <strong>cck_default_value_php</strong> and will override any other default value or function specified above. Expected format: <pre>!sample</pre>To figure out the expected format, you can use the <em>devel load</em> tab provided by <a href="@link_devel">devel module</a> on a content page.', array(
118 '!sample' => $sample,
119 '@link_devel' => 'http://www.drupal.org/project/devel',
120 )),
41d887a5
YC
121 '#weight' => 5,
122 '#parents' => array('instance', 'default_value_php'),
2d9c2350 123 );
d5d3500b 124
41d887a5
YC
125 // Add a field where users can specify a function
126 // to return the default value.
127 $form['instance']['default_value_widget']['default_value_function'] = array(
128 '#type' => 'textfield',
129 '#title' => t('Default value function'),
130 '#default_value' => $default_value_function,
131 '#description' => t('The name of a function that will return the default value.'),
132 '#states' => array(
133 'visible' => array(
134 ':input[name="instance[default_value_php]"]' => array('empty' => TRUE),
135 ),
136 ),
137 '#weight' => 6,
138 '#parents' => array('instance', 'default_value_function'),
139 );
2d9c2350
KS
140}
141
142/**
143 * Validation handler to store php allowed values.
144 */
41d887a5 145function cck_allowed_values_validate(&$form, &$form_state) {
d5d3500b
YC
146 $field = $form['#field'];
147
2d9c2350
KS
148 $php_code = $form_state['values']['field']['settings']['allowed_values_php'];
149 $allowed_values_function = $form_state['values']['field']['settings']['allowed_values_function'];
150 if (!empty($php_code)) {
151 $allowed_values_function = 'cck_allowed_values_php';
152 }
153 elseif (empty($php_code) && $allowed_values_function == 'cck_allowed_values_php') {
154 $allowed_values_function = '';
155 }
41d887a5
YC
156 form_set_value($form['field']['settings']['allowed_values_function'], $allowed_values_function, $form_state);
157 // @todo This should be done at submit time, not validate.
2d9c2350
KS
158 cck_field_set_setting('allowed_values_php', 'field', $php_code, $field);
159}
160
161/**
162 * Validation handler to store php default values.
163 */
41d887a5 164function cck_default_value_validate(&$form, &$form_state) {
d5d3500b
YC
165 $field = $form['#field'];
166 $instance = $form['#instance'];
167
2d9c2350 168 $default_value_function = $form_state['values']['instance']['default_value_function'];
41d887a5 169 $php_code = $form_state['values']['instance']['default_value_php'];
2d9c2350
KS
170 if (!empty($php_code)) {
171 $default_value_function = 'cck_default_value_php';
172 }
173 elseif (empty($php_code) && $default_value_function == 'cck_default_value_php') {
174 $default_value_function = '';
175 }
41d887a5
YC
176 form_set_value($form['instance']['default_value_widget']['default_value_function'], $default_value_function, $form_state);
177 // @todo This should be done at submit time, not validate.
d5d3500b 178 cck_field_set_setting('default_value_php', 'instance', $php_code, $field, $instance);
2d9c2350
KS
179}
180
181
c573bbbd 182function cck_debug_field_info() {
8376bb8b 183 if (function_exists('dsm')) {
de7b1259
YC
184 module_load_include('inc', 'field', 'field.info');
185 dsm(_field_info_collate_types());
186 dsm(_field_info_collate_fields());
187 return '';
188 }
189 else {
190 return t('You need to enable devel.module to see this page');
191 }
c573bbbd
KS
192}
193
194/**
c6189ea2
KS
195 * We store all settings in a flat text field, but some settings
196 * will be arrays that need to be serialized and unserialized,
197 * like the default_value.
198 */
199function cck_serialized_settings() {
200 return array('default_value');
201}
202
203/**
204 * Helper function to retrieve field settings stored by CCK.
fda5a014 205 *
c6189ea2
KS
206 * CCK uses the 'cck_field_settings' table to store custom settings
207 * not used by core.
fda5a014 208 *
99d33fb1 209 * Field settings will have no $instance nor a db bundle column.
c6189ea2 210 */
b338b91f 211function cck_field_get_setting($setting, $setting_type, $field, $instance = NULL, $langcode = LANGUAGE_NONE) {
99d33fb1
KS
212 if ($setting_type == 'field' || empty($instance)) {
213 $value = db_select('cck_field_settings', 'fs')->fields('fs', array('setting_option'))
78cc2178 214 ->condition('fs.field_name', $field['field_name'])
99d33fb1
KS
215 ->condition('fs.setting', $setting)
216 ->condition('fs.setting_type', $setting_type)
fda5a014 217 ->execute()->fetchField();
99d33fb1
KS
218 }
219 else {
220 $value = db_select('cck_field_settings', 'fs')->fields('fs', array('setting_option'))
99d33fb1 221 ->condition('fs.field_name', $field['field_name'])
78cc2178 222 ->condition('fs.entity_type', $instance['entity_type'])
99d33fb1 223 ->condition('fs.bundle', $instance['bundle'])
b338b91f 224 ->condition('fs.language', $langcode)
78cc2178
KS
225 ->condition('fs.setting', $setting)
226 ->condition('fs.setting_type', $setting_type)
99d33fb1
KS
227 ->execute()->fetchField();
228 }
fda5a014 229
c6189ea2
KS
230 if (in_array($setting, cck_serialized_settings())) {
231 $value = unserialize($value);
232 }
233 return $value;
234}
235
236/**
237 * Helper function to set field settings stored by CCK.
fda5a014 238 *
c6189ea2
KS
239 * CCK uses the 'cck_field_settings' table to store custom settings
240 * not used by core.
fda5a014 241 *
99d33fb1 242 * Field settings will have no $instance nor a db bundle column.
c6189ea2 243 */
b338b91f 244function cck_field_set_setting($setting, $setting_type, $value, $field, $instance = NULL, $langcode = LANGUAGE_NONE) {
c6189ea2 245 // Delete any prior values.
99d33fb1 246 $bundle = ($setting_type == 'field' || empty($instance)) ? NULL : $instance['bundle'];
a8397343 247 $entity_type = ($setting_type == 'field' || empty($instance)) ? NULL : $instance['entity_type'];
99d33fb1
KS
248 if ($setting_type == 'field' || empty($instance)) {
249 db_delete('cck_field_settings')
250 ->condition('field_name', $field['field_name'])
251 ->condition('setting', $setting)
252 ->condition('setting_type', $setting_type)
253 ->execute();
254 }
255 else {
256 db_delete('cck_field_settings')
257 ->condition('field_name', $field['field_name'])
a8397343 258 ->condition('entity_type', $entity_type)
99d33fb1 259 ->condition('bundle', $bundle)
b338b91f 260 ->condition('language', $langcode)
99d33fb1
KS
261 ->condition('setting', $setting)
262 ->condition('setting_type', $setting_type)
263 ->execute();
264 }
c6189ea2
KS
265 // Create the new values.
266 if (in_array($setting, cck_serialized_settings())) {
267 $value = serialize($value);
268 }
269 $record = array(
270 'field_name' => $field['field_name'],
a8397343 271 'entity_type' => $entity_type,
99d33fb1 272 'bundle' => $bundle,
b338b91f 273 'language' => $langcode,
c6189ea2
KS
274 'setting' => $setting,
275 'setting_option' => $value,
276 'setting_type' => $setting_type,
277 );
278 $primary_keys = array();
279 drupal_write_record('cck_field_settings', $record, $primary_keys);
280}
281
282/**
b338b91f
KS
283 * Callback to return default value constructed
284 * from php code snippet.
285 */
286function cck_default_value_php($entity_type, $entity, $field, $instance, $langcode = LANGUAGE_NONE) {
287 $default_value = array();
288 ob_start();
289 $result = eval(cck_field_get_setting('default_value_php', 'instance', $field, $instance, $langcode, $flatten = TRUE));
41d887a5 290 ob_end_clean();
b338b91f 291 if (is_array($result)) {
41d887a5 292 $default_value = $result;
b338b91f 293 }
41d887a5 294 return $default_value;
b338b91f
KS
295}
296
297/**
78cc2178
KS
298 * Callback to return allowed values constructed
299 * from php code snippet.
300 */
301function cck_allowed_values_php($field, $flatten = TRUE) {
302 $allowed_values = array();
303 ob_start();
304 $result = eval(cck_field_get_setting('allowed_values_php', 'field', $field));
41d887a5 305 ob_end_clean();
78cc2178
KS
306 if (is_array($result)) {
307 if ($flatten) {
308 $result = cck_array_flatten($result);
309 }
310 $allowed_values = $result;
311 }
78cc2178
KS
312 return $allowed_values;
313}
314
315/**
316 * Helper function to flatten an array of allowed values.
317 *
318 * @param $array
319 * A single or multidimensional array.
320 * @return
321 * A flattened array.
322 */
323function cck_array_flatten($array) {
324 $result = array();
325 if (is_array($array)) {
326 foreach ($array as $key => $value) {
327 if (is_array($value)) {
328 $result += cck_array_flatten($value);
329 }
330 else {
331 $result[$key] = $value;
332 }
333 }
334 }
335 return $result;
336}
337
338/**
78cc2178 339 * Implements hook_content_migrate_field_alter().
d5d3500b 340 *
78cc2178
KS
341 * Use this to tweak the conversion of field settings
342 * from the D6 style to the D7 style for specific
343 * situations not handled by basic conversion,
344 * as when field types or settings are changed.
d5d3500b 345 *
78cc2178
KS
346 * $field_value['widget_type'] is available to
347 * see what widget type was originally used.
bccc8ae0 348 */
78cc2178 349function cck_content_migrate_field_alter(&$field_value) {
f0fdcdbf 350 if (!empty($field_value['settings']['allowed_values_php'])) {
78cc2178
KS
351 $field_value['settings']['allowed_values_function'] = 'cck_allowed_values_php';
352 cck_field_set_setting('allowed_values_php', 'field', $field_value['settings']['allowed_values_php'], $field_value);
353 }
b338b91f
KS
354}
355
356/**
357 * Implements hook_content_migrate_instance_alter().
d5d3500b 358 *
b338b91f
KS
359 * Use this to tweak the conversion of instance or widget settings
360 * from the D6 style to the D7 style for specific
361 * situations not handled by basic conversion, as when
362 * formatter or widget names or settings are changed.
363 */
364function cck_content_migrate_instance_alter(&$instance_value) {
365 if (!empty($instance_value['settings']['default_value_php'])) {
366 $field_value = content_migrate_get_field_values($instance_value['field_name']);
367 $instance_value['settings']['default_value_function'] = 'cck_default_value_php';
368 cck_field_set_setting('default_value_php', 'instance', $instance_value['settings']['default_value_php'], $field_value, $instance_value);
369 }
370}