diff --git a/src/Backend.php b/src/Backend.php index bb10cc6..8cea70c 100644 --- a/src/Backend.php +++ b/src/Backend.php @@ -19,7 +19,6 @@ use dcCore; use dcPage; use dcFavorites; use dcNsProcess; -use Dotclear\App; use Dotclear\Helper\File\Files; /** @@ -71,15 +70,23 @@ class Backend extends dcNsProcess ); }, - // Add actions to improve - 'improveTaskAdd' => function (Tasks $actions): void { - $dir = __DIR__ . DIRECTORY_SEPARATOR . 'Task' . DIRECTORY_SEPARATOR; - foreach (Files::scandir($dir) as $file) { - if (str_ends_with($file, '.php') && is_file($dir . $file)) { - $class = __NAMESPACE__ . '\\Task\\' . basename($file, '.php'); - $actions->add(new $class()); - } - } + // Add taks to improve + 'improveTaskAdd' => function (Tasks $tasks): void { + $tasks + ->add(new Task\CssHeader()) + ->add(new Task\DcDeprecated()) + ->add(new Task\DcStore()) + ->add(new Task\EndOfFile()) + ->add(new Task\GitShields()) + ->add(new Task\LicenseFile()) + ->add(new Task\NewLine()) + ->add(new Task\PhpCsFixer()) + ->add(new Task\PhpHeader()) + ->add(new Task\PhpStan()) + ->add(new Task\Po2Php()) + ->add(new Task\Tab()) + ->add(new Task\Zip()) + ; }, ]); diff --git a/src/Config.php b/src/Config.php index 9670b91..930684c 100644 --- a/src/Config.php +++ b/src/Config.php @@ -97,10 +97,10 @@ class Config extends dcNsProcess $items = []; $settings = dcCore::app()->blog->settings->get(My::id()); - foreach ($improve->tasks->dump() as $action) { + foreach ($improve->tasks->dump() as $task) { $items[] = (new Para())->items([ - (new Checkbox(['disabled[]', 'disabled_' . $action->id()], $action->isDisabled()))->value($action->id()), - (new Label($action->id(), Label::OUTSIDE_LABEL_AFTER))->class('classic')->for('disabled_' . $action->id()), + (new Checkbox(['disabled[]', 'disabled_' . $task->properties->id], $task->isDisabled()))->value($task->properties->id), + (new Label($task->properties->id, Label::OUTSIDE_LABEL_AFTER))->class('classic')->for('disabled_' . $task->properties->id), ]); } diff --git a/src/Core.php b/src/Core.php index cfbe946..4b85a2b 100644 --- a/src/Core.php +++ b/src/Core.php @@ -14,7 +14,6 @@ declare(strict_types=1); namespace Dotclear\Plugin\improve; -use ArrayObject; use dcCore; use dcLog; use dcModuleDefine; @@ -32,9 +31,6 @@ class Core /** @var Tasks $tasks The tasks stack instance */ public readonly Tasks $tasks; - /** @var array $disabled Disabled tasks modules */ - private $disabled = []; - /** @var array $logs Logs by actions modules */ private $logs = []; @@ -55,8 +51,10 @@ class Core protected function __construct() { $this->tasks = new Tasks(); + + // mark some tasks as disabled (by settings) $disable = explode(';', (string) dcCore::app()->blog?->settings->get(My::id())->get('disabled')); - foreach($disable as $id) { + foreach ($disable as $id) { $this->tasks->get($id)?->disable(); } } @@ -153,26 +151,26 @@ class Core return $lines; } - public function fixModule(dcModuleDefine $module, array $actions): float + public function fixModule(dcModuleDefine $module, array $tasks): float { $time_start = microtime(true); $workers = []; - foreach ($actions as $action) { - if ($this->tasks->get($action)?->isConfigured() - && $this->tasks->get($action)?->isDisabled() === false + foreach ($tasks as $id) { + if (!$this->tasks->get($id)?->isDisabled() + && $this->tasks->get($id)?->isConfigured() ) { - $workers[] = $this->tasks->get($action); + $workers[] = $this->tasks->get($id); } } - foreach ($workers as $action) { + foreach ($workers as $task) { // trace all path and action in logs - $this->logs[My::id()][__('Begin')][] = $action->id(); + $this->logs[My::id()][__('Begin')][] = $task->properties->id; // info: set current module - $action->setModule($module); - $action->setPath(__('Begin'), '', true); + $task->setModule($module); + $task->setPath(__('Begin'), '', true); // action: open module - $action->openModule(); + $task->openModule(); } if (!$module->get('root_writable') || !is_writable($module->get('root'))) { throw new Exception(__('Module path is not writable')); @@ -182,61 +180,63 @@ class Core if (!file_exists($file[0])) { continue; } - foreach ($workers as $action) { + foreach ($workers as $task) { // trace all path and action in logs - $this->logs[My::id()][$file[0]][] = $action->id(); + $this->logs[My::id()][$file[0]][] = $task->properties->id; // info: set current path - $action->setPath($file[0], $file[1], $file[2]); + $task->setPath($file[0], $file[1], $file[2]); } if (!$file[2]) { - foreach ($workers as $action) { + foreach ($workers as $task) { // action: open a directory. full path - $action->openDirectory(); + $task->openDirectory(); } } else { - foreach ($workers as $action) { + foreach ($workers as $task) { // action: before openning a file. full path, extension - $action->openFile(); + $task->openFile(); } if (in_array($file[1], self::$readfile_extensions)) { if (false !== ($content = file_get_contents($file[0]))) { $no_content = empty($content); - foreach ($workers as $action) { + foreach ($workers as $task) { // action: read a file content. full path, extension, content - $action->readFile($content); + $task->readFile($content); if (empty($content) && !$no_content) { throw new Exception(sprintf( __('File content has been removed: %s by %s'), $file[0], - $action->name() + $task->properties->name )); } } Files::putContent($file[0], $content); } - foreach ($workers as $action) { + foreach ($workers as $task) { // action: after closing a file. full path, extension - $action->closeFile(); + $task->closeFile(); } } } } - foreach ($workers as $action) { + foreach ($workers as $task) { // trace all path and action in logs - $this->logs[My::id()][__('End')][] = $action->id(); + $this->logs[My::id()][__('End')][] = $task->properties->id; // info: set current module - $action->setPath(__('End'), '', true); + $task->setPath(__('End'), '', true); // action: close module - $action->closeModule(); + $task->closeModule(); } // info: get acions reports - foreach ($workers as $action) { - $this->logs[$action->id()] = $action->getLogs(); + foreach ($workers as $task) { + $logs = []; foreach ($this->has_log as $type => $v) { - if ($action->hasLog($type)) { + if (!$task->{$type}->empty()) { + $logs[$type] = $task->{$type}->dump(); $this->has_log[$type] = true; } } + $this->logs[$task->properties->id] = $logs; } return round(microtime(true) - $time_start, 5); diff --git a/src/Manage.php b/src/Manage.php index a32dc01..5c58ca1 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -42,14 +42,14 @@ use Exception; */ class Manage extends dcNsProcess { - /** @var Core $improve improve core instance */ - private static $improve = null; - /** @var string $type Current module(s) type */ - private static $type = 'plugin'; - /** @var string $module Current module id */ - private static $module = '-'; - /** @var Action|null $action Current action module */ - private static $action = null; + /** @var string $type Current module(s) type */ + private static string $type = 'plugin'; + + /** @var string $module Current module id */ + private static string $module = '-'; + + /** @var null|Task $task Current action module */ + private static ?Task $task = null; public static function init(): bool { @@ -61,6 +61,212 @@ class Manage extends dcNsProcess return static::$init; } + public static function process(): bool + { + if (!static::$init) { + return false; + } + + self::$type = self::getType(); + self::$module = self::getModule(); + self::$task = self::getTask(); + + $log_id = ''; + $done = self::setPreferences(); + + if (!empty($_POST['fix'])) { + if (empty($_POST['actions'])) { + dcAdminNotices::addWarningNotice(__('No action selected')); + } elseif (self::$module == '-') { + dcAdminNotices::addWarningNotice(__('No module selected')); + } else { + try { + $time = Core::instance()->fixModule( + self::$type == 'plugin' ? dcCore::app()->plugins->getDefine(self::$module) : dcCore::app()->themes->getDefine(self::$module), + $_POST['actions'] + ); + $log_id = Core::instance()->writeLogs(); + dcCore::app()->blog?->triggerBlog(); + + if (Core::instance()->hasLog('error')) { + $notice = ['type' => dcAdminNotices::NOTICE_ERROR, 'msg' => __('Fix of "%s" complete in %s secondes with errors')]; + } elseif (Core::instance()->hasLog('warning')) { + $notice = ['type' => dcAdminNotices::NOTICE_WARNING, 'msg' => __('Fix of "%s" complete in %s secondes with warnings')]; + } elseif (Core::instance()->hasLog('success')) { + $notice = ['type' => dcAdminNotices::NOTICE_SUCCESS, 'msg' => __('Fix of "%s" complete in %s secondes')]; + } else { + $notice = ['type' => dcAdminNotices::NOTICE_SUCCESS, 'msg' => __('Fix of "%s" complete in %s secondes without messages')]; + } + dcAdminNotices::addNotice($notice['type'], sprintf($notice['msg'], self::$module, $time)); + + $done = true; + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + $done = false; + } + } + } + + if ($done) { + dcCore::app()->adminurl?->redirect('admin.plugin.' . My::id(), ['type' => self::$type, 'module' => self::$module, 'upd' => $log_id]); + } + + return true; + } + + public static function render(): void + { + if (!static::$init) { + return; + } + + dcPage::openModule( + My::name(), + dcPage::jsModuleLoad(My::id() . '/js/index.js') . + (self::$task === null ? '' : self::$task->header()) + ); + + echo + dcPage::breadcrumb([ + __('Plugins') => '', + My::name() => '', + empty($_REQUEST['config']) ? (self::$type == 'theme' ? __('Themes actions') : __('Plugins actions')) : __('Configure module') => '', + ]) . + dcPage::notices(); + + if (empty($_REQUEST['config'])) { + self::displayActions(); + } else { + self::displayConfigurator(); + } + + dcPage::closeModule(); + } + + private static function displayConfigurator(): void + { + $back_url = $_REQUEST['redir'] ?? dcCore::app()->adminurl?->get('admin.plugin.' . My::id(), ['type' => self::$type]); + + if (null === self::$task) { + echo ' +

' . __('Unknow module') . '

+

' . __('Back') . '

'; + } else { + $redir = $_REQUEST['redir'] ?? dcCore::app()->adminurl?->get('admin.plugin.' . My::id(), ['type' => self::$type, 'config' => self::$task->properties->id]); + $res = self::$task->configure($redir); + + echo ' +

' . sprintf(__('Configure module "%s"'), self::$task->properties->name) . '

+

' . __('Back') . '

+

' . Html::escapeHTML(self::$task->properties->description) . '

' . + + (new Form('form-actions'))->method('post')->action(dcCore::app()->adminurl?->get('admin.plugin.' . My::id()))->fields([ + empty($res) ? (new Text('p', __('Nothing to configure')))->class('message') : (new Text('', $res)), + (new Para())->class('clear')->items([ + (new Submit(['save']))->value(__('Save')), + (new Hidden('type', self::$type)), + (new Hidden('config', self::$task->properties->id)), + (new Hidden('redir', $redir)), + dcCore::app()->formNonce(false), + ]), + ])->render(); + } + } + + private static function displayActions(): void + { + echo + (new Form('improve_menu'))->method('get')->action(dcCore::app()->adminurl?->get('admin.plugin.' . My::id()))->fields([ + (new Para())->class('anchor-nav')->items([ + (new Label(__('Goto:'), Label::OUTSIDE_LABEL_BEFORE))->for('type')->class('classic'), + (new Select('type'))->default(self::$type)->items([__('Plugins') => 'plugin', __('Themes') => 'theme']), + (new Submit('simenu'))->value(__('Save')), + (new Hidden('p', My::id())), + ]), + ])->render(); + + $combo_modules = self::comboModules(); + if (count($combo_modules) == 1) { + echo '

' . __('No module to manage') . '

'; + } else { + echo '

' . + '' . + ''; + foreach (Core::instance()->tasks->dump() as $task) { + if ($task->isDisabled() || !in_array(self::$type, $task->properties->types)) { + continue; + } + echo + '' . + '' . + '' . + '' . + '' . + (DC_DEBUG ? '' : '') . /* @phpstan-ignore-line */ + ''; + } + + echo '
' . __('List of available tasks') . '
' . __('Task') . '' . + '' . __('Description') . '' . + '' . __('Configuration') . '' . + (DC_DEBUG ? '' . __('Priority') . '' : '') . /* @phpstan-ignore-line */ + '
' . + (new Checkbox( + ['actions[]', 'action_' . $task->properties->id], + in_array($task->properties->id, self::getPreference()) && $task->isConfigured() + ))->value($task->properties->id)->disabled(!$task->isConfigured())->render() . + '' . + (new Label(Html::escapeHTML($task->properties->name), Label::OUTSIDE_LABEL_AFTER))->for('action_' . $task->properties->id)->class('classic')->render() . + '' . $task->properties->description . '' . ( + false === $task->properties->configurator ? '' : + 'properties->name) . '">' . __('Configure') . '' + ) . '' . $task->properties->priority . '
' . + (new Div())->class('two-cols')->items([ + (new Para())->class('col left')->items([ + (new Checkbox('save_preferences', !empty($_POST['save_preferences'])))->value(1), + (new Label(__('Save fields selection as preference'), Label::OUTSIDE_LABEL_AFTER))->for('save_preferences')->class('classic'), + ]), + (new Para())->class('col right')->items([ + (new Label(__('Select a module:'), Label::OUTSIDE_LABEL_BEFORE))->for('module')->class('classic'), + (new Select('module'))->default(self::$module)->items($combo_modules), + (new Submit('fix'))->value(__('Fix it')), + (new Hidden(['type'], self::$type)), + dcCore::app()->formNonce(false), + ]), + ])->render() . + '
+
'; + + if (!empty($_REQUEST['upd']) && !dcCore::app()->blog?->settings->get(My::id())->get('nodetails')) { + $logs = Core::instance()->parseLogs((int) $_REQUEST['upd']); + + if (!empty($logs)) { + echo '

