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 @ 74f6bef0

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
  module_load_include('inc', 'features', 'features.export'); // For features_var_export() (optional).
19
  $output = $indent . '$flags = array();' . "\n";
20
  foreach ($flags as $item) {
21
    if (is_object($item)) {
22
      $flag = $item;
23
    }
24
    else {
25
      // We got just the flag name, for example from the features
26
      // implementation.
27
      if (!($flag = flag_load($item, TRUE))) {
28
        continue;
29
      }
30
    }
31
    if (!$flag->is_compatible()) {
32
      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');
33
      continue;
34
    }
35

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

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

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

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

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

    
80
  $form['import'] = array(
81
    '#title' => t('Flag import code'),
82
    '#type' => 'textarea',
83
    '#default_value' => '',
84
    '#rows' => 15,
85
    '#required' => TRUE,
86
    '#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'))),
87
  );
88
  $form['submit'] = array(
89
    '#value' => t('Import'),
90
    '#type' => 'submit',
91
  );
92

    
93
  return $form;
94
}
95

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

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

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

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

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

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

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

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

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

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

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

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

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

    
211
    $form['export'] = array(
212
      '#type' => 'textarea',
213
      '#title' => t('Flag exports'),
214
      '#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)),
215
      '#value' => $code,
216
      '#rows' => 15,
217
    );
218
  }
219

    
220
  return $form;
221
}
222

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

    
230
/**
231
 * Page for displaying an upgrade message and export form for Flag 1.x flags.
232
 */
233
function flag_update_page($flag) {
234
  if ($flag->is_compatible()) {
235
    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)));
236
    drupal_goto(FLAG_ADMIN_PATH);
237
  }
238

    
239
  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');
240

    
241
  flag_update_export($flag);
242

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
375
      unset($flag->show_on_entity, $flag->show_on_comment);
376
    }
377
  }
378
}