Projet

Général

Profil

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

root / drupal7 / sites / all / modules / feeds / mappers / file.inc @ b5aa1857

1
<?php
2

    
3
/**
4
 * @file
5
 * On behalf implementation of Feeds mapping API for file.module and
6
 * image.module.
7
 */
8

    
9
/**
10
 * Flag for dealing with existing files: Replace the existing file if it is
11
 * different. Do nothing if the new file is exactly the same as the existing
12
 * file.
13
 */
14
define('FEEDS_FILE_EXISTS_REPLACE_DIFFERENT', 3);
15

    
16
/**
17
 * Flag for dealing with existing files: If the new file is different, rename
18
 * it by appending a number until the name is unique. Do nothing if the new file
19
 * is exactly the same as the existing file.
20
 */
21
define('FEEDS_FILE_EXISTS_RENAME_DIFFERENT', 4);
22

    
23
/**
24
 * Flag for dealing with existing files: Do nothing if a file with the same name
25
 * already exists.
26
 */
27
define('FEEDS_FILE_EXISTS_SKIP', 5);
28

    
29
/**
30
 * Implements hook_feeds_processor_targets().
31
 */
32
function file_feeds_processor_targets($entity_type, $bundle_name) {
33
  $targets = array();
34

    
35
  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
36
    $info = field_info_field($name);
37

    
38
    if (in_array($info['type'], array('file', 'image'))) {
39
      $targets[$name . ':uri'] = array(
40
        'name' => t('@label: URI', array('@label' => $instance['label'])),
41
        'callback' => 'file_feeds_set_target',
42
        'description' => t('The URI of the @label field.', array('@label' => $instance['label'])),
43
        'real_target' => $name,
44
        'summary_callbacks' => array('file_feeds_summary_callback'),
45
        'form_callbacks' => array('file_feeds_form_callback'),
46
      );
47

    
48
      // Keep the old target name for backwards compatibility, but hide it from
49
      // the UI.
50
      $targets[$name] = $targets[$name . ':uri'];
51
      $targets[$name]['deprecated'] = TRUE;
52

    
53
      if ($info['type'] == 'image') {
54
        $targets[$name . ':alt'] = array(
55
          'name' => t('@label: Alt', array('@label' => $instance['label'])),
56
          'callback' => 'file_feeds_set_target',
57
          'description' => t('The alt tag of the @label field.', array('@label' => $instance['label'])),
58
          'real_target' => $name,
59
        );
60
        $targets[$name . ':title'] = array(
61
          'name' => t('@label: Title', array('@label' => $instance['label'])),
62
          'callback' => 'file_feeds_set_target',
63
          'description' => t('The title of the @label field.', array('@label' => $instance['label'])),
64
          'real_target' => $name,
65
        );
66
      }
67
      elseif ($info['type'] === 'file') {
68
        $targets[$name . ':description'] = array(
69
          'name' => t('@label: Description', array('@label' => $instance['label'])),
70
          'callback' => 'file_feeds_set_target',
71
          'description' => t('The description of the @label field.', array('@label' => $instance['label'])),
72
          'real_target' => $name,
73
        );
74
      }
75
    }
76
  }
77

    
78
  return $targets;
79
}
80

    
81
/**
82
 * Callback for mapping file fields.
83
 */
84
function file_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
85
  $language = $mapping['language'];
86
  $mapping += array('file_exists' => FILE_EXISTS_RENAME);
87

    
88
  // Add default of uri for backwards compatibility.
89
  list($field_name, $sub_field) = explode(':', $target . ':uri');
90
  $info = field_info_field($field_name);