' . __('Details') . '

'; + foreach ($logs as $path => $types) { + echo '
' . $path . '
'; + foreach ($types as $type => $tools) { + echo '
    '; + foreach ($tools as $tool => $msgs) { + $a = Core::instance()->tasks->get($tool); + if (null !== $a) { + echo '
  • ' . $a->properties->name . '
      '; + foreach ($msgs as $msg) { + echo '
    • ' . $msg . '
    • '; + } + } + echo '
  • '; + } + echo '
'; + } + echo ''; + } + echo '
'; + } + } + } + } + private static function getType(): string { return $_REQUEST['type'] ?? 'plugin'; @@ -76,9 +282,9 @@ class Manage extends dcNsProcess return $module; } - private static function getAction(): ?Action + private static function getTask(): ?Task { - return empty($_REQUEST['config']) ? null : self::$improve->tasks->get($_REQUEST['config']); + return empty($_REQUEST['config']) ? null : Core::instance()->tasks->get($_REQUEST['config']); } private static function getPreference(bool $all = false): array @@ -105,9 +311,9 @@ class Manage extends dcNsProcess $preferences = self::getPreference(true); $preferences[self::$type] = []; if (!empty($_POST['actions'])) { - foreach (self::$improve->tasks->dump() as $action) { - if (!$action->isDisabled() && in_array(self::$type, $action->types()) && in_array($action->id(), $_POST['actions'])) { - $preferences[self::$type][] = $action->id(); + foreach (Core::instance()->tasks->dump() as $task) { + if (!$task->isDisabled() && in_array(self::$type, $task->properties->types) && in_array($task->properties->id, $_POST['actions'])) { + $preferences[self::$type][] = $task->properties->id; } } } @@ -151,211 +357,4 @@ class Manage extends dcNsProcess return array_merge([__('Select a module') => '-'], $combo_modules); } - - public static function process(): bool - { - if (!static::$init) { - return false; - } - - self::$improve = Core::instance(); - self::$type = self::getType(); - self::$module = self::getModule(); - self::$action = self::getAction(); - - $log_id = ''; - $done = self::setPreferences(); - - if (!empty($_POST['fix'])) { - if (empty($_POST['actions'])) { - dcAdminNotices::addWarningNotice(__('No action selected')); - } elseif (self::$module == '-') { - dcAdminNotices::addWarningNotice(__('No module selected')); - } else { - try { - $time = self::$improve->fixModule( - self::$type == 'plugin' ? dcCore::app()->plugins->getDefine(self::$module) : dcCore::app()->themes->getDefine(self::$module), - $_POST['actions'] - ); - $log_id = self::$improve->writeLogs(); - dcCore::app()->blog?->triggerBlog(); - - if (self::$improve->hasLog('error')) { - $notice = ['type' => dcAdminNotices::NOTICE_ERROR, 'msg' => __('Fix of "%s" complete in %s secondes with errors')]; - } elseif (self::$improve->hasLog('warning')) { - $notice = ['type' => dcAdminNotices::NOTICE_WARNING, 'msg' => __('Fix of "%s" complete in %s secondes with warnings')]; - } elseif (self::$improve->hasLog('success')) { - $notice = ['type' => dcAdminNotices::NOTICE_SUCCESS, 'msg' => __('Fix of "%s" complete in %s secondes')]; - } else { - $notice = ['type' => dcAdminNotices::NOTICE_SUCCESS, 'msg' => __('Fix of "%s" complete in %s secondes without messages')]; - } - dcAdminNotices::addNotice($notice['type'], sprintf($notice['msg'], self::$module, $time)); - - $done = true; - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - $done = false; - } - } - } - - if ($done) { - dcCore::app()->adminurl?->redirect('admin.plugin.' . My::id(), ['type' => self::$type, 'module' => self::$module, 'upd' => $log_id]); - } - - return true; - } - - public static function render(): void - { - if (!static::$init) { - return; - } - - dcPage::openModule( - My::name(), - dcPage::jsModuleLoad(My::id() . '/js/index.js') . - (self::$action === null ? '' : self::$action->header()) - ); - - echo - dcPage::breadcrumb([ - __('Plugins') => '', - My::name() => '', - empty($_REQUEST['config']) ? (self::$type == 'theme' ? __('Themes actions') : __('Plugins actions')) : __('Configure module') => '', - ]) . - dcPage::notices(); - - if (empty($_REQUEST['config'])) { - self::displayActions(); - } else { - self::displayConfigurator(); - } - - dcPage::closeModule(); - } - - private static function displayConfigurator(): void - { - $back_url = $_REQUEST['redir'] ?? dcCore::app()->adminurl?->get('admin.plugin.' . My::id(), ['type' => self::$type]); - - if (null === self::$action) { - echo ' -

' . __('Unknow module') . '

-

' . __('Back') . '

'; - } else { - $redir = $_REQUEST['redir'] ?? dcCore::app()->adminurl?->get('admin.plugin.' . My::id(), ['type' => self::$type, 'config' => self::$action->id()]); - $res = self::$action->configure($redir); - - echo ' -

' . sprintf(__('Configure module "%s"'), self::$action->name()) . '

-

' . __('Back') . '

-

' . Html::escapeHTML(self::$action->description()) . '

' . - - (new Form('form-actions'))->method('post')->action(dcCore::app()->adminurl?->get('admin.plugin.' . My::id()))->fields([ - empty($res) ? (new Text('p', __('Nothing to configure')))->class('message') : (new Text('', $res)), - (new Para())->class('clear')->items([ - (new Submit(['save']))->value(__('Save')), - (new Hidden('type', self::$type)), - (new Hidden('config', self::$action->id())), - (new Hidden('redir', $redir)), - dcCore::app()->formNonce(false), - ]), - ])->render(); - } - } - - private static function displayActions(): void - { - echo - (new Form('improve_menu'))->method('get')->action(dcCore::app()->adminurl?->get('admin.plugin.' . My::id()))->fields([ - (new Para())->class('anchor-nav')->items([ - (new Label(__('Goto:'), Label::OUTSIDE_LABEL_BEFORE))->for('type')->class('classic'), - (new Select('type'))->default(self::$type)->items([__('Plugins') => 'plugin', __('Themes') => 'theme']), - (new Submit('simenu'))->value(__('Save')), - (new Hidden('p', My::id())), - ]), - ])->render(); - - $combo_modules = self::comboModules(); - if (count($combo_modules) == 1) { - echo '

' . __('No module to manage') . '

