From 7ebd8b9ffcfc2aacd1eaeff730c26ba09fa38b8a Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Fri, 23 Nov 2018 11:07:36 -0600 Subject: [PATCH] Implement canCommitTemplate and canResetTemplate checks, added UX for commit / reset buttons (load indicator & success flash messages) --- modules/cms/classes/AutoDatasource.php | 58 +++++++++++++++---- modules/cms/classes/Theme.php | 20 +++++-- modules/cms/controllers/Index.php | 31 ++++++---- .../index/_common_toolbar_actions.htm | 2 + modules/cms/lang/en/lang.php | 8 ++- 5 files changed, 93 insertions(+), 26 deletions(-) diff --git a/modules/cms/classes/AutoDatasource.php b/modules/cms/classes/AutoDatasource.php index 42d3b6594..9f734f40b 100644 --- a/modules/cms/classes/AutoDatasource.php +++ b/modules/cms/classes/AutoDatasource.php @@ -2,6 +2,7 @@ use Cache; use Exception; +use October\Rain\Halcyon\Model; use October\Rain\Halcyon\Processors\Processor; use October\Rain\Halcyon\Datasource\Datasource; use October\Rain\Halcyon\Exception\DeleteFileException; @@ -33,7 +34,7 @@ class AutoDatasource extends Datasource implements DatasourceInterface /** * Create a new datasource instance. * - * @param array $datasources Array of datasources to utilize. Lower indexes = higher priority + * @param array $datasources Array of datasources to utilize. Lower indexes = higher priority ['datasourceName' => $datasource] * @return void */ public function __construct($datasources) @@ -69,13 +70,34 @@ class AutoDatasource extends Datasource implements DatasourceInterface } /** - * Returns the datasource instances being used internally + * Check to see if the specified datasource has the provided Halcyon Model * - * @return array + * @param string $source The string key of the datasource to check + * @param Model $model The Halcyon Model to check for + * @return boolean */ - public function getDatasources() + public function sourceHasModel(string $source, Model $model) { - return $this->datasources; + $result = false; + + $keys = array_keys($this->datasources); + if (in_array($source, $keys)) { + // Get the datasource's cache index key + $cacheIndex = array_search($source, $keys); + + // Generate the path + list($name, $extension) = $model->getFileNameParts(); + $path = $this->makeFilePath($model->getObjectTypeDirName(), $name, $extension); + + // Deleted paths are included as being handled by a datasource + // The functionality built on this will need to make sure they + // include deleted records when actually performing sycning actions + if (isset($this->pathCache[$cacheIndex][$path])) { + $result = true; + } + } + + return $result; } /** @@ -107,6 +129,8 @@ class AutoDatasource extends Datasource implements DatasourceInterface throw new Exception("$path is deleted"); } + $datasourceIndex = array_keys($this->datasources)[$datasourceIndex]; + return $this->datasources[$datasourceIndex]; } @@ -166,6 +190,17 @@ class AutoDatasource extends Datasource implements DatasourceInterface return $dirName . '/' . $fileName . '.' . $extension; } + /** + * Get the first datasource for use with CRUD operations + * + * @return DatasourceInterface + */ + protected function getFirstDatasource() + { + $keys = array_keys($this->datasources); + return $this->datasources[$keys[0]]; + } + /** * Returns a single template. * @@ -249,7 +284,8 @@ class AutoDatasource extends Datasource implements DatasourceInterface */ public function insert($dirName, $fileName, $extension, $content) { - $result = $this->datasources[0]->insert($dirName, $fileName, $extension, $content); + // Insert only on the first datasource + $result = $this->getFirstDatasource()->insert($dirName, $fileName, $extension, $content); // Refresh the cache $this->populateCache(true); @@ -281,10 +317,12 @@ class AutoDatasource extends Datasource implements DatasourceInterface $this->allowCacheRefreshes = true; } - if (!empty($this->datasources[0]->selectOne($dirName, $searchFileName, $searchExt))) { - $result = $this->datasources[0]->update($dirName, $fileName, $extension, $content, $oldFileName, $oldExtension); + $datasource = $this->getFirstDatasource(); + + if (!empty($datasource->selectOne($dirName, $searchFileName, $searchExt))) { + $result = $datasource->update($dirName, $fileName, $extension, $content, $oldFileName, $oldExtension); } else { - $result = $this->datasources[0]->insert($dirName, $fileName, $extension, $content); + $result = $datasource->insert($dirName, $fileName, $extension, $content); } // Refresh the cache @@ -305,7 +343,7 @@ class AutoDatasource extends Datasource implements DatasourceInterface { try { // Delete from only the first datasource - $this->datasources[0]->delete($dirName, $fileName, $extension); + $this->getFirstDatasource()->delete($dirName, $fileName, $extension); } catch (Exception $ex) { // Check to see if this is a valid path to delete diff --git a/modules/cms/classes/Theme.php b/modules/cms/classes/Theme.php index f975c0e72..ab54a35ce 100644 --- a/modules/cms/classes/Theme.php +++ b/modules/cms/classes/Theme.php @@ -16,6 +16,7 @@ use Cms\Models\ThemeData; use System\Models\Parameter; use October\Rain\Halcyon\Datasource\DbDatasource; use October\Rain\Halcyon\Datasource\FileDatasource; +use October\Rain\Halcyon\Datasource\DatasourceInterface; /** * This class represents the CMS theme. @@ -514,14 +515,14 @@ class Theme { $enableDbLayer = Config::get('cms.enableDatabaseLayer', false); if (is_null($enableDbLayer)) { - $enableDbLayer = !Config::get('app.debug'); + $enableDbLayer = !Config::get('app.debug', false); } return $enableDbLayer && App::hasDatabase(); } /** - * Ensures this theme is registered as a Halcyon them datasource. + * Ensures this theme is registered as a Halcyon datasource. * @return void */ public function registerHalyconDatasource() @@ -531,8 +532,8 @@ class Theme if (!$resolver->hasDatasource($this->dirName)) { if (static::databaseLayerEnabled()) { $datasource = new AutoDatasource([ - new DbDatasource($this->dirName, 'cms_theme_contents'), - new FileDatasource($this->getPath(), App::make('files')), + 'database' => new DbDatasource($this->dirName, 'cms_theme_contents'), + 'filesystem' => new FileDatasource($this->getPath(), App::make('files')), ]); } else { $datasource = new FileDatasource($this->getPath(), App::make('files')); @@ -542,6 +543,17 @@ class Theme } } + /** + * Get the theme's datasource + * + * @return DatasourceInterface + */ + public function getDatasource() + { + $resolver = App::make('halcyon'); + return $resolver->datasource($this->getDirName()); + } + /** * Implements the getter functionality. * @param string $name diff --git a/modules/cms/controllers/Index.php b/modules/cms/controllers/Index.php index fc5a8bf7d..059be61aa 100644 --- a/modules/cms/controllers/Index.php +++ b/modules/cms/controllers/Index.php @@ -16,6 +16,7 @@ use Cms\Classes\Router; use Cms\Classes\Layout; use Cms\Classes\Partial; use Cms\Classes\Content; +use Cms\Classes\CmsObject; use Cms\Classes\CmsCompoundObject; use Cms\Classes\ComponentManager; use Cms\Classes\ComponentPartial; @@ -391,7 +392,7 @@ class Index extends Controller /** * Commits the DB changes of a template to the filesystem * - * @return void + * @return array $response */ public function onCommit() { @@ -400,7 +401,9 @@ class Index extends Controller $template = $this->loadTemplate($type, trim(Request::input('templatePath'))); if ($this->canCommitTemplate($template)) { + // @TODO: Implement commit logic + Flash::success(Lang::get('cms::lang.editor.commit_success', ['type' => $type])); } return $this->getUpdateResponse($template, $type); @@ -409,7 +412,7 @@ class Index extends Controller /** * Resets a template to the version on the filesystem * - * @return void + * @return array $response */ public function onReset() { @@ -418,7 +421,9 @@ class Index extends Controller $template = $this->loadTemplate($type, trim(Request::input('templatePath'))); if ($this->canResetTemplate($template)) { + // @TODO: Implement reset logic + Flash::success(Lang::get('cms::lang.editor.reset_success', ['type' => $type])); } return $this->getUpdateResponse($template, $type); @@ -435,7 +440,7 @@ class Index extends Controller * @param string $type The type of template being affected * @return array $result; */ - protected function getUpdateResponse($template, $type) + protected function getUpdateResponse(CmsObject $template, string $type) { $result = [ 'templatePath' => $template->fileName, @@ -458,16 +463,20 @@ class Index extends Controller /** * Check to see if the provided template can be committed + * Only available in debug mode, the DB layer must be enabled, and the template must exist in the database * * @param CmsObject $template * @return boolean */ - protected function canCommitTemplate($template) + protected function canCommitTemplate(CmsObject $template) { - $result = true; // will set to false by default - - if (Theme::databaseLayerEnabled()) { + $result = false; + if (Config::get('app.debug', false) && + Theme::databaseLayerEnabled() && + Theme::getActiveTheme()->getDatasource()->sourceHasModel('database', $template) + ) { + $result = true; } return $result; @@ -475,16 +484,18 @@ class Index extends Controller /** * Check to see if the provided template can be reset + * Only available when the DB layer is enabled and the template exists in both the DB & Filesystem * * @param CmsObject $template * @return boolean */ - protected function canResetTemplate($template) + protected function canResetTemplate(CmsObject $template) { - $result = true; // will set to false by default + $result = false; if (Theme::databaseLayerEnabled()) { - + $datasource = Theme::getActiveTheme()->getDatasource(); + $result = $datasource->sourceHasModel('database', $template) && $datasource->sourceHasModel('filesystem', $template); } return $result; diff --git a/modules/cms/controllers/index/_common_toolbar_actions.htm b/modules/cms/controllers/index/_common_toolbar_actions.htm index 42b247e8e..07aaa19c4 100644 --- a/modules/cms/controllers/index/_common_toolbar_actions.htm +++ b/modules/cms/controllers/index/_common_toolbar_actions.htm @@ -3,6 +3,7 @@ class="btn btn-danger oc-icon-download hide" data-request="onCommit" data-request-confirm="" + data-load-indicator="" data-control="commit-button"> @@ -12,6 +13,7 @@ class="btn btn-danger oc-icon-bomb hide" data-request="onReset" data-request-confirm="" + data-load-indicator="" data-control="reset-button"> diff --git a/modules/cms/lang/en/lang.php b/modules/cms/lang/en/lang.php index 7bf82ba7c..a6096b04d 100644 --- a/modules/cms/lang/en/lang.php +++ b/modules/cms/lang/en/lang.php @@ -186,10 +186,14 @@ return [ 'close_searchbox' => 'Close Search box', 'open_replacebox' => 'Open Replace box', 'close_replacebox' => 'Close Replace box', - 'reset' => 'Reset', 'commit' => 'Commit', - 'reset_confirm' => 'Are you sure you want to reset this file to the copy that is on the filesystem? This will completely replace it with the file that is on the filesystem', + 'reset' => 'Reset', 'commit_confirm' => 'Are you sure you want to commit your changes to this file to the filesystem? This will overwrite the existing file on the filesystem', + 'reset_confirm' => 'Are you sure you want to reset this file to the copy that is on the filesystem? This will completely replace it with the file that is on the filesystem', + 'committing' => 'Committing', + 'resetting' => 'Resetting', + 'commit_success' => 'The :type has been committed to the filesystem', + 'reset_success' => 'The :type has been reset to the filesystem version', ], 'asset' => [ 'menu_label' => 'Assets',