Projet

Général

Profil

Paste
Télécharger (14 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / field / tests / field_test.storage.inc @ 76597ebf

1
<?php
2

    
3
/**
4
 * @file
5
 * Defines a field storage backend.
6
 */
7

    
8

    
9
/**
10
 * Implements hook_field_storage_info().
11
 */
12
function field_test_field_storage_info() {
13
  return array(
14
    'field_test_storage' => array(
15
      'label' => t('Test storage'),
16
      'description' => t('Dummy test storage backend. Stores field values in the variable table.'),
17
    ),
18
    'field_test_storage_failure' => array(
19
      'label' => t('Test storage failure'),
20
      'description' => t('Dummy test storage backend. Always fails to create fields.'),
21
    ),
22
  );
23
}
24

    
25
/**
26
 * Implements hook_field_storage_details().
27
 */
28
function field_test_field_storage_details($field) {
29
  $details = array();
30

    
31
  // Add field columns.
32
  $columns = array();
33
  foreach ((array) $field['columns'] as $column_name => $attributes) {
34
    $columns[$column_name] = $column_name;
35
  }
36
  return array(
37
    'drupal_variables' => array(
38
      'field_test_storage_data[FIELD_LOAD_CURRENT]' => $columns,
39
      'field_test_storage_data[FIELD_LOAD_REVISION]' => $columns,
40
    ),
41
  );
42
}
43

    
44
/**
45
 * Implements hook_field_storage_details_alter().
46
 *
47
 * @see FieldAttachStorageTestCase::testFieldStorageDetailsAlter()
48
 */
49
function field_test_field_storage_details_alter(&$details, $field) {
50

    
51
  // For testing, storage details are changed only because of the field name.
52
  if ($field['field_name'] == 'field_test_change_my_details') {
53
    $columns = array();
54
    foreach ((array) $field['columns'] as $column_name => $attributes) {
55
      $columns[$column_name] = $column_name;
56
    }
57
    $details['drupal_variables'] = array(
58
      FIELD_LOAD_CURRENT => array(
59
        'moon' => $columns,
60
      ),
61
      FIELD_LOAD_REVISION => array(
62
        'mars' => $columns,
63
      ),
64
    );
65
  }
66
}
67

    
68
/**
69
 * Helper function: stores or retrieves data from the 'storage backend'.
70
 */
71
function _field_test_storage_data($data = NULL) {
72
  if (!isset($data)) {
73
    return variable_get('field_test_storage_data', array());
74
  }
75
  else {
76
    variable_set('field_test_storage_data', $data);
77
  }
78
}
79

    
80
/**
81
 * Implements hook_field_storage_load().
82
 */
83
function field_test_field_storage_load($entity_type, $entities, $age, $fields, $options) {
84
  $data = _field_test_storage_data();
85

    
86
  $load_current = $age == FIELD_LOAD_CURRENT;
87

    
88
  foreach ($fields as $field_id => $ids) {
89
    $field = field_info_field_by_id($field_id);
90
    $field_name = $field['field_name'];
91
    $field_data = $data[$field['id']];
92
    $sub_table = $load_current ? 'current' : 'revisions';
93
    $delta_count = array();
94
    foreach ($field_data[$sub_table] as $row) {
95
      if ($row->type == $entity_type && (!$row->deleted || $options['deleted'])) {
96
        if (($load_current && in_array($row->entity_id, $ids)) || (!$load_current && in_array($row->revision_id, $ids))) {
97
          if (in_array($row->language, field_available_languages($entity_type, $field))) {
98
            if (!isset($delta_count[$row->entity_id][$row->language])) {
99
              $delta_count[$row->entity_id][$row->language] = 0;
100
            }
101
            if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->language] < $field['cardinality']) {
102
              $item = array();
103
              foreach ($field['columns'] as $column => $attributes) {
104
                $item[$column] = $row->{$column};
105
              }
106
              $entities[$row->entity_id]->{$field_name}[$row->language][] = $item;
107
              $delta_count[$row->entity_id][$row->language]++;
108
            }
109
          }
110
        }
111
      }
112
    }
113
  }
114
}
115

    
116
/**
117
 * Implements hook_field_storage_write().
118
 */
119
function field_test_field_storage_write($entity_type, $entity, $op, $fields) {
120
  $data = _field_test_storage_data();
121

    
122
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
123

    
124
  foreach ($fields as $field_id) {
125
    $field = field_info_field_by_id($field_id);
126
    $field_name = $field['field_name'];
127
    $field_data = &$data[$field_id];
128

    
129
    $all_languages = field_available_languages($entity_type, $field);
130
    $field_languages = array_intersect($all_languages, array_keys((array) $entity->$field_name));
131

    
132
    // Delete and insert, rather than update, in case a value was added.
133
    if ($op == FIELD_STORAGE_UPDATE) {
134
      // Delete languages present in the incoming $entity->$field_name.
135
      // Delete all languages if $entity->$field_name is empty.
136
      $languages = !empty($entity->$field_name) ? $field_languages : $all_languages;
137
      if ($languages) {
138
        foreach ($field_data['current'] as $key => $row) {
139
          if ($row->type == $entity_type && $row->entity_id == $id && in_array($row->language, $languages)) {
140
            unset($field_data['current'][$key]);
141
          }
142
        }
143
        if (isset($vid)) {
144
          foreach ($field_data['revisions'] as $key => $row) {
145
            if ($row->type == $entity_type && $row->revision_id == $vid) {
146
              unset($field_data['revisions'][$key]);
147
            }
148
          }
149
        }
150
      }
151
    }
152

    
153
    foreach ($field_languages as $langcode) {
154
      $items = (array) $entity->{$field_name}[$langcode];
155
      $delta_count = 0;
156
      foreach ($items as $delta => $item) {
157
        $row = (object) array(
158
          'field_id' => $field_id,
159
          'type' => $entity_type,
160
          'entity_id' => $id,
161
          'revision_id' => $vid,
162
          'bundle' => $bundle,
163
          'delta' => $delta,
164
          'deleted' => FALSE,
165
          'language' => $langcode,
166
        );
167
        foreach ($field['columns'] as $column => $attributes) {
168
          $row->{$column} = isset($item[$column]) ? $item[$column] : NULL;
169
        }
170

    
171
        $field_data['current'][] = $row;
172
        if (isset($vid)) {
173
          $field_data['revisions'][] = $row;
174
        }
175

    
176
        if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
177
          break;
178
        }
179
      }
180
    }
181
  }
182

    
183
  _field_test_storage_data($data);
184
}
185

    
186
/**
187
 * Implements hook_field_storage_delete().
188
 */
189
function field_test_field_storage_delete($entity_type, $entity, $fields) {
190
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
191

    
192
  // Note: reusing field_test_storage_purge(), like field_sql_storage.module
193
  // does, is highly inefficient in our case...
194
  foreach (field_info_instances($bundle) as $instance) {
195
    if (isset($fields[$instance['field_id']])) {
196
      $field = field_info_field_by_id($instance['field_id']);
197
      field_test_field_storage_purge($entity_type, $entity, $field, $instance);
198
    }
199
  }
200
}
201

    
202
/**
203
 * Implements hook_field_storage_purge().
204
 */
205
function field_test_field_storage_purge($entity_type, $entity, $field, $instance) {
206
  $data = _field_test_storage_data();
207

    
208
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
209

    
210
  $field_data = &$data[$field['id']];
211
  foreach (array('current', 'revisions') as $sub_table) {
212
    foreach ($field_data[$sub_table] as $key => $row) {
213
      if ($row->type == $entity_type && $row->entity_id == $id) {
214
        unset($field_data[$sub_table][$key]);
215
      }
216
    }
217
  }
218

    
219
  _field_test_storage_data($data);
220
}
221

    
222
/**
223
 * Implements hook_field_storage_delete_revision().
224
 */