'; - } else { - echo '
' . - '' . - ''; - foreach (self::$improve->tasks->dump() as $action) { - if ($action->isDisabled() || !in_array(self::$type, $action->types())) { - continue; - } - echo - '' . - '' . - '' . - '' . - '' . - (DC_DEBUG ? '' : '') . /* @phpstan-ignore-line */ - ''; - } - - echo '
' . __('Action') . '' . - '' . __('Description') . '' . - '' . __('Configuration') . '' . - (DC_DEBUG ? '' . __('Priority') . '' : '') . /* @phpstan-ignore-line */ - '
' . - (new Checkbox( - ['actions[]', 'action_' . $action->id()], - in_array($action->id(), self::getPreference()) && $action->isConfigured() - ))->value($action->id())->disabled(!$action->isConfigured())->render() . - '' . - (new Label(Html::escapeHTML($action->name()), Label::OUTSIDE_LABEL_AFTER))->for('action_' . $action->id())->class('classic')->render() . - '' . $action->description() . '' . ( - false === $action->configurator() ? '' : - 'name()) . '">' . __('Configure') . '' - ) . '' . $action->priority() . '
' . - (new Div())->class('two-cols')->items([ - (new Para())->class('col left')->items([ - (new Checkbox('save_preferences', !empty($_POST['save_preferences'])))->value(1), - (new Label(__('Save fields selection as preference'), Label::OUTSIDE_LABEL_AFTER))->for('save_preferences')->class('classic'), - ]), - (new Para())->class('col right')->items([ - (new Label(__('Select a module:'), Label::OUTSIDE_LABEL_BEFORE))->for('module')->class('classic'), - (new Select('module'))->default(self::$module)->items($combo_modules), - (new Submit('fix'))->value(__('Fix it')), - (new Hidden(['type'], self::$type)), - dcCore::app()->formNonce(false), - ]), - ])->render() . - '
-
'; - - if (!empty($_REQUEST['upd']) && !dcCore::app()->blog?->settings->get(My::id())->get('nodetails')) { - $logs = self::$improve->parseLogs((int) $_REQUEST['upd']); - - if (!empty($logs)) { - echo '

' . __('Details') . '

'; - foreach ($logs as $path => $types) { - echo '
' . $path . '
'; - foreach ($types as $type => $tools) { - echo '
    '; - foreach ($tools as $tool => $msgs) { - $a = self::$improve->tasks->get($tool); - if (null !== $a) { - echo '
  • ' . $a->name() . '
      '; - foreach ($msgs as $msg) { - echo '
    • ' . $msg . '
    • '; - } - } - echo '
  • '; - } - echo '
