diff --git a/wire/core/Fieldgroup.php b/wire/core/Fieldgroup.php index 984891d1..19de3dc0 100644 --- a/wire/core/Fieldgroup.php +++ b/wire/core/Fieldgroup.php @@ -133,7 +133,7 @@ class Fieldgroup extends WireArray implements Saveable, Exportable, HasLookupIte /** * Remove a field from this fieldgroup * - * Note that this must be followed up with a `$field->save()` before it does anything destructive. + * Note that this must be followed up with a `$fieldgroup->save()` before it does anything destructive. * This method does nothing more than queue the removal. * * _Technical Details_ diff --git a/wire/core/Fieldtype.php b/wire/core/Fieldtype.php index e5d66868..93272dcb 100644 --- a/wire/core/Fieldtype.php +++ b/wire/core/Fieldtype.php @@ -555,7 +555,21 @@ abstract class Fieldtype extends WireData implements Module { /** * Get associative array of options and info (name => value) that Fieldtype supports for importValue * - * - `test` (bool): indicates Fieldtype supports testing import before committing. + * Current recognized options include the following: + * + * - `importable` (bool): Is the field importable (and exportable)? (default=auto-detect) + * + * - `test` (bool): Indicates Fieldtype supports testing import before committing & populates notices to + * returned Wire object. (default=false) + * + * - `returnsPageValue` (bool): True if it returns the value that should set back to Page? False if return + * value should not be set to Page. When false, it indicates the Fieldtype::importValue() handles the + * actual commit to DB of import data. (default=true) + * + * - `requiresExportValue` (bool): Indicates Fieldtype::importValue() requires an 'exportValue' of the + * current value from Page in $options. (default=false) + * + * - `restoreOnException` (bool): Restore previous value if Exception thrown during import (default=false). * * #pw-internal * @@ -564,8 +578,15 @@ abstract class Fieldtype extends WireData implements Module { * */ public function getImportValueOptions(Field $field) { - if($field) {} // ignore - return array(); + $schema = $this->getDatabaseSchema($field); + $options = array( + 'importable' => (!isset($schema['xtra']['all']) || $schema['xtra']['all'] !== true) ? false : true, + 'test' => false, + 'returnsPageValue' => true, + 'requiresExportValue' => false, + 'restoreOnException' => false, + ); + return $options; } /** diff --git a/wire/core/PagesExportImport.php b/wire/core/PagesExportImport.php index 3769dde0..eb904a44 100644 --- a/wire/core/PagesExportImport.php +++ b/wire/core/PagesExportImport.php @@ -882,9 +882,20 @@ class PagesExportImport extends Wire { } } - $fieldtypeSupportsOptions = $field->type->getImportValueOptions($field); + $fieldtypeImportDefaults = array( + // supports testing before commit (populates notices to returned Wire). + 'test' => false, + // returns the value that should set back to Page? (false=return value for notices only). + // when false, it also indicates the Fieldtype::importValue() handles the actual commit to DB of import data. + 'returnsPageValue' => true, + // indicates Fieldtype::importValue() would like an 'exportValue' of the current value from Page in $options + 'requiresExportValue' => false, + ); + + $fieldtypeImportOptions = array_merge($fieldtypeImportDefaults, $field->type->getImportValueOptions($field)); $o = array( + 'importType' => $page->get('_importType'), 'system' => true, 'caller' => $this, 'commit' => $options['commit'], @@ -892,7 +903,7 @@ class PagesExportImport extends Wire { ); // fake-commit for more verbose testing of certain fieldtypes - $fakeCommit = $options['commit'] || !empty($fieldtypeSupportsOptions['test']); + $fakeCommit = $options['commit'] || !empty($fieldtypeImportOptions['test']); if($page->get('_importType') == 'create' && !$options['commit'] && !$fakeCommit) { // test import on a new page, so value will always be used @@ -910,17 +921,36 @@ class PagesExportImport extends Wire { // use '===' for all other value comparisons if($exportValue === $importValue) return; } + + // at this point, values appear to be different + if($fieldtypeImportOptions['requiresExportValue']) $o['exportValue'] = $exportValue; if($options['commit'] || $fakeCommit) { - $pageValue = $field->type->importValue($page, $field, $importValue, $o); - if($pageValue !== null) $page->set($field->name, $pageValue); + $commitException = false; + try { + $pageValue = $field->type->importValue($page, $field, $importValue, $o); + } catch(\Exception $e) { + if($options['commit'] && $fieldtypeImportOptions['restoreOnException']) { + $commitException = true; + $pageValue = $field->type->importValue($page, $field, $exportValue, $o); + $page->warning("$field: " . $e->getMessage()); + $page->warning("$field: Attempted to restore previous value"); + } + } + if(!$commitException) { + if($pageValue !== null && $fieldtypeImportOptions['returnsPageValue']) { + $page->set($field->name, $pageValue); + } else if(!$fieldtypeImportOptions['returnsPageValue']) { + $page->trackChange("{$field->name}__"); + } + } if(is_object($pageValue) && $pageValue instanceof Wire) { // movie notices from the pageValue to the page $this->wire('notices')->move($pageValue, $page); } } else { // test import on existing page, avoids actually setting value to the page - $page->trackChange($field->name); // values appear to be different + $page->trackChange($field->name); } if($options['debug']) { @@ -1327,19 +1357,19 @@ class PagesExportImport extends Wire { } else { // test to see if exportable try { - $schema = $fieldtype->getDatabaseSchema($field); + $importInfo = $fieldtype->getImportValueOptions($field); } catch(\Exception $e) { $exportable = false; $reason = $e->getMessage(); } - if($exportable && (!isset($schema['xtra']['all']) || $schema['xtra']['all'] !== true)) { + if($exportable && !$importInfo['importable']) { // this fieldtype is storing data outside of the DB or in other unknown tables // there's a good chance we won't be able to export/import this into an array // @todo check if fieldtype implements its own exportValue/importValue, and if // it does then allow the value to be exported $exportable = false; - $reason = "Field '$field' cannot be used because $field->type uses data outside table '$field->table'"; + $reason = "Field '$field' cannot be used because $field->type indicates imports are not supported"; } } diff --git a/wire/core/PagesLoader.php b/wire/core/PagesLoader.php index ea191236..a9e7b539 100644 --- a/wire/core/PagesLoader.php +++ b/wire/core/PagesLoader.php @@ -810,9 +810,9 @@ class PagesLoader extends Wire { // if page is already loaded and cache allowed, then get the path from it if($options['useCache'] && $page = $this->pages->getCache($id)) { /** @var Page $page */ - if($languages) $languages->setLanguage($language); + if($languageID) $languages->setLanguage($language); $path = $page->path(); - if($languages) $languages->unsetLanguage(); + if($languageID) $languages->unsetLanguage(); return $path; } else if($id == $homepageID && $languages && !$languageID) { diff --git a/wire/modules/Process/ProcessPagesExportImport/ProcessPagesExportImport.module b/wire/modules/Process/ProcessPagesExportImport/ProcessPagesExportImport.module index 88f89886..8fbb9871 100644 --- a/wire/modules/Process/ProcessPagesExportImport/ProcessPagesExportImport.module +++ b/wire/modules/Process/ProcessPagesExportImport/ProcessPagesExportImport.module @@ -183,7 +183,7 @@ class ProcessPagesExportImport extends Process { $submitCommit = $input->post('submit_commit_import') ? true : false; $submitTest = $input->post('submit_test_import') ? true : false; - $submitZIP = !empty($_FILES['import_zip']); + $submitZIP = !empty($_FILES['import_zip']) && !empty($_FILES['import_zip']['name'][0]); $fileField = null; $filesPath = $this->wire('session')->getFor($this, 'filesPath'); $jsonFile = ''; @@ -815,6 +815,10 @@ class ProcessPagesExportImport extends Process { } if($numChanges) { + foreach($changes as $key => $change) { + // i.e. 'field_name__' as disguised change + if(substr($change, -2) == '__') $changes[$key] = substr($change, 0, -2); + } if($languages) { // indicate language in name and status changes foreach($changes as $key => $change) {