View source
<?php
use Drupal\feed_import_base\FeedImport;
use Drupal\Core\Url;
define('FEED_IMPORT_PATH', 'admin/config/services/feed_import');
function feed_import_help($path, $arg) {
if ($path == 'admin/help#feed_import') {
$vars = array(
'!project_page' => \Drupal::l('Feed Import', \Drupal\Core\Url::fromUri('http://drupal.org/project/feed_import')),
);
$help = t('Imports content from various file types (like XML, HTML, CSV, JSON, ...) or from databases.');
$help .= '<br />';
$help .= t('For more info please go to !project_page.', $vars);
return $help;
}
}
function feed_import_load($feed) {
return FeedImport::loadFeed($feed);
}
function feed_import_feed_import_reader_info() {
$items = array();
$stream = array(
'#type' => 'textarea',
'#title' => t('Stream context options'),
'#description' => t('You can set string context options in JSON format.') . ' ' . t('For more info check %link', array(
'%link' => \Drupal::l('stream_context_create()', \Drupal\Core\Url::fromUri('http://www.php.net/manual/en/function.stream-context-create.php')),
)),
'#element_validate' => array(
'feed_import_element_validate_json',
),
);
$sxeclass = array(
'#type' => 'textfield',
'#title' => t('SimpleXMLElement class'),
'#default_value' => 'SimpleXMLElement',
'#required' => TRUE,
'#element_validate' => array(
'feed_import_element_validate_simplexmlclass',
),
);
if (!defined('LIBXML_PARSEHUGE')) {
define('LIBXML_PARSEHUGE', 524288);
}
$parent_xpath = array(
'#type' => 'textfield',
'#title' => t('Parent XPATH, this is the context for desired items'),
'#description' => t('All field paths must be relative to parent.'),
'#maxlength' => 1024,
'#required' => TRUE,
);
$libxml = array(
'#type' => 'select',
'#multiple' => TRUE,
'#title' => t('LibXml options'),
'#description' => t('Select desired libxml options.') . ' ' . t('For more info check %link', array(
'%link' => \Drupal::l('libxml options', Url::fromUri('http://www.php.net/manual/en/libxml.constants.php')),
)),
'#default_value' => array(
LIBXML_NOBLANKS,
LIBXML_NOCDATA,
),
'#size' => 6,
'#options' => array(
LIBXML_NOBLANKS => t('Remove blank nodes'),
LIBXML_NOCDATA => t('Merge CDATA as text nodes'),
LIBXML_NOENT => t('Substitute entities'),
LIBXML_PARSEHUGE => t('Parse huge'),
LIBXML_XINCLUDE => t('Implement XInclude substitution'),
LIBXML_NOERROR => t('No error reports'),
LIBXML_NOWARNING => t('No warning reports'),
),
);
$raw = array(
'#type' => 'textarea',
'#title' => t('Raw source string'),
'#description' => t('You can use this source for tests if you remove the URL.'),
'#default_value' => '',
);
$items['xml'] = array(
'name' => t('XML Document'),
'description' => t('Use this reader when the XML file is not huge.') . ' ' . t('Paths must be in XPATH 1.0 format.'),
'inherit_options' => FALSE,
'class' => 'Drupal\\feed_import_base\\SimpleXMLFIReader',
'options' => array(
'url' => array(
'#type' => 'textfield',
'#title' => t('URL to a valid XML resource'),
'#description' => t('You can also use local filesystem paths.'),
'#maxlength' => 1024,
),
'parent' => $parent_xpath,
'class' => $sxeclass,
'options' => $libxml,
'namespaces' => array(
'#type' => 'textarea',
'#title' => t('Register namespaces for XML (only for XMLs having namespaces)'),
'#description' => t('Each namespace must be on a line in the following format: name=URI'),
),
'stream' => $stream,
'raw' => $raw,
),
);
$items['xml-chunked'] = array(
'name' => t('XML Chunked'),
'description' => t('Use this reader when the XML file is huge.') . ' ' . t('Paths must be in XPATH 1.0 format.'),
'inherit_options' => FALSE,
'class' => 'Drupal\\feed_import_base\\ChunkedXMLFIReader',
'options' => array(
'url' => array(
'#type' => 'textfield',
'#title' => t('URL to a valid XML resource'),
'#description' => t('You can also use local filesystem paths.'),
'#required' => TRUE,
'#maxlength' => 1024,
),
'parent' => $parent_xpath,
'size' => array(
'#type' => 'textfield',
'#title' => t('Chunk size in bytes'),
'#description' => t('How many bytes to read in each chunk.'),
'#default_value' => 8192,
'#size' => 10,
'#required' => TRUE,
'#element_validate' => array(
'element_validate_integer_positive',
),
),
'substr' => array(
'#type' => 'select',
'#title' => t('Substring function'),
'#description' => t('Which substring function to use.'),
'#options' => array(
'substr' => t('Default PHP substring'),
'mb_substr' => t('Multibyte PHP substring'),
'drupal_substr' => t('Drupal substring'),
),
'#default_value' => 'substr',
'#required' => TRUE,
),
'properties' => array(
'#type' => 'textfield',
'#title' => t('XML properties'),
'#description' => t('Change XML properties (like encoding).'),
'#default_value' => '<?xml version="1.0" encoding="utf-8"?>',
'#maxlength' => 1024,
'#element_validate' => array(
'feed_import_element_validate_xmldec',
),
),
'stream' => $stream,
'class' => $sxeclass,
),
);
$items['dom'] = array(
'name' => t('DomDocument XML/HTML'),
'description' => t('Use this reader for XML or HTML files.') . ' ' . t('Path must be in XPATH 1.0 format, but you can register PHP functions for XPATH.'),
'class' => 'Drupal\\feed_import_base\\DomXMLFIReader',
'inherit_options' => FALSE,
'options' => array(
'format' => array(
'#type' => 'select',
'#title' => t('Document format'),
'#options' => array(
'xml' => 'XML',
'html' => 'HTML',
),
'#default_value' => 'xml',
'#required' => TRUE,
),
'url' => array(
'#type' => 'textfield',
'#title' => t('URL to a valid XML/HTML resource'),
'#description' => t('You can also use local filesystem paths.'),
'#maxlength' => 1024,
),
'parent' => $parent_xpath,
'php_func' => array(
'#type' => 'textarea',
'#title' => t('Register php functions for XPATHs'),
'#description' => t('Use one function per line. You may use them in xpaths like this @xpath', array(
'@xpath' => '//book[php:functionString("substr", title, 0, 3) = "PHP"]',
)),
'#default_value' => '',
),
'namespaces' => array(
'#type' => 'textarea',
'#title' => t('Register namespaces for XML (only for XMLs having namespaces)'),
'#description' => t('Each namespace must be on a line in the following format: name=URI'),
),
'options' => $libxml,
'silence_load_errors' => array(
'#type' => 'checkbox',
'#title' => t('Silence load errors'),
'#description' => t('This will not report errors on document load.'),
'#default_value' => FALSE,
),
'strictErrorChecking' => array(
'#type' => 'checkbox',
'#title' => t('Strict error checking'),
'#description' => t('Throws DOM errors.'),
'#default_value' => FALSE,
),
'preserveWhiteSpace' => array(
'#type' => 'checkbox',
'#title' => t('Preserve whitespace'),
'#description' => t('Do not remove redundant white space.'),
'#default_value' => FALSE,
),
'resolveExternals' => array(
'#type' => 'checkbox',
'#title' => t('Resolve externals'),
'#description' => t('Load external entities from a doctype declaration.'),
'#default_value' => FALSE,
),
'recover' => array(
'#type' => 'checkbox',
'#title' => t('Recover'),
'#description' => t('Try to parse non-well formed documents.'),
'#default_value' => FALSE,
),
'normalizeDocument' => array(
'#type' => 'checkbox',
'#title' => t('Normalize document'),
'#description' => t('Putting the document in a "normal" form by simulating save and load.'),
'#default_value' => FALSE,
),
'stream' => $stream,
'raw' => $raw,
),
);
$items['sql'] = array(
'name' => t('SQL resultset'),
'description' => t('Use this reader for SQL resultset.') . ' ' . t('Paths must be column names.') . ' ' . t('You can group multiple paths using | (pipe).'),
'class' => 'Drupal\\feed_import_base\\SQLFIReader',
'inherit_options' => FALSE,
'options' => array(
'dsn' => array(
'#type' => 'textfield',
'#title' => t('Data Source Name'),
'#maxlength' => 1024,
'#description' => t('Required info to connect to the database.') . ' ' . t('For more info check %link', array(
'%link' => \Drupal::l('PDO', \Drupal\Core\Url::fromUri('http://www.php.net/manual/en/pdo.construct.php')),
)),
'#required' => TRUE,
),
'user' => array(
'#type' => 'textfield',
'#title' => t('Username'),
'#description' => t('Database username.'),
'#required' => TRUE,
),
'pass' => array(
'#type' => 'textfield',
'#title' => t('Password'),
'#description' => t('Database password.'),
),
'query' => array(
'#type' => 'textarea',
'#title' => t('SQL Query'),
'#description' => t('This SQL query must extract desired information for import. Use ? or :param_name as placeholder for params.'),
'#required' => TRUE,
),
'params' => array(
'#type' => 'textarea',
'#title' => t('Query params'),
'#description' => t('Params will be binded to query. Use one param per line.') . ' ' . t('Param format is :name=value (where :name is the placeholder) or simply value if you want to replace the ? placeholder.'),
),
),
);
$items['csv'] = array(
'name' => t('CSV file'),
'description' => t('Use this reader for CSV files.') . ' ' . t('Paths must be indexes or column names.') . ' ' . t('You can group multiple paths using | (pipe).'),
'inherit_options' => FALSE,
'class' => 'Drupal\\feed_import_base\\CSVFIReader',
'options' => array(
'url' => array(
'#type' => 'textfield',
'#title' => t('URL to a valid CSV resource'),
'#description' => t('You can also use local filesystem paths.'),
'#maxlength' => 1024,
'#required' => TRUE,
),
'use_column_names' => array(
'#type' => 'checkbox',
'#title' => t('Use column names for paths'),
'#description' => t('Use this only when the CSV have on the first line the column names.'),
'#default_value' => FALSE,
),
'length' => array(
'#type' => 'textfield',
'#title' => t('Line length'),
'#description' => t('This is only a hint.'),
'#required' => TRUE,
'#default_value' => 0,
'#element_validate' => array(
'element_validate_integer',
),
),
'delimiter' => array(
'#type' => 'textfield',
'#title' => t('Delimiter'),
'#description' => t('CSV delimiter char.'),
'#default_value' => ',',
'#maxlength' => 1,
'#size' => 1,
'#element_validate' => 'feed_import_element_validate_not_empty',
),
'enclosure' => array(
'#type' => 'textfield',
'#title' => t('Enclosure'),
'#description' => t('CSV enclosure char.'),
'#default_value' => '"',
'#maxlength' => 1,
'#size' => 1,
'#required' => TRUE,
),
'escape' => array(
'#type' => 'textfield',
'#title' => t('Escape'),
'#description' => t('CSV escape char.'),
'#default_value' => '\\',
'#maxlength' => 1,
'#size' => 1,
'#required' => TRUE,
),
'stream' => $stream,
),
);
$items['json'] = array(
'name' => t('JSON file'),
'description' => t('Use this reader for JSON files.') . ' ' . t('Path format is a/b/c.') . ' ' . t('You can group multiple paths using | (pipe).'),
'class' => 'Drupal\\feed_import_base\\JSONFIReader',
'inherit_options' => FALSE,
'options' => array(
'url' => array(
'#type' => 'textfield',
'#title' => t('URL to a valid JSON resource'),
'#description' => t('You can also use local filesystem paths.'),
'#maxlength' => 1024,
),
'parent' => array(
'#type' => 'textfield',
'#title' => t('Parent path, this is the context for desired items'),
'#description' => t('All field paths must be relative to parent.'),
'#maxlength' => 1024,
),
'stream' => $stream,
'raw' => $raw + array(
'#element_validate' => array(
'feed_import_element_validate_json',
),
),
),
);
return $items;
}
function feed_import_feed_import_processor_info() {
return array(
'default' => array(
'name' => t('Feed Import Processor'),
'description' => t('Processor provided by Feed Import module'),
'class' => 'Drupal\\feed_import_base\\FeedImportProcessor',
'inherit_options' => FALSE,
'options' => array(
'items_count' => array(
'#type' => 'textfield',
'#title' => 'After how many created entities to save them',
'#description' => t('Use 0 for creating all entities first.'),
'#default_value' => 300,
'#required' => TRUE,
'#element_validate' => array(
'element_validate_integer',
),
),
'skip_imported' => array(
'#type' => 'checkbox',
'#title' => t('Skip already imported items'),
'#default_value' => FALSE,
'#description' => t('This is possible only when items are monitored.'),
),
'updates_only' => array(
'#type' => 'checkbox',
'#title' => t('Only update already imported items'),
'#default_value' => FALSE,
'#description' => t('Using this option no new entity will be created.') . ' ' . t('This is possible only when items are monitored.'),
'#element_validate' => array(
'feed_import_element_validate_updates_only',
),
),
'reset_cache' => array(
'#type' => 'textfield',
'#title' => t('Reset entity static cache'),
'#description' => t('After how many cached entities to reset the in-memory cache.') . ' ' . t('This can reduce memory usage. Use 0 to ignore it.'),
'#default_value' => 100,
'#element_validate' => array(
'element_validate_integer',
),
'#required' => TRUE,
),
'throw_exception' => array(
'#type' => 'checkbox',
'#title' => t('Throw exception on error'),
'#default_value' => TRUE,
'#description' => t('Will break import on errors.') . ' ' . t('Also, this is useful for developers.'),
),
'max_reported_errors' => array(
'#type' => 'textfield',
'#title' => t('Maximum number of errors to log'),
'#default_value' => 100,
'#element_validate' => array(
'element_validate_integer_positive',
),
'#required' => TRUE,
),
'break_on_undefined_filter' => array(
'#type' => 'checkbox',
'#title' => t('Stop import if a filter function is not declared'),
'#default_value' => TRUE,
),
'skip_defined_functions_check' => array(
'#type' => 'checkbox',
'#title' => t('Skip creating already declared dynamic functions'),
'#description' => t('This is usefull if you try to import multiple feeds that declare same dynamic function names.') . ' ' . t('However, it is recommended to put those functions in a php filter file rather than creating them dynamically.'),
'#default_value' => FALSE,
),
'uniq_callback' => array(
'#type' => 'textfield',
'#title' => t('Unique id alter callback'),
'#description' => t('Function to call before the hash is computed using unique id value.'),
'#default_value' => '',
),
'after_save' => array(
'#type' => 'textfield',
'#title' => t('Entity after save/update callback'),
'#description' => t('Function to call after entity was saved or updated.'),
'#default_value' => '',
),
'before_combine' => array(
'#type' => 'textfield',
'#title' => t('Entity before combine callback'),
'#description' => t('Return of this function decides if new and current entity versions will be combined, skipped or rescheduled.'),
'#default_value' => '',
),
'after_combine' => array(
'#type' => 'textfield',
'#title' => t('Entity after combine callback'),
'#description' => t('Return of this function decides if the new entity will be updated, skipped or rescheduled.'),
'#default_value' => '',
),
'before_create' => array(
'#type' => 'textfield',
'#title' => t('Entity before create callback'),
'#description' => t('Return of this function decides if will skip the entity import, create or save.'),
'#default_value' => '',
),
'before_save' => array(
'#type' => 'textfield',
'#title' => t('Entity before save callback'),
'#description' => t('Return of this function decides if will skip entity import or save.'),
'#default_value' => '',
),
),
),
);
}
function feed_import_feed_import_hash_manager_info() {
$items = array(
'sql' => array(
'name' => t('SQL Hash Manager'),
'description' => t('Monitored data is saved in database.'),
'inherit_options' => FALSE,
'class' => 'Drupal\\feed_import_base\\FeedImportSQLHashes',
'options' => array(
'group' => array(
'#type' => 'textfield',
'#title' => t('Group'),
'#description' => t('Multiple feeds can update same entities if belong to same group.'),
'#default_value' => '',
'#required' => TRUE,
),
'ttl' => array(
'#type' => 'textfield',
'#title' => t('Keep imported items (seconds)'),
'#description' => t('This is used to delete items after expiration. Use 0 to keep items forever.'),
'#default_value' => 0,
'#element_validate' => array(
'element_validate_integer',
),
'#required' => TRUE,
),
'update_chunk' => array(
'#type' => 'textfield',
'#title' => t('Minimum number of hashes to commit update'),
'#default_value' => 300,
'#element_validate' => array(
'element_validate_integer_positive',
),
'#required' => TRUE,
),
'insert_chunk' => array(
'#type' => 'textfield',
'#title' => t('Minimum number of hashes to commit insert'),
'#default_value' => 300,
'#element_validate' => array(
'element_validate_integer_positive',
),
'#required' => TRUE,
),
),
),
);
$items['sqlv2compatible'] = array(
'class' => 'Drupal\\feed_import_base\\FeedImportSQLHashesv2Compatible',
'name' => t('SQL Hash Manager 2.x compatible'),
'description' => t('Monitored data is saved in database.') . '<br>' . t('Do not use this for new feeds and do not change it if used!'),
'inherit_options' => 'sql',
'options' => array(
'group' => array(
'#description' => t('You cannot change the group, but you can use this group in other feeds.'),
'#disabled' => TRUE,
),
),
);
return $items;
}
function feed_import_feed_import_filter_info() {
return array(
'default' => array(
'name' => t('Feed Import filter'),
'description' => t('Filter class provided by Feed Import module'),
'inherit_options' => FALSE,
'class' => 'Drupal\\feed_import_base\\FeedImportMultiFilter',
'options' => array(
'param' => array(
'#title' => t('Filter param placeholder'),
'#description' => t('The value of field placeholder used for filter params.'),
'#default_value' => '[field]',
'#type' => 'textfield',
'#required' => TRUE,
'#element_validate' => array(
'feed_import_element_validate_not_numeric',
),
),
'include' => array(
'#type' => 'textarea',
'#title' => t('Include the following PHP files'),
'#description' => t('This files should contain additional filters.') . ' ' . t('Enter paths to PHP files (one per line).') . ' ' . t('Paths are relative to @dir folder.', array(
'@dir' => _feed_import_base_get_filters_dir(),
)) . '<br />' . t('You can use absolute paths by prepending /.'),
'#rows' => 5,
'#default_value' => '',
),
),
),
);
}
function feed_import_feed_import_setting_types() {
return array(
'processor' => array(
'hook' => 'feed_import_processor_info',
'base' => 'Drupal\\feed_import_base\\FeedImportProcessor',
),
'reader' => array(
'hook' => 'feed_import_reader_info',
'base' => 'Drupal\\feed_import_base\\FeedImportReader',
),
'hashes' => array(
'hook' => 'feed_import_hash_manager_info',
'base' => 'Drupal\\feed_import_base\\FeedImportHashManager',
),
'filter' => array(
'hook' => 'feed_import_filter_info',
'base' => 'Drupal\\feed_import_base\\FeedImportMultiFilter',
),
);
}
function feed_import_element_validate_not_empty($element, &$form_state) {
if (!strlen($element['#value'])) {
form_error($element, t('%name must not be empty.', array(
'%name' => $element['#title'],
)));
}
}
function feed_import_element_validate_json($element, &$form_state, $form) {
if ($element['#value'] && !@json_decode($element['#value'])) {
form_error($element, t('%title contains invalid JSON code!', array(
'%title' => $element['#title'],
)));
}
}
function feed_import_element_validate_simplexmlclass($element, &$form_state, $form) {
if (!$element['#value']) {
return;
}
if ($element['#value'] != 'SimpleXMLElement' && !is_subclass_of($element['#value'], 'SimpleXMLElement')) {
form_error($element, t('%title must extend SimpleXMLElement class!', array(
'%title' => $element['#title'],
)));
}
}
function feed_import_element_validate_xmldec($element, &$form_state, $form) {
if ($element['#value'] !== '' && !preg_match("/^\\<\\?xml (.*)\\?\\>\$/", $element['#value'])) {
form_error($element, t('%title must have a valid XML declaration!', array(
'%title' => $element['#title'],
)));
}
}
function feed_import_element_validate_not_numeric($element, &$form_state, $form) {
if (is_numeric($element['#value'])) {
form_error($element, t('%title must not be numeric!', array(
'%title' => $element['#title'],
)));
}
}
function feed_import_element_validate_updates_only($element, &$form_state, $form) {
if ($element['#value'] && $form_state['values']['options']['skip_imported']) {
form_error($element, t('"%title" must not be used if "Skip already imported items" is also used. Doing so, the import makes no sense!', array(
'%title' => $element['#title'],
)));
}
}
function feed_import_entity_type_build(array &$entity_types) {
$entity_types['feed_importer']
->setFormClass('edit', 'Drupal\\feed_import\\Form\\FeedImporterEditForm')
->setFormClass('source', 'Drupal\\feed_import\\Form\\ClassSettingsForm')
->setFormClass('add', 'Drupal\\feed_import\\Form\\FeedImporterAddForm')
->setFormClass('delete', 'Drupal\\feed_import\\Form\\DeleteFeedForm')
->setListBuilderClass('Drupal\\feed_import\\FeedImporterListBuilder')
->setLinkTemplate('admin', '/admin/confg/services/feed_import')
->setLinkTemplate('edit-form', '/admin/config/services/feed_import/edit/{feed_importer}')
->setLinkTemplate('process', '/admin/config/services/feed_import/process/{feed_importer}')
->setLinkTemplate('export', '/admin/config/services/feed_import/export/{feed_importer}')
->setLinkTemplate('delete-form', '/admin/config/services/feed_import/delete/{feed_importer}')
->setLinkTemplate('source-form', '/admin/config/services/feed_import/edit/{feed_importer}/source');
}