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 @ ed9a13f1

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
          }
194
        }
195
        break;
196
    }
197

    
198
    $delta++;
199
  }
200

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

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

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

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

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

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

    
227
/**
228
 * Mapping configuration form callback for file targets.
229
 */
230
function file_feeds_form_callback($mapping, $target, $form, $form_state) {
231
  $description = array(
232
    '#theme' => 'item_list',
233
    '#items' => array(
234
      t('Rename: files whose name is already in use are renamed.'),
235
      t('Replace: files on the site with the same name are replaced.'),
236
      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.'),
237
      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.'),
238
      t('Skip existing: files whose name is already in use are not imported.'),
239
    ),
240
  );
241

    
242
  return array(
243
    'file_exists' => array(
244
      '#type' => 'select',
245
      '#title' => t('Replacement method'),
246
      '#default_value' => !empty($mapping['file_exists']) ? $mapping['file_exists'] : FILE_EXISTS_RENAME,
247
      '#options' => array(
248
        FILE_EXISTS_RENAME => t('Rename'),
249
        FILE_EXISTS_REPLACE => t('Replace'),
250
        FEEDS_FILE_EXISTS_REPLACE_DIFFERENT => t('Replace only if different'),
251
        FEEDS_FILE_EXISTS_RENAME_DIFFERENT => t('Rename only if different'),
252
        FEEDS_FILE_EXISTS_SKIP => t('Skip existing'),
253
      ),
254
      '#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.'),
255
    ),
256
  );
257
}
258

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

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

    
287
  return TRUE;
288
}