Drupal: пишем свой парсер для Feeds

от автора

Модуль Feeds является очень популярным среди Drupal-разработчиков. Но возникает вопрос, что делать если необходимо несколько расширить его функциональность. В этом нам поможет система плагинов модуля Feeds.
Существует 3 вида плагинов от которых необходимо наследовать новые:

  • FeedsFetcher — плагин сборщика. Cтандартные: HTTP и File Upload. С помощью этого типа плагинов можно добавить новый источник данных.
  • FeedsProcessor — плагин обработки сущностей. Cтандартные: Node processor, Taxonomy term processor, User processor. С помощью нового плагина можно добавить новый обработчик, который будет создавать особенные сущности, не вписывающиеся в стандартный набор.
  • FeedsParser — плагин парсера. Стандартные парсеры в Feeds это XML, CSV и многие другие.

В этой статье я хотел бы остановиться именно на написании модуля парсера, так как довольно часто приходится иметь дело с импортом файлов со специфической структурой.

Создание модуля

Как и обычно для создания модуля нам нужно создать info файл и файл модуля:

json_example_parser.info

name = Json example parser description = Simple json parser package = Feeds core = 7.x dependencies[] = feeds 

json_example_parser.module

<?php /**  * @file  * Json example parser - simple parser plugin  */  /**  * Implementation of hook_feeds_plugins().  * Регистрация плагина в системе.  */ function json_example_parser_feeds_plugins() {   $info = array();   $info['JsonExampleParser'] = array(     'name' => 'JSON parser',     'description' => 'Parses custom JSON.',     'handler' => array(       'parent' => 'FeedsParser', // родительский класс от которого наследуем парсер, стандартные классы Feeds - FeedsFetcher, FeedsParser и FeedsProcessor       'class' => 'JsonExampleParser', // название парсера, должно совпадать с ключом в массиве       'file' => 'JsonExampleParser.inc', // файл класса парсера       'path' => drupal_get_path('module', 'json_example_parser'), // путь к классу парсера     ),   );   return $info; }  // очистка кеша плагинов Feeds при включении модуля function json_example_parser_enable() {   //clear the cache to display in Feeds as available plugin.   cache_clear_all('plugins:feeds:plugins', 'cache'); } ?> 

В комментариях описаны основных моменты хуков.

Исходные данные

Для примера за импортируемый материал возьмем ноду “Компьютерная игра” со следующими полями:

Данные, которые будем парсить, будут приходить в JSON формате. Не важно будет это загружаемый файл либо HTTP сборщик, за это отвечает Fetcher и способы получения данных зависят от набора плагинов для сборщика.

Входной JSON:

[   { "name":"Team Fortress 2",     "year":2007,     "price":0   },   { "name":"Warcraft III: The Frozen Throne",     "year":2003,     "price":13.9   },   { "name":"Diablo III",     "year":2012,     "price":33   } ] 
Создание класса парсера

Для того чтобы создать класс парсера его нужно наследовать от стандартного абстрактного класса FeedsParser и переопределить методы parse и getMappingSources. Переопределение остальных методов не является обязательным.

JsonExampleParser.inc

<?php /**  * A JSON example parser  */ class JsonExampleParser extends FeedsParser {   /**    * Implements FeedsParser::parse().    */   public function parse(FeedsSource $source, FeedsFetcherResult $fetcher_result) {     $result = new FeedsParserResult();     // получаем последние настройки     $source_config = $source->getConfigFor($this);     // извлекаем JSON данные     $fetch_items = json_decode($fetcher_result->getRaw());     foreach ($fetch_items as $value) {       $item = array('name' => $value->name);       if ($value->year) {         $item['year'] = intval($value->year);       }       if ($value->price) {         $item['price'] = floatval($value->price);       }       // применение настроек из формы       if (  $source_config['type'] == 'all' ||             ($source_config['type'] == 'free' && $item['price'] == 0) ||             ($source_config['type'] == 'paid' && $item['price'] > 0)) {         // добавляем запись для импорта         $result->items[] = $item;       }     }     return $result;   }    /**    * Implements FeedsParser::getMappingSources().    */   public function getMappingSources() {     return array(       'name' => array(         'name' => t('Game name'),         'description' => t('The name of the computer game.'),       ),       'year' => array(         'name' => t('Release year'),         'description' => t('Release year of the computer game.'),       ),       'price' => array(         'name' => t('Game price'),         'description' => t('The cost of the computer game.'),       ),     ) + parent::getMappingSources();   }    /**    * Configuration form.    * Конфигурационная форма, которая будет отображаться на странице настройки импортера.    */   public function configForm(&$form_state) {     $form = array();     $form['type'] = array(       '#type' => 'select',       '#title' => t('Game type'),       '#description' => t('Game filter by type.'),       '#options' => array(         'all' => t('All game'),         'paid' => t('Paid'),         'free' => t('Free'),       ),       '#default_value' => $this->config['type'],     );     return $form;   }    /**    * Define default configuration values.    * Стандартные настройки для парсера, которые будут применены если форма открыта впервые.    */   public function configDefaults() {     return array(       'type' => 'all',     );   }    /**    * Define defaults.    * Определение настроек отправленных из формы.    */   public function sourceDefaults() {     return array(       'type' => $this->config['type'],     );   }    /**    * Show configuration form for users.    * Конфигурационная форма которая будет отображаться пользователям на странице импорта.    */   public function sourceForm($source_config) {     $form = array();     $form['#weight'] = -10;     $form['help']['#markup'] = '<div class="help"><p>' . t('Select the type of game you want to import') . ':</p></div>';     $form['type'] = array(       '#type' => 'select',       '#title' => t('Game type'),       '#description' => t('Game filter by type.'),       '#options' => array(         'all' => t('All game'),         'paid' => t('Paid'),         'free' => t('Free'),       ),       '#default_value' => isset($source_config['type']) ? $source_config['type'] : 'all',     );     return $form;   } } 

Немного о методах.

parse — метод парсинга, получает объект класса источника FeedsSource и объект класса FeedsFetcherResult из которого извлекаются считанные данные. Данный метод формирует готовый объект FeedsParserResult с набором сущностей items для сохранения.

getMappingSources — метод который определяет поля которые будут доступны из источника для записи в поля создаваемого объекта. Например в данном случае поле маппинга name будет записываться в заголовок ноды и т.д.

configForm — этот метод предоставляет форму настройки, которая будет отображаться на странице администратора, в настройках импортера. Сохранение данных происходит автоматически.

configDefaults — стандартные настройки, если пользователь не использовал форму для конфигурации парсера.

sourceDefaults — переопределенный метод для получения доступа к сохраненным параметрам из формы конфигурации.

sourceForm — форма которая будет доступна пользователям при импорте, дополняя форму Fetcher’a.

Заключение

В результате мы получили полноценный плагин для модуля Feeds с неограниченными возможностями кастомизации настроек и обработки любых входных данных. Для более детального представление о плагинах Feeds советую посмотреть исходные коды стандартных дополнений, которые идут вместе с модулем.

ссылка на оригинал статьи http://habrahabr.ru/post/164707/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *