Projet

Général

Profil

Paste
Télécharger (12,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / flag / includes / flag.export.inc @ 76e2e7c3

1
<?php
2

    
3
/**
4
 * @file
5
 * Import/Export functionality provided by Flag module.
6
 */
7

    
8
/**
9
 * Export a flag to code.
10
 *
11
 * @param $flags
12
 *   An array of flag objects, or flag name.
13
 * @param $module
14
 *   Optional. The name of the module that will be created if exporting to use
15
 *   in hook_flag_default_flags().
16
 */
17
function flag_export_flags($flags = array(), $module = '', $indent = '') {
18
  // For features_var_export() (optional).
19
  module_load_include('inc', 'features', 'features.export');
20
  $output = $indent . '$flags = array();' . "\n";
21
  foreach ($flags as $item) {
22
    if (is_object($item)) {
23
      $flag = $item;
24
    }
25
    else {
26
      // We got just the flag name, for example from the features
27
      // implementation.
28
      if (!($flag = flag_load($item, TRUE))) {
29
        continue;
30
      }
31
    }
32
    if (!$flag->is_compatible()) {
33
      drupal_set_message(t('Could not export flag %flag-name: Your flag was created by a different version of the Flag module than is now being used.', array('%flag-name' => $flag->name)), 'error');
34
      continue;
35
    }
36

    
37
    $flag->api_version = FLAG_API_VERSION;
38
    $new_flag = (array) $flag;
39

    
40
    if (!empty($module)) {
41
      // Even though Flag adds the module name itself later, we add the module
42
      // name here for reference by other modules (such as Features).
43
      $new_flag['module'] = $module;
44
      // Lock the flag name, as is normally desired by modules using
45
      // hook_flag_default_flags(), and needed by Features.
46
      $new_flag['locked'] = array('name');
47
    }
48
    // Allow other modules to change the exported flag.
49
    drupal_alter('flag_export', $new_flag);
50

    
51
    // Remove properties we don't export.
52
    $unset_properties = array(
53
      // Remove the flag ID.
54
      'fid',
55
      // The name is emitted as the key for the array.
56
      'name',
57
      // The entity info is just used as helper data.
58
      'entity_info',
59
      // Remove roles.
60
      'roles',
61
      // Remove errors.
62
      'errors',
63
    );
64
    foreach ($unset_properties as $property) {
65
      unset($new_flag[$property]);
66
    }
67

    
68
    $output .= $indent . '// Exported flag: "' . check_plain($flag->get_title()) . '"' . ".\n";
69
    $output .= $indent . '$flags[\'' . $flag->name . '\'] = ' . (function_exists('features_var_export') ? features_var_export($new_flag, $indent) : var_export($new_flag, TRUE)) . ";\n";
70
  }
71
  $output .= $indent . 'return $flags;' . "\n";
72
  return $output;
73
}
74

    
75
/**
76
 * Form to import a flag.
77
 */
78
function flag_import_form() {
79
  $form = array();
80

    
81
  $form['import'] = array(
82
    '#title' => t('Flag import code'),
83
    '#type' => 'textarea',
84
    '#default_value' => '',
85
    '#rows' => 15,
86
    '#required' => TRUE,
87
    '#description' => t('Paste the code from a <a href="@export-url">flag export</a> here to import it into you site. Flags imported with the same name will update existing flags. Flags with a new name will be created.', array('@export-url' => url(FLAG_ADMIN_PATH . '/export'))),
88
  );
89
  $form['submit'] = array(
90
    '#value' => t('Import'),
91
    '#type' => 'submit',
92
  );
93

    
94
  return $form;
95
}
96

    
97
/**
98
 * Validate handler; Import a flag.
99
 */
100
function flag_import_form_validate($form, &$form_state) {
101
  $flags = array();
102
  ob_start();
103
  eval($form_state['values']['import']);
104
  ob_end_clean();
105

    
106
  if (!isset($flags) || !is_array($flags)) {
107
    form_set_error('import', t('A valid list of flags could not be found in the import code.'));
108
    return;
109
  }
110

    
111
  // Create the flag object.
112
  foreach ($flags as $flag_name => $flag_info) {
113
    // Backward compatibility: old exported flags have their names in $flag_info
114
    // instead, so we use the += operator to not overwrite it.
115
    $flag_info += array(
116
      'name' => $flag_name,
117
    );
118
    $new_flag = flag_flag::factory_by_array($flag_info);
119

    
120
    // Give new flags with the same name a matching FID, which tells Flag to
121
    // update the existing flag, rather than creating a new one.
122
    if ($existing_flag = flag_get_flag($new_flag->name)) {
123
      $new_flag->fid = $existing_flag->fid;
124
    }
125

    
126
    if ($errors = $new_flag->validate()) {
127
      $message = t('The import of the %flag flag failed because the following errors were encountered during the import:', array('%flag' => $new_flag->name));
128
      $message_errors = array();
129
      foreach ($errors as $field => $field_errors) {
130
        foreach ($field_errors as $error) {
131
          $message_errors[] = $error['message'];
132
        }
133
      }
134
      form_set_error('import', $message . theme('item_list', array('items' => $message_errors)));
135
    }
136
    else {
137
      // Save the new flag for the submit handler.
138
      $form_state['flags'][] = $new_flag;
139
    }
140
  }
141
}
142

    
143
/**
144
 * Submit handler; Import a flag.
145
 */
146
function flag_import_form_submit($form, &$form_state) {
147
  module_load_include('inc', 'flag', 'includes/flag.admin');
148

    
149
  // Build up values for the cache clear.
150
  $entity_types = array();
151
  $new = FALSE;
152

    
153
  foreach ($form_state['flags'] as $flag) {
154
    $flag->save();
155
    if (!empty($flag->status)) {
156
      $flag->enable();
157
    }
158
    if ($flag->is_new) {
159
      drupal_set_message(t('Flag @name has been imported.', array('@name' => $flag->name)));
160
      $new = TRUE;
161
    }
162
    else {
163
      drupal_set_message(t('Flag @name has been updated.', array('@name' => $flag->name)));
164
    }
165
    $entity_types[] = $flag->entity_type;
166
  }
167
  _flag_clear_cache($entity_types, $new);
168

    
169
  $form_state['redirect'] = FLAG_ADMIN_PATH;
170
}
171

    
172
/**
173
 * Export a flag and display it in a form.
174
 */
175
function flag_export_form($form, &$form_state, $flag = NULL) {
176
  // If we were passed a flag, use it as the list of flags to export.
177
  if ($flag) {
178
    $flags = array($flag);
179
  }
180

    
181
  // Display a list of flags to export.
182
  if (!isset($flags)) {
183
    if (isset($form_state['values']['flags'])) {
184
      $flags = array();
185
      foreach ($form_state['values']['flags'] as $flag_name) {
186
        if ($flag_name && $flag = flag_get_flag($flag_name)) {
187
          $flags[] = $flag;
188
        }
189
      }
190
    }
191
    else {
192
      $form['flags'] = array(
193
        '#type' => 'checkboxes',
194
        '#title' => t('Flags to export'),
195
        '#options' => drupal_map_assoc(array_keys(flag_get_flags())),
196
        '#description' => t('Exporting your flags is useful for moving flags from one site to another, or when including your flag definitions in a module.'),
197
      );
198
      $form['submit'] = array(
199
        '#type' => 'submit',
200
        '#value' => t('Export'),
201
      );
202
    }
203
  }
204

    
205
  if (isset($flags)) {
206
    $code = flag_export_flags($flags);
207

    
208
    // Link to the Features page if module is present, otherwise link to the
209
    // Drupal project page.
210
    $features_link = module_exists('features') ? url('admin/build/features') : url('http://drupal.org/project/features');
211

    
212
    $form['export'] = array(
213
      '#type' => 'textarea',
214
      '#title' => t('Flag exports'),
215
      '#description' => t('Use the exported code to later <a href="@import-flag">import</a> it. Exports can be included in modules using <a href="http://drupal.org/node/305086#default-flags">hook_flag_default_flags()</a> or using the <a href="@features-url">Features</a> module.', array('@import-flag' => url(FLAG_ADMIN_PATH . '/import'), '@features-url' => $features_link)),
216
      '#value' => $code,
217
      '#rows' => 15,
218
    );
219
  }
220

    
221
  return $form;
222
}
223

    
224
/**
225
 * Submit handler; Rebuild the export form after the list of flags has been set.
226
 */
227
function flag_export_form_submit($form, &$form_state) {
228
  $form_state['rebuild'] = TRUE;
229
}
230

    
231
/**
232
 * Page for displaying an upgrade message and export form for Flag 1.x flags.
233
 */
234
function flag_update_page($flag) {
235
  if ($flag->is_compatible()) {
236
    drupal_set_message(t('The flag %name is already up-to-date with the latest Flag API and does not need upgrading.', array('%name' => $flag->name)));
237
    drupal_goto(FLAG_ADMIN_PATH);
238
  }
239

    
240
  drupal_set_message(t('The flag %name is currently using the Flag API version @version, which is not compatible with the current version of Flag. You can upgrade this flag by pasting the below code into <em>@module_flag_default_flags()</em> function in the @module.module file.', array('%name' => $flag->name, '@version' => $flag->api_version, '@module' => $flag->module)), 'warning');
241

    
242
  flag_update_export($flag);
243

    
244
  return drupal_get_form('flag_export_form', $flag);
245
}
246

    
247
/**
248
 * Update a flag before export.
249
 *
250
 * @param $flag
251
 *   The flag object passed by reference.
252
 */
253
function flag_update_export(&$flag) {
254
  // Set the API version to 1 by default: version 1 did not explicitly define
255
  // the API version.
256
  if (empty($flag->api_version)) {
257
    $flag->api_version = 1;
258
  }
259

    
260
  // Get all our update classes.
261
  // This is not terribly graceful, but the alternative is declaring our classes
262
  // explicitly, or registering them with the Drupal autoloader and then running
263
  // a database query, which seems a waste of space given we only ever need
264
  // these here.
265
  $classes = get_declared_classes();
266
  $update_handlers = array();
267
  foreach ($classes as $class) {
268
    // Any class whose name is of the form 'FlagUpdate_foo' is one of ours, we
269
    // assume. Should this prove problematic, we can add use of reflection here.
270
    if (substr($class, 0, 11) == 'FlagUpdate_') {
271
      // @todo: change this to work with the static class when we drop support
272
      // for PHP 5.2: see commit d5b517.
273
      $update_handler = new $class();
274
      // Cast to string, as decimals as array keys seem to be rounded down to
275
      // ints, WTF PHP?
276
      $version = (string) $update_handler->old_api_version;
277

    
278
      $update_handlers[$version] = $update_handler;
279
    }
280
  }
281
  // Sort the classes by old version number.
282
  uksort($update_handlers, 'version_compare');
283

    
284
  // Work through each update handler.
285
  foreach ($update_handlers as $old_api_version => $update_handler) {
286
    // Skip update classes that are older than our current flag.
287
    if (version_compare($old_api_version, $flag->api_version, '<')) {
288
      continue;
289
    }
290

    
291
    // Run the update and change the API version on the flag.
292
    $update_handler->update($flag);
293
    $flag->api_version = $update_handler->new_api_version;
294
  }
295
}
296

    
297
/**
298
 * Flag update class for API 1 flags -> API 2.
299
 *
300
 * The class name after the prefix is immaterial, though we follow the Drupal
301
 * system update convention whereby the number here is what we update to.
302
 */
303
class FlagUpdate_2 {
304

    
305
  /**
306
   * The API version this class updates a flag from.
307
   *
308
   * @todo: Change this to a class constant when we drop support for PHP 5.2.
309
   */
310
  public $old_api_version = 1;
311

    
312
  /**
313
   * The API version this class updates a flag to.
314
   */
315
  public $new_api_version = 2;
316

    
317
  /**
318
   * The update function for the flag.
319
   */
320
  static function update(&$flag) {
321
    if (isset($flag->roles) && !isset($flag->roles['flag'])) {
322
      $flag->roles = array(
323
        'flag' => $flag->roles,
324
        'unflag' => $flag->roles,
325
      );
326
    }
327
  }
328
}
329

    
330
/**
331
 * Flag update class for API 2 flags -> API 3.
332
 */
333
class FlagUpdate_3 {
334

    
335
  public $old_api_version = 2;
336
  public $new_api_version = 3;
337

    
338
  static function update(&$flag) {
339
    // Change the content_type property to entity_type.
340
    if (isset($flag->content_type)) {
341
      $flag->entity_type = $flag->content_type;
342
      unset($flag->content_type);
343
    }
344

    
345
    // We can't convert the flag roles data to user permissions at this point
346
    // because the flag is disabled and hence hook_permission() doesn't see it
347
    // to define its permissions.
348
    // Instead, we copy it to import_roles, which the flag add form will handle
349
    // on new flags (which this flag will behave as when it is re-enabled).
350
    // @see flag_form()
351
    if (isset($flag->roles)) {
352
      $flag->import_roles = $flag->roles;
353
    }
354

    
355
    // Update show_on_teaser property to use new view mode settings.
356
    if (!empty($flag->show_on_teaser)) {
357
      $flag->show_in_links['teaser'] = TRUE;
358
      unset($flag->show_on_teaser);
359
    }
360

    
361
    // Update show_on_page property to use new view mode settings.
362
    if (!empty($flag->show_on_page)) {
363
      $flag->show_in_links['full'] = TRUE;
364
      unset($flag->show_on_page);
365
    }
366

    
367
    // Update show_on_comment and show_on_entity properties to use new view
368
    // mode settings. Since the old logic was to show on all view modes, do
369
    // that.
370
    if (!empty($flag->show_on_entity) || !empty($flag->show_on_comment)) {
371
      if ($entity_info = entity_get_info($flag->entity_type)) {
372
        foreach ($entity_info['view modes'] as $view_mode => $value) {
373
          $flag->show_in_links[$view_mode] = TRUE;
374
        }
375
      }
376

    
377
      unset($flag->show_on_entity, $flag->show_on_comment);
378
    }
379
  }
380
}