225
function field_test_field_storage_delete_revision($entity_type, $entity, $fields) {
226
  $data = _field_test_storage_data();
227

    
228
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
229
  foreach ($fields as $field_id) {
230
    $field_data = &$data[$field_id];
231
    foreach (array('current', 'revisions') as $sub_table) {
232
      foreach ($field_data[$sub_table] as $key => $row) {
233
        if ($row->type == $entity_type && $row->entity_id == $id && $row->revision_id == $vid) {
234
          unset($field_data[$sub_table][$key]);
235
        }
236
      }
237
    }
238
  }
239

    
240
  _field_test_storage_data($data);
241
}
242

    
243
/**
244
 * Implements hook_field_storage_query().
245
 */
246
function field_test_field_storage_query($field_id, $conditions, $count, &$cursor = NULL, $age) {
247
  $data = _field_test_storage_data();
248

    
249
  $load_current = $age == FIELD_LOAD_CURRENT;
250

    
251
  $field = field_info_field_by_id($field_id);
252
  $field_columns = array_keys($field['columns']);
253

    
254
  $field_data = $data[$field['id']];
255
  $sub_table = $load_current ? 'current' : 'revisions';
256
  // We need to sort records by entity type and entity id.
257
  usort($field_data[$sub_table], '_field_test_field_storage_query_sort_helper');
258

    
259
    // Initialize results array.
260
  $return = array();
261
  $entity_count = 0;
262
  $rows_count = 0;
263
  $rows_total = count($field_data[$sub_table]);
264
  $skip = $cursor;
265
  $skipped = 0;
266

    
267
  foreach ($field_data[$sub_table] as $row) {
268
    if ($count != FIELD_QUERY_NO_LIMIT && $entity_count >= $count) {
269
      break;
270
    }
271

    
272
    if ($row->field_id == $field['id']) {
273
      $match = TRUE;
274
      $condition_deleted = FALSE;
275
      // Add conditions.
276
      foreach ($conditions as $condition) {
277
        @list($column, $value, $operator) = $condition;
278
        if (empty($operator)) {
279
          $operator = is_array($value) ? 'IN' : '=';
280
        }
281
        switch ($operator) {
282
          case '=':
283
            $match = $match && $row->{$column} == $value;
284
            break;
285
          case '<>':
286
          case '<':
287
          case '<=':
288
          case '>':
289
          case '>=':
290
            eval('$match = $match && ' . $row->{$column} . ' ' . $operator . ' '. $value);
291
            break;
292
          case 'IN':
293
            $match = $match && in_array($row->{$column}, $value);
294
            break;
295
          case 'NOT IN':
296
            $match = $match && !in_array($row->{$column}, $value);
297
            break;
298
          case 'BETWEEN':
299
            $match = $match && $row->{$column} >= $value[0] && $row->{$column} <= $value[1];
300
            break;
301
          case 'STARTS_WITH':
302
          case 'ENDS_WITH':
303
          case 'CONTAINS':
304
            // Not supported.
305
            $match = FALSE;
306
            break;
307
        }
308
        // Track condition on 'deleted'.
309
        if ($column == 'deleted') {
310
          $condition_deleted = TRUE;
311
        }
312
      }
313

    
314
      // Exclude deleted data unless we have a condition on it.
315
      if (!$condition_deleted && $row->deleted) {
316
        $match = FALSE;
317
      }
318

    
319
      if ($match) {
320
        if (!isset($skip) || $skipped >= $skip) {
321
          $cursor++;
322
          // If querying all revisions and the entity type has revisions, we need
323
          // to key the results by revision_ids.
324
          $entity_type = entity_get_info($row->type);
325
          $id = ($load_current || empty($entity_type['entity keys']['revision'])) ? $row->entity_id : $row->revision_id;
326

    
327
          if (!isset($return[$row->type][$id])) {
328
            $return[$row->type][$id] = entity_create_stub_entity($row->type, array($row->entity_id, $row->revision_id, $row->bundle));
329
            $entity_count++;
330
          }
331
        }
332
        else {
333
          $skipped++;
334
        }
335
      }
336
    }
337
    $rows_count++;
338

    
339
    // The query is complete if we walked the whole array.
340
    if ($count != FIELD_QUERY_NO_LIMIT && $rows_count >= $rows_total) {
341
      $cursor = FIELD_QUERY_COMPLETE;
342
    }
343
  }
344

    
345
  return $return;
346
}
347

    
348
/**
349
 * Sort helper for field_test_field_storage_query().
350
 *
351
 * Sorts by entity type and entity id.
352
 */