'; - } - echo ''; - } - echo '
'; - } - } - } - } } diff --git a/src/Task.php b/src/Task.php index 26cb5a1..f3ea646 100644 --- a/src/Task.php +++ b/src/Task.php @@ -14,101 +14,65 @@ declare(strict_types=1); namespace Dotclear\Plugin\improve; -use ArrayObject; -use dcCore; use dcModuleDefine; -use dcPage; use Dotclear\Helper\Network\Http; /** * Improve action class helper */ -abstract class AbstractTask +abstract class Task { - /** @var dcModuleDefine Current module */ - protected $module; + /** @var TaskDescriptor Task descriptor instance */ + public readonly TaskDescriptor $properties; - /** @var string Current full path */ - protected $path_full = ''; + /** @var TaskMessages Task success messages instance */ + public readonly TaskMessages $success; - /** @var string Current file extension */ - protected $path_extension = ''; + /** @var TaskMessages Task warning messages instance */ + public readonly TaskMessages $warning; - /** @var boolean Current path is directory */ - protected $path_is_dir = null; + /** @var TaskMessages Task error messages instance */ + public readonly TaskMessages $error; - /** @var string The child class name */ - private $class_name = ''; + /** @var TaskSettings Task settings instance */ + protected readonly TaskSettings $settings; - /** @var array Messages logs */ - private $logs = ['success' => [], 'warning' => [], 'error' => []]; - - /** @var array Action module settings */ - private $settings = []; - - /** @var array List of allowed properties */ - protected static $allowed_properties = ['id', 'name', 'description', 'priority', 'configurator', 'types']; + /** @var dcModuleDefine Current module */ + protected dcModuleDefine $module; /** @var bool Is disabled action */ - private $disabled = false; + private bool $disabled = false; - /** @var string Module id */ - private $id = ''; + /** @var string Current full path */ + protected string $path_full = ''; - /** @var string Module name */ - private $name = ''; + /** @var string Current file extension */ + protected string $path_extension = ''; - /** @var string Module description */ - private $description = ''; - - /** @var integer Module id */ - private $priority = 500; - - /** @var boolean Module has config page */ - private $configurator = false; - - /** @var array Module supported types */ - private $types = ['plugin']; + /** @var null|bool Current path is directory */ + protected ?bool $path_is_dir = null; /** * Action constructor inits properties and settings of a child class. */ final public function __construct() { - $this->class_name = str_replace(__NAMESPACE__ . '\\Task\\', '', get_called_class()); + $this->success = new TaskMessages(); + $this->warning = new TaskMessages(); + $this->error = new TaskMessages(); + $this->properties = $this->getProperties(); + $this->settings = new TaskSettings($this->properties->id); $this->module = new dcModuleDefine('undefined'); - $settings = dcCore::app()->blog?->settings->get(My::id())->get('settings_' . $this->class_name); - if (null != $settings) { - $settings = json_decode($settings, true); - } - $this->settings = is_array($settings) ? $settings : []; - $this->init(); - - // can overload priority by settings - if (1 < ($p = (int) dcCore::app()->blog?->settings->get(My::id())->get('priority_' . $this->class_name))) { - $this->priority = $p; - } } /** - * Set action as disabled. + * Get task description. + * + * @return TaskDescriptor The task description */ - final public function disable() - { - $this->disabled = true; - } - - /** - * Check if actio is disabled. - * - * @return bool True on disabled - */ - final public function isDisabled() - { - return $this->disabled; - } + abstract protected function getProperties(): TaskDescriptor; /** * Action initialisation function. @@ -120,135 +84,47 @@ abstract class AbstractTask */ abstract protected function init(): bool; - /// @name Properties methods - //@{ /** - * Get a definition property of action class + * Get a setting. * - * @param string $key a property or setting id + * @param string $key The setting ID * - * @return mixed Value of property or setting of action. + * @return mixed Value of property or setting of action. */ final public function get(string $key) { - if (isset($this->settings[$key])) { - return $this->settings[$key]; - } - - return null; - } - - /** Get action module id */ - final public function id(): string - { - return $this->id; - } - - /** Get action module name */ - final public function name(): string - { - return $this->name; - } - - /** Get action module description */ - final public function description(): string - { - return $this->description; - } - - /** Get action module priority */ - final public function priority(): int - { - return $this->priority; - } - - /** Get action module configuration url if any */ - final public function configurator(): bool - { - return $this->configurator; - } - - /** Get action module supported types */ - final public function types(): array - { - return $this->types; + return $this->settings->get($key); } /** - * Set properties of action class - * - * @param array $properties Properties - * - * @return boolean Success + * Set task as disabled. */ - final protected function setProperties(array $properties): bool + final public function disable() { - foreach ($properties as $key => $value) { - if (in_array($key, self::$allowed_properties)) { - $this->{$key} = $value; - } - } - - return true; - } - //@} - - /// @name Settings methods - //@{ - /** - * Get a settings of action class - * - * @param string $setting a settings id - * - * @return mixed A setting of action. - */ - final protected function getSetting(string $setting) - { - return $this->settings[$setting] ?? null; + $this->disabled = true; } /** - * Set one or more setting of action class + * Check if task is disabled. * - * @param mixed $settings one or more settings - * @param mixed $value value for a single setting - * - * @return mixed A setting of action. + * @return bool True on disabled */ - final protected function setSettings($settings, $value = null) + final public function isDisabled() { - $settings = is_array($settings) ? $settings : [$settings => $value]; - foreach ($settings as $k => $v) { - $this->settings[$k] = $v; - } - - return true; + return $this->disabled; } /** - * Redirection after settings update + * Do HTTP redirection. * - * This save settings update before redirect. + * Used after settings form validation to save settings. * - * @param string $url redirect url after settings update + * @param string $url The URL redirection */ - final protected function redirect(string $url): bool + final protected function redirect(string $url): void { - if (!is_null(dcCore::app()->blog)) { - dcCore::app()->blog->settings->get(My::id())->put( - 'settings_' . $this->class_name, - json_encode($this->settings), - 'string', - null, - true, - true - ); - dcCore::app()->blog->triggerBlog(); - dcPage::addSuccessNotice(__('Configuration successfully updated')); - } + $this->settings->save(); Http::redirect($url); - - return true; } /** @@ -285,7 +161,6 @@ abstract class AbstractTask { return null; } - //@} /** * Set in class var current module definitions. @@ -314,6 +189,10 @@ abstract class AbstractTask $this->path_extension = $path_extension; $this->path_is_dir = $path_is_dir; + $this->success->path($path_full); + $this->warning->path($path_full); + $this->error->path($path_full); + return true; } @@ -374,133 +253,4 @@ abstract class AbstractTask return null; } //@} - - /// @name Logs methods - //@{ - /** - * Set an action log. - * - * Log must be use every time an action something happen. - * - * @param string $type type of message, can be error, warning, succes - * @param string $message message to log - * - * @return boolean True if message is logged. - */ - final public function setLog(string $type, string $message): bool - { - if (empty($this->path_full) || !array_key_exists($type, $this->logs)) { - return false; - } - $this->logs[$type][$this->path_full][] = $message; - - return true; - } - - /** - * Check if action class has log of given type. - * - * @param string $type type of message, can be error, warning, succes - * - * @return boolean True if messages exist. - */ - final public function hasLog(string $type): bool - { - return array_key_exists($type, $this->logs) && !empty($this->logs[$type]); - } - - /** - * Get action logs. - * - * @param string|null $type type of message, can be error, warning, succes - * - * @return array Arry of given type of log or all if type is null - */ - final public function getLogs($type = null): array - { - if (null === $type) { - return $this->logs; - } - if (empty($this->path_full) - || !array_key_exists($type, $this->logs) - || !array_key_exists($this->path_full, $this->logs[$type]) - ) { - return []; - } - - return $this->logs[$type][$this->path_full]; - } - - /** - * Set a log of type error. - */ - final public function setError(string $message): bool - { - return $this->setLog('error', $message); - } - - /** - * Check logs of type error exists. - */ - final public function hasError(): bool - { - return !empty($this->getLogs('error')); - } - - /** - * Get logs of type error. - */ - final public function getErrors(): array - { - return $this->getLogs('error'); - } - - /** - * Set a log of type warning. - */ - final public function setWarning(string $message): bool - { - return $this->setLog('warning', $message); - } - - /** - * Check logs of type error warnings. - */ - final public function hasWarning(): bool - { - return !empty($this->getLogs('warning')); - } - - /** - * Get logs of type warning. - */ - final public function getWarnings(): array - { - return $this->getLogs('warning'); - } - - /** - * Set a log of type success. - */ - final public function setSuccess(string $message): bool - { - return $this->setLog('success', $message); - } - - /** - * Check logs of type error success. - */ - final public function hasSuccess(): bool - { - return !empty($this->getLogs('success')); - } - - /** - * Get logs of type success. - */ - final public function getSuccess(): array - { - return $this->getLogs('success'); - } - //@} } diff --git a/src/Task/CssHeader.php b/src/Task/CssHeader.php index 5fbd047..91b5f31 100644 --- a/src/Task/CssHeader.php +++ b/src/Task/CssHeader.php @@ -27,13 +27,16 @@ use Dotclear\Helper\Html\Form\{ Textarea }; use Dotclear\Helper\Html\Html; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; use Exception; /** * Improve action module php header */ -class cssheader extends AbstractTask +class CssHeader extends Task { /** @var string Exemple of header */ private static $exemple = <<setProperties([ - 'id' => 'cssheader', - 'name' => __('CSS header'), - 'description' => __('Add or remove phpdoc header bloc from css file'), - 'priority' => 340, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - $this->action_bloc = [ __('Do nothing') => 0, __('Add bloc if it does not exist') => 'create', @@ -92,7 +98,7 @@ class cssheader extends AbstractTask __('Remove existing bloc header') => 'remove', ]; - $bloc_content = $this->getSetting('bloc_content'); + $bloc_content = $this->settings->get('bloc_content'); $this->bloc_content = is_string($bloc_content) ? $bloc_content : ''; return true; @@ -100,13 +106,13 @@ class cssheader extends AbstractTask public function isConfigured(): bool { - return !empty($this->getSetting('bloc_action')); + return !empty($this->settings->get('bloc_action')); } public function configure($url): ?string { if (!empty($_POST['save'])) { - $this->setSettings([ + $this->settings->set([ 'bloc_action' => !empty($_POST['bloc_action']) ? $_POST['bloc_action'] : '', 'bloc_content' => !empty($_POST['bloc_content']) ? $_POST['bloc_content'] : '', 'exclude_locales' => !empty($_POST['exclude_locales']), @@ -121,16 +127,16 @@ class cssheader extends AbstractTask // bloc_action (new Para())->items([ (new Label(__('Action:'), Label::OUTSIDE_LABEL_BEFORE))->for('bloc_action'), - (new Select('bloc_action'))->default($this->getSetting('bloc_action'))->items($this->action_bloc), + (new Select('bloc_action'))->default($this->settings->get('bloc_action'))->items($this->action_bloc), ]), // exclude_locales (new Para())->items([ - (new Checkbox('exclude_locales', !empty($this->getSetting('exclude_locales'))))->value(1), + (new Checkbox('exclude_locales', !empty($this->settings->get('exclude_locales'))))->value(1), (new Label(__('Do not add bloc to files from "locales" and "libs" folder'), Label::OUTSIDE_LABEL_AFTER))->for('exclude_locales')->class('classic'), ]), // exclude_templates (new Para())->items([ - (new Checkbox('exclude_templates', !empty($this->getSetting('exclude_templates'))))->value(1), + (new Checkbox('exclude_templates', !empty($this->settings->get('exclude_templates'))))->value(1), (new Label(__('Do not add bloc to files from "tpl" and "default-templates" folder'), Label::OUTSIDE_LABEL_AFTER))->for('exclude_templates')->class('classic'), ]), ]), @@ -157,7 +163,7 @@ class cssheader extends AbstractTask public function openModule(): ?bool { if (is_null(dcCore::app()->auth)) { - $this->setWarning(__('Auth is not set')); + $this->warning->add(__('Auth is not set')); return null; } @@ -165,7 +171,7 @@ class cssheader extends AbstractTask $bloc = trim($this->bloc_content); if (empty($bloc)) { - $this->setWarning(__('bloc is empty')); + $this->warning->add(__('bloc is empty')); return null; } @@ -195,11 +201,11 @@ class cssheader extends AbstractTask (string) $bloc ) ); - $this->setSuccess(__('Prepare header info')); + $this->success->add(__('Prepare header info')); return null; } catch (Exception $e) { - $this->setError(__('Failed to parse bloc')); + $this->error->add(__('Failed to parse bloc')); return null; } @@ -209,11 +215,11 @@ class cssheader extends AbstractTask { $skipped = $this->stop_scan; $this->stop_scan = false; - if (!empty($this->getSetting('exclude_locales')) && preg_match('/\/(locales|libs)(\/.*?|)$/', $this->path_full) - || !empty($this->getSetting('exclude_templates')) && preg_match('/\/(tpl|default-templates)(\/.*?|)$/', $this->path_full) + if (!empty($this->settings->get('exclude_locales')) && preg_match('/\/(locales|libs)(\/.*?|)$/', $this->path_full) + || !empty($this->settings->get('exclude_templates')) && preg_match('/\/(tpl|default-templates)(\/.*?|)$/', $this->path_full) ) { if (!$skipped) { - $this->setSuccess(__('Skip directory')); + $this->success->add(__('Skip directory')); } $this->stop_scan = true; } @@ -223,22 +229,22 @@ class cssheader extends AbstractTask public function readFile(&$content): ?bool { - if ($this->stop_scan || $this->path_extension != 'css' || $this->hasError()) { + if ($this->stop_scan || $this->path_extension != 'css' || !$this->error->empty()) { return null; } - if (empty($this->getSetting('bloc_action'))) { + if (empty($this->settings->get('bloc_action'))) { return null; } $clean = $this->deleteDocBloc($content); - if ($this->getSetting('bloc_action') == 'remove') { + if ($this->settings->get('bloc_action') == 'remove') { $content = $clean; return null; } - if ($content != $clean && $this->getSetting('bloc_action') == 'create') { + if ($content != $clean && $this->settings->get('bloc_action') == 'create') { return null; } - if ($content == $clean && $this->getSetting('bloc_action') == 'replace') { + if ($content == $clean && $this->settings->get('bloc_action') == 'replace') { return null; } @@ -264,7 +270,7 @@ class cssheader extends AbstractTask ); if ($count && $res) { $res = str_replace("\n * \n", "\n *\n", $res); - $this->setSuccess(__('Write new doc bloc content')); + $this->success->add(__('Write new doc bloc content')); } return (string) $res; @@ -286,7 +292,7 @@ class cssheader extends AbstractTask $count ); if ($count) { - $this->setSuccess(__('Delete old doc bloc content')); + $this->succes->set(__('Delete old doc bloc content')); } return (string) $res; diff --git a/src/Task/DcDeprecated.php b/src/Task/DcDeprecated.php index ed8087a..40f1183 100644 --- a/src/Task/DcDeprecated.php +++ b/src/Task/DcDeprecated.php @@ -18,35 +18,36 @@ use Dotclear\Helper\File\{ Files, Path }; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; /** * Improve action module Dotclear depreciated */ -class dcdeprecated extends AbstractTask +class DcDeprecated extends Task { /** @var array Deprecated functions [filetype [pattern, deprecated, replacement, version, help link]] */ private $deprecated = ['php' => [], 'js' => []]; - protected function init(): bool + protected function getProperties(): TaskDescriptor { - $this->setProperties([ - 'id' => 'dcdeprecated', - 'name' => __('Dotclear deprecated'), - 'description' => __('Search for use of deprecated Dotclear functions'), - 'priority' => 520, - 'types' => ['plugin', 'theme'], - ]); - $this->loadDeprecatedDefinition(); - - return true; + return new TaskDescriptor( + id: 'dcdeprecated', + name: __('Dotclear deprecated'), + description: __('Search for use of deprecated Dotclear functions'), + configurator: false, + types: ['plugin', 'theme'], + priority: 520 + ); } - private function loadDeprecatedDefinition(): void + protected function init(): bool { $path = Path::real(__DIR__ . '/dcdeprecated'); if (!$path || !is_dir($path) || !is_readable($path)) { - return; + return false; } $files = Files::scandir($path); @@ -62,6 +63,8 @@ class dcdeprecated extends AbstractTask $this->deprecated['js'] = array_merge($this->deprecated['js'], $tmp['js']); } } + + return true; } public function isConfigured(): bool @@ -76,7 +79,7 @@ class dcdeprecated extends AbstractTask } foreach ($this->deprecated[$this->path_extension] as $d) { if (preg_match('/' . $d[0] . '/i', $content)) { - $this->setWarning(sprintf(__('Possible use of deprecated "%s", you should use "%s" instead since Dotclear %s.'), $d[1], __($d[2]), $d[3]) . (empty($d[4]) ? '' : ' ' . __('Help') . ' ')); + $this->warning->add(sprintf(__('Possible use of deprecated "%s", you should use "%s" instead since Dotclear %s.'), $d[1], __($d[2]), $d[3]) . (empty($d[4]) ? '' : ' ' . __('Help') . ' ')); } } diff --git a/src/Task/DcStore.php b/src/Task/DcStore.php index 7838d05..12760c8 100644 --- a/src/Task/DcStore.php +++ b/src/Task/DcStore.php @@ -27,29 +27,35 @@ use Dotclear\Helper\Html\Form\{ }; use Dotclear\Helper\Html\XmlTag; use Dotclear\Helper\Text; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + taskDescriptor +}; use Exception; /** * Improve action module dcstore.xml */ -class dcstore extends AbstractTask +class DcStore extends Task { /** @var string Settings dcstore zip url pattern */ private $pattern = ''; + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'dcstore', + name: __('Store file'), + description: __('Re-create dcstore.xml file according to _define.php variables'), + configurator: true, + types: ['plugin', 'theme'], + priority: 420 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'dcstore', - 'name' => __('Store file'), - 'description' => __('Re-create dcstore.xml file according to _define.php variables'), - 'priority' => 420, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - - $pattern = $this->getSetting('pattern'); + $pattern = $this->settings->get('pattern'); $this->pattern = is_string($pattern) ? $pattern : ''; return true; @@ -57,13 +63,13 @@ class dcstore extends AbstractTask public function isConfigured(): bool { - return !empty($this->getSetting('pattern')); + return !empty($this->settings->get('pattern')); } public function configure($url): ?string { if (!empty($_POST['save']) && !empty($_POST['dcstore_pattern'])) { - $this->setSettings('pattern', (string) $_POST['dcstore_pattern']); + $this->settings->set('pattern', (string) $_POST['dcstore_pattern']); $this->redirect($url); } @@ -85,7 +91,7 @@ class dcstore extends AbstractTask public function openModule(): ?bool { $content = $this->generateXML(); - if ($this->hasError()) { + if (!$this->error->empty()) { return false; } @@ -93,9 +99,9 @@ class dcstore extends AbstractTask try { Files::putContent($this->module->get('root') . DIRECTORY_SEPARATOR . 'dcstore.xml', $content); - $this->setSuccess(__('Write dcstore.xml file.')); + $this->success->add(__('Write dcstore.xml file.')); } catch (Exception $e) { - $this->setError(__('Failed to write dcstore.xml file')); + $this->error->add(__('Failed to write dcstore.xml file')); return false; } @@ -113,37 +119,37 @@ class dcstore extends AbstractTask # name if (empty($this->module->get('name'))) { - $this->setError(__('unknow module name')); + $this->error->add(__('unknow module name')); } $rsp->insertNode(new XmlTag('name', $this->module->get('name'))); # version if (empty($this->module->get('version'))) { - $this->setError(__('unknow module version')); + $this->error->add(__('unknow module version')); } $rsp->insertNode(new XmlTag('version', $this->module->get('version'))); # author if (empty($this->module->get('author'))) { - $this->setError(__('unknow module author')); + $this->error->add(__('unknow module author')); } $rsp->insertNode(new XmlTag('author', $this->module->get('author'))); # desc if (empty($this->module->get('desc'))) { - $this->setError(__('unknow module description')); + $this->error->add(__('unknow module description')); } $rsp->insertNode(new XmlTag('desc', $this->module->get('desc'))); # repository if (empty($this->module->get('repository'))) { - $this->setError(__('no repository set in _define.php')); + $this->error->add(__('no repository set in _define.php')); } # file $file_pattern = $this->parseFilePattern(); if (empty($file_pattern)) { - $this->setError(__('no zip file pattern set in configuration')); + $this->error->add(__('no zip file pattern set in configuration')); } $rsp->insertNode(new XmlTag('file', $file_pattern)); @@ -161,14 +167,14 @@ class dcstore extends AbstractTask } } if (empty($this->module->get('dc_min'))) { - $this->setWarning(__('no minimum dotclear version')); + $this->warning->add(__('no minimum dotclear version')); } else { $rsp->insertNode(new XmlTag('da:dcmin', $this->module->get('dc_min'))); } # da details if (empty($this->module->get('details'))) { - $this->setWarning(__('no details URL')); + $this->warning->add(__('no details URL')); } else { $rsp->insertNode(new XmlTag('da:details', $this->module->get('details'))); } @@ -183,7 +189,7 @@ class dcstore extends AbstractTask # da support if (empty($this->module->get('support'))) { - $this->setWarning(__('no support URL')); + $this->warning->add(__('no support URL')); } else { $rsp->insertNode(new XmlTag('da:support', $this->module->get('support'))); } diff --git a/src/Task/EndOfFile.php b/src/Task/EndOfFile.php index aa35b0a..05180b9 100644 --- a/src/Task/EndOfFile.php +++ b/src/Task/EndOfFile.php @@ -23,24 +23,30 @@ use Dotclear\Helper\Html\Form\{ Note, Para }; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; /** * Improve action module end of file */ -class endoffile extends AbstractTask +class EndOfFile extends Task { + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'endoffile', + name: __('End of files'), + description: __('Remove php tag and empty lines from end of files'), + configurator: true, + types: ['plugin', 'theme'], + priority: 860 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'endoffile', - 'name' => __('End of files'), - 'description' => __('Remove php tag and empty lines from end of files'), - 'priority' => 860, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - return true; } @@ -52,7 +58,7 @@ class endoffile extends AbstractTask public function configure($url): ?string { if (!empty($_POST['save'])) { - $this->setSettings('psr2', !empty($_POST['endoffile_psr2'])); + $this->settings->set('psr2', !empty($_POST['endoffile_psr2'])); $this->redirect($url); } @@ -60,7 +66,7 @@ class endoffile extends AbstractTask (new Fieldset())->class('fieldset')->legend((new Legend(__('Contents'))))->fields([ // endoffile_psr2 (new Para())->items([ - (new Checkbox('endoffile_psr2', !empty($this->getSetting('psr2'))))->value(1), + (new Checkbox('endoffile_psr2', !empty($this->settings->get('psr2'))))->value(1), (new Label(__('Add a blank line to the end of file'), Label::OUTSIDE_LABEL_AFTER))->for('endoffile_psr2')->class('classic'), ]), (new Note())->text(__('PSR2 must have a blank line, whereas PSR12 must not.'))->class('form-note'), @@ -77,9 +83,9 @@ class endoffile extends AbstractTask ['/(\s*)(\?>\s*)$/', '/\n+$/'], '', $content - ) . ($this->getSetting('psr2') ? "\n" : ''); + ) . ($this->settings->get('psr2') ? "\n" : ''); if ($content != $clean) { - $this->setSuccess(__('Replace end of file')); + $this->success->add(__('Replace end of file')); $content = $clean; } diff --git a/src/Task/GitShields.php b/src/Task/GitShields.php index 043a47d..70689e9 100644 --- a/src/Task/GitShields.php +++ b/src/Task/GitShields.php @@ -25,12 +25,15 @@ use Dotclear\Helper\Html\Form\{ Note, Para }; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; /** * Improve action module Github shields.io */ -class gitshields extends AbstractTask +class GitShields extends Task { /** @var string Username of git repo */ private $username = ''; @@ -60,33 +63,36 @@ class gitshields extends AbstractTask 'license' => '[![License](https://img.shields.io/github/license/%username%/%module%)](https://github.com/%username%/%module%/blob/master/LICENSE)', ]; + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'gitshields', + name: __('Shields badges'), + description: __('Add and maintain shields.io badges to the REDAME.md file'), + configurator: true, + types: ['plugin', 'theme'], + priority: 380 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'gitshields', - 'name' => __('Shields badges'), - 'description' => __('Add and maintain shields.io badges to the REDAME.md file'), - 'priority' => 380, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - - $username = $this->getSetting('username'); + $username = $this->settings->get('username'); $this->username = is_string($username) ? $username : ''; - $this->dotaddict = (bool) $this->getSetting('dotaddict'); + $this->dotaddict = (bool) $this->settings->get('dotaddict'); return true; } public function isConfigured(): bool { - return !empty($this->getSetting('username')); + return !empty($this->settings->get('username')); } public function configure($url): ?string { if (!empty($_POST['save']) && !empty($_POST['username'])) { - $this->setSettings([ + $this->settings->set([ 'username' => (string) $_POST['username'], 'dotaddict' => !empty($_POST['dotaddict']), ]); @@ -158,7 +164,7 @@ class gitshields extends AbstractTask )); } $this->blocs = $blocs; - $this->setSuccess(__('Prepare custom shield info')); + $this->success->add(__('Prepare custom shield info')); } private function getDotclearVersion(): string @@ -192,7 +198,7 @@ class gitshields extends AbstractTask $count ); if ($count && $res) { - $this->setSuccess(__('Write new shield bloc')); + $this->success->add(__('Write new shield bloc')); } return (string) $res; @@ -208,7 +214,7 @@ class gitshields extends AbstractTask $count ); if ($count && $res) { - $this->setSuccess(__('Delete old shield bloc')); + $this->success->add(__('Delete old shield bloc')); } return (string) $res; diff --git a/src/Task/LicenseFile.php b/src/Task/LicenseFile.php index bbe796b..4292ba7 100644 --- a/src/Task/LicenseFile.php +++ b/src/Task/LicenseFile.php @@ -24,13 +24,16 @@ use Dotclear\Helper\Html\Form\{ Para, Select }; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; use Exception; /** * Improve action module license file */ -class licensefile extends AbstractTask +class LicenseFile extends Task { /** @var array Possible license filenames */ protected static $license_filenames = [ @@ -45,16 +48,20 @@ class licensefile extends AbstractTask /** @var array Action */ private $action_full = []; + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'license', + name: __('License file'), + description: __('Add or remove full license file to module root'), + configurator: true, + types: ['plugin', 'theme'], + priority: 330 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'license', - 'name' => __('License file'), - 'description' => __('Add or remove full license file to module root'), - 'priority' => 330, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); $this->action_version = [ __('no version selected') => '', __('gpl2 - GNU General Public License v2') => 'gpl2', @@ -82,7 +89,7 @@ class licensefile extends AbstractTask public function configure($url): ?string { if (!empty($_POST['save'])) { - $this->setSettings([ + $this->settings->set([ 'action_version' => !empty($_POST['action_version']) ? $_POST['action_version'] : '', 'action_full' => !empty($_POST['action_full']) ? $_POST['action_full'] : '', ]); @@ -94,12 +101,12 @@ class licensefile extends AbstractTask // action_version (new Para())->items([ (new Label(__('License version:'), Label::OUTSIDE_LABEL_BEFORE))->for('action_version'), - (new Select('action_version'))->default($this->getSetting('action_version'))->items($this->action_version), + (new Select('action_version'))->default($this->settings->get('action_version'))->items($this->action_version), ]), // action_full (new Para())->items([ (new Label(__('Action on file:'), Label::OUTSIDE_LABEL_BEFORE))->for('action_full'), - (new Select('action_full'))->default($this->getSetting('action_full'))->items($this->action_full), + (new Select('action_full'))->default($this->settings->get('action_full'))->items($this->action_full), ]), ]), ])->render(); @@ -107,12 +114,12 @@ class licensefile extends AbstractTask public function openModule(): ?bool { - if (in_array($this->getSetting('action_full'), ['remove', 'full','overwrite'])) { - $this->deleteFullLicense(($this->getSetting('action_full') == 'overwrite')); + if (in_array($this->settings->get('action_full'), ['remove', 'full','overwrite'])) { + $this->deleteFullLicense(($this->settings->get('action_full') == 'overwrite')); } - if (in_array($this->getSetting('action_full'), ['create', 'overwrite', 'full'])) { - if (empty($this->getSetting('action_version'))) { - $this->setWarning(__('No full license type selected')); + if (in_array($this->settings->get('action_full'), ['create', 'overwrite', 'full'])) { + if (empty($this->settings->get('action_version'))) { + $this->warning->add(__('No full license type selected')); } else { $this->writeFullLicense(); } @@ -124,16 +131,16 @@ class licensefile extends AbstractTask private function writeFullLicense(): ?bool { try { - $full = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'licensefile' . DIRECTORY_SEPARATOR . $this->getSetting('action_version') . '.full.txt'); + $full = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'licensefile' . DIRECTORY_SEPARATOR . $this->settings->get('action_version') . '.full.txt'); if (empty($full)) { - $this->setError(__('Failed to load license content')); + $this->error->add(__('Failed to load license content')); return null; } Files::putContent($this->module->get('root') . DIRECTORY_SEPARATOR . 'LICENSE', str_replace("\r\n", "\n", $full)); - $this->setSuccess(__('Write new license file "LICENSE"')); + $this->success->add(__('Write new license file "LICENSE"')); } catch (Exception $e) { - $this->setError(__('Failed to write new license file')); + $this->error->add(__('Failed to write new license file')); return null; } @@ -148,11 +155,11 @@ class licensefile extends AbstractTask continue; } if (!Files::isDeletable($this->module->get('root') . DIRECTORY_SEPARATOR . $file)) { - $this->setWarning(sprintf(__('Old license file is not deletable (%s)'), $file)); + $this->warning->add(sprintf(__('Old license file is not deletable (%s)'), $file)); } elseif (!@unlink($this->module->get('root') . DIRECTORY_SEPARATOR . $file)) { - $this->setError(sprintf(__('Failed to delete old license file (%s)'), $file)); + $this->error->add(sprintf(__('Failed to delete old license file (%s)'), $file)); } else { - $this->setSuccess(sprintf(__('Delete old license file "%s"'), $file)); + $this->success->add(sprintf(__('Delete old license file "%s"'), $file)); } } diff --git a/src/Task/NewLine.php b/src/Task/NewLine.php index c18541c..f9e89dd 100644 --- a/src/Task/NewLine.php +++ b/src/Task/NewLine.php @@ -24,45 +24,49 @@ use Dotclear\Helper\Html\Form\{ Para }; use Dotclear\Plugin\improve\{ - AbstractTask, - Core + Task, + Core, + TaskDescriptor }; /** * Improve action module new line */ -class newline extends AbstractTask +class NewLine extends Task { + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'newline', + name: __('Newlines'), + description: __('Replace bad and repetitive and empty newline by single newline in files'), + configurator: true, + types: ['plugin', 'theme'], + priority: 840 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'newline', - 'name' => __('Newlines'), - 'description' => __('Replace bad and repetitive and empty newline by single newline in files'), - 'priority' => 840, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - return true; } public function isConfigured(): bool { - return !empty($this->getSetting('extensions')); + return !empty($this->settings->get('extensions')); } public function configure($url): ?string { if (!empty($_POST['save']) && !empty($_POST['newline_extensions'])) { - $this->setSettings( + $this->settings->set( 'extensions', Core::cleanExtensions($_POST['newline_extensions']) ); $this->redirect($url); } - $ext = $this->getSetting('extensions'); + $ext = $this->settings->get('extensions'); if (!is_array($ext)) { $ext = []; } @@ -81,7 +85,7 @@ class newline extends AbstractTask public function readFile(string &$content): ?bool { - $ext = $this->getSetting('extensions'); + $ext = $this->settings->get('extensions'); if (!is_array($ext) || !in_array($this->path_extension, $ext)) { return null; } @@ -99,7 +103,7 @@ class newline extends AbstractTask ) ); if ($content != $clean) { - $this->setSuccess(__('Replace bad new lines')); + $this->success->add(__('Replace bad new lines')); $content = $clean; } diff --git a/src/Task/PhpCsFixer.php b/src/Task/PhpCsFixer.php index 3b1087d..a1dee17 100644 --- a/src/Task/PhpCsFixer.php +++ b/src/Task/PhpCsFixer.php @@ -29,15 +29,16 @@ use Dotclear\Helper\Html\Form\{ }; use Dotclear\Helper\Html\Html; use Dotclear\Plugin\improve\{ - AbstractTask, - My + Task, + My, + TaskDescriptor }; use Exception; /** * Improve action module PHP CS Fixer */ -class phpcsfixer extends AbstractTask +class PhpCsFixer extends Task { /** @var array Type of runtime errors */ protected static $errors = [ @@ -59,17 +60,20 @@ class phpcsfixer extends AbstractTask /** @var string Settings PHP executable path */ private $phpexe_path = ''; + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'phpcsfixer', + name: __('PHP CS Fixer'), + description: __('Fix PSR coding style using Php CS Fixer'), + configurator: true, + types: ['plugin', 'theme'], + priority: 920 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'phpcsfixer', - 'name' => __('PHP CS Fixer'), - 'description' => __('Fix PSR coding style using Php CS Fixer'), - 'priority' => 920, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - $this->getPhpPath(); if (null !== dcCore::app()->auth?->user_prefs) { @@ -98,7 +102,7 @@ class phpcsfixer extends AbstractTask public function configure($url): ?string { if (!empty($_POST['save'])) { - $this->setSettings([ + $this->settings->set([ 'phpexe_path' => !empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : '', ]); $this->redirect($url); @@ -142,18 +146,18 @@ class phpcsfixer extends AbstractTask exec($command, $output, $error); if (empty($output)) { if (isset(self::$errors[$error])) { - $this->setError(self::$errors[$error]); + $this->error->add(self::$errors[$error]); return false; } throw new Exception('oops'); } - $this->setSuccess(sprintf('
%s
', implode('
', $output))); + $this->success->add(sprintf('
%s
', implode('
', $output))); return true; } catch (Exception $e) { - $this->setError(__('Failed to run php-cs-fixer')); + $this->error->add(__('Failed to run php-cs-fixer')); return false; } @@ -164,7 +168,7 @@ class phpcsfixer extends AbstractTask */ private function getPhpPath(): void { - $phpexe_path = $this->getSetting('phpexe_path'); + $phpexe_path = $this->settings->get('phpexe_path'); if (!is_string($phpexe_path)) { $phpexe_path = ''; } diff --git a/src/Task/PhpHeader.php b/src/Task/PhpHeader.php index 9bc7070..9f33c76 100644 --- a/src/Task/PhpHeader.php +++ b/src/Task/PhpHeader.php @@ -27,13 +27,16 @@ use Dotclear\Helper\Html\Form\{ Textarea }; use Dotclear\Helper\Html\Html; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; use Exception; /** * Improve action module php header */ -class phpheader extends AbstractTask +class PhpHeader extends Task { /** @var string Exemple of header */ private static $exemple = <<setProperties([ - 'id' => 'phpheader', - 'name' => __('PHP header'), - 'description' => __('Add or remove phpdoc header bloc from php file'), - 'priority' => 340, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - $this->action_bloc = [ __('Do nothing') => 0, __('Add bloc if it does not exist') => 'create', @@ -92,7 +98,7 @@ class phpheader extends AbstractTask __('Remove existing bloc header') => 'remove', ]; - $bloc_content = $this->getSetting('bloc_content'); + $bloc_content = $this->settings->get('bloc_content'); $this->bloc_content = is_string($bloc_content) ? $bloc_content : ''; return true; @@ -100,13 +106,13 @@ class phpheader extends AbstractTask public function isConfigured(): bool { - return !empty($this->getSetting('bloc_action')) || !empty($this->getSetting('remove_old')); + return !empty($this->settings->get('bloc_action')) || !empty($this->settings->get('remove_old')); } public function configure($url): ?string { if (!empty($_POST['save'])) { - $this->setSettings([ + $this->settings->set([ 'bloc_action' => !empty($_POST['bloc_action']) ? $_POST['bloc_action'] : '', 'bloc_content' => !empty($_POST['bloc_content']) ? $_POST['bloc_content'] : '', 'remove_old' => !empty($_POST['remove_old']), @@ -120,16 +126,16 @@ class phpheader extends AbstractTask // bloc_action (new Para())->items([ (new Label(__('Action:'), Label::OUTSIDE_LABEL_BEFORE))->for('bloc_action'), - (new Select('bloc_action'))->default($this->getSetting('bloc_action'))->items($this->action_bloc), + (new Select('bloc_action'))->default($this->settings->get('bloc_action'))->items($this->action_bloc), ]), // remove_old (new Para())->items([ - (new Checkbox('remove_old', !empty($this->getSetting('remove_old'))))->value(1), + (new Checkbox('remove_old', !empty($this->settings->get('remove_old'))))->value(1), (new Label(__('Remove old style bloc header (using #)'), Label::OUTSIDE_LABEL_AFTER))->for('remove_old')->class('classic'), ]), // exclude_locales (new Para())->items([ - (new Checkbox('exclude_locales', !empty($this->getSetting('exclude_locales'))))->value(1), + (new Checkbox('exclude_locales', !empty($this->settings->get('exclude_locales'))))->value(1), (new Label(__('Do not add bloc to files from "locales" and "libs" folder'), Label::OUTSIDE_LABEL_AFTER))->for('exclude_locales')->class('classic'), ]), ]), @@ -156,7 +162,7 @@ class phpheader extends AbstractTask public function openModule(): ?bool { if (is_null(dcCore::app()->auth)) { - $this->setWarning(__('Auth is not set')); + $this->warning->add(__('Auth is not set')); return null; } @@ -164,7 +170,7 @@ class phpheader extends AbstractTask $bloc = trim($this->bloc_content); if (empty($bloc)) { - $this->setWarning(__('bloc is empty')); + $this->waring->set(__('bloc is empty')); return null; } @@ -194,11 +200,11 @@ class phpheader extends AbstractTask (string) $bloc ) ); - $this->setSuccess(__('Prepare header info')); + $this->success->add(__('Prepare header info')); return null; } catch (Exception $e) { - $this->setError(__('Failed to parse bloc')); + $this->error->add(__('Failed to parse bloc')); return null; } @@ -208,9 +214,9 @@ class phpheader extends AbstractTask { $skipped = $this->stop_scan; $this->stop_scan = false; - if (!empty($this->getSetting('exclude_locales')) && preg_match('/\/(locales|libs)(\/.*?|)$/', $this->path_full)) { + if (!empty($this->settings->get('exclude_locales')) && preg_match('/\/(locales|libs)(\/.*?|)$/', $this->path_full)) { if (!$skipped) { - $this->setSuccess(__('Skip directory')); + $this->success->add(__('Skip directory')); } $this->stop_scan = true; } @@ -220,26 +226,26 @@ class phpheader extends AbstractTask public function readFile(&$content): ?bool { - if ($this->stop_scan || $this->path_extension != 'php' || $this->hasError()) { + if ($this->stop_scan || $this->path_extension != 'php' || !$this->error->empty()) { return null; } - if (!empty($this->getSetting('remove_old'))) { + if (!empty($this->settings->get('remove_old'))) { $content = $this->deleteOldBloc($content); } - if (empty($this->getSetting('bloc_action'))) { + if (empty($this->settings->get('bloc_action'))) { return null; } $clean = $this->deleteDocBloc($content); - if ($this->getSetting('bloc_action') == 'remove') { + if ($this->settings->get('bloc_action') == 'remove') { $content = $clean; return null; } - if ($content != $clean && $this->getSetting('bloc_action') == 'create') { + if ($content != $clean && $this->settings->get('bloc_action') == 'create') { return null; } - if ($content == $clean && $this->getSetting('bloc_action') == 'replace') { + if ($content == $clean && $this->settings->get('bloc_action') == 'replace') { return null; } @@ -265,7 +271,7 @@ class phpheader extends AbstractTask ); if ($count && $res) { $res = str_replace("\n * \n", "\n *\n", $res); - $this->setSuccess(__('Write new doc bloc content')); + $this->success->add(__('Write new doc bloc content')); } return (string) $res; @@ -287,7 +293,7 @@ class phpheader extends AbstractTask $count ); if ($count) { - $this->setSuccess(__('Delete old doc bloc content')); + $this->success->add(__('Delete old doc bloc content')); } return (string) $res; @@ -309,7 +315,7 @@ class phpheader extends AbstractTask $count ); if ($count) { - $this->setSuccess(__('Delete old style bloc content')); + $this->success->add(__('Delete old style bloc content')); } return (string) $res; diff --git a/src/Task/PhpStan.php b/src/Task/PhpStan.php index 3309ccc..f13c0c4 100644 --- a/src/Task/PhpStan.php +++ b/src/Task/PhpStan.php @@ -31,15 +31,16 @@ use Dotclear\Helper\Html\Form\{ }; use Dotclear\Helper\Html\Html; use Dotclear\Plugin\improve\{ - AbstractTask, - My + Task, + My, + TaskDescriptor }; use Exception; /** * Improve action module PHPStan */ -class phpstan extends AbstractTask +class PhpStan extends Task { /** @var boolean User pref to use colored synthax */ protected static $user_ui_colorsyntax = false; @@ -56,23 +57,26 @@ class phpstan extends AbstractTask /** @var string Settings PHP executable path */ private $phpexe_path = ''; + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'phpstan', + name: __('PHPStan'), + description: __('Analyse php code using PHPStan'), + configurator: true, + types: ['plugin'], + priority: 910 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'phpstan', - 'name' => __('PHPStan'), - 'description' => __('Analyse php code using PHPStan'), - 'priority' => 910, - 'configurator' => true, - 'types' => ['plugin'], - ]); - $this->getPhpPath(); - $run_level = $this->getSetting('run_level'); + $run_level = $this->settings->get('run_level'); $this->run_level = is_int($run_level) ? $run_level : 5; - $ignored_vars = $this->getSetting('ignored_vars'); + $ignored_vars = $this->settings->get('ignored_vars'); $this->ignored_vars = is_string($ignored_vars) ? $ignored_vars : ''; if (null !== dcCore::app()->auth?->user_prefs) { @@ -101,7 +105,7 @@ class phpstan extends AbstractTask public function configure($url): ?string { if (!empty($_POST['save'])) { - $this->setSettings([ + $this->settings->set([ 'phpexe_path' => (!empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : ''), 'run_level' => (int) $_POST['run_level'], 'ignored_vars' => (!empty($_POST['ignored_vars']) ? $_POST['ignored_vars'] : ''), @@ -140,19 +144,19 @@ class phpstan extends AbstractTask )->class('form-note'), // ignored_default (new Para())->items([ - (new Checkbox('ignored_default', !empty($this->getSetting('ignored_default'))))->value(1), + (new Checkbox('ignored_default', !empty($this->settings->get('ignored_default'))))->value(1), (new Label(__('Do not use rules from default ignored errors list.'), Label::OUTSIDE_LABEL_AFTER))->for('ignored_default')->class('classic'), ]), (new Note())->text(__('See ignored errors from configuration file below.'))->class('form-note'), // split_report (new Para())->items([ - (new Checkbox('split_report', !empty($this->getSetting('split_report'))))->value(1), + (new Checkbox('split_report', !empty($this->settings->get('split_report'))))->value(1), (new Label(__('Split report by file rather than all in the end.'), Label::OUTSIDE_LABEL_AFTER))->for('split_report')->class('classic'), ]), (new Note())->text(__('Enable this can cause timeout.'))->class('form-note'), // clear_cache (new Para())->items([ - (new Checkbox('clear_cache', !empty($this->getSetting('clear_cache'))))->value(1), + (new Checkbox('clear_cache', !empty($this->settings->get('clear_cache'))))->value(1), (new Label(__('Clear result cache before each analizes.'), Label::OUTSIDE_LABEL_AFTER))->for('clear_cache')->class('classic'), ]), (new Note())->text(__('Enable this can cause timeout.'))->class('form-note'), @@ -174,7 +178,7 @@ class phpstan extends AbstractTask public function openModule(): bool { if (!$this->writeConf()) { - $this->setError(__('Failed to write phpstan configuration')); + $this->error->add(__('Failed to write phpstan configuration')); return false; } @@ -184,27 +188,27 @@ class phpstan extends AbstractTask public function closeFile(): ?bool { - if (!$this->getSetting('split_report') + if (!$this->settings->get('split_report') || !in_array($this->path_extension, ['php', 'in']) ) { return null; } - $clear = $this->getSetting('clear_cache') ? $this->execClear($this->path_full) : true; + $clear = $this->settings->get('clear_cache') ? $this->execClear($this->path_full) : true; return $clear && $this->execFixer($this->path_full); } public function closeModule(): ?bool { - if ($this->getSetting('split_report')) { + if ($this->settings->get('split_report')) { return null; } - if ($this->hasError()) { + if (!$this->error->empty()) { return false; } - $clear = $this->getSetting('clear_cache') ? $this->execClear() : true; + $clear = $this->settings->get('clear_cache') ? $this->execClear() : true; return $clear && $this->execFixer(); } @@ -245,14 +249,14 @@ class phpstan extends AbstractTask throw new Exception('oops'); } if (count($output) < 4) { - $this->setSuccess($from_clear ? __('Cache cleared') : __('No errors found')); + $this->success->add($from_clear ? __('Cache cleared') : __('No errors found')); } else { - $this->setWarning(sprintf('
%s
', implode('
', $output))); + $this->warning->add(sprintf('
%s
', implode('
', $output))); } return true; } catch (Exception $e) { - $this->setError(__('Failed to run phpstan')); + $this->error->add(__('Failed to run phpstan')); return false; } @@ -263,7 +267,7 @@ class phpstan extends AbstractTask */ private function getPhpPath(): void { - $phpexe_path = $this->getSetting('phpexe_path'); + $phpexe_path = $this->settings->get('phpexe_path'); if (!is_string($phpexe_path)) { $phpexe_path = ''; } @@ -279,7 +283,7 @@ class phpstan extends AbstractTask private function writeConf(): bool { - $full = $this->getSetting('ignored_default') ? '' : 'full.'; + $full = $this->settings->get('ignored_default') ? '' : 'full.'; $content = str_replace( [ '%LEVEL%', diff --git a/src/Task/Po2Php.php b/src/Task/Po2Php.php index 6d2b2d4..7f606a8 100644 --- a/src/Task/Po2Php.php +++ b/src/Task/Po2Php.php @@ -15,12 +15,15 @@ declare(strict_types=1); namespace Dotclear\Plugin\improve\Task; use Dotclear\Helper\L10n; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; /** * Improve action module dcstore.xml */ -class po2php extends AbstractTask +class Po2Php extends Task { /** @var string License bloc */ private $license = <<setProperties([ - 'id' => 'po2php', - 'name' => __('Translation files'), - 'description' => __('Compile existing translation .po files to fresh .lang.php files'), - 'priority' => 310, - 'types' => ['plugin', 'theme'], - ]); - return true; } @@ -57,9 +64,9 @@ class po2php extends AbstractTask } if (L10n::generatePhpFileFromPo(substr($this->path_full, 0, -3), $this->license)) { - $this->setSuccess(__('Compile .po file to .lang.php')); + $this->success->add(__('Compile .po file to .lang.php')); } else { - $this->setError(__('Failed to compile .po file')); + $this->error->add(__('Failed to compile .po file')); } return true; diff --git a/src/Task/Tab.php b/src/Task/Tab.php index 6158040..c3536b9 100644 --- a/src/Task/Tab.php +++ b/src/Task/Tab.php @@ -14,23 +14,30 @@ declare(strict_types=1); namespace Dotclear\Plugin\improve\Task; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; /** * Improve action module tab */ -class tab extends AbstractTask +class Tab extends Task { + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'tab', + name: __('Tabulations'), + description: __('Replace tabulation by four space in php files'), + configurator: false, + types: ['plugin', 'theme'], + priority: 820 + ); + } + protected function init(): bool { - $this->setProperties([ - 'id' => 'tab', - 'name' => __('Tabulations'), - 'description' => __('Replace tabulation by four space in php files'), - 'priority' => 820, - 'types' => ['plugin', 'theme'], - ]); - return true; } @@ -41,7 +48,7 @@ class tab extends AbstractTask } $clean = preg_replace('/(\t)/', ' ', $content);// . "\n"; if ($content != $clean) { - $this->setSuccess(__('Replace tabulation by spaces')); + $this->success->add(__('Replace tabulation by spaces')); $content = $clean; } diff --git a/src/Task/Zip.php b/src/Task/Zip.php index 448618c..af4f4b3 100644 --- a/src/Task/Zip.php +++ b/src/Task/Zip.php @@ -29,12 +29,15 @@ use Dotclear\Helper\Html\Form\{ Note, Para }; -use Dotclear\Plugin\improve\AbstractTask; +use Dotclear\Plugin\improve\{ + Task, + TaskDescriptor +}; /** * Improve action module zip */ -class zip extends AbstractTask +class Zip extends Task { /** @var array List of excluded file pattern */ public static $exclude = [ @@ -68,26 +71,29 @@ class zip extends AbstractTask /** @var string Settings Second package filename */ private $secondpack_filename = ''; + protected function getProperties(): TaskDescriptor + { + return new TaskDescriptor( + id: 'zip', + name: __('Zip module'), + description: __('Compress module into a ready to install package'), + configurator: true, + types: ['plugin', 'theme'], + priority: 980 + ); + } + protected function init(): bool { require_once implode(DIRECTORY_SEPARATOR, [__DIR__, 'zip', 'Zip.php']); - $this->setProperties([ - 'id' => 'zip', - 'name' => __('Zip module'), - 'description' => __('Compress module into a ready to install package'), - 'priority' => 980, - 'configurator' => true, - 'types' => ['plugin', 'theme'], - ]); - - $pack_excludefiles = $this->getSetting('pack_excludefiles'); + $pack_excludefiles = $this->settings->get('pack_excludefiles'); $this->pack_excludefiles = is_string($pack_excludefiles) ? $pack_excludefiles : ''; - $pack_filename = $this->getSetting('pack_filename'); + $pack_filename = $this->settings->get('pack_filename'); $this->pack_filename = is_string($pack_filename) ? $pack_filename : ''; - $secondpack_filename = $this->getSetting('secondpack_filename'); + $secondpack_filename = $this->settings->get('secondpack_filename'); $this->secondpack_filename = is_string($secondpack_filename) ? $secondpack_filename : ''; return true; @@ -95,13 +101,13 @@ class zip extends AbstractTask public function isConfigured(): bool { - return !empty($this->getSetting('pack_repository')) && !empty($this->getSetting('pack_filename')); + return !empty($this->settings->get('pack_repository')) && !empty($this->settings->get('pack_filename')); } public function configure($url): ?string { if (!empty($_POST['save'])) { - $this->setSettings([ + $this->settings->set([ 'pack_repository' => !empty($_POST['pack_repository']) ? $_POST['pack_repository'] : '', 'pack_filename' => !empty($_POST['pack_filename']) ? $_POST['pack_filename'] : '', 'secondpack_filename' => !empty($_POST['secondpack_filename']) ? $_POST['secondpack_filename'] : '', @@ -117,7 +123,7 @@ class zip extends AbstractTask // pack_repository (new Para())->items([ (new Label(__('Path to repository:'), Label::OUTSIDE_LABEL_BEFORE))->for('pack_repository'), - (new Input('pack_repository'))->size(65)->maxlenght(255)->value($this->getSetting('pack_repository')), + (new Input('pack_repository'))->size(65)->maxlenght(255)->value($this->settings->get('pack_repository')), ]), (new Note())->text(sprintf( __('Preconization: %s'), @@ -129,18 +135,18 @@ class zip extends AbstractTask // pack_filename (new Para())->items([ (new Label(__('Name of exported package:'), Label::OUTSIDE_LABEL_BEFORE))->for('pack_filename'), - (new Input('pack_filename'))->size(65)->maxlenght(255)->value($this->getSetting('pack_filename')), + (new Input('pack_filename'))->size(65)->maxlenght(255)->value($this->settings->get('pack_filename')), ]), (new Note())->text(sprintf(__('Preconization: %s'), '%type%-%id%'))->class('form-note'), // secondpack_filename (new Para())->items([ (new Label(__('Name of second exported package:'), Label::OUTSIDE_LABEL_BEFORE))->for('secondpack_filename'), - (new Input('secondpack_filename'))->size(65)->maxlenght(255)->value($this->getSetting('secondpack_filename')), + (new Input('secondpack_filename'))->size(65)->maxlenght(255)->value($this->settings->get('secondpack_filename')), ]), (new Note())->text(sprintf(__('Preconization: %s'), '%type%-%id%-%version%'))->class('form-note'), // pack_overwrite (new Para())->items([ - (new Checkbox('pack_overwrite', !empty($this->getSetting('pack_overwrite'))))->value(1), + (new Checkbox('pack_overwrite', !empty($this->settings->get('pack_overwrite'))))->value(1), (new Label(__('Overwrite existing languages'), Label::OUTSIDE_LABEL_AFTER))->for('pack_overwrite')->class('classic'), ]), ]), @@ -148,12 +154,12 @@ class zip extends AbstractTask // pack_excludefiles (new Para())->items([ (new Label(__('Extra files to exclude from package:'), Label::OUTSIDE_LABEL_BEFORE))->for('pack_excludefiles'), - (new Input('pack_excludefiles'))->size(65)->maxlenght(255)->value($this->getSetting('pack_excludefiles')), + (new Input('pack_excludefiles'))->size(65)->maxlenght(255)->value($this->settings->get('pack_excludefiles')), ]), (new Note())->text(sprintf(__('By default all these files are always removed from packages : %s'), implode(', ', self::$exclude)))->class('form-note'), // pack_nocomment (new Para())->items([ - (new Checkbox('pack_nocomment', !empty($this->getSetting('pack_nocomment'))))->value(1), + (new Checkbox('pack_nocomment', !empty($this->settings->get('pack_nocomment'))))->value(1), (new Label(__('Remove comments from files'), Label::OUTSIDE_LABEL_AFTER))->for('pack_nocomment')->class('classic'), ]), ]), @@ -166,15 +172,15 @@ class zip extends AbstractTask self::$exclude, explode(',', $this->pack_excludefiles) ); - $this->setSuccess(sprintf(__('Prepare excluded files "%s"'), implode(', ', $exclude))); - if (!empty($this->getSetting('pack_nocomment'))) { + $this->success->add(sprintf(__('Prepare excluded files "%s"'), implode(', ', $exclude))); + if (!empty($this->settings->get('pack_nocomment'))) { zip\Zip::$remove_comment = true; - $this->setSuccess(__('Prepare comment removal')); + $this->success->add(__('Prepare comment removal')); } - if (!empty($this->getSetting('pack_filename'))) { + if (!empty($this->settings->get('pack_filename'))) { $this->zipModule($this->pack_filename, $exclude); } - if (!empty($this->getSetting('secondpack_filename'))) { + if (!empty($this->settings->get('secondpack_filename'))) { $this->zipModule($this->secondpack_filename, $exclude); } @@ -198,14 +204,14 @@ class zip extends AbstractTask foreach ($parts as $i => $part) { $parts[$i] = Files::tidyFileName($part); } - $path = $this->getSetting('pack_repository') . '/' . implode('/', $parts) . '.zip'; - if (file_exists($path) && empty($this->getSetting('pack_overwrite'))) { - $this->setWarning(__('Destination filename already exists')); + $path = $this->settings->get('pack_repository') . '/' . implode('/', $parts) . '.zip'; + if (file_exists($path) && empty($this->settings->get('pack_overwrite'))) { + $this->warning->add(__('Destination filename already exists')); return; } if (!is_dir(dirname($path)) || !is_writable(dirname($path))) { - $this->setError(__('Destination path is not writable')); + $this->error->add(__('Destination path is not writable')); return; } @@ -229,6 +235,6 @@ class zip extends AbstractTask $zip->write(); unset($zip); - $this->setSuccess(sprintf(__('Zip module into "%s"'), $path)); + $this->success->add(sprintf(__('Zip module into "%s"'), $path)); } } diff --git a/src/TaskDescriptor.php b/src/TaskDescriptor.php new file mode 100644 index 0000000..8ebb9ff --- /dev/null +++ b/src/TaskDescriptor.php @@ -0,0 +1,55 @@ +blog) && 1 < ($p = (int) dcCore::app()->blog?->settings->get(My::id())->get(self::PREFIX . $this->id))) { + $this->priority = $p; + } else { + $this->priority = abs($priority); + } + } +} diff --git a/src/TaskMessages.php b/src/TaskMessages.php new file mode 100644 index 0000000..3487cce --- /dev/null +++ b/src/TaskMessages.php @@ -0,0 +1,79 @@ + $stack The messages by path stack */ + private array $stack; + + /** @ var string $path The current path */ + private string $path = 'root'; + + /** + * Set current working path. + * + * @param string $path The path + */ + public function path(string $path = 'root'): void + { + $this->path = $path; + } + + /** + * Check if there are messages. + * + * return bool True if not empty + */ + public function empty(): bool + { + return empty($this->stack); + } + + /** + * Add a message for current path. + * + * @param string $message The message + */ + public function add(string $message): void + { + $this->stack[$this->path][] = $message; + } + + /** + * Get a path messages. + * + * @param string The path + * + * @return array The messages + */ + public function get(string $path): array + { + return $this->stack[$path] ?? []; + } + + /** + * Get all messages + * + * @return array The messages stack + */ + public function dump(): array + { + return $this->stack; + } +} diff --git a/src/TaskSettings.php b/src/TaskSettings.php new file mode 100644 index 0000000..2ecc9e5 --- /dev/null +++ b/src/TaskSettings.php @@ -0,0 +1,90 @@ + $stack The settings stack */ + private array $stack = []; + + /** + * Constructor sets settings suffix. + * + * @param string $suffit The settings suffix (ie taks id) + */ + public function __construct( + private string $suffix + ) { + if (is_null(dcCore::app()->blog)) { + throw new Exception(__('Blog is not set')); + } + + if (null !== ($settings = dcCore::app()->blog->settings->get(My::id())->get(self::PREFIX . $this->suffix))) { + $settings = json_decode($settings, true); + $this->stack = is_array($settings) ? $settings : []; + } + } + + /** + * Get a task setting. + * + * @param string $key The setting ID + * + * @return mixed The setting value + */ + public function get(string $key) + { + return $this->stack[$key] ?? null; + } + + /** + * Set one or more setting(s). + * + * @param mixed $settings one or more settings + * @param mixed $value value for a single setting + */ + public function set($settings, $value = null): void + { + foreach (is_array($settings) ? $settings : [$settings => $value] as $k => $v) { + $this->stack[$k] = $v; + } + } + + /** + * Save settings. + */ + public function save() + { + if (!is_null(dcCore::app()->blog)) { + dcCore::app()->blog->settings->get(My::id())->put( + self::PREFIX . $this->suffix, + json_encode($this->stack), + 'string', + null, + true, + true + ); + dcCore::app()->blog->triggerBlog(); + } + } +} diff --git a/src/Tasks.php b/src/Tasks.php index c78f9ad..d9db796 100644 --- a/src/Tasks.php +++ b/src/Tasks.php @@ -15,14 +15,13 @@ declare(strict_types=1); namespace Dotclear\Plugin\improve; use dcCore; -use Exception; /** * The Tasks stack. */ class Tasks { - /** @var array $stack The tasks stack */ + /** @var array $stack The tasks stack */ private array $stack = []; /** @@ -33,21 +32,21 @@ class Tasks # --BEHAVIOR-- improveTaskAdd: Tasks dcCore::app()->callBehavior('improveTaskAdd', $this); - uasort($this->stack, fn ($a, $b) => $a->name() <=> $b->name()); - uasort($this->stack, fn ($a, $b) => $a->priority() <=> $b->priority()); + uasort($this->stack, fn ($a, $b) => $a->properties->name <=> $b->properties->name); + uasort($this->stack, fn ($a, $b) => $a->properties->priority <=> $b->properties->priority); } /** * Add an task. * - * @param AbstractTask $task The task instance + * @param Task $task The task instance * * @return Tasks Self instance */ - public function add(AbstractTask $task): Tasks + public function add(Task $task): Tasks { - if (!isset($this->stack[$task->id()])) { - $this->stack[$task->id()] = $task; + if (!isset($this->stack[$task->properties->id])) { + $this->stack[$task->properties->id] = $task; } return $this; @@ -56,7 +55,7 @@ class Tasks /** * Get all tasks. * - * @return array The tasks stack + * @return array The tasks stack */ public function dump(): array { @@ -68,9 +67,9 @@ class Tasks * * @param string $id The task id * - * @return null|AbstractTask The task + * @return null|Task The task */ - public function get(string $id): ?AbstractTask + public function get(string $id): ?Task { return $this->stack[$id] ?? null; }