Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 3.0 #27

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
404 changes: 179 additions & 225 deletions content/content.importers.php

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions extension.driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ public function setXMLImporter(&$name, &$error, $new) {

// Options:
var_export($new['can-update'], true),
var_export($new['fields'], true),
$this->layoutVar($new['fields']),
var_export($new['included-elements'], true),
var_export($new['namespaces'], true),
$this->layoutVar($new['namespaces'], true),
var_export($new['source'], true),
var_export($new['timeout'], true),
var_export($new['section'], true),
Expand All @@ -221,6 +221,17 @@ public function setXMLImporter(&$name, &$error, $new) {
return true;
}

private function layoutVar($variable) {
$result = var_export($variable, true);
$result = str_replace(" ", " ", $result);
$result = str_replace("array (", "array(", $result);
$result = str_replace(" => " . PHP_EOL . " ", " => ", $result);
$result = str_replace("," . PHP_EOL . " ),", PHP_EOL . " ),", $result);
$result = str_replace(PHP_EOL, PHP_EOL . " ", $result);

return $result;
}

public function validateXPath($expression, $namespaces = array()) {
$document = new DOMDocument();
$document->loadXML('<data />');
Expand Down
11 changes: 9 additions & 2 deletions extension.meta.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,15 @@
<author>
<name github="brendo" symphony="brendo">Brendan Abbott</name>
</author>
<author>
<name github="hananils" symphony="hananils">Büro für Web- und Textgestaltung</name>
<website>http://hananils.de</website>
</author>
</authors>
<releases>
<release version="3.0.0" min="2.5.0">
- Switched from custom data fetching to Data Sources
</release>
<release version="2.2" date="2014-09-28" min="2.5.0">
- Symphony 2.5 support
- Fix to allow multiple importers to be selectable on the index again
Expand All @@ -39,13 +46,13 @@
- Update modification date on import
- Fix string handling
</release>
<release version="2.1" date="2013-05-27" min="2.3.1">
<release version="2.1.0" date="2013-05-27" min="2.3.1">
- Added support for the `ImportableField` interface
- Added logging for when errors occur
- Handle non existent importers better
- Update duplicator markup
</release>
<release version="2.0" date="2012-06-08" min="2.3">
<release version="2.0.0" date="2012-06-08" min="2.3">
- Symphony 2.3 support
- Improved localisation support
- Ability to use `{$root}` in the URL
Expand Down
240 changes: 158 additions & 82 deletions lib/class.xmlimporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

class XMLImporter {
const __OK__ = 100;
const __PARTIAL_OK__ = 110;
const __ERROR_PREPARING__ = 200;
const __ERROR_VALIDATING__ = 210;
const __ERROR_CREATING__ = 220;
Expand Down Expand Up @@ -81,6 +82,7 @@ function handleXMLError($errno, $errstr, $errfile, $errline, $context) {
$options = $this->options();
$passed = true;

// If $remote, override the source of the XMLImporter with the given $source
if ($remote) {
if (!is_null($source)) {
$options['source'] = $source;
Expand All @@ -106,8 +108,35 @@ function handleXMLError($errno, $errstr, $errfile, $errline, $context) {
}
}

else if (!is_null($source)) {
$data = $source;
else if (isset($options['source'])) {
$param_pool = array();
$ds = DatasourceManager::create($options['source'], $param_pool, true);

// Not a DataSource (legacy)
if(!($ds instanceof Datasource)) {
$data = $source;
}
// DataSource output
else {
$xml = $ds->execute($param_pool);

if(isset($ds->dsParamNAMESPACES)) {
foreach($ds->dsParamNAMESPACES as $name => $uri) {
$options['namespaces'][] = array(
'name' => $name,
'uri' => $uri
);
}
}

if($xml->getAttribute('valid') == 'false') {
$this->_errors[] = __('Failed to retrieve data from source: %s', array($xml->generate()));
$passed = false;
}
else {
$data = '<data>' . $xml->generate(true) . '</data>';
}
}
}

else {
Expand Down Expand Up @@ -216,10 +245,12 @@ function handleXMLError($errno, $errstr, $errfile, $errline, $context) {
// Validate:
$passed = true;

foreach ($this->_entries as &$current) {
foreach ($this->_entries as $index => &$current) {
$entry = EntryManager::create();
$entry->set('section_id', $options['section']);
$entry->set('author_id', is_null(Symphony::Engine()->Author()) ? '1' : Symphony::Engine()->Author()->get('id'));
$entry->set('modification_date_gmt', DateTimeObj::getGMT('Y-m-d H:i:s'));
$entry->set('modification_date', DateTimeObj::get('Y-m-d H:i:s'));

$values = array();

Expand Down Expand Up @@ -254,7 +285,7 @@ function handleXMLError($errno, $errstr, $errfile, $errline, $context) {
if ($type == 'author') {
if ($field->get('allow_multiple_selection') == 'no') {
if(is_array($value)){
$value = array(implode('', $value));
$value = array(implode('', $value));
}
}
}
Expand All @@ -272,12 +303,20 @@ function handleXMLError($errno, $errstr, $errfile, $errline, $context) {
}

// Validate:
if (__ENTRY_FIELD_ERROR__ == $entry->checkPostData($values, $current['errors'])) {
$passed = false;
}
try {
if (__ENTRY_FIELD_ERROR__ == $entry->checkPostData($values, $current['errors'])) {
$passed = false;
}

else if (__ENTRY_OK__ != $entry->setDataFromPost($values, $current['errors'], true, true)) {
else if (__ENTRY_OK__ != $entry->setDataFromPost($values, $current['errors'], true, true)) {
$passed = false;
}
}
catch (Exception $ex) {
$passed = false;
$current['errors'] = array($ex->getMessage());

Symphony::Log()->pushToLog(sprintf('XMLImporter: Failed to set values for entry in position %d, %s', $index, $ex->getMessage()), E_NOTICE, true);
}

$current['entry'] = $entry;
Expand All @@ -289,94 +328,95 @@ function handleXMLError($errno, $errstr, $errfile, $errline, $context) {
return self::__OK__;
}

public function commit() {
public function commit($status) {
$options = $this->options();
$section = SectionManager::fetch($options['section']);
$existing = array();

$section = SectionManager::fetch($options['section']);
// if $status = PARTIAL_OK
if($status == self::__PARTIAL_OK__) {
$entries = $this->_entries;
foreach($entries as $index => $current) {
if(!empty($current['errors'])) {
$this->_entries[$index]['entry']->set('importer_status', 'failed');
unset($entries[$index]);
}
}
}
else {
$entries = $this->_entries;
}

// Check uniqueness
if ((integer)$options['unique-field'] > 0) {
$field = FieldManager::fetch($options['unique-field']);

if (!empty($field)) foreach ($this->_entries as $index => $current) {
$entry = $current['entry'];

$data = $entry->getData($options['unique-field']);
$where = $joins = $group = null;

$field->buildDSRetrievalSQL($data, $joins, $where);

$group = $field->requiresSQLGrouping();
$entries = EntryManager::fetch(null, $options['section'], 1, null, $where, $joins, $group, false, null, false);

if (is_array($entries) && !empty($entries)) {
$existing[$index] = $entries[0]['id'];
}

else {
$existing[$index] = null;
}
}
}

foreach ($this->_entries as $index => $current) {
foreach ($entries as $index => $current) {
$entry = $current['entry'];
$values = $current['values'];
$date = DateTimeObj::get('Y-m-d H:i:s');
$dateGMT = DateTimeObj::getGMT('Y-m-d H:i:s');

$exists = !empty($existing[$index]);
$skip = ($options['can-update'] !== 'yes');

// Skip entry
if ($exists && $skip) {
$entry->set('importer_status', 'skipped');

###
# Delegate: XMLImporterEntryPostSkip
# Description: Skipping an entry. Entry object is provided.
Symphony::ExtensionManager()->notifyMembers(
'XMLImporterEntryPostSkip', '/xmlimporter/importers/run/',
array(
'section' => $section,
'entry' => $entry,
'fields' => $values
)
);
}

// Edit entry
elseif ($exists) {
$entry->set('id', $existing[$index]);
$entry->set('modification_date', $date);
$entry->set('modification_date_gmt', $dateGMT);

###
# Delegate: XMLImporterEntryPreEdit
# Description: Just prior to editing of an Entry.
Symphony::ExtensionManager()->notifyMembers(
'XMLImporterEntryPreEdit', '/xmlimporter/importers/run/',
array(
'section' => $section,
'fields' => &$values,
'entry' => &$entry
)
);

EntryManager::edit($entry);
$entry->set('importer_status', 'updated');
// Uniqueness check (if required)
if(!empty($field)) {
$this->checkExisting($field, $entry, $index, $existing);
};

// Matches an existing entry
if (!is_null($existing[$index])) {
// Update
if ($options['can-update'] == 'yes') {
$entry->set('id', $existing[$index]);
$entry->set('modification_date', $date);
$entry->set('modification_date_gmt', $dateGMT);

###
# Delegate: XMLImporterEntryPreEdit
# Description: Just prior to editing of an Entry.
Symphony::ExtensionManager()->notifyMembers(
'XMLImporterEntryPreEdit', '/xmlimporter/importers/run/',
array(
'section' => $section,
'fields' => &$values,
'entry' => &$entry
)
);

EntryManager::edit($entry);
$entry->set('importer_status', 'updated');

###
# Delegate: XMLImporterEntryPostEdit
# Description: Editing an entry. Entry object is provided.
Symphony::ExtensionManager()->notifyMembers(
'XMLImporterEntryPostEdit', '/xmlimporter/importers/run/',
array(
'section' => $section,
'entry' => $entry,
'fields' => $values
)
);
}

###
# Delegate: XMLImporterEntryPostEdit
# Description: Editing an entry. Entry object is provided.
Symphony::ExtensionManager()->notifyMembers(
'XMLImporterEntryPostEdit', '/xmlimporter/importers/run/',
array(
'section' => $section,
'entry' => $entry,
'fields' => $values
)
);
// Skip
else {
$entry->set('importer_status', 'skipped');

###
# Delegate: XMLImporterEntryPostSkip
# Description: Skipping an entry. Entry object is provided.
Symphony::ExtensionManager()->notifyMembers(
'XMLImporterEntryPostSkip', '/xmlimporter/importers/run/',
array(
'section' => $section,
'entry' => $entry,
'fields' => $values
)
);

continue;
}
}

// Create entry
Expand Down Expand Up @@ -415,4 +455,40 @@ public function commit() {
}
}
}

/**
* Given the `$field`, and the `$entry`, this function
* will take the value that is about to be imported and
* check to see if it's already in the system.
* If it is, the `entry_id` of `$entry` will be added
* to the `$existing` array.
*
* @param Field $field
* The unique field
* @param Entry $entry
* The current entry that is about to be imported
* @param integer $index
* The current position of the Entry in the import
* @param array $existing
* An associative array, by reference. The key is the position of
* the entry in the import, and the value is the `entry_id` if
* a match was found, otherwise null.
*/
private function checkExisting(Field $field, Entry $entry, $index, array &$existing) {
$data = $entry->getData($field->get('id'));
$where = $joins = $group = null;

$field->buildDSRetrievalSQL($data, $joins, $where);

$group = $field->requiresSQLGrouping();
$existing_entries = EntryManager::fetch(null, $field->get('parent_section'), 1, null, $where, $joins, $group, false, null, false);

if (is_array($existing_entries) && !empty($existing_entries)) {
$existing[$index] = $existing_entries[0]['id'];
}

else {
$existing[$index] = null;
}
}
}
3 changes: 2 additions & 1 deletion lib/class.xmlimportermanager.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ public function about($name){
$handle = $this->__getHandleFromFilename(basename($path));

if(is_callable(array($classname, 'about'))){
$about = call_user_func(array($classname, 'about'));
$importer = new $classname;
$about = $importer->about();
return array_merge($about, array('handle' => $handle));
}

Expand Down
Loading