diff --git a/Block/System/Config/Form/SyncButton.php b/Block/System/Config/Form/SyncButton.php index 644a669..3598409 100644 --- a/Block/System/Config/Form/SyncButton.php +++ b/Block/System/Config/Form/SyncButton.php @@ -9,6 +9,7 @@ namespace Magenerds\SystemDiff\Block\System\Config\Form; +use Magenerds\SystemDiff\Helper\Config; use Magento\Config\Block\System\Config\Form\Field; use Magento\Framework\Data\Form\Element\AbstractElement; @@ -24,15 +25,41 @@ class SyncButton extends Field */ protected $element; + /** + * @var Config + */ + public $configHelper; + + /** + * SyncButton constructor. + * + * Additionally injects config helper. + * + * @param \Magento\Backend\Block\Template\Context $context + * @param array $data + * @param Config $configHelper + */ + public function __construct( + \Magento\Backend\Block\Template\Context $context, + Config $configHelper, + array $data = [] + ) { + $this->configHelper = $configHelper; + + parent::__construct($context, $data); + } + /** * Remove scope label * * @param AbstractElement $element + * * @return string */ public function render(AbstractElement $element) { $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue(); + return parent::render($element); } @@ -40,6 +67,7 @@ public function render(AbstractElement $element) * Return element html * * @param AbstractElement $element + * * @return string */ protected function _getElementHtml(AbstractElement $element) @@ -73,7 +101,7 @@ public function getButtonHtml() ); $button->setData( [ - 'id' => $this->element->getHtmlId(), + 'id' => $this->element->getHtmlId(), 'label' => __('Run'), 'class' => 'disabled' // reset when page loaded, see template script ] @@ -82,6 +110,24 @@ public function getButtonHtml() return $button->toHtml(); } + /** + * Returns info about last sync date time as a string for usage in "'"-JS string. + * + * @return string + */ + public function getLastSyncInfo() + { + $formattedDateTime = $this->configHelper->getLastSyncDatetimeFormatted(); + + return (string)filter_var( + sprintf( + __('Last diff on %s'), + $formattedDateTime + ), + FILTER_SANITIZE_MAGIC_QUOTES + ); + } + /** * Returns the element defined in system.xml * @@ -91,4 +137,4 @@ public function getElement() { return $this->element; } -} \ No newline at end of file +} diff --git a/Console/Command/ExecuteCommand.php b/Console/Command/ExecuteCommand.php index 7409bd2..6e76734 100644 --- a/Console/Command/ExecuteCommand.php +++ b/Console/Command/ExecuteCommand.php @@ -9,6 +9,7 @@ namespace Magenerds\SystemDiff\Console\Command; +use Magenerds\SystemDiff\Helper\Config; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -26,20 +27,34 @@ class ExecuteCommand extends Command */ const COMMAND_DESCRIPTION = 'system-diff:execute'; + /** + * Exit code when exception occurred + */ + const EXIT_CODE_EXCEPTION = 4; + /** * @var PerformSystemDiffService */ private $performSystemDiffService; + /** + * @var Config + */ + private $configHelper; + /** * ExecuteCommand constructor. + * * @param PerformSystemDiffService $performSystemDiffService + * @param Config $configHelper */ public function __construct( - PerformSystemDiffService $performSystemDiffService - ){ + PerformSystemDiffService $performSystemDiffService, + Config $configHelper + ) { parent::__construct(self::COMMAND_NAME); $this->performSystemDiffService = $performSystemDiffService; + $this->configHelper = $configHelper; } /** @@ -54,16 +69,28 @@ public function configure() } /** - * @param InputInterface $input An InputInterface instance + * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance - * @return null|int null or 0 if everything went fine, or an error code + * + * @return int 0 if everything went fine, or an error code */ public function execute(InputInterface $input, OutputInterface $output) { + $exitStatus = 0; try { + $output->write('Performing sync and diff...'); $this->performSystemDiffService->performDiff(); + $output->writeln( + sprintf( + 'Done at %s.', + $this->configHelper->getLastSyncDatetimeFormatted() + ) + ); } catch (\Exception $e) { + $exitStatus = self::EXIT_CODE_EXCEPTION; $output->writeln(sprintf('An error occurred during diff: %s', $e->getMessage())); } + + return $exitStatus; } } \ No newline at end of file diff --git a/Controller/Adminhtml/SystemDiff/Diff.php b/Controller/Adminhtml/SystemDiff/Diff.php index 2918ba2..971183f 100644 --- a/Controller/Adminhtml/SystemDiff/Diff.php +++ b/Controller/Adminhtml/SystemDiff/Diff.php @@ -9,6 +9,7 @@ namespace Magenerds\SystemDiff\Controller\Adminhtml\SystemDiff; +use Magenerds\SystemDiff\Helper\Config; use Magenerds\SystemDiff\Service\PerformSystemDiffService; use Magento\Backend\App\Action; use Magento\Backend\App\Action\Context; @@ -31,21 +32,29 @@ class Diff extends Action */ private $performSystemDiffService; + /** + * @var Config + */ + private $configHelper; + /** * Diff action constructor. * - * @param Context $context - * @param JsonFactory $jsonFactory + * @param Context $context + * @param JsonFactory $jsonFactory * @param PerformSystemDiffService $performSystemDiffService + * @param Config $configHelper */ public function __construct( Context $context, JsonFactory $jsonFactory, - PerformSystemDiffService $performSystemDiffService + PerformSystemDiffService $performSystemDiffService, + Config $configHelper ) { $this->context = $context; $this->jsonFactory = $jsonFactory; $this->performSystemDiffService = $performSystemDiffService; + $this->configHelper = $configHelper; parent::__construct($context); } @@ -60,15 +69,23 @@ public function execute() $result = $this->jsonFactory->create(); - $message = 'OK'; + $message = 'Diff successfully done at %s.'; try { $this->performSystemDiffService->performDiff(); } catch (\Exception $e) { - $message = "Error performing system diff."; + $message = __("Error performing system diff at %s."); + $result->setStatusHeader(500); } - $result->setData(['message' => $message]); + $result->setData( + [ + 'message' => sprintf( + __($message), + $this->configHelper->getLastSyncDatetimeFormatted() + ), + ] + ); return $result; } diff --git a/DataWriter/StoreConfigDataWriter.php b/DataWriter/StoreConfigDataWriter.php index 7ae8a04..2843a58 100644 --- a/DataWriter/StoreConfigDataWriter.php +++ b/DataWriter/StoreConfigDataWriter.php @@ -16,17 +16,6 @@ class StoreConfigDataWriter implements DataWriterInterface { - /** - * Holds database field names - */ - const LOCAL_VALUE_FIELD_NAME = 'diff_value_local'; - const REMOTE_VALUE_FIELD_NAME = 'diff_value_remote'; - const SCOPE_FIELD_NAME = 'scope'; - const SCOPE_ID_FIELD_NAME = 'scope_id'; - const PATH_FIELD_NAME = 'path'; - const SCOPE_VALUE_WEBSITES = 'websites'; - const SCOPE_VALUE_STORES = 'stores'; - /** * Holds further necessary consts */ @@ -101,8 +90,8 @@ public function write(array $diffData) foreach ($localValues as $localPath => $localValue) { if (array_key_exists($localPath, $remoteValues)) { $combinedValues[$localPath] = [ - self::LOCAL_VALUE_FIELD_NAME => $localValue, - self::REMOTE_VALUE_FIELD_NAME => $remoteValues[$localPath] + DiffConfigResource::LOCAL_VALUE_FIELD_NAME => $localValue, + DiffConfigResource::REMOTE_VALUE_FIELD_NAME => $remoteValues[$localPath] ]; unset($localValues[$localPath]); @@ -110,8 +99,8 @@ public function write(array $diffData) } } - $localModels = $this->mapDataToModels($localValues, $scope, self::LOCAL_VALUE_FIELD_NAME); - $remoteModels = $this->mapDataToModels($remoteValues, $scope, self::REMOTE_VALUE_FIELD_NAME); + $localModels = $this->mapDataToModels($localValues, $scope, DiffConfigResource::LOCAL_VALUE_FIELD_NAME); + $remoteModels = $this->mapDataToModels($remoteValues, $scope, DiffConfigResource::REMOTE_VALUE_FIELD_NAME); $combinedModels = $this->mapDataToModels($combinedValues, $scope); $scopeModels = array_merge($localModels, $remoteModels, $combinedModels); @@ -144,11 +133,11 @@ protected function mapDataToModels(array $data, $scope, $valueField = null) foreach ($data as $path => $value) { /** @var DiffConfigModel $diffConfigModel */ $diffConfigModel = $this->diffConfigFactory->create(); - $diffConfigModel->setData(self::SCOPE_FIELD_NAME, $scope); + $diffConfigModel->setScope($scope); $scopeId = self::DEFAULT_SCOPE_ID; - if ($scope === self::SCOPE_VALUE_WEBSITES || $scope === self::SCOPE_VALUE_STORES) { + if ($scope === DiffConfigResource::SCOPE_VALUE_WEBSITES || $scope === DiffConfigResource::SCOPE_VALUE_STORES) { if (empty($path)) { continue; } @@ -162,17 +151,17 @@ protected function mapDataToModels(array $data, $scope, $valueField = null) $code = $splittedPath[0]; $path = $splittedPath[1]; - if ($scope === self::SCOPE_VALUE_WEBSITES) { + if ($scope === DiffConfigResource::SCOPE_VALUE_WEBSITES) { $scopeId = $this->getWebsiteId($code); } - if ($scope === self::SCOPE_VALUE_STORES) { + if ($scope === DiffConfigResource::SCOPE_VALUE_STORES) { $scopeId = $this->getStoreId($code); } } - $diffConfigModel->setData(self::SCOPE_ID_FIELD_NAME, $scopeId); - $diffConfigModel->setData(self::PATH_FIELD_NAME, $path); + $diffConfigModel->setScope($scopeId); + $diffConfigModel->setPath($path); if (is_array($value) && is_null($valueField)) { foreach ($value as $fieldName => $v) { @@ -182,7 +171,6 @@ protected function mapDataToModels(array $data, $scope, $valueField = null) $diffConfigModel->setData($valueField, $value); } - $models[] = $diffConfigModel; } diff --git a/Helper/Config.php b/Helper/Config.php index c5b8141..53f208d 100644 --- a/Helper/Config.php +++ b/Helper/Config.php @@ -9,7 +9,14 @@ namespace Magenerds\SystemDiff\Helper; +use DateTimeInterface; +use Magenerds\SystemDiff\Model\DiffConfig; +use Magenerds\SystemDiff\Model\ResourceModel\DiffConfig as DiffConfigResource; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magenerds\SystemDiff\Model\ResourceModel\DiffConfig\CollectionFactory; +use Magenerds\SystemDiff\Model\DiffConfigFactory; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\Framework\Stdlib\DateTime\DateTime; /** * Class to read module-specific configuration @@ -27,20 +34,54 @@ class Config const XML_PATH_ACCESS_TOKEN = 'system_diff/connection/access_token'; const XML_PATH_API_TYPE = 'system_diff/connection/api_type'; const XML_PATH_DISPLAY_STORE_CONFIG = 'system_diff/display/store_config'; + const XML_PATH_LAST_SYNC_DATETIME = 'system_diff/general/last_sync_datetime'; /** * @var ScopeConfigInterface */ private $scopeConfig; + /** + * @var CollectionFactory + */ + private $diffConfigCollectionFactory; + + /** + * @var DiffConfigFactory + */ + private $diffConfigFactory; + + /** + * @var DateTime + */ + private $dateTime; + + /** + * @var TimezoneInterface + */ + private $timezone; + /** * Config constructor. + * * @param ScopeConfigInterface $scopeConfig + * @param CollectionFactory $collectionFactory + * @param DiffConfigFactory $diffConfigFactory + * @param TimezoneInterface $timezone + * @param DateTime $dateTime */ public function __construct( - ScopeConfigInterface $scopeConfig + ScopeConfigInterface $scopeConfig, + CollectionFactory $collectionFactory, + DiffConfigFactory $diffConfigFactory, + TimezoneInterface $timezone, + DateTime $dateTime ) { $this->scopeConfig = $scopeConfig; + $this->diffConfigCollectionFactory = $collectionFactory; + $this->diffConfigFactory = $diffConfigFactory; + $this->dateTime = $dateTime; + $this->timezone = $timezone; } /** @@ -84,4 +125,74 @@ public function isDisplayStoreConfig() { return $this->scopeConfig->isSetFlag(self::XML_PATH_DISPLAY_STORE_CONFIG); } + + /** + * Return a string with date time of last sync or n/a. + * + * @return string + */ + public function getLastSyncDatetimeFormatted() + { + $dateTime = $this->getLastSyncDatetime(); + if ($dateTime instanceof DateTimeInterface) { + + return $this->timezone->formatDateTime($dateTime, \IntlDateFormatter::SHORT, true); + } + + return (string)__('n/a'); + } + + /** + * The last saved sync datetime timestamp as string. + * + * Should be a gmt timestamp. + * + * @return DateTimeInterface|null; + */ + public function getLastSyncDatetime() + { + $dataObject = $this->getLastSyncDiffConfig(); + $dateTime = null; + if ($dataObject instanceof DiffConfig) { + $timeStampString = $dataObject->getDiffValueLocal(); + $dateTime = \DateTime::createFromFormat("U", $timeStampString); + } + + return $dateTime; + } + + /** + * DiffConfig entry that holds the last sync time. + * + * @return DiffConfig|null; + */ + protected function getLastSyncDiffConfig() + { + $collection = $this->diffConfigCollectionFactory->create(); + + /** @var DiffConfig $dataObject */ + $dataObject = $collection->getItemByColumnValue( + DiffConfigResource::PATH_FIELD_NAME, + self::XML_PATH_LAST_SYNC_DATETIME + ); + + return $dataObject; + } + + /** + * Create or update last sync entry. + * + * @return void + */ + public function updateLastDiffTimestamp() + { + $diffConfig = $this->getLastSyncDiffConfig(); + if (!($diffConfig instanceof DiffConfig)) { + $diffConfig = $this->diffConfigFactory->create(); + $diffConfig->setScope('default'); + $diffConfig->setPath(Config::XML_PATH_LAST_SYNC_DATETIME); + } + $diffConfig->setDiffValueLocal($this->dateTime->gmtTimestamp()); + $diffConfig->save(); + } } \ No newline at end of file diff --git a/Model/DiffConfig.php b/Model/DiffConfig.php index 2b80f6d..d746035 100644 --- a/Model/DiffConfig.php +++ b/Model/DiffConfig.php @@ -28,4 +28,36 @@ protected function _construct() { $this->_init(DiffConfigResource::class); } + + /** + * @param string $value + */ + public function setDiffValueLocal($value) + { + $this->setData(DiffConfigResource::LOCAL_VALUE_FIELD_NAME, $value); + } + + /** + * @return string + */ + public function getDiffValueLocal() + { + return (string)$this->getData(DiffConfigResource::LOCAL_VALUE_FIELD_NAME); + } + + /** + * @param string $path + */ + public function setPath(string $path) + { + $this->setData(DiffConfigResource::PATH_FIELD_NAME, $path); + } + + /** + * @param string $scope + */ + public function setScope(string $scope) + { + $this->setData(DiffConfigResource::SCOPE_FIELD_NAME, $scope); + } } \ No newline at end of file diff --git a/Model/ResourceModel/DiffConfig.php b/Model/ResourceModel/DiffConfig.php index 290923c..35c1d76 100644 --- a/Model/ResourceModel/DiffConfig.php +++ b/Model/ResourceModel/DiffConfig.php @@ -17,6 +17,21 @@ */ class DiffConfig extends AbstractDb { + /** + * Holds database field names + */ + const LOCAL_VALUE_FIELD_NAME = 'diff_value_local'; + const REMOTE_VALUE_FIELD_NAME = 'diff_value_remote'; + const SCOPE_FIELD_NAME = 'scope'; + const SCOPE_ID_FIELD_NAME = 'scope_id'; + const PATH_FIELD_NAME = 'path'; + + /** + * Values for scope + */ + const SCOPE_VALUE_WEBSITES = 'websites'; + const SCOPE_VALUE_STORES = 'stores'; + /** * Resource initialization * diff --git a/Service/SaveDiffToTableService.php b/Service/SaveDiffToTableService.php index 8b22a0a..1648f18 100644 --- a/Service/SaveDiffToTableService.php +++ b/Service/SaveDiffToTableService.php @@ -12,6 +12,7 @@ use Magenerds\SystemDiff\Api\Service\SaveDiffToTableServiceInterface; use Magenerds\SystemDiff\DataWriter\DataWriterInterface; use Magenerds\SystemDiff\DataWriter\DataWriterPool; +use Magenerds\SystemDiff\Helper\Config; /** * Class SaveDiffToTableService @@ -24,17 +25,32 @@ class SaveDiffToTableService implements SaveDiffToTableServiceInterface */ private $writerPool; + /** + * @var Config + */ + private $configHelper; + /** * StoreConfigDataWriter constructor. + * * @param DataWriterPool $writerPool + * @param Config $configHelper + * + * @internal param DiffConfigFactory $diffConfigFactory + * @internal param DateTime $dateTime + * @internal param StoreConfigUpdater $configUpdater */ - public function __construct(DataWriterPool $writerPool) - { + public function __construct( + DataWriterPool $writerPool, + Config $configHelper + ) { $this->writerPool = $writerPool; + $this->configHelper = $configHelper; } /** * @param [] $diffData + * * @return void */ public function saveData(array $diffData) @@ -43,5 +59,7 @@ public function saveData(array $diffData) /** @var DataWriterInterface $writer */ $writer->write($diffData); } + + $this->configHelper->updateLastDiffTimestamp(); } } \ No newline at end of file diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index b051c9a..a5c22a3 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -40,7 +40,7 @@ REST: http[s]://[remotehost]/index.php/rest/all/V1/systemConfig/all
SOAP: http[s]://[remotehost]/soap?wsdl&services=magenerdsSystemDiffServiceFetchLocalDataServiceV1

- See http://devdocs.magento.com/guides/v2.2/get-started/soap/soap-web-api-calls.html + See http://devdocs.magento.com/guides/v2.2/get-started/soap/soap-web-api-calls.html ]]> diff --git a/view/adminhtml/templates/system/config/sync_button.phtml b/view/adminhtml/templates/system/config/sync_button.phtml index 72e8a42..2b3ba1a 100644 --- a/view/adminhtml/templates/system/config/sync_button.phtml +++ b/view/adminhtml/templates/system/config/sync_button.phtml @@ -13,26 +13,50 @@ require( ['jquery', 'prototype'], function(jQuery){ + var buttonId = 'getElement()->getHtmlId() ?>'; + var buttonSelector = '#'+buttonId; + var infoSelector = buttonSelector+'_info'; + + var $info = jQuery(infoSelector); + var $button = jQuery(buttonSelector); + function enableSyncButton() { - Form.Element.enable('getElement()->getHtmlId() ?>'); - jQuery('#getElement()->getHtmlId() ?>').removeClass('disabled'); + Form.Element.enable(buttonId); + $button.removeClass('disabled'); } function disableSyncButton() { - Form.Element.disable('getElement()->getHtmlId() ?>'); - jQuery('#getElement()->getHtmlId() ?>').addClass('disabled'); + Form.Element.disable(buttonId); + $button.addClass('disabled'); } - Event.observe(window, 'load', function(){ + function message(message, type) { + $info.html(message); + $info.addClass('message'); + + if (type === "error") { + $info.addClass('message-error'); + } else { + $info.removeClass('message-error'); + } + } + + jQuery(document).ready(function(){ enableSyncButton(); }); - jQuery('#getElement()->getHtmlId() ?>').click( + jQuery(buttonSelector).click( function () { disableSyncButton(); + message(''); jQuery.get( 'getAjaxUrl() ?>' - ).always(function(){ + ).done(function (data) { + message(data.message); + }).fail(function (jqXHR, textStatus, errorThrown) { + message(errorThrown, "error"); + + }).always(function(){ enableSyncButton(); }) ; @@ -42,4 +66,5 @@ require( ); -getButtonHtml() ?> \ No newline at end of file +getButtonHtml() ?> +getLastSyncInfo(); ?> diff --git a/view/adminhtml/web/css/style.css b/view/adminhtml/web/css/style.css index 69f35fa..6f832cf 100644 --- a/view/adminhtml/web/css/style.css +++ b/view/adminhtml/web/css/style.css @@ -26,4 +26,10 @@ .diff-hidden { display: none; +} + +.message.magenerds_sync_info { + display: block; + float: none; + margin: .5em 0; } \ No newline at end of file