1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * Create/Read/Update/Delete functions for CCK-defined object types. |
---|
6 | * |
---|
7 | * The content module field API will allow $field arguments to |
---|
8 | * be input either in the field => widget nested array that is used |
---|
9 | * by the content module, or in flattened $form_values arrays, by |
---|
10 | * converting flattened arrays to the nested format. |
---|
11 | * |
---|
12 | * A hook_content_fieldapi() is available for each field instance action, |
---|
13 | * and each hook receives the nested field => widget array as an argument. |
---|
14 | * |
---|
15 | * The hook_content_fieldapi() $ops include: |
---|
16 | * |
---|
17 | * - create instance |
---|
18 | * - read instance |
---|
19 | * - update instance |
---|
20 | * - delete instance |
---|
21 | * |
---|
22 | * Another function, content_module_delete($module) will clean up |
---|
23 | * after a module that has been deleted by removing all data and |
---|
24 | * settings information that was created by that module. |
---|
25 | */ |
---|
26 | |
---|
27 | /** |
---|
28 | * Create an array of default values for a field type. |
---|
29 | */ |
---|
30 | function content_field_default_values($field_type) { |
---|
31 | $field_types = _content_field_types(); |
---|
32 | $module = $field_types[$field_type]['module']; |
---|
33 | |
---|
34 | $field = array( |
---|
35 | 'module' => $module, |
---|
36 | 'type' => $field_type, |
---|
37 | 'active' => 0, |
---|
38 | ); |
---|
39 | |
---|
40 | if (module_exists($module)) { |
---|
41 | $field['active'] = 1; |
---|
42 | } |
---|
43 | |
---|
44 | $field['columns'] = (array) module_invoke($module, 'field_settings', 'database columns', $field); |
---|
45 | // Ensure columns always default to NULL values. |
---|
46 | foreach ($field['columns'] as $column_name => $column) { |
---|
47 | $field['columns'][$column_name]['not null'] = FALSE; |
---|
48 | } |
---|
49 | |
---|
50 | $field['required'] = 0; |
---|
51 | $field['multiple'] = 0; |
---|
52 | $field['db_storage'] = CONTENT_DB_STORAGE_PER_CONTENT_TYPE; |
---|
53 | |
---|
54 | // Make sure field settings all have an index in the array. |
---|
55 | $setting_names = (array) module_invoke($module, 'field_settings', 'save', $field); |
---|
56 | drupal_alter('field_settings', $setting_names, 'save', $field); |
---|
57 | foreach ($setting_names as $setting) { |
---|
58 | $field[$setting] = NULL; |
---|
59 | } |
---|
60 | return $field; |
---|
61 | } |
---|
62 | |
---|
63 | /** |
---|
64 | * Create an array of default values for a field instance. |
---|
65 | */ |
---|
66 | function content_instance_default_values($field_name, $type_name, $widget_type) { |
---|
67 | $widget_types = _content_widget_types(); |
---|
68 | $module = $widget_types[$widget_type]['module']; |
---|
69 | |
---|
70 | $widget = array( |
---|
71 | 'field_name' => $field_name, |
---|
72 | 'type_name' => $type_name, |
---|
73 | 'weight' => 0, |
---|
74 | 'label' => $field_name, |
---|
75 | 'description' => '', |
---|
76 | 'widget_type' => $widget_type, |
---|
77 | 'widget_module' => $module, |
---|
78 | 'display_settings' => array(), |
---|
79 | 'widget_settings' => array(), |
---|
80 | ); |
---|
81 | |
---|
82 | if (module_exists($module)) { |
---|
83 | $widget['widget_active'] = 1; |
---|
84 | } |
---|
85 | |
---|
86 | $settings_names = array_merge(array('label'), array_keys(content_build_modes())); |
---|
87 | $widget['display_settings'] = array(); |
---|
88 | foreach ($settings_names as $name) { |
---|
89 | $widget['display_settings'][$name]['format'] = ($name == 'label') ? 'above' : 'default'; |
---|
90 | $widget['display_settings'][$name]['exclude'] = 0; |
---|
91 | } |
---|
92 | |
---|
93 | // Make sure widget settings all have an index in the array. |
---|
94 | $settings_names = (array) module_invoke($module, 'widget_settings', 'save', $widget); |
---|
95 | drupal_alter('widget_settings', $settings_names, 'save', $widget); |
---|
96 | $widget['widget_settings'] = array(); |
---|
97 | foreach ($settings_names as $name) { |
---|
98 | $widget['widget_settings'][$name] = NULL; |
---|
99 | } |
---|
100 | return $widget; |
---|
101 | } |
---|
102 | |
---|
103 | /** |
---|
104 | * Expand field info to create field => widget info. |
---|
105 | */ |
---|
106 | function content_field_instance_expand($field) { |
---|
107 | if (isset($field['widget'])) { |
---|
108 | return $field; |
---|
109 | } |
---|
110 | $field['widget'] = !empty($field['widget_settings']) ? $field['widget_settings'] : array(); |
---|
111 | $field['widget']['label'] = !empty($field['label']) ? $field['label'] : $field['field_name']; |
---|
112 | $field['widget']['weight'] = !empty($field['weight']) ? $field['weight'] : 0; |
---|
113 | $field['widget']['description'] = !empty($field['description']) ? $field['description'] : ''; |
---|
114 | |
---|
115 | if (!empty($field['widget_type'])) { |
---|
116 | $field['widget']['type'] = $field['widget_type']; |
---|
117 | $widget_types = _content_widget_types(); |
---|
118 | $field['widget']['module'] = isset($widget_types[$field['widget_type']]['module']) ? $widget_types[$field['widget_type']]['module'] : $field['widget_module']; |
---|
119 | } |
---|
120 | elseif (!empty($field['widget_module'])) { |
---|
121 | $field['widget']['module'] = $field['widget_module']; |
---|
122 | } |
---|
123 | |
---|
124 | unset($field['widget_type']); |
---|
125 | unset($field['weight']); |
---|
126 | unset($field['label']); |
---|
127 | unset($field['description']); |
---|
128 | unset($field['widget_module']); |
---|
129 | unset($field['widget_settings']); |
---|
130 | |
---|
131 | // If content.module is handling the default value, |
---|
132 | // initialize $widget_settings with default values, |
---|
133 | if (isset($field['default_value']) && isset($field['default_value_php']) && |
---|
134 | content_callback('widget', 'default value', $field) == CONTENT_CALLBACK_DEFAULT) { |
---|
135 | $field['widget']['default_value'] = !empty($field['default_value']) ? $field['default_value'] : NULL; |
---|
136 | $field['widget']['default_value_php'] = !empty($field['default_value_php']) ? $field['default_value_php'] : NULL; |
---|
137 | unset($field['default_value']); |
---|
138 | unset($field['default_value_php']); |
---|
139 | } |
---|
140 | return $field; |
---|
141 | } |
---|
142 | |
---|
143 | /** |
---|
144 | * Collapse field info from field => widget to flattened form values. |
---|
145 | */ |
---|
146 | function content_field_instance_collapse($field) { |
---|
147 | if (!isset($field['widget'])) { |
---|
148 | return $field; |
---|
149 | } |
---|
150 | $field['widget_settings'] = !empty($field['widget']) ? $field['widget'] : array(); |
---|
151 | $field['widget_type'] = !empty($field['widget']['type']) ? $field['widget']['type'] : ''; |
---|
152 | $field['weight'] = !empty($field['widget']['weight']) ? $field['widget']['weight'] : 0; |
---|
153 | $field['label'] = !empty($field['widget']['label']) ? $field['widget']['label'] : $field['field_name']; |
---|
154 | $field['description'] = !empty($field['widget']['description']) ? $field['widget']['description'] : ''; |
---|
155 | $field['type_name'] = !empty($field['type_name']) ? $field['type_name'] : ''; |
---|
156 | |
---|
157 | if (!empty($field['widget']['module'])) { |
---|
158 | $widget_module = $field['widget']['module']; |
---|
159 | } |
---|
160 | elseif (!empty($field['widget']['type'])) { |
---|
161 | $widget_types = _content_widget_types(); |
---|
162 | $widget_module = $widget_types[$field['widget']['type']]['module']; |
---|
163 | } |
---|
164 | else { |
---|
165 | $widget_module = ''; |
---|
166 | } |
---|
167 | $field['widget_module'] = $widget_module; |
---|
168 | unset($field['widget_settings']['type']); |
---|
169 | unset($field['widget_settings']['weight']); |
---|
170 | unset($field['widget_settings']['label']); |
---|
171 | unset($field['widget_settings']['description']); |
---|
172 | unset($field['widget_settings']['module']); |
---|
173 | unset($field['widget']); |
---|
174 | return $field; |
---|
175 | } |
---|
176 | |
---|
177 | /** |
---|
178 | * Create a new field instance. |
---|
179 | * |
---|
180 | * @param $field |
---|
181 | * An array of properties to create the field with, input either in |
---|
182 | * the field => widget format used by the content module or as an |
---|
183 | * array of form values. |
---|
184 | * |
---|
185 | * Required values: |
---|
186 | * - field_name, the name of the field to be created |
---|
187 | * - type_name, the content type of the instance to be created |
---|
188 | * |
---|
189 | * If there is no prior instance to create this from, we also need: |
---|
190 | * - type, the type of field to create |
---|
191 | * - widget_type, the type of widget to use |
---|
192 | * @param $rebuild |
---|
193 | * TRUE to clear content type caches and rebuild menu (default). |
---|
194 | * FALSE allows the caller to process several fields at a time quickly, but then |
---|
195 | * the caller is reponsible to clear content type caches and rebuild menu as soon |
---|
196 | * as all fields have been processed. For example: |
---|
197 | * @code |
---|
198 | * // Create several fields at a time. |
---|
199 | * foreach ($fields as $field) { |
---|
200 | * content_field_instance_create($field, FALSE); |
---|
201 | * } |
---|
202 | * // Clear caches and rebuild menu. |
---|
203 | * content_clear_type_cache(TRUE); |
---|
204 | * menu_rebuild(); |
---|
205 | * @endcode |
---|
206 | * @see content_clear_type_cache() |
---|
207 | * @see menu_rebuild() |
---|
208 | */ |
---|
209 | function content_field_instance_create($field, $rebuild = TRUE) { |
---|
210 | include_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc'); |
---|
211 | |
---|
212 | $form_values = $field; |
---|
213 | $field = content_field_instance_expand($field); |
---|
214 | |
---|
215 | // If there are prior instances, fill out missing values from the prior values, |
---|
216 | // otherwise get missing values from default values. |
---|
217 | $prior_instances = content_field_instance_read(array('field_name' => $field['field_name'])); |
---|
218 | if (!empty($prior_instances) && is_array($prior_instances)) { |
---|
219 | $prev_field = content_field_instance_expand($prior_instances[0]); |
---|
220 | |
---|
221 | // Weight, label, and description may have been forced into the $field |
---|
222 | // by content_field_instance_expand(). If there is a previous instance to |
---|
223 | // get these values from and there was no value supplied originally, use |
---|
224 | // the previous value. |
---|
225 | $field['widget']['weight'] = isset($form_values['weight']) ? $form_values['weight'] : $prev_field['widget']['weight']; |
---|
226 | $field['widget']['label'] = isset($form_values['label']) ? $form_values['label'] : $prev_field['widget']['label']; |
---|
227 | $field['widget']['description'] = isset($form_values['description']) ? $form_values['description'] : $prev_field['widget']['description']; |
---|
228 | } |
---|
229 | else { |
---|
230 | $prev_field = array('widget' => array()); |
---|
231 | } |
---|
232 | |
---|
233 | // If we have a field type, we can build default values for this field type. |
---|
234 | $default_values = array('widget' => array()); |
---|
235 | if (isset($field['type'])) { |
---|
236 | $default_values = content_field_default_values($field['type']); |
---|
237 | $default_instance_values = content_instance_default_values($field['field_name'], $field['type_name'], $field['widget']['type']); |
---|
238 | $default_values = content_field_instance_expand(array_merge($default_values, $default_instance_values)); |
---|
239 | } |
---|
240 | |
---|
241 | // Merge default values, previous values, and current values to create |
---|
242 | // a complete field array. |
---|
243 | $widget = array_merge($default_values['widget'], $prev_field['widget'], $field['widget']); |
---|
244 | $field = array_merge($default_values, $prev_field, $field); |
---|
245 | $field['widget'] = $widget; |
---|
246 | |
---|
247 | // Make sure we know what module to invoke for field info. |
---|
248 | if (empty($field['module']) && !empty($field['type'])) { |
---|
249 | $field_types = _content_field_types(); |
---|
250 | $field['module'] = $field_types[$field['type']]['module']; |
---|
251 | } |
---|
252 | |
---|
253 | // The storage type may need to be updated. |
---|
254 | $field['db_storage'] = content_storage_type($field); |
---|
255 | |
---|
256 | // Get a fresh copy of the column information whenever a field is created. |
---|
257 | $field['columns'] = (array) module_invoke($field['module'], 'field_settings', 'database columns', $field); |
---|
258 | |
---|
259 | if (empty($prev_field['widget']) || $prior_instances < 1) { |
---|
260 | // If this is the first instance, create the field. |
---|
261 | $field['db_storage'] = $field['multiple'] > 0 ? CONTENT_DB_STORAGE_PER_FIELD : CONTENT_DB_STORAGE_PER_CONTENT_TYPE; |
---|
262 | _content_field_write($field, 'create'); |
---|
263 | } |
---|
264 | elseif (!empty($prev_field['widget']) && $prev_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE && count($prior_instances) > 0) { |
---|
265 | // If the database storage has changed, update the field and previous instances. |
---|
266 | $field['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD; |
---|
267 | |
---|
268 | foreach ($prior_instances as $instance) { |
---|
269 | $new_instance = $instance; |
---|
270 | $new_instance['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD; |
---|
271 | |
---|
272 | // Invoke hook_content_fieldapi(). |
---|
273 | module_invoke_all('content_fieldapi', 'update instance', $new_instance); |
---|
274 | |
---|
275 | content_alter_schema($instance, $new_instance); |
---|
276 | } |
---|
277 | } |
---|
278 | |
---|
279 | // Invoke hook_content_fieldapi(). |
---|
280 | module_invoke_all('content_fieldapi', 'create instance', $field); |
---|
281 | |
---|
282 | // Update the field and the instance with the latest values. |
---|
283 | _content_field_write($field, 'update'); |
---|
284 | _content_field_instance_write($field, 'create'); |
---|
285 | |
---|
286 | content_alter_schema(array(), $field); |
---|
287 | |
---|
288 | if ($rebuild) { |
---|
289 | content_clear_type_cache(TRUE); |
---|
290 | menu_rebuild(); |
---|
291 | } |
---|
292 | |
---|
293 | return $field; |
---|
294 | } |
---|
295 | |
---|
296 | /** |
---|
297 | * Update an existing field instance. |
---|
298 | * |
---|
299 | * @param $field |
---|
300 | * An array of properties to update the field with, input either in |
---|
301 | * the field => widget format used by the content module or as an |
---|
302 | * array of form values. |
---|
303 | * @param $rebuild |
---|
304 | * TRUE to clear content type caches and rebuild menu (default). |
---|
305 | * FALSE allows the caller to process several fields at a time quickly, but then |
---|
306 | * the caller is reponsible to clear content type caches and rebuild menu as soon |
---|
307 | * as all fields have been processed. For example: |
---|
308 | * @code |
---|
309 | * // Update several fields at a time. |
---|
310 | * foreach ($fields as $field) { |
---|
311 | * content_field_instance_update($field, FALSE); |
---|
312 | * } |
---|
313 | * // Clear caches and rebuild menu. |
---|
314 | * content_clear_type_cache(TRUE); |
---|
315 | * menu_rebuild(); |
---|
316 | * @endcode |
---|
317 | * @see content_clear_type_cache() |
---|
318 | * @see menu_rebuild() |
---|
319 | */ |
---|
320 | function content_field_instance_update($field, $rebuild = TRUE) { |
---|
321 | include_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc'); |
---|
322 | |
---|
323 | // Ensure the field description is in the 'expanded' form. |
---|
324 | $field = content_field_instance_expand($field); |
---|
325 | |
---|
326 | // Get the previous value from the table. |
---|
327 | $previous = content_field_instance_read(array('field_name' => $field['field_name'], 'type_name' => $field['type_name'])); |
---|
328 | $prev_field = array_pop($previous); |
---|
329 | |
---|
330 | // Create a complete field array by merging the previous and current values, |
---|
331 | // letting the current values overwrite the previous ones. |
---|
332 | $widget = array_merge($prev_field['widget'], $field['widget']); |
---|
333 | $field = array_merge($prev_field, $field); |
---|
334 | $field['widget'] = $widget; |
---|
335 | |
---|
336 | // Make sure we know what module to invoke for field info. |
---|
337 | if (empty($field['module']) && !empty($field['type'])) { |
---|
338 | $field_types = _content_field_types(); |
---|
339 | $field['module'] = $field_types[$field['type']]['module']; |
---|
340 | } |
---|
341 | |
---|
342 | // The storage type may need to be updated. |
---|
343 | $field['db_storage'] = content_storage_type($field); |
---|
344 | |
---|
345 | // Changes in field values may affect columns, or column |
---|
346 | // information may have changed, get a fresh copy. |
---|
347 | $field['columns'] = (array) module_invoke($field['module'], 'field_settings', 'database columns', $field); |
---|
348 | |
---|
349 | // If the database storage has changed, update the field and previous instances. |
---|
350 | $prior_instances = content_field_instance_read(array('field_name' => $field['field_name'])); |
---|
351 | |
---|
352 | if ($prev_field['db_storage'] == CONTENT_DB_STORAGE_PER_CONTENT_TYPE && count($prior_instances) > 1) { |
---|
353 | // Update the field's data storage. |
---|
354 | $field['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD; |
---|
355 | |
---|
356 | // Update the schema for prior instances to adapt to the change in db storage. |
---|
357 | foreach ($prior_instances as $instance) { |
---|
358 | if ($instance['type_name'] != $field['type_name']) { |
---|
359 | $new_instance = $instance; |
---|
360 | $new_instance['db_storage'] = CONTENT_DB_STORAGE_PER_FIELD; |
---|
361 | |
---|
362 | // Invoke hook_content_fieldapi(). |
---|
363 | module_invoke_all('content_fieldapi', 'update instance', $new_instance); |
---|
364 | |
---|
365 | content_alter_schema($instance, $new_instance); |
---|
366 | } |
---|
367 | } |
---|
368 | } |
---|
369 | |
---|
370 | // Invoke hook_content_fieldapi(). |
---|
371 | module_invoke_all('content_fieldapi', 'update instance', $field); |
---|
372 | |
---|
373 | // Update the field and the instance with the latest values. |
---|
374 | _content_field_write($field, 'update'); |
---|
375 | _content_field_instance_write($field, 'update'); |
---|
376 | |
---|
377 | content_alter_schema($prev_field, $field); |
---|
378 | |
---|
379 | if ($rebuild) { |
---|
380 | content_clear_type_cache(TRUE); |
---|
381 | |
---|
382 | // The label is in the menu tree, so we need a menu rebuild |
---|
383 | // if the label changes. |
---|
384 | if ($prev_field['widget']['label'] != $field['widget']['label']) { |
---|
385 | menu_rebuild(); |
---|
386 | } |
---|
387 | } |
---|
388 | |
---|
389 | return $field; |
---|
390 | } |
---|
391 | |
---|
392 | /** |
---|
393 | * Write a field record. |
---|
394 | * |
---|
395 | * @param $field |
---|
396 | * The field array to process. |
---|
397 | */ |
---|
398 | function _content_field_write($field, $op = 'update') { |
---|
399 | // Rearrange the data to create the global_settings array. |
---|
400 | $field['global_settings'] = array(); |
---|
401 | $setting_names = (array) module_invoke($field['module'], 'field_settings', 'save', $field); |
---|
402 | drupal_alter('field_settings', $setting_names, 'save', $field); |
---|
403 | |
---|
404 | foreach ($setting_names as $setting) { |
---|
405 | // Unlike _content_field_instance_write() and 'widget_settings', 'global_settings' |
---|
406 | // is never preexisting, so we take no particular precautions here. |
---|
407 | $field['global_settings'][$setting] = isset($field[$setting]) ? $field[$setting] : ''; |
---|
408 | unset($field[$setting]); |
---|
409 | } |
---|
410 | // 'columns' is a reserved word in MySQL4, so our column is named 'db_columns'. |
---|
411 | $field['db_columns'] = $field['columns']; |
---|
412 | |
---|
413 | switch ($op) { |
---|
414 | case 'create': |
---|
415 | drupal_write_record(content_field_tablename(), $field); |
---|
416 | break; |
---|
417 | case 'update': |
---|
418 | drupal_write_record(content_field_tablename(), $field, 'field_name'); |
---|
419 | break; |
---|
420 | } |
---|
421 | unset($field['db_columns']); |
---|
422 | return $field; |
---|
423 | } |
---|
424 | |
---|
425 | /** |
---|
426 | * Write a field instance record. |
---|
427 | * |
---|
428 | * @param $field |
---|
429 | * The field array to process. |
---|
430 | */ |
---|
431 | function _content_field_instance_write($field, $op = 'update') { |
---|
432 | // Collapse the field => widget format, so that the values to be saved by |
---|
433 | // drupal_write_record are on top-level. |
---|
434 | $field = content_field_instance_collapse($field); |
---|
435 | |
---|
436 | // Rearrange the data to create the widget_settings array. |
---|
437 | $setting_names = (array) module_invoke($field['widget_module'], 'widget_settings', 'save', $field); |
---|
438 | drupal_alter('widget_settings', $setting_names, 'save', $field); |
---|
439 | foreach ($setting_names as $setting) { |
---|
440 | // In some cases (when the updated $field was originally read from |
---|
441 | // the db, as opposed to gathered from the values of a form), the values |
---|
442 | // are already in the right place, we take care to not wipe them. |
---|
443 | if (isset($field[$setting])) { |
---|
444 | $field['widget_settings'][$setting] = $field[$setting]; |
---|
445 | unset($field[$setting]); |
---|
446 | } |
---|
447 | } |
---|
448 | |
---|
449 | switch ($op) { |
---|
450 | case 'create': |
---|
451 | drupal_write_record(content_instance_tablename(), $field); |
---|
452 | break; |
---|
453 | case 'update': |
---|
454 | drupal_write_record(content_instance_tablename(), $field, array('field_name', 'type_name')); |
---|
455 | break; |
---|
456 | } |
---|
457 | return $field; |
---|
458 | } |
---|
459 | |
---|
460 | /** |
---|
461 | * Load a field instance. |
---|
462 | * |
---|
463 | * @param $param |
---|
464 | * An array of properties to use in selecting a field instance. Valid keys: |
---|
465 | * - 'type_name' - The name of the content type in which the instance exists. |
---|
466 | * - 'field_name' - The name of the field whose instance is to be loaded. |
---|
467 | * if NULL, all instances will be returned. |
---|
468 | * @param $include_inactive |
---|
469 | * TRUE will return field instances that are 'inactive', because their field |
---|
470 | * module or widget module is currently disabled. |
---|
471 | * @return |
---|
472 | * The field arrays. |
---|
473 | */ |
---|
474 | function content_field_instance_read($param = NULL, $include_inactive = FALSE) { |
---|
475 | $cond = array(); |
---|
476 | $args = array(); |
---|
477 | if (is_array($param)) { |
---|
478 | // Turn the conditions into a query. |
---|
479 | foreach ($param as $key => $value) { |
---|
480 | $cond[] = 'nfi.'. db_escape_string($key) ." = '%s'"; |
---|
481 | $args[] = $value; |
---|
482 | } |
---|
483 | } |
---|
484 | if (!$include_inactive) { |
---|
485 | $cond[] = 'nf.active = 1'; |
---|
486 | $cond[] = 'nfi.widget_active = 1'; |
---|
487 | } |
---|
488 | $where = $cond ? ' WHERE '. implode(' AND ', $cond) : ''; |
---|
489 | |
---|
490 | $db_result = db_query("SELECT * FROM {". content_instance_tablename() ."} nfi ". |
---|
491 | " JOIN {". content_field_tablename() ."} nf ON nfi.field_name = nf.field_name ". |
---|
492 | "$where ORDER BY nfi.weight ASC, nfi.label ASC", $args); |
---|
493 | |
---|
494 | $fields = array(); |
---|
495 | while ($instance = db_fetch_array($db_result)) { |
---|
496 | // Unserialize arrays. |
---|
497 | foreach (array('widget_settings', 'display_settings', 'global_settings', 'db_columns') as $key) { |
---|
498 | $instance[$key] = (!empty($instance[$key])) ? (array) unserialize($instance[$key]) : array(); |
---|
499 | } |
---|
500 | // 'columns' is a reserved word in MySQL4, so our column is named 'db_columns'. |
---|
501 | $instance['columns'] = $instance['db_columns']; |
---|
502 | unset($instance['db_columns']); |
---|
503 | |
---|
504 | // Unfold 'global_settings'. |
---|
505 | foreach ($instance['global_settings'] as $key => $value) { |
---|
506 | $instance[$key] = $value; |
---|
507 | } |
---|
508 | unset($instance['global_settings']); |
---|
509 | |
---|
510 | // Put the field in the $field => 'widget' structure that is used |
---|
511 | // all around content.module. |
---|
512 | $field = content_field_instance_expand($instance); |
---|
513 | |
---|
514 | // Invoke hook_content_fieldapi(). |
---|
515 | module_invoke_all('content_fieldapi', 'read instance', $field); |
---|
516 | $fields[] = $field; |
---|
517 | } |
---|
518 | return $fields; |
---|
519 | } |
---|
520 | |
---|
521 | /** |
---|
522 | * Delete an existing field instance. |
---|
523 | * |
---|
524 | * @param $field_name |
---|
525 | * The field name to delete. |
---|
526 | * @param $type_name |
---|
527 | * The content type where the field instance is going to be deleted. |
---|
528 | * @param $rebuild |
---|
529 | * TRUE to clear content type caches and rebuild menu (default). |
---|
530 | * FALSE allows the caller to process several fields at a time quickly, but then |
---|
531 | * the caller is reponsible to clear content type caches and rebuild menu as soon |
---|
532 | * as all fields have been processed. For example: |
---|
533 | * @code |
---|
534 | * // Delete several fields at a time. |
---|
535 | * foreach ($fields as $field) { |
---|
536 | * content_field_instance_delete($field['field_name'], $type_name, FALSE); |
---|
537 | * } |
---|
538 | * // Clear caches and rebuild menu. |
---|
539 | * content_clear_type_cache(TRUE); |
---|
540 | * menu_rebuild(); |
---|
541 | * @endcode |
---|
542 | * @see content_clear_type_cache() |
---|
543 | * @see menu_rebuild() |
---|
544 | */ |
---|
545 | function content_field_instance_delete($field_name, $type_name, $rebuild = TRUE) { |
---|
546 | include_once('./'. drupal_get_path('module', 'content') .'/includes/content.admin.inc'); |
---|
547 | |
---|
548 | // Get the previous field value. |
---|
549 | $field = array_pop(content_field_instance_read(array('field_name' => $field_name, 'type_name' => $type_name))); |
---|
550 | |
---|
551 | // Invoke hook_content_fieldapi(). |
---|
552 | module_invoke_all('content_fieldapi', 'delete instance', $field); |
---|
553 | |
---|
554 | db_query("DELETE FROM {". content_instance_tablename() . |
---|
555 | "} WHERE field_name = '%s' AND type_name = '%s'", $field['field_name'], $field['type_name']); |
---|
556 | |
---|
557 | // If no instances remain, delete the field entirely. |
---|
558 | $instances = content_field_instance_read(array('field_name' => $field_name)); |
---|
559 | if (sizeof($instances) < 1) { |
---|
560 | db_query("DELETE FROM {". content_field_tablename() ."} WHERE field_name = '%s'", $field['field_name']); |
---|
561 | content_alter_schema($field, array()); |
---|
562 | } |
---|
563 | // If only one instance remains, we may need to change the database |
---|
564 | // representation for this field. |
---|
565 | elseif (sizeof($instances) == 1 && !($field['multiple'])) { |
---|
566 | // Multiple-valued fields are always stored per-field-type. |
---|
567 | $instance = $instances[0]; |
---|
568 | $new_instance = $instance; |
---|
569 | $new_instance['db_storage'] = CONTENT_DB_STORAGE_PER_CONTENT_TYPE; |
---|
570 | _content_field_write($new_instance, 'update'); |
---|
571 | |
---|
572 | content_alter_schema($instance, $new_instance); |
---|
573 | } |
---|
574 | |
---|
575 | // If the deleted instance was the last field for the content type, |
---|
576 | // we drop the per-type table. We also consider possibly inactive fields. |
---|
577 | if (!content_field_instance_read(array('type_name' => $field['type_name']), TRUE)) { |
---|
578 | $base_tablename = _content_tablename($field['type_name'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE); |
---|
579 | if (db_table_exists($base_tablename)) { |
---|
580 | db_drop_table($ret, $base_tablename); |
---|
581 | } |
---|
582 | } |
---|
583 | |
---|
584 | if ($rebuild) { |
---|
585 | content_clear_type_cache(TRUE); |
---|
586 | menu_rebuild(); |
---|
587 | } |
---|
588 | |
---|
589 | return $field; |
---|
590 | } |
---|
591 | |
---|
592 | /** |
---|
593 | * Delete all data related to a module. |
---|
594 | * |
---|
595 | * @param string $module |
---|
596 | */ |
---|
597 | function content_module_delete($module) { |
---|
598 | // Delete the field data. |
---|
599 | // If content module has been uninstalled first, all tables |
---|
600 | // have already been dropped, and running that code will raise errors. |
---|
601 | if (db_table_exists(content_instance_tablename())) { |
---|
602 | $results = db_query("SELECT field_name, type_name FROM {". content_instance_tablename() ."} WHERE widget_module = '%s'", $module); |
---|
603 | while ($field = db_fetch_array($results)) { |
---|
604 | content_field_instance_delete($field['field_name'], $field['type_name'], FALSE); |
---|
605 | } |
---|
606 | // Force the caches and static arrays to update to the new info. |
---|
607 | content_clear_type_cache(TRUE); |
---|
608 | menu_rebuild(); |
---|
609 | } |
---|
610 | } |
---|
611 | |
---|
612 | /** |
---|
613 | * Make changes needed when a content type is created. |
---|
614 | * |
---|
615 | * @param $info |
---|
616 | * value supplied by hook_node_type() |
---|
617 | * |
---|
618 | * node_get_types() is still missing the new type at this point due to |
---|
619 | * a static caching bug. We ask it to rebuild its cache so that |
---|
620 | * content_clear_type_cache() can do its job properly. |
---|
621 | */ |
---|
622 | function content_type_create($info) { |
---|
623 | node_get_types(NULL, NULL, TRUE); |
---|
624 | content_clear_type_cache(TRUE); |
---|
625 | } |
---|
626 | |
---|
627 | /** |
---|
628 | * Make changes needed when an existing content type is updated. |
---|
629 | * |
---|
630 | * @param $info |
---|
631 | * value supplied by hook_node_type() |
---|
632 | */ |
---|
633 | function content_type_update($info) { |
---|
634 | if (!empty($info->old_type) && $info->old_type != $info->type) { |
---|
635 | // Rename the content type in all fields that use changed content type. |
---|
636 | db_query("UPDATE {". content_instance_tablename() ."} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type)); |
---|
637 | |
---|
638 | // Rename the content fields table to match new content type name. |
---|
639 | $old_type = content_types($info->old_type); |
---|
640 | $old_name = _content_tablename($old_type['type'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE); |
---|
641 | $new_name = _content_tablename($info->type, CONTENT_DB_STORAGE_PER_CONTENT_TYPE); |
---|
642 | if (db_table_exists($old_name)) { |
---|
643 | $ret = array(); |
---|
644 | db_rename_table($ret, $old_name, $new_name); |
---|
645 | watchdog('content', 'Content fields table %old_name has been renamed to %new_name and field instances have been updated.', array( |
---|
646 | '%old_name' => $old_name, '%new_name' => $new_name)); |
---|
647 | } |
---|
648 | |
---|
649 | // Rename the variable storing weights for non-CCK fields. |
---|
650 | if ($extra = variable_get('content_extra_weights_'. $info->old_type, array())) { |
---|
651 | variable_set('content_extra_weights_'. $info->type, $extra); |
---|
652 | variable_del('content_extra_weights_'. $info->old_type); |
---|
653 | } |
---|
654 | } |
---|
655 | |
---|
656 | // Reset all content type info. |
---|
657 | // Menu needs to be rebuilt as well, but node types need to be rebuilt first. |
---|
658 | // node_type_form_submit() takes care of this. |
---|
659 | content_clear_type_cache(TRUE); |
---|
660 | } |
---|
661 | |
---|
662 | /** |
---|
663 | * Make changes needed when a content type is deleted. |
---|
664 | * |
---|
665 | * @param $info |
---|
666 | * value supplied by hook_node_type() |
---|
667 | * |
---|
668 | * TODO should we skip doing this entirely since core leaves the |
---|
669 | * nodes in the database as orphans and wait until the nodes are |
---|
670 | * deleted to respond? |
---|
671 | * |
---|
672 | */ |
---|
673 | function content_type_delete($info) { |
---|
674 | // Don't delete data for content-types defined by disabled modules. |
---|
675 | if (!empty($info->disabled)) { |
---|
676 | return; |
---|
677 | } |
---|
678 | |
---|
679 | // TODO : What about inactive fields ? |
---|
680 | // Currently, content_field_instance_delete doesn't work on those... |
---|
681 | $fields = content_field_instance_read(array('type_name' => $info->type)); |
---|
682 | foreach ($fields as $field) { |
---|
683 | content_field_instance_delete($field['field_name'], $info->type, FALSE); |
---|
684 | } |
---|
685 | $table = _content_tablename($info->type, CONTENT_DB_STORAGE_PER_CONTENT_TYPE); |
---|
686 | if (db_table_exists($table)) { |
---|
687 | $ret = array(); |
---|
688 | db_drop_table($ret, $table); |
---|
689 | watchdog('content', 'The content fields table %name has been deleted.', array('%name' => $table)); |
---|
690 | } |
---|
691 | // Menu needs to be rebuilt as well, but node types need to be rebuilt first. |
---|
692 | // node_type_form_submit() takes care of this. |
---|
693 | content_clear_type_cache(TRUE); |
---|
694 | } |
---|