91

    
92
  if ($sub_field == 'uri') {
93

    
94
    foreach ($values as $k => $v) {
95
      if (!($v instanceof FeedsEnclosure)) {
96
        if (!empty($v) && is_string($v)) {
97
          $values[$k] = new FeedsEnclosure($v, file_get_mimetype($v));
98
        }
99
        else {
100
          // Set the value for FALSE rather than remove it to keep our deltas
101
          // correct.
102
          $values[$k] = FALSE;
103
        }
104
      }
105
    }
106

    
107
    if ($entity instanceof Entity) {
108
      $entity_type = $entity->entityType();
109
      $bundle = $entity->bundle();
110
    }
111
    else {
112
      $entity_type = $source->importer->processor->entityType();
113
      $bundle = $source->importer->processor->bundle();
114
    }
115
    $instance_info = field_info_instance($entity_type, $field_name, $bundle);
116

    
117
    // Determine file destination.
118
    // @todo This needs review and debugging.
119
    $data = array();
120
    if (!empty($entity->uid)) {
121
      $data[$entity_type] = $entity;
122
    }
123

    
124
    $destination = file_field_widget_uri($info, $instance_info, $data);
125
  }
126

    
127
  // Populate entity.
128
  $field = isset($entity->$field_name) ? $entity->$field_name : array($language => array());
129
  $delta = 0;
130
  foreach ($values as $v) {
131
    if ($info['cardinality'] == $delta) {
132
      break;
133
    }
134

    
135
    if (!isset($field[$language][$delta])) {
136
      $field[$language][$delta] = array();
137
    }
138

    
139
    switch ($sub_field) {
140
      case 'alt':
141
      case 'title':
142
      case 'description':
143
        $field[$language][$delta][$sub_field] = $v;
144
        break;
145

    
146
      case 'uri':
147
        $skip = FALSE;
148
        if ($v) {
149
          if ($mapping['file_exists'] == FEEDS_FILE_EXISTS_SKIP) {
150
            if (file_exists($destination . '/' . basename($v->getValue()))) {
151
              $skip = TRUE;
152
            }
153
            else {
154
              // We already know the file doesn't exist so we don't have to
155
              // worry about anything being renamed, but we do need a valid
156
              // replace value for file_save().
157
              $mapping['file_exists'] = FILE_EXISTS_RENAME;
158
            }
159
          }
160
          if ($mapping['file_exists'] == FEEDS_FILE_EXISTS_REPLACE_DIFFERENT) {
161
            if (file_exists($destination . '/' . basename($v->getValue())) && file_feeds_file_compare($v->getValue(), $destination . '/' . basename($v->getValue()))) {
162
              $skip = TRUE;
163
            }
164
            else {
165
              // Either the file doesn't exist or it does and it's different.
166
              $mapping['file_exists'] = FILE_EXISTS_REPLACE;
167
            }
168
          }
169
          if ($mapping['file_exists'] == FEEDS_FILE_EXISTS_RENAME_DIFFERENT) {
170
            if (file_exists($destination . '/' . basename($v->getValue())) && file_feeds_file_compare($v->getValue(), $destination . '/' . basename($v->getValue()))) {
171
              $skip = TRUE;
172
            }
173
            else {
174
              // Either the file doesn't exist or it does and it's different.
175
              $mapping['file_exists'] = FILE_EXISTS_RENAME;
176
            }
177
          }
178
          if ($skip) {
179
            // Create a new dummy feeds enclosure where the value is the file
180
            // already in the file system (it will be skipped by getFile()).
181
            $mapping['file_exists'] = FEEDS_FILE_EXISTS_SKIP;
182
            $existing_path = $destination . '/' . basename($v->getValue());
183
            $v = new FeedsEnclosure($existing_path, file_get_mimetype($existing_path));
184
          }
185
          try {
186
            $v->setAllowedExtensions($instance_info['settings']['file_extensions']);
187
            $field[$language][$delta] += (array) $v->getFile($destination, $mapping['file_exists']);
188
            // @todo: Figure out how to properly populate this field.
189
            $field[$language][$delta]['display'] = 1;
190
          }
191
          catch (Exception $e) {
192
            watchdog('feeds', check_plain($e->getMessage()));
193
            continue;
194
          }
195
        }
196
        break;
197
    }
198

    
199
    $delta++;
200
  }
