View source
<?php
namespace Drupal\feed_import_base;
use Drupal\field\Entity\FieldStorageConfig;
class FeedImport {
const FEED_OK = 1;
const FEED_SOURCE_ERR = 2;
const FEED_ITEMS_ERR = 3;
const FEED_OVERLAP_ERR = 4;
const FEED_CONFIG_ERR = 5;
protected static $entityInfo = array();
public static function getEntityInfo($entity_name) {
if (empty($entity_name)) {
return FALSE;
}
elseif (isset(static::$entityInfo[$entity_name])) {
return static::$entityInfo[$entity_name];
}
if (!($entity = \Drupal::entityTypeManager()
->getDefinition($entity_name))) {
return FALSE;
}
$info = (object) array(
'name' => $entity_name,
'idKey' => $entity
->getKey('id') ? $entity
->getKey('id') : NULL,
'langKey' => $entity
->getKey('langcode') ? $entity
->getKey('langcode') : 'langcode',
'bundleKey' => $entity
->getKey('bundle') ? $entity
->getKey('bundle') : NULL,
'controller' => \Drupal::entityTypeManager()
->getStorage($entity_name),
'properties' => array(),
'fields' => array(),
);
if ($info->controller) {
$info->controller->canSave = method_exists($info->controller, 'save');
$info->controller->canDelete = method_exists($info->controller, 'delete');
}
else {
$info->controller = (object) array(
'canCreate' => FALSE,
'canSave' => FALSE,
'canDelete' => FALSE,
'canResetCache' => FALSE,
);
}
$bundles = \Drupal::service('entity_type.bundle.info')
->getBundleInfo($entity_name);
foreach (array_keys($bundles) as $bundle_name) {
if ($fieldlist = \Drupal::service('entity_field.manager')
->getFieldDefinitions($entity_name, $bundle_name)) {
foreach ($fieldlist as &$field) {
$field_info = FieldStorageConfig::loadByName($entity_name, $field
->getName());
if ($field_info && (method_exists($field, 'isDeleted') && !$field
->isDeleted()) && !isset($info->fields[$field
->getName()])) {
$info->fields[$field
->getName()] = array(
'name' => $field
->getName(),
'column' => key($field_info
->getSchema()['columns']),
'columns' => array_keys($field_info
->getSchema()['columns']),
'cardinality' => $field_info
->getCardinality(),
'type' => $field
->getType(),
'module' => $field_info
->getTypeProvider(),
);
}
else {
if (!isset($info->properties[$field
->getName()])) {
$info->properties[$field
->getName()] = $field
->getName();
}
}
}
}
}
return static::$entityInfo[$entity_name] = $info;
}
protected static $entityNames = array();
public static function getAllEntities() {
if (!static::$entityNames) {
foreach (\Drupal::entityManager()
->getDefinitions() as $entity => $info) {
static::$entityNames[$entity] = $info
->getLabel();
}
}
return static::$entityNames;
}
public static $defaultFieldCompareFunction = '_feed_import_base_compare_other_fields';
public static function setProcessorSettings(FeedImportProcessor $fi, $feed, $filter_dir) {
$s = $feed->settings;
$ok = TRUE;
$ok = $ok && $fi
->setEntityInfo(static::getEntityInfo($feed->entity));
$ok = $ok && $fi
->setOptions($s['processor']['options']);
if (!isset($s['functions'])) {
$s['functions'] = NULL;
}
$ok = $ok && $fi
->setFilter(new $s['filter']['class']($filter_dir, $s['filter']['options']), $s['functions']);
$ok = $ok && $fi
->setReader(new $s['reader']['class']($s['reader']['options']));
$hm = new $s['hashes']['class']($feed->entity, $feed->machine_name);
$hm
->setOptions($s['hashes']['options']);
$ok = $ok && $fi
->setHashManager($hm);
$ok = $ok && $fi
->setUniq($s['uniq_path']);
$ok = $ok && $fi
->setFields($s['fields'], $s['static_fields'], static::getFieldsCompareFunctions(), static::getMergeFieldClasses(), static::$defaultFieldCompareFunction);
$ok = $ok && $fi
->setCustomSettings(array_diff_key($s, array(
'uniq_path' => 1,
'processor' => 1,
'reader' => 1,
'hashes' => 1,
'filter' => 1,
'fields' => 1,
'static_fields' => 1,
'feed' => 1,
'functions' => 1,
)));
return $ok ? TRUE : $fi
->getErrors();
}
public static function getFieldsCompareFunctions() {
$funcs = \Drupal::moduleHandler()
->invokeAll('feed_import_field_compare_functions');
foreach ($funcs as $type => &$f) {
if (is_array($f)) {
for ($i = 0, $max = count($f); $i < $max; $i++) {
if (is_callable($f[$i])) {
$f = $f[$i];
continue 2;
}
}
unset($funcs[$type]);
}
elseif (!is_callable($f)) {
unset($funcs[$type]);
}
}
return $funcs;
}
public static function getMergeFieldClasses() {
$classes = \Drupal::moduleHandler()
->invokeAll('feed_import_field_merge_classes');
foreach ($classes as $key => &$class) {
if (isset($class['class'])) {
$class = $class['class'];
}
else {
unset($classes[$key]);
}
}
return $classes;
}
protected static $feedsList = array();
public static function loadAllFeeds() {
if (static::$feedsList) {
return static::$feedsList;
}
$feeds = db_select('feed_import_settings', 'f')
->fields('f')
->orderBy('id', 'DESC')
->execute()
->fetchAll();
$ret = array();
foreach ($feeds as &$feed) {
$feed->settings = unserialize($feed->settings);
$ret[$feed->machine_name] = $feed;
}
return static::$feedsList = $ret;
}
public static function loadFeed($name) {
$feed = db_select('feed_import_settings', 'f')
->fields('f')
->condition((int) $name ? 'id' : 'machine_name', $name, '=')
->range(0, 1)
->execute()
->fetchObject();
if (!$feed) {
return FALSE;
}
$feed->settings = unserialize($feed->settings);
return $feed;
}
public static function deleteFeed($feed, $hashes = TRUE) {
db_delete('feed_import_settings')
->condition('machine_name', $feed->machine_name)
->execute();
if ($hashes && isset($feed->settings['hashes']['class'])) {
$class = $feed->settings['hashes']['class'];
$class::deleteByFeed($feed->machine_name);
}
}
public static function getEmptyFeed() {
return array(
'name' => NULL,
'machine_name' => NULL,
'entity' => NULL,
'cron_import' => 0,
'last_run' => 0,
'last_run_duration' => 0,
'last_run_items' => 0,
'settings' => array(
'uniq_path' => NULL,
'preprocess' => NULL,
'feed' => array(
'protect_on_invalid_source' => FALSE,
'protect_on_fewer_items' => 0,
),
'processor' => array(
'name' => 'default',
'class' => 'Drupal\\feed_import_base\\FeedImportProcessor',
'options' => array(
'items_count' => 0,
'skip_imported' => FALSE,
'reset_cache' => 100,
'break_on_undefined_filter' => TRUE,
'skip_defined_functions_check' => FALSE,
'updates_only' => FALSE,
),
),
'reader' => array(
'name' => 'xml',
'class' => 'Drupal\\feed_import_base\\SimpleXMLFIReader',
'options' => array(),
),
'hashes' => array(
'name' => 'sql',
'class' => 'Drupal\\feed_import_base\\FeedImportSQLHashes',
'options' => array(
'ttl' => 0,
'insert_chunk' => 300,
'update_chunk' => 300,
'group' => '',
),
),
'filter' => array(
'name' => 'default',
'class' => 'Drupal\\feed_import_base\\FeedImportMultiFilter',
'options' => array(
'param' => '[field]',
'include' => NULL,
),
),
'fields' => array(),
'static_fields' => array(),
'functions' => array(),
),
);
}
public static function saveFeed($feed) {
if (empty($feed->name) || empty($feed->machine_name) || empty($feed->entity) || empty($feed->settings)) {
return FALSE;
}
if (!isset($feed->cron_import)) {
$feed->cron_import = 0;
}
$fields = array(
'name' => $feed->name,
'machine_name' => $feed->machine_name,
'entity' => $feed->entity,
'cron_import' => (int) $feed->cron_import,
'settings' => serialize($feed->settings),
);
if (isset($feed->id)) {
db_update('feed_import_settings')
->fields($fields)
->condition('id', $feed->id)
->execute();
}
else {
$fields += array(
'last_run' => 0,
'last_run_duration' => 0,
'last_run_items' => 0,
);
db_insert('feed_import_settings')
->fields($fields)
->execute();
}
return TRUE;
}
public static function saveFeedImportStatus($feed) {
db_update('feed_import_settings')
->fields(array(
'last_run' => (int) $feed->last_run,
'last_run_duration' => (int) $feed->last_run_duration,
'last_run_items' => (int) $feed->last_run_items,
))
->condition('machine_name', $feed->machine_name)
->execute();
}
public static $activeImport = NULL;
public static function import($feed, $filters_dir) {
if (!empty($feed->settings['preprocess']) && function_exists($feed->settings['preprocess'])) {
call_user_func($feed->settings['preprocess'], $feed);
}
$class = $feed->settings['processor']['class'];
$fi = new $class($feed->machine_name);
$fi
->setErrorHandler(TRUE);
$f = static::setProcessorSettings($fi, $feed, $filters_dir);
if ($f !== TRUE) {
$fi
->setErrorHandler(FALSE);
return array(
'init_error' => TRUE,
'errors' => $f,
);
}
unset($f);
$lastimport = static::$activeImport;
static::$activeImport = $fi;
$f = $fi
->process();
static::$activeImport = $lastimport;
$fi
->setErrorHandler(FALSE);
return $f;
}
public static function getHashManagers() {
static $hm = array();
if (!$hm) {
foreach (static::loadAllFeeds() as $feed) {
if (!empty($feed->settings['hashes']['class'])) {
$hm[] = $feed->settings['hashes']['class'];
}
}
$hm = array_unique($hm);
}
return $hm;
}
public static function deleteExpired($max = 0) {
$deleted = 0;
foreach (static::loadAllFeeds() as $feed) {
if (empty($feed->settings['hashes']['class'])) {
continue;
}
$class = $feed->settings['hashes']['class'];
$items = $class::getExpired($feed->machine_name, $max);
foreach ($items as $e => &$ids) {
$entity = static::getEntityInfo($e);
if ($entity->deleteCallback) {
$f = $entity->deleteCallback . '_multiple';
if (function_exists($f)) {
$f($ids);
}
else {
array_map($entity->deleteCallback, $ids);
}
}
else {
$entity->controller
->delete($ids);
}
$class::delete(array_keys($ids));
$deleted += count($ids);
unset($items[$e], $entity);
}
}
return $deleted;
}
protected static $deletedEntities = array();
public static function addDeletedEntity($entity_type, $id) {
static $unregistered = TRUE;
if ($unregistered) {
$unregistered = FALSE;
register_shutdown_function(array(
__CLASS__,
'removeEntityHashes',
));
}
static::$deletedEntities[$entity_type][] = $id;
}
public static function removeEntityHashes($entities = NULL) {
if ($entities == NULL) {
$entities =& static::$deletedEntities;
}
foreach (static::getHashManagers() as $hm) {
array_walk($entities, array(
$hm,
'deleteEntities',
));
}
$entities = NULL;
}
}