FeedsPlugin.inc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. <?php
  2. /**
  3. * @file
  4. * Definition of FeedsPlugin class.
  5. */
  6. /**
  7. * Base class for a fetcher, parser or processor result.
  8. */
  9. class FeedsResult {}
  10. /**
  11. * Implement source interface for all plugins.
  12. *
  13. * Note how this class does not attempt to store source information locally.
  14. * Doing this would break the model where source information is represented by
  15. * an object that is being passed into a Feed object and its plugins.
  16. */
  17. abstract class FeedsPlugin extends FeedsConfigurable implements FeedsSourceInterface {
  18. /**
  19. * The plugin definition.
  20. *
  21. * @var array
  22. */
  23. protected $pluginDefinition;
  24. /**
  25. * Constructs a FeedsPlugin object.
  26. *
  27. * A copy of FeedsConfigurable::__construct() that doesn't call
  28. * configDefaults() so that we avoid circular dependencies.
  29. *
  30. * @param string $id
  31. * The importer id.
  32. */
  33. protected function __construct($id) {
  34. $this->id = $id;
  35. $this->export_type = FEEDS_EXPORT_NONE;
  36. $this->disabled = FALSE;
  37. }
  38. /**
  39. * Instantiates a FeedsPlugin object.
  40. *
  41. * Don't use directly, use feeds_plugin() instead.
  42. *
  43. * @see feeds_plugin()
  44. */
  45. public static function instance($class, $id, array $plugin_definition = array()) {
  46. if (!strlen($id)) {
  47. throw new InvalidArgumentException(t('Empty configuration identifier.'));
  48. }
  49. $instances = &drupal_static(__METHOD__, array());
  50. if (!isset($instances[$class][$id])) {
  51. $instance = new $class($id);
  52. // The ordering here is important. The plugin definition should be usable
  53. // in getConfig().
  54. $instance->setPluginDefinition($plugin_definition);
  55. $instance->setConfig($instance->configDefaults());
  56. $instances[$class][$id] = $instance;
  57. }
  58. return $instances[$class][$id];
  59. }
  60. /**
  61. * Returns the type of plugin.
  62. *
  63. * @return string
  64. * One of either 'fetcher', 'parser', or 'processor'.
  65. */
  66. abstract public function pluginType();
  67. /**
  68. * Returns the plugin definition.
  69. *
  70. * @return array
  71. * The plugin definition array.
  72. *
  73. * @see ctools_get_plugins()
  74. */
  75. public function pluginDefinition() {
  76. return $this->pluginDefinition;
  77. }
  78. /**
  79. * Sets the plugin definition.
  80. *
  81. * This is protected since we're only using it in FeedsPlugin::instance().
  82. *
  83. * @param array $plugin_definition
  84. * The plugin definition.
  85. */
  86. protected function setPluginDefinition(array $plugin_definition) {
  87. $this->pluginDefinition = $plugin_definition;
  88. }
  89. /**
  90. * Save changes to the configuration of this object.
  91. * Delegate saving to parent (= Feed) which will collect
  92. * information from this object by way of getConfig() and store it.
  93. */
  94. public function save() {
  95. feeds_importer($this->id)->save();
  96. }
  97. /**
  98. * Returns TRUE if $this->sourceForm() returns a form.
  99. */
  100. public function hasSourceConfig() {
  101. $form = $this->sourceForm(array());
  102. return !empty($form);
  103. }
  104. /**
  105. * Implements FeedsSourceInterface::sourceDefaults().
  106. */
  107. public function sourceDefaults() {
  108. $values = array_flip(array_keys($this->sourceForm(array())));
  109. foreach ($values as $k => $v) {
  110. $values[$k] = '';
  111. }
  112. return $values;
  113. }
  114. /**
  115. * Callback methods, exposes source form.
  116. */
  117. public function sourceForm($source_config) {
  118. return array();
  119. }
  120. /**
  121. * Validation handler for sourceForm.
  122. */
  123. public function sourceFormValidate(&$source_config) {}
  124. /**
  125. * A source is being saved.
  126. */
  127. public function sourceSave(FeedsSource $source) {}
  128. /**
  129. * A source is being deleted.
  130. */
  131. public function sourceDelete(FeedsSource $source) {}
  132. /**
  133. * Loads on-behalf implementations from mappers/ directory.
  134. *
  135. * FeedsProcessor::map() does not load from mappers/ as only node and user
  136. * processor ship with on-behalf implementations.
  137. *
  138. * @see FeedsNodeProcessor::map()
  139. * @see FeedsUserProcessor::map()
  140. *
  141. * @todo: Use CTools Plugin API.
  142. */
  143. public static function loadMappers() {
  144. static $loaded = FALSE;
  145. if (!$loaded) {
  146. $path = drupal_get_path('module', 'feeds') . '/mappers';
  147. $files = drupal_system_listing('/.*\.inc$/', $path, 'name', 0);
  148. foreach ($files as $file) {
  149. if (strstr($file->uri, '/mappers/')) {
  150. require_once(DRUPAL_ROOT . '/' . $file->uri);
  151. }
  152. }
  153. }
  154. $loaded = TRUE;
  155. }
  156. /**
  157. * Get all available plugins.
  158. */
  159. public static function all() {
  160. ctools_include('plugins');
  161. $plugins = ctools_get_plugins('feeds', 'plugins');
  162. $result = array();
  163. foreach ($plugins as $key => $info) {
  164. if (!empty($info['hidden'])) {
  165. continue;
  166. }
  167. $result[$key] = $info;
  168. }
  169. // Sort plugins by name and return.
  170. uasort($result, 'feeds_plugin_compare');
  171. return $result;
  172. }
  173. /**
  174. * Determines whether given plugin is derived from given base plugin.
  175. *
  176. * @param $plugin_key
  177. * String that identifies a Feeds plugin key.
  178. * @param $parent_plugin
  179. * String that identifies a Feeds plugin key to be tested against.
  180. *
  181. * @return
  182. * TRUE if $parent_plugin is directly *or indirectly* a parent of $plugin,
  183. * FALSE otherwise.
  184. */
  185. public static function child($plugin_key, $parent_plugin) {
  186. ctools_include('plugins');
  187. $plugins = ctools_get_plugins('feeds', 'plugins');
  188. $info = $plugins[$plugin_key];
  189. if (empty($info['handler']['parent'])) {
  190. return FALSE;
  191. }
  192. elseif ($info['handler']['parent'] == $parent_plugin) {
  193. return TRUE;
  194. }
  195. else {
  196. return self::child($info['handler']['parent'], $parent_plugin);
  197. }
  198. }
  199. /**
  200. * Determines the type of a plugin.
  201. *
  202. * @todo PHP5.3: Implement self::type() and query with $plugin_key::type().
  203. *
  204. * @param $plugin_key
  205. * String that identifies a Feeds plugin key.
  206. *
  207. * @return
  208. * One of the following values:
  209. * 'fetcher' if the plugin is a fetcher
  210. * 'parser' if the plugin is a parser
  211. * 'processor' if the plugin is a processor
  212. * FALSE otherwise.
  213. */
  214. public static function typeOf($plugin_key) {
  215. if (self::child($plugin_key, 'FeedsFetcher')) {
  216. return 'fetcher';
  217. }
  218. elseif (self::child($plugin_key, 'FeedsParser')) {
  219. return 'parser';
  220. }
  221. elseif (self::child($plugin_key, 'FeedsProcessor')) {
  222. return 'processor';
  223. }
  224. return FALSE;
  225. }
  226. /**
  227. * Gets all available plugins of a particular type.
  228. *
  229. * @param $type
  230. * 'fetcher', 'parser' or 'processor'
  231. */
  232. public static function byType($type) {
  233. $plugins = self::all();
  234. $result = array();
  235. foreach ($plugins as $key => $info) {
  236. if ($type == self::typeOf($key)) {
  237. $result[$key] = $info;
  238. }
  239. }
  240. return $result;
  241. }
  242. /**
  243. * Implements FeedsConfigurable::dependencies().
  244. */
  245. public function dependencies() {
  246. $dependencies = parent::dependencies();
  247. // Find out which module provides this plugin.
  248. $plugin_info = $this->pluginDefinition();
  249. if (isset($plugin_info['module'])) {
  250. $dependencies[$plugin_info['module']] = $plugin_info['module'];
  251. }
  252. return $dependencies;
  253. }
  254. }
  255. /**
  256. * Used when a plugin is missing.
  257. */
  258. class FeedsMissingPlugin extends FeedsPlugin {
  259. public function pluginType() {
  260. return 'missing';
  261. }
  262. public function save() {}
  263. /**
  264. * Fetcher methods.
  265. */
  266. public function fetch(FeedsSource $source) {
  267. return new FeedsFetcherResult('');
  268. }
  269. public function clear(FeedsSource $source) {}
  270. public function request($feed_nid = 0) {
  271. drupal_access_denied();
  272. }
  273. public function menuItem() {
  274. return array();
  275. }
  276. public function subscribe(FeedsSource $source) {}
  277. public function unsubscribe(FeedsSource $source) {}
  278. public function importPeriod(FeedsSource $source) {}
  279. /**
  280. * Parser methods.
  281. */
  282. public function parse(FeedsSource $source, FeedsFetcherResult $fetcher_result) {
  283. return new FeedsParserResult();
  284. }
  285. public function getMappingSources() {
  286. return array();
  287. }
  288. /**
  289. * Processor methods.
  290. */
  291. public function process(FeedsSource $source, FeedsParserResult $parser_result) {}
  292. public function entityType() {}
  293. public function bundle() {}
  294. public function bundleOptions() {
  295. return array();
  296. }
  297. public function getLimit() {
  298. return 0;
  299. }
  300. public function getMappings() {
  301. return array();
  302. }
  303. public function getMappingTargets() {
  304. return array();
  305. }
  306. public function expire(FeedsSource $source, $time = NULL) {}
  307. public function itemCount(FeedsSource $source) {
  308. return 0;
  309. }
  310. public function expiryTime() {
  311. return FEEDS_EXPIRE_NEVER;
  312. }
  313. }
  314. /**
  315. * Sort callback for FeedsPlugin::all().
  316. */
  317. function feeds_plugin_compare($a, $b) {
  318. return strcasecmp($a['name'], $b['name']);
  319. }