201

    
202
  $entity->$field_name = $field;
203
}
204

    
205
/**
206
 * Mapping configuration summary callback for file targets.
207
 */
208
function file_feeds_summary_callback($mapping, $target, $form, $form_state) {
209
  $mapping += array('file_exists' => FILE_EXISTS_RENAME);
210
  switch ($mapping['file_exists']) {
211
    case FILE_EXISTS_REPLACE:
212
      return t('Replace existing files');
213

    
214
    case FILE_EXISTS_RENAME:
215
      return t('Rename if file exists');
216

    
217
    case FEEDS_FILE_EXISTS_REPLACE_DIFFERENT:
218
      return t('Replace only if file exists, but is different');
219

    
220
    case FEEDS_FILE_EXISTS_RENAME_DIFFERENT:
221
      return t('Rename only if file exists, but is different');
222

    
223
    case FEEDS_FILE_EXISTS_SKIP:
224
      return t('Skip if file exists');
225
  }
226
}
227

    
228
/**
229
 * Mapping configuration form callback for file targets.
230
 */
231
function file_feeds_form_callback($mapping, $target, $form, $form_state) {
232
  $description = array(
233
    '#theme' => 'item_list',
234
    '#items' => array(
235
      t('Rename: files whose name is already in use are renamed.'),
236
      t('Replace: files on the site with the same name are replaced.'),
237
      t('Replace only if different: files on the site with the same name are replaced only if the file to import is different, in other cases the file will not be imported. Works only if the file to import is locally accessible.'),
238
      t('Rename only if different: files on the site with the same name are renamed only if the file to import is different, in other cases the file will not be imported. Works only if the file to import is locally accessible.'),
239
      t('Skip existing: files whose name is already in use are not imported.'),
240
    ),
241
  );
242

    
243
  return array(
244
    'file_exists' => array(
245
      '#type' => 'select',
246
      '#title' => t('Replacement method'),
247
      '#default_value' => !empty($mapping['file_exists']) ? $mapping['file_exists'] : FILE_EXISTS_RENAME,
248
      '#options' => array(
249
        FILE_EXISTS_RENAME => t('Rename'),
250
        FILE_EXISTS_REPLACE => t('Replace'),
251
        FEEDS_FILE_EXISTS_REPLACE_DIFFERENT => t('Replace only if different'),
252
        FEEDS_FILE_EXISTS_RENAME_DIFFERENT => t('Rename only if different'),
253
        FEEDS_FILE_EXISTS_SKIP => t('Skip existing'),
254
      ),
255
      '#description' => t('New files are always copied. Files that have a name that is already in use on the site are handled based on this setting.') . drupal_render($description) . t('Note that this setting has no effect when using the File (Field) Paths module.'),
256
    ),
257
  );
258
}
259

    
260
/**
261
 * Compares two files to determine if they are the same.
262
 *
263
 * @param string $file1
264
 *   The path to the first file to compare.
265
 *
266
 * @param string $file2
267
 *   The path to the second file to compare.
268
 *
269
 * @return bool
270
 *   TRUE if the files are the same.
271
 *   FALSE otherwise.
272
 */
273
function file_feeds_file_compare($file1, $file2) {
274
  // If the file size is different then assume they are different files.
275
  // However, remote files may return FALSE from filesize() so only compare
276
  // file sizes if both values are not empty.
277
  $filesize1 = filesize($file1);
278
  $filesize2 = filesize($file2);
279
  if ($filesize1 !== FALSE && $filesize2 !== FALSE && $filesize1 !== $filesize2) {
280
    return FALSE;
281
  }
282

    
283
  // File sizes are the same so check md5 hash of files.
284
  if (md5_file($file1) != md5_file($file2)) {
285
    return FALSE;
286
  }
287

    
288
  return TRUE;
289
}