353
function _field_test_field_storage_query_sort_helper($a, $b) {
354
  if ($a->type == $b->type) {
355
    if ($a->entity_id == $b->entity_id) {
356
      return 0;
357
    }
358
    else {
359
      return $a->entity_id < $b->entity_id ? -1 : 1;
360
    }
361
  }
362
  else {
363
    return $a->type < $b->type ? -1 : 1;
364
  }
365
}
366

    
367
/**
368
 * Implements hook_field_storage_create_field().
369
 */
370
function field_test_field_storage_create_field($field) {
371
  if ($field['storage']['type'] == 'field_test_storage_failure') {
372
    throw new Exception('field_test_storage_failure engine always fails to create fields');
373
  }
374

    
375
  $data = _field_test_storage_data();
376

    
377
  $data[$field['id']] = array(
378
    'current' => array(),
379
    'revisions' => array(),
380
  );
381

    
382
  _field_test_storage_data($data);
383
}
384

    
385
/**
386
 * Implements hook_field_storage_delete_field().
387
 */
388
function field_test_field_storage_delete_field($field) {
389
  $data = _field_test_storage_data();
390

    
391
  $field_data = &$data[$field['id']];
392
  foreach (array('current', 'revisions') as $sub_table) {
393
    foreach ($field_data[$sub_table] as &$row) {
394
      $row->deleted = TRUE;
395
    }
396
  }
397

    
398
  _field_test_storage_data($data);
399
}
400

    
401
/**
402
 * Implements hook_field_storage_delete_instance().
403
 */
404
function field_test_field_storage_delete_instance($instance) {
405
  $data = _field_test_storage_data();
406

    
407
  $field = field_info_field($instance['field_name']);
408
  $field_data = &$data[$field['id']];
409
  foreach (array('current', 'revisions') as $sub_table) {
410
    foreach ($field_data[$sub_table] as &$row) {
411
      if ($row->bundle == $instance['bundle']) {
412
        $row->deleted = TRUE;
413
      }
414
    }
415
  }
416

    
417
  _field_test_storage_data($data);
418
}
419

    
420
/**
421
 * Implements hook_field_attach_create_bundle().
422
 */
423
function field_test_field_attach_create_bundle($bundle) {
424
  // We don't need to do anything here.
425
}
426

    
427
/**
428
 * Implements hook_field_attach_rename_bundle().
429
 */
430
function field_test_field_attach_rename_bundle($bundle_old, $bundle_new) {
431
  $data = _field_test_storage_data();
432

    
433
  // We need to account for deleted or inactive fields and instances.
434
  $instances = field_read_instances(array('bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
435
  foreach ($instances as $field_name => $instance) {
436
    $field = field_info_field_by_id($instance['field_id']);
437
    if ($field['storage']['type'] == 'field_test_storage') {
438
      $field_data = &$data[$field['id']];
439
      foreach (array('current', 'revisions') as $sub_table) {
440
        foreach ($field_data[$sub_table] as &$row) {
441
          if ($row->bundle == $bundle_old) {
442
            $row->bundle = $bundle_new;
443
          }
444
        }
445
      }
446
    }
447
  }
448

    
449
  _field_test_storage_data($data);
450
}
451

    
452
/**
453
 * Implements hook_field_attach_delete_bundle().
454
 */
455
function field_test_field_attach_delete_bundle($entity_type, $bundle, $instances) {
456
  $data = _field_test_storage_data();
457

    
458
  foreach ($instances as $field_name => $instance) {
459
    $field = field_info_field($field_name);
460
    if ($field['storage']['type'] == 'field_test_storage') {
461
      $field_data = &$data[$field['id']];
462
      foreach (array('current', 'revisions') as $sub_table) {
463
        foreach ($field_data[$sub_table] as &$row) {
464
          if ($row->bundle == $bundle_old) {
465
            $row->deleted = TRUE;
466
          }
467
        }
468
      }
469
    }
470
  }
471

    
472
  _field_test_storage_data($data);
473
}