source: sipes/modules_contrib/feeds/includes/FeedsSource.inc @ c43ea01

stableversion-3.0
Last change on this file since c43ea01 was 177a560, checked in by José Gregorio Puentes <jpuentes@…>, 8 años ago

se agrego el directorio de modulos contribuidos de drupal

  • Propiedad mode establecida a 100755
File size: 11.4 KB
Línea 
1<?php
2
3/**
4 * @file
5 * Definition of FeedsSourceInterface and FeedsSource class.
6 */
7
8/**
9 * Declares an interface for a class that defines default values and form
10 * descriptions for a FeedSource.
11 */
12interface FeedsSourceInterface {
13
14  /**
15   * Crutch: for ease of use, we implement FeedsSourceInterface for every
16   * plugin, but then we need to have a handle which plugin actually implements
17   * a source.
18   *
19   * @see FeedsPlugin class.
20   *
21   * @return
22   *   TRUE if a plugin handles source specific configuration, FALSE otherwise.
23   */
24  public function hasSourceConfig();
25
26  /**
27   * Return an associative array of default values.
28   */
29  public function sourceDefaults();
30
31  /**
32   * Return a Form API form array that defines a form configuring values. Keys
33   * correspond to the keys of the return value of sourceDefaults().
34   */
35  public function sourceForm($source_config);
36
37  /**
38   * Validate user entered values submitted by sourceForm().
39   */
40  public function sourceFormValidate(&$source_config);
41
42  /**
43   * A source is being saved.
44   */
45  public function sourceSave(FeedsSource $source);
46
47  /**
48   * A source is being deleted.
49   */
50  public function sourceDelete(FeedsSource $source);
51}
52
53/**
54 * This class encapsulates a source of a feed. It stores where the feed can be
55 * found and how to import it.
56 *
57 * Information on how to import a feed is encapsulated in a FeedsImporter object
58 * which is identified by the common id of the FeedsSource and the
59 * FeedsImporter. More than one FeedsSource can use the same FeedsImporter
60 * therefore a FeedsImporter never holds a pointer to a FeedsSource object, nor
61 * does it hold any other information for a particular FeedsSource object.
62 *
63 * Classes extending FeedsPlugin can implement a sourceForm to expose
64 * configuration for a FeedsSource object. This is for instance how FeedsFetcher
65 * exposes a text field for a feed URL or how FeedsCSVParser exposes a select
66 * field for choosing between colon or semicolon delimiters.
67 *
68 * It is important that a FeedsPlugin does not directly hold information about
69 * a source but leave all storage up to FeedsSource. An instance of a
70 * FeedsPlugin class only exists once per FeedsImporter configuration, while an
71 * instance of a FeedsSource class exists once per feed_nid to be imported.
72 *
73 * As with FeedsImporter, the idea with FeedsSource is that it can be used
74 * without actually saving the object to the database.
75 */
76class FeedsSource extends FeedsConfigurable {
77
78  // Contains the node id of the feed this source info object is attached to.
79  // Equals 0 if not attached to any node - i. e. if used on a
80  // standalone import form within Feeds or by other API users.
81  protected $feed_nid;
82
83  // The FeedsImporter object that this source is expected to be used with.
84  protected $importer;
85
86  // A FeedsBatch object. NULL if there is no active batch.
87  protected $batch;
88
89  /**
90   * Instantiate a unique object per class/id/feed_nid. Don't use
91   * directly, use feeds_source() instead.
92   */
93  public static function instance($importer_id, $feed_nid) {
94    $class = variable_get('feeds_source_class', 'FeedsSource');
95    static $instances = array();
96    if (!isset($instances[$class][$importer_id][$feed_nid])) {
97      $instances[$class][$importer_id][$feed_nid] = new $class($importer_id, $feed_nid);
98    }
99    return $instances[$class][$importer_id][$feed_nid];
100  }
101
102  /**
103   * Constructor.
104   */
105  protected function __construct($importer_id, $feed_nid) {
106    $this->feed_nid = $feed_nid;
107    $this->importer = feeds_importer($importer_id);
108    parent::__construct($importer_id);
109    $this->load();
110  }
111
112  /**
113   * Preview = fetch and parse a feed.
114   *
115   * @return
116   *   FeedsImportBatch object, fetched and parsed.
117   *
118   * @throws
119   *   Throws Exception if an error occurs when fetching or parsing.
120   */
121  public function preview() {
122    $this->batch = $this->importer->fetcher->fetch($this);
123    $this->importer->parser->parse($this->batch, $this);
124    module_invoke_all('feeds_after_parse', $this->importer, $this);
125    $batch = $this->batch;
126    unset($this->batch);
127    return $batch;
128  }
129
130  /**
131   * Import a feed: execute fetching, parsing and processing stage.
132   *
133   * @return
134   *   FEEDS_BATCH_COMPLETE if the import process finished. A decimal between
135   *   0.0 and 0.9 periodic if import is still in progress.
136   *
137   * @throws
138   *   Throws Exception if an error occurs when importing.
139   */
140  public function import() {
141    try {
142      if (!$this->batch || !($this->batch instanceof FeedsImportBatch)) {
143        $this->batch = $this->importer->fetcher->fetch($this);
144        $this->importer->parser->parse($this->batch, $this);
145        module_invoke_all('feeds_after_parse', $this->importer, $this);
146      }
147      $this->importer->processor->process($this->batch, $this);
148      $result = $this->batch->getProgress();
149      if ($result == FEEDS_BATCH_COMPLETE) {
150        unset($this->batch);
151        module_invoke_all('feeds_after_import', $this->importer, $this);
152      }
153    }
154    catch (Exception $e) {
155      unset($this->batch);
156      $this->save();
157      throw $e;
158    }
159    $this->save();
160    return $result;
161  }
162
163  /**
164   * Remove all items from a feed.
165   *
166   * @return
167   *   FEEDS_BATCH_COMPLETE if the clearing process finished. A decimal between
168   *   0.0 and 0.9 periodic if clearing is still in progress.
169   *
170   * @throws
171   *   Throws Exception if an error occurs when clearing.
172   */
173  public function clear() {
174    try {
175      $this->importer->fetcher->clear($this);
176      $this->importer->parser->clear($this);
177      if (!$this->batch || !($this->batch instanceof FeedsClearBatch)) {
178        $this->batch = new FeedsClearBatch();
179      }
180      $this->importer->processor->clear($this->batch, $this);
181      $result = $this->batch->getProgress();
182      if ($result == FEEDS_BATCH_COMPLETE) {
183        unset($this->batch);
184        module_invoke_all('feeds_after_clear', $this->importer, $this);
185      }
186    }
187    catch (Exception $e) {
188      unset($this->batch);
189      $this->save();
190      throw $e;
191    }
192    $this->save();
193    return $result;
194  }
195
196  /**
197   * Schedule this source.
198   */
199  public function schedule() {
200    // Check whether any fetcher is overriding the import period.
201    $period = $this->importer->config['import_period'];
202    $fetcher_period = $this->importer->fetcher->importPeriod($this);
203    if (is_numeric($fetcher_period)) {
204      $period = $fetcher_period;
205    }
206    $job = array(
207      'callback' => 'feeds_source_import',
208      'type' => $this->id,
209      'id' => $this->feed_nid,
210      // Schedule as soon as possible if a batch is active.
211      'period' => !empty($this->batch) ? 0 : $period,
212      'periodic' => TRUE,
213    );
214    if ($job['period'] != FEEDS_SCHEDULE_NEVER) {
215      job_scheduler()->set($job);
216    }
217    else {
218      job_scheduler()->remove($job);
219    }
220  }
221
222  /**
223   * Save configuration.
224   */
225  public function save() {
226    $config = $this->getConfig();
227    // Alert implementers of FeedsSourceInterface to the fact that we're saving.
228    foreach ($this->importer->plugin_types as $type) {
229      $this->importer->$type->sourceSave($this);
230    }
231    // Store the source property of the fetcher in a separate column so that we
232    // can do fast lookups on it.
233    $source = '';
234    if (isset($config[get_class($this->importer->fetcher)]['source'])) {
235      $source = $config[get_class($this->importer->fetcher)]['source'];
236    }
237    $object = array(
238      'id' => $this->id,
239      'feed_nid' => $this->feed_nid,
240      'config' => $config,
241      'source' => $source,
242      'batch' => isset($this->batch) ? $this->batch : FALSE,
243    );
244    if (db_result(db_query_range("SELECT 1 FROM {feeds_source} WHERE id = '%s' AND feed_nid = %d", $this->id, $this->feed_nid, 0, 1))) {
245      drupal_write_record('feeds_source', $object, array('id', 'feed_nid'));
246    }
247    else {
248      drupal_write_record('feeds_source', $object);
249    }
250  }
251
252  /**
253   * Load configuration and unpack.
254   *
255   * @todo Patch CTools to move constants from export.inc to ctools.module.
256   */
257  public function load() {
258    if ($record = db_fetch_object(db_query("SELECT config, batch FROM {feeds_source} WHERE id = '%s' AND feed_nid = %d", $this->id, $this->feed_nid))) {
259      // While FeedsSource cannot be exported, we still use CTool's export.inc
260      // export definitions.
261      ctools_include('export');
262      $this->export_type = EXPORT_IN_DATABASE;
263      $this->config = unserialize($record->config);
264      $this->batch = unserialize($record->batch);
265    }
266  }
267
268  /**
269   * Delete configuration. Removes configuration information
270   * from database, does not delete configuration itself.
271   */
272  public function delete() {
273    // Alert implementers of FeedsSourceInterface to the fact that we're
274    // deleting.
275    foreach ($this->importer->plugin_types as $type) {
276      $this->importer->$type->sourceDelete($this);
277    }
278    db_query("DELETE FROM {feeds_source} WHERE id = '%s' AND feed_nid = %d", $this->id, $this->feed_nid);
279    // Remove from schedule.
280    $job = array(
281      'callback' => 'feeds_source_import',
282      'type' => $this->id,
283      'id' => $this->feed_nid,
284    );
285    job_scheduler()->remove($job);
286  }
287
288  /**
289   * Only return source if configuration is persistent and valid.
290   *
291   * @see FeedsConfigurable::existing().
292   */
293  public function existing() {
294    // If there is no feed nid given, there must be no content type specified.
295    // If there is a feed nid given, there must be a content type specified.
296    // Ensure that importer is persistent (= defined in code or DB).
297    // Ensure that source is persistent (= defined in DB).
298    if ((empty($this->feed_nid) && empty($this->importer->config['content_type'])) ||
299        (!empty($this->feed_nid) && !empty($this->importer->config['content_type']))) {
300      $this->importer->existing();
301      return parent::existing();
302    }
303    throw new FeedsNotExistingException(t('Source configuration not valid.'));
304  }
305
306  /**
307   * Convenience function. Returns the configuration for a specific class.
308   *
309   * @param FeedsSourceInterface $client
310   *   An object that is an implementer of FeedsSourceInterface.
311   *
312   * @return
313   *   An array stored for $client.
314   */
315  public function getConfigFor(FeedsSourceInterface $client) {
316    $class = get_class($client);
317    return isset($this->config[$class]) ? $this->config[$class] : $client->sourceDefaults();
318  }
319
320  /**
321   * Return defaults for feed configuration.
322   */
323  public function configDefaults() {
324    // Collect information from plugins.
325    $defaults = array();
326    foreach ($this->importer->plugin_types as $type) {
327      if ($this->importer->$type->hasSourceConfig()) {
328        $defaults[get_class($this->importer->$type)] = $this->importer->$type->sourceDefaults();
329      }
330    }
331    return $defaults;
332  }
333
334  /**
335   * Override parent::configForm().
336   */
337  public function configForm(&$form_state) {
338    // Collect information from plugins.
339    $form = array();
340    foreach ($this->importer->plugin_types as $type) {
341      if ($this->importer->$type->hasSourceConfig()) {
342        $class = get_class($this->importer->$type);
343        $form[$class] = $this->importer->$type->sourceForm($this->config[$class]);
344        $form[$class]['#tree'] = TRUE;
345      }
346    }
347    return $form;
348  }
349
350  /**
351   * Override parent::configFormValidate().
352   */
353  public function configFormValidate(&$values) {
354    foreach ($this->importer->plugin_types as $type) {
355      $class = get_class($this->importer->$type);
356      if (isset($values[$class]) && $this->importer->$type->hasSourceConfig()) {
357        $this->importer->$type->sourceFormValidate($values[$class]);
358      }
359    }
360  }
361}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.