Projet

Général

Profil

Paste
Télécharger (13,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / diff / diff.diff.inc @ 87dbc3bf

1
<?php
2

    
3
/**
4
 * @file
5
 * Includes the hooks defined by diff_hook_info().
6
 */
7

    
8
/**
9
 * Implements hook_entity_diff().
10
 *
11
 * Helper function to invoke the depreciated hook_diff() for node entities.
12
 *
13
 * This manually invokes hook_diff() to avoid a function name clash with the
14
 * PHP 5 (>= 5.3.0) date_diff() function or the Dates modules implementation.
15
 *
16
 * @param object $old_entity
17
 *   The older node revision.
18
 * @param object $new_entity
19
 *   The newer node revision.
20
 * @param array $context
21
 *   An associative array containing:
22
 *   - entity_type: The entity type; e.g., 'node' or 'user'.
23
 *   - old_entity: The older entity.
24
 *   - new_entity: The newer entity.
25
 *   - view_mode: The view mode to use. Defaults to FALSE.
26
 */
27
function diff_entity_diff($old_entity, $new_entity, $context) {
28
  $return = array();
29

    
30
  $entity_type = $context['entity_type'];
31
  $info = entity_get_info($entity_type);
32
  if (!empty($info['fieldable'])) {
33
    $return = diff_entity_fields_diff($old_entity, $new_entity, $context);
34
  }
35

    
36
  return $return;
37
}
38

    
39
/**
40
 * Internal callback to handle fieldable entities.
41
 *
42
 * Field comparison is handled for core modules, but is expandable to any other
43
 * fields if the module defines MODULE_field_diff_view().
44
 *
45
 * @param object $old_entity
46
 *   The older entity entity revision.
47
 * @param object $new_entity
48
 *   The newer entity entity revision.
49
 * @param array $context
50
 *   An associative array containing:
51
 *   - entity_type: The entity type; e.g., 'node' or 'user'.
52
 *   - old_entity: The older entity.
53
 *   - new_entity: The newer entity.
54
 *   - view_mode: The view mode to use. Defaults to FALSE.
55
 *
56
 * @return array
57
 *   An associative array of values keyed by the field name and delta value.
58
 */
59
function diff_entity_fields_diff($old_entity, $new_entity, $context) {
60
  $result = array();
61

    
62
  $entity_type = $context['entity_type'];
63
  $view_mode = $context['view_mode'];
64

    
65
  $field_context = $context;
66

    
67
  $actual_mode = FALSE;
68
  list(,, $bundle_name) = entity_extract_ids($entity_type, $new_entity);
69
  $instances = field_info_instances($entity_type, $bundle_name);
70

    
71
  // Some fields piggy back the display settings, so we need to fake these by
72
  // ensuring that the field mode is always set.
73
  if (empty($view_mode)) {
74
    $actual_mode = 'diff_standard';
75
    $field_context['custom_settings'] = FALSE;
76
  }
77
  $view_mode_settings = field_view_mode_settings($entity_type, $bundle_name);
78
  $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings'])) ? $view_mode : 'default';
79
  if (!isset($field_context['custom_settings'])) {
80
    $field_context['custom_settings'] = $actual_mode && $actual_mode == $view_mode;
81
  }
82

    
83
  $field_context['old_entity'] = $old_entity;
84
  $field_context['new_entity'] = $new_entity;
85
  $field_context['bundle_name'] = $bundle_name;
86

    
87
  foreach ($instances as $instance) {
88
    // Any view mode is supported in relation to hiding fields, but only if
89
    // selected (todo see if this is a valid option).
90
    if ($actual_mode && $instance['display'][$actual_mode]['type'] == 'hidden') {
91
      continue;
92
    }
93
    $field_name = $instance['field_name'];
94
    $field = field_info_field($field_name);
95
    $field_context['field'] = $field;
96
    $field_context['instance'] = $instance;
97
    $field_context['display'] = $instance['display'][$actual_mode];
98

    
99
    // We provide a loose check on the field access.
100
    if (field_access('view', $field, $entity_type) || field_access('edit', $field, $entity_type)) {
101
      $langcode = field_language($entity_type, $new_entity, $field_name);
102

    
103
      $field_context['language'] = $langcode;
104
      $field_context['field'] = $field;
105
      $field_context['instance'] = $instance;
106

    
107
      $old_items = array();
108
      if (!empty($old_entity->{$field_name}[$langcode])) {
109
        $old_items = $old_entity->{$field_name}[$langcode];
110
      }
111

    
112
      $new_items = array();
113
      if (!empty($new_entity->{$field_name}[$langcode])) {
114
        $new_items = $new_entity->{$field_name}[$langcode];
115
      }
116

    
117
      // Load files containing the field callbacks.
118
      _diff_autoload($field);
119

    
120
      $field_context['settings'] = diff_get_field_settings($field_context);
121

    
122
      // Reference fields can optionally prepare objects in bulk to reduce
123
      // overheads related to multiple database calls. If a field considers
124
      // that the delta values is meaningless, they can order and rearrange
125
      // to provide cleaner results.
126
      $func = $field['module'] . '_field_diff_view_prepare';
127
      if (function_exists($func)) {
128
        $func($old_items, $new_items, $field_context);
129
      }
130
      // Allow other modules to act safely on behalf of the core field module.
131
      drupal_alter('field_diff_view_prepare', $old_items, $new_items, $field_context);
132

    
133
      // These functions compiles the items into comparable arrays of strings.
134
      $func = $field['module'] . '_field_diff_view';
135
      if (!function_exists($func)) {
136
        $func = 'diff_field_diff_view';
137
      }
138

    
139
      // These callbacks should be independent of revision.
140
      $old_context = $field_context;
141
      $old_context['entity'] = $old_entity;
142
      $old_values = $func($old_items, $old_context);
143
      $new_context = $field_context;
144
      $new_context['entity'] = $new_entity;
145
      $new_values = $func($new_items, $new_context);
146

    
147
      // Allow other modules to act safely on behalf of the core field module.
148
      drupal_alter('field_diff_view', $old_values, $old_items, $old_context);
149
      drupal_alter('field_diff_view', $new_values, $new_items, $new_context);
150

    
151
      $max = max(array(count($old_values), count($new_values)));
152
      if ($max) {
153
        $result[$field_name] = array(
154
          '#name' => $instance['label'],
155
          '#old' => array(),
156
          '#new' => array(),
157
          '#settings' => $field_context['settings'],
158
        );
159
        for ($delta = 0; $delta < $max; $delta++) {
160
          if (isset($old_values[$delta])) {
161
            $result[$field_name]['#old'][] = is_array($old_values[$delta]) ? implode("\n", $old_values[$delta]) : $old_values[$delta];
162
          }
163
          if (isset($new_values[$delta])) {
164
            $result[$field_name]['#new'][] = is_array($new_values[$delta]) ? implode("\n", $new_values[$delta]) : $new_values[$delta];
165
          }
166
        }
167
        $result[$field_name]['#old'] = implode("\n", $result[$field_name]['#old']);
168
        $result[$field_name]['#new'] = implode("\n", $result[$field_name]['#new']);
169

    
170
        if ($actual_mode) {
171
          $result[$field_name]['#weight'] = $instance['display'][$actual_mode]['weight'];
172
        }
173

    
174
      }
175
    }
176
  }
177
  return $result;
178
}
179

    
180
/**
181
 * A generic handler for parsing field values.
182
 *
183
 * This callback can only handle the most basic of fields that populates the
184
 * safe_value during field load or use the value column for data storage.
185
 *
186
 * @param array $items
187
 *   An array of field items.
188
 * @param array $context
189
 *   An associative array containing:
190
 *   - entity: The entity that the items belong to.
191
 *   - entity_type: The entity type; e.g., 'node' or 'user'.
192
 *   - bundle: The bundle name.
193
 *   - field: The field that the items belong to.
194
 *   - instance: The instance that the items belong to.
195
 *   - language: The language associated with $items.
196
 *   - old_entity: The older entity.
197
 *   - new_entity: The newer entity.
198
 *
199
 * @return array
200
 *   An array of strings representing the value, keyed by delta index.
201
 */
202
function diff_field_diff_view($items, $context) {
203
  $diff_items = array();
204
   $entity = clone $context['entity'];
205
   $langcode = field_language($context['entity_type'], $entity, $context['field']['field_name']);
206
   $view_mode = empty($context['view_mode']) ? 'diff_standard' : $context['view_mode'];
207
   $element = field_view_field($context['entity_type'], $entity, $context['field']['field_name'], $view_mode, $langcode);
208

    
209
   foreach (element_children($element) as $delta) {
210
     $diff_items[$delta] = drupal_render($element[$delta]);
211
   }
212
  return $diff_items;
213
}
214

    
215
/**
216
 * Helper function to get the settings for a given field or formatter.
217
 *
218
 * @param array $context
219
 *   This will get the settings for a field.
220
 *   - field (required): The field that the items belong to.
221
 *   - entity: The entity that we are looking up.
222
 *   - instance: The instance that the items belong to.
223
 *   - view_mode: The view mode to use. Defaults to FALSE.
224
 *
225
 * @return array
226
 *   The settings for this field type.
227
 */
228
function diff_get_field_settings($field_context) {
229
  $field = $field_context['field'];
230

    
231
  // Update saved settings from the global settings for this field type.
232
  $settings = variable_get("diff_{$field['module']}_field_{$field['type']}_default_options", array());
233

    
234
  $settings = _diff_field_default_settings($field['module'], $field['type'], $settings);
235

    
236
  // Allow modules to alter the field settings based on the current context.
237
  drupal_alter('diff_field_settings', $settings, $field_context);
238

    
239
  return $settings;
240
}
241

    
242
/**
243
 * Helper function to initiate any global form elements.
244
 */
245
function diff_global_settings_form(&$subform, $form_state, $type, $settings) {
246
  $subform['show_header'] = array(
247
    '#type' => 'checkbox',
248
    '#title' => t('Show field title'),
249
    '#default_value' => $settings['show_header'],
250
    '#weight' => -5,
251
  );
252
  $subform['markdown'] = array(
253
    '#type' => 'select',
254
    '#title' => t('Markdown callback'),
255
    '#default_value' => $settings['markdown'],
256
    '#options' => array(
257
      'drupal_html_to_text' => t('Drupal HTML to Text'),
258
      'filter_xss' => t('Filter XSS (some tags)'),
259
      'diff_filter_xss' => t('Filter XSS (all tags)'),
260
    ),
261
    '#description' => t('These provide ways to clean markup tags to make comparisons easier to read.'),
262
    '#empty_option' => t('- Do not process -'),
263
  );
264
  $subform['line_counter'] = array(
265
    '#type' => 'radios',
266
    '#title' => t('Line counter'),
267
    '#default_value' => $settings['line_counter'],
268
    '#description' => t('This outputs the (approximate) line numbers as a heading before every change.'),
269
    '#options' => array(
270
      '' => t('None. Counter ignore and not incremented.'),
271
      'hidden' => t('Count lines but do not show line headers.'),
272
      'line' => t('Count and show lines, restarting counter at 0.'),
273
      'line_continuous' => t('Count and show lines, incrementing counter from last item.'),
274
    ),
275
  );
276

    
277
  /*
278
This would be cool, but to do anything else than inline with the text appears
279
to be very hard, requiring a refactoring of both the modules API but also the
280
DiffFormatter and Diff classes. Diff 8.x-4.x maybe.
281

    
282
  $subform['show_delta'] = array(
283
    '#type' => 'checkbox',
284
    '#title' => t('Show delta values'),
285
    '#default_value' => $settings['show_delta'],
286
  );
287
  $subform['delta_format'] = array(
288
    '#type' => 'radios',
289
    '#title' => t('Delta insertion method'),
290
    '#default_value' => $settings['delta_format'],
291
    '#options' => array(
292
      'inline' => t('Prefix to item'),
293
      'row' => t('Individual row'),
294
    ),
295
    '#states' => array(
296
      'invisible' => array(
297
        "input[id$='show-delta']" => array('checked' => FALSE),
298
      ),
299
    ),
300
  );
301
  */
302
}
303

    
304
/**
305
 * Helper function to populate the settings array.
306
 */
307
function _diff_field_default_settings($module, $field_type, $settings = array()) {
308
  // Load files containing the field callbacks.
309
  _diff_autoload($module);
310

    
311
  // Populate any missing values from CALLBACK_field_diff_default_options().
312
  $func = $module . '_field_diff_default_options';
313
  if (function_exists($func)) {
314
    $settings += $func($field_type);
315
  }
316

    
317
  // Check for Diff support. If it doesn't exist, the default markdown should
318
  // escape the field display, otherwise a raw format should be used.
319
  $func = $module . '_field_diff_view';
320

    
321
  // Global settings.
322
  $settings += array(
323
    'markdown' => function_exists($func) ? '' : 'drupal_html_to_text',
324
    'line_counter' => '',
325
    'show_header' => 1,
326
    // Can we? This seems too hard to track in the DiffFormatter as all we
327
    // have is a string or an array of strings.
328
    //'show_delta' => 0,
329
    //'delta_format' => 'row',
330
  );
331
  return $settings;
332
}
333

    
334
/**
335
 * Private helper function to load field includes.
336
 *
337
 * @param array|string $field_or_module
338
 *   The field definition array or the module that implements the field.
339
 */
340
function _diff_autoload($field_or_module) {
341
  $includes = &drupal_static(__FUNCTION__, FALSE);
342
  if (!$includes) {
343
    $includes = array(
344
      'file' => module_exists('file'),
345
      'image' => module_exists('image'),
346
      'list' => module_exists('list'),
347
      'taxonomy' => module_exists('taxonomy'),
348
      'text' => module_exists('text'),
349
      'number' => module_exists('number'),
350
    );
351
  }
352

    
353
  $module = is_string($field_or_module) ? $field_or_module : $field_or_module['module'];
354

    
355
  // Since field hooks are not real hooks, we manually load the field modules
356
  // MODULE.diff.inc. We handle the five core field defining modules.
357
  if (!isset($includes[$module])) {
358
    module_load_include('diff.inc', $module);
359
    $includes[$module] = 0;
360
  }
361
  elseif (!empty($includes[$module])) {
362
    module_load_include('inc', 'diff', 'includes/' . $module);
363
    $includes[$module] = 0;
364
  }
365
}
366

    
367
/**
368
 * Helper function to parse out the state in the diff results.
369
 */
370
function diff_extract_state($diff, $state = 'raw') {
371
  $states = array(
372
    0 => NULL,
373
    1 => NULL,
374
  );
375
  if (isset($diff['#states'][$state])) {
376
    if (isset($diff['#states'][$state]['#old'])) {
377
      $states[0] = $diff['#states'][$state]['#old'];
378
    }
379
    if (isset($diff['#states'][$state]['#new'])) {
380
      $states[1] = $diff['#states'][$state]['#new'];
381
    }
382
  }
383
  return $states;
384
}