split Task class properties

This commit is contained in:
Jean-Christian Denis 2023-04-29 00:34:01 +02:00
parent effb961f6c
commit 0c304755e1
Signed by: JcDenis
GPG key ID: 1B5B8C5B90B6C951
22 changed files with 909 additions and 858 deletions

View file

@ -19,7 +19,6 @@ use dcCore;
use dcPage; use dcPage;
use dcFavorites; use dcFavorites;
use dcNsProcess; use dcNsProcess;
use Dotclear\App;
use Dotclear\Helper\File\Files; use Dotclear\Helper\File\Files;
/** /**
@ -71,15 +70,23 @@ class Backend extends dcNsProcess
); );
}, },
// Add actions to improve // Add taks to improve
'improveTaskAdd' => function (Tasks $actions): void { 'improveTaskAdd' => function (Tasks $tasks): void {
$dir = __DIR__ . DIRECTORY_SEPARATOR . 'Task' . DIRECTORY_SEPARATOR; $tasks
foreach (Files::scandir($dir) as $file) { ->add(new Task\CssHeader())
if (str_ends_with($file, '.php') && is_file($dir . $file)) { ->add(new Task\DcDeprecated())
$class = __NAMESPACE__ . '\\Task\\' . basename($file, '.php'); ->add(new Task\DcStore())
$actions->add(new $class()); ->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())
;
}, },
]); ]);

View file

@ -97,10 +97,10 @@ class Config extends dcNsProcess
$items = []; $items = [];
$settings = dcCore::app()->blog->settings->get(My::id()); $settings = dcCore::app()->blog->settings->get(My::id());
foreach ($improve->tasks->dump() as $action) { foreach ($improve->tasks->dump() as $task) {
$items[] = (new Para())->items([ $items[] = (new Para())->items([
(new Checkbox(['disabled[]', 'disabled_' . $action->id()], $action->isDisabled()))->value($action->id()), (new Checkbox(['disabled[]', 'disabled_' . $task->properties->id], $task->isDisabled()))->value($task->properties->id),
(new Label($action->id(), Label::OUTSIDE_LABEL_AFTER))->class('classic')->for('disabled_' . $action->id()), (new Label($task->properties->id, Label::OUTSIDE_LABEL_AFTER))->class('classic')->for('disabled_' . $task->properties->id),
]); ]);
} }

View file

@ -14,7 +14,6 @@ declare(strict_types=1);
namespace Dotclear\Plugin\improve; namespace Dotclear\Plugin\improve;
use ArrayObject;
use dcCore; use dcCore;
use dcLog; use dcLog;
use dcModuleDefine; use dcModuleDefine;
@ -32,9 +31,6 @@ class Core
/** @var Tasks $tasks The tasks stack instance */ /** @var Tasks $tasks The tasks stack instance */
public readonly Tasks $tasks; public readonly Tasks $tasks;
/** @var array<int,string> $disabled Disabled tasks modules */
private $disabled = [];
/** @var array<string,array> $logs Logs by actions modules */ /** @var array<string,array> $logs Logs by actions modules */
private $logs = []; private $logs = [];
@ -55,8 +51,10 @@ class Core
protected function __construct() protected function __construct()
{ {
$this->tasks = new Tasks(); $this->tasks = new Tasks();
// mark some tasks as disabled (by settings)
$disable = explode(';', (string) dcCore::app()->blog?->settings->get(My::id())->get('disabled')); $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(); $this->tasks->get($id)?->disable();
} }
} }
@ -153,26 +151,26 @@ class Core
return $lines; return $lines;
} }
public function fixModule(dcModuleDefine $module, array $actions): float public function fixModule(dcModuleDefine $module, array $tasks): float
{ {
$time_start = microtime(true); $time_start = microtime(true);
$workers = []; $workers = [];
foreach ($actions as $action) { foreach ($tasks as $id) {
if ($this->tasks->get($action)?->isConfigured() if (!$this->tasks->get($id)?->isDisabled()
&& $this->tasks->get($action)?->isDisabled() === false && $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 // 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 // info: set current module
$action->setModule($module); $task->setModule($module);
$action->setPath(__('Begin'), '', true); $task->setPath(__('Begin'), '', true);
// action: open module // action: open module
$action->openModule(); $task->openModule();
} }
if (!$module->get('root_writable') || !is_writable($module->get('root'))) { if (!$module->get('root_writable') || !is_writable($module->get('root'))) {
throw new Exception(__('Module path is not writable')); throw new Exception(__('Module path is not writable'));
@ -182,61 +180,63 @@ class Core
if (!file_exists($file[0])) { if (!file_exists($file[0])) {
continue; continue;
} }
foreach ($workers as $action) { foreach ($workers as $task) {
// trace all path and action in logs // 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 // info: set current path
$action->setPath($file[0], $file[1], $file[2]); $task->setPath($file[0], $file[1], $file[2]);
} }
if (!$file[2]) { if (!$file[2]) {
foreach ($workers as $action) { foreach ($workers as $task) {
// action: open a directory. full path // action: open a directory. full path
$action->openDirectory(); $task->openDirectory();
} }
} else { } else {
foreach ($workers as $action) { foreach ($workers as $task) {
// action: before openning a file. full path, extension // action: before openning a file. full path, extension
$action->openFile(); $task->openFile();
} }
if (in_array($file[1], self::$readfile_extensions)) { if (in_array($file[1], self::$readfile_extensions)) {
if (false !== ($content = file_get_contents($file[0]))) { if (false !== ($content = file_get_contents($file[0]))) {
$no_content = empty($content); $no_content = empty($content);
foreach ($workers as $action) { foreach ($workers as $task) {
// action: read a file content. full path, extension, content // action: read a file content. full path, extension, content
$action->readFile($content); $task->readFile($content);
if (empty($content) && !$no_content) { if (empty($content) && !$no_content) {
throw new Exception(sprintf( throw new Exception(sprintf(
__('File content has been removed: %s by %s'), __('File content has been removed: %s by %s'),
$file[0], $file[0],
$action->name() $task->properties->name
)); ));
} }
} }
Files::putContent($file[0], $content); Files::putContent($file[0], $content);
} }
foreach ($workers as $action) { foreach ($workers as $task) {
// action: after closing a file. full path, extension // 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 // 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 // info: set current module
$action->setPath(__('End'), '', true); $task->setPath(__('End'), '', true);
// action: close module // action: close module
$action->closeModule(); $task->closeModule();
} }
// info: get acions reports // info: get acions reports
foreach ($workers as $action) { foreach ($workers as $task) {
$this->logs[$action->id()] = $action->getLogs(); $logs = [];
foreach ($this->has_log as $type => $v) { 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->has_log[$type] = true;
} }
} }
$this->logs[$task->properties->id] = $logs;
} }
return round(microtime(true) - $time_start, 5); return round(microtime(true) - $time_start, 5);

View file

@ -42,14 +42,14 @@ use Exception;
*/ */
class Manage extends dcNsProcess class Manage extends dcNsProcess
{ {
/** @var Core $improve improve core instance */
private static $improve = null;
/** @var string $type Current module(s) type */ /** @var string $type Current module(s) type */
private static $type = 'plugin'; private static string $type = 'plugin';
/** @var string $module Current module id */ /** @var string $module Current module id */
private static $module = '-'; private static string $module = '-';
/** @var Action|null $action Current action module */
private static $action = null; /** @var null|Task $task Current action module */
private static ?Task $task = null;
public static function init(): bool public static function init(): bool
{ {
@ -61,6 +61,212 @@ class Manage extends dcNsProcess
return static::$init; 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 '
<p class="warning">' . __('Unknow module') . '</p>
<p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>';
} 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 '
<h3>' . sprintf(__('Configure module "%s"'), self::$task->properties->name) . '</h3>
<p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>
<h4>' . Html::escapeHTML(self::$task->properties->description) . '</h4>' .
(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 '<p class="message">' . __('No module to manage') . '</p>';
} else {
echo '<p /><form action="' . dcCore::app()->adminurl?->get('admin.plugin.' . My::id()) . '" method="post" id="form-actions">' .
'<table><caption>' . __('List of available tasks') . '</caption><thead><tr>' .
'<th colspan="2" class="first">' . __('Task') . '</td>' .
'<th scope="col">' . __('Description') . '</td>' .
'<th scope="col">' . __('Configuration') . '</td>' .
(DC_DEBUG ? '<th scope="col">' . __('Priority') . '</td>' : '') . /* @phpstan-ignore-line */
'</tr></thead><tbody>';
foreach (Core::instance()->tasks->dump() as $task) {
if ($task->isDisabled() || !in_array(self::$type, $task->properties->types)) {
continue;
}
echo
'<tr class="line' . ($task->isConfigured() ? '' : ' offline') . '">' .
'<td class="minimal">' .
(new Checkbox(
['actions[]', 'action_' . $task->properties->id],
in_array($task->properties->id, self::getPreference()) && $task->isConfigured()
))->value($task->properties->id)->disabled(!$task->isConfigured())->render() .
'</td>' .
'<td class="minimal nowrap">' .
(new Label(Html::escapeHTML($task->properties->name), Label::OUTSIDE_LABEL_AFTER))->for('action_' . $task->properties->id)->class('classic')->render() .
'</td>' .
'<td class="maximal">' . $task->properties->description . '</td>' .
'<td class="minimal nowrap modules">' . (
false === $task->properties->configurator ? '' :
'<a class="module-config" href="' . dcCore::app()->adminurl?->get('admin.plugin.' . My::id(), ['type' => self::$type, 'config' => $task->properties->id]) .
'" title="' . sprintf(__("Configure action '%s'"), $task->properties->name) . '">' . __('Configure') . '</a>'
) . '</td>' .
(DC_DEBUG ? '<td class="minimal"><span class="debug">' . $task->properties->priority . '</span></td>' : '') . /* @phpstan-ignore-line */
'</tr>';
}
echo '</tbody></table>' .
(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() .
'<br class="clear" />
</form>';
if (!empty($_REQUEST['upd']) && !dcCore::app()->blog?->settings->get(My::id())->get('nodetails')) {
$logs = Core::instance()->parseLogs((int) $_REQUEST['upd']);
if (!empty($logs)) {
echo '<div class="fieldset"><h4>' . __('Details') . '</h4>';
foreach ($logs as $path => $types) {
echo '<h5>' . $path . '</h5>';
foreach ($types as $type => $tools) {
echo '<div class="' . $type . '"><ul>';
foreach ($tools as $tool => $msgs) {
$a = Core::instance()->tasks->get($tool);
if (null !== $a) {
echo '<li>' . $a->properties->name . '<ul>';
foreach ($msgs as $msg) {
echo '<li>' . $msg . '</li>';
}
}
echo '</ul></li>';
}
echo '</ul></div>';
}
echo '';
}
echo '</div>';
}
}
}
}
private static function getType(): string private static function getType(): string
{ {
return $_REQUEST['type'] ?? 'plugin'; return $_REQUEST['type'] ?? 'plugin';
@ -76,9 +282,9 @@ class Manage extends dcNsProcess
return $module; 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 private static function getPreference(bool $all = false): array
@ -105,9 +311,9 @@ class Manage extends dcNsProcess
$preferences = self::getPreference(true); $preferences = self::getPreference(true);
$preferences[self::$type] = []; $preferences[self::$type] = [];
if (!empty($_POST['actions'])) { if (!empty($_POST['actions'])) {
foreach (self::$improve->tasks->dump() as $action) { foreach (Core::instance()->tasks->dump() as $task) {
if (!$action->isDisabled() && in_array(self::$type, $action->types()) && in_array($action->id(), $_POST['actions'])) { if (!$task->isDisabled() && in_array(self::$type, $task->properties->types) && in_array($task->properties->id, $_POST['actions'])) {
$preferences[self::$type][] = $action->id(); $preferences[self::$type][] = $task->properties->id;
} }
} }
} }
@ -151,211 +357,4 @@ class Manage extends dcNsProcess
return array_merge([__('Select a module') => '-'], $combo_modules); 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 '
<p class="warning">' . __('Unknow module') . '</p>
<p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>';
} 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 '
<h3>' . sprintf(__('Configure module "%s"'), self::$action->name()) . '</h3>
<p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>
<h4>' . Html::escapeHTML(self::$action->description()) . '</h4>' .
(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 '<p class="message">' . __('No module to manage') . '</p>';
} else {
echo '<form action="' . dcCore::app()->adminurl?->get('admin.plugin.' . My::id()) . '" method="post" id="form-actions">' .
'<table><caption class="hidden">' . __('Actions') . '</caption><thead><tr>' .
'<th colspan="2" class="first">' . __('Action') . '</td>' .
'<th scope="col">' . __('Description') . '</td>' .
'<th scope="col">' . __('Configuration') . '</td>' .
(DC_DEBUG ? '<th scope="col">' . __('Priority') . '</td>' : '') . /* @phpstan-ignore-line */
'</tr></thead><tbody>';
foreach (self::$improve->tasks->dump() as $action) {
if ($action->isDisabled() || !in_array(self::$type, $action->types())) {
continue;
}
echo
'<tr class="line' . ($action->isConfigured() ? '' : ' offline') . '">' .
'<td class="minimal">' .
(new Checkbox(
['actions[]', 'action_' . $action->id()],
in_array($action->id(), self::getPreference()) && $action->isConfigured()
))->value($action->id())->disabled(!$action->isConfigured())->render() .
'</td>' .
'<td class="minimal nowrap">' .
(new Label(Html::escapeHTML($action->name()), Label::OUTSIDE_LABEL_AFTER))->for('action_' . $action->id())->class('classic')->render() .
'</td>' .
'<td class="maximal">' . $action->description() . '</td>' .
'<td class="minimal nowrap modules">' . (
false === $action->configurator() ? '' :
'<a class="module-config" href="' . dcCore::app()->adminurl?->get('admin.plugin.' . My::id(), ['type' => self::$type, 'config' => $action->id()]) .
'" title="' . sprintf(__("Configure action '%s'"), $action->name()) . '">' . __('Configure') . '</a>'
) . '</td>' .
(DC_DEBUG ? '<td class="minimal"><span class="debug">' . $action->priority() . '</span></td>' : '') . /* @phpstan-ignore-line */
'</tr>';
}
echo '</tbody></table>' .
(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() .
'<br class="clear" />
</form>';
if (!empty($_REQUEST['upd']) && !dcCore::app()->blog?->settings->get(My::id())->get('nodetails')) {
$logs = self::$improve->parseLogs((int) $_REQUEST['upd']);
if (!empty($logs)) {
echo '<div class="fieldset"><h4>' . __('Details') . '</h4>';
foreach ($logs as $path => $types) {
echo '<h5>' . $path . '</h5>';
foreach ($types as $type => $tools) {
echo '<div class="' . $type . '"><ul>';
foreach ($tools as $tool => $msgs) {
$a = self::$improve->tasks->get($tool);
if (null !== $a) {
echo '<li>' . $a->name() . '<ul>';
foreach ($msgs as $msg) {
echo '<li>' . $msg . '</li>';
}
}
echo '</ul></li>';
}
echo '</ul></div>';
}
echo '';
}
echo '</div>';
}
}
}
}
} }

View file

@ -14,101 +14,65 @@ declare(strict_types=1);
namespace Dotclear\Plugin\improve; namespace Dotclear\Plugin\improve;
use ArrayObject;
use dcCore;
use dcModuleDefine; use dcModuleDefine;
use dcPage;
use Dotclear\Helper\Network\Http; use Dotclear\Helper\Network\Http;
/** /**
* Improve action class helper * Improve action class helper
*/ */
abstract class AbstractTask abstract class Task
{ {
/** @var TaskDescriptor Task descriptor instance */
public readonly TaskDescriptor $properties;
/** @var TaskMessages Task success messages instance */
public readonly TaskMessages $success;
/** @var TaskMessages Task warning messages instance */
public readonly TaskMessages $warning;
/** @var TaskMessages Task error messages instance */
public readonly TaskMessages $error;
/** @var TaskSettings Task settings instance */
protected readonly TaskSettings $settings;
/** @var dcModuleDefine Current module */ /** @var dcModuleDefine Current module */
protected $module; protected dcModuleDefine $module;
/** @var string Current full path */
protected $path_full = '';
/** @var string Current file extension */
protected $path_extension = '';
/** @var boolean Current path is directory */
protected $path_is_dir = null;
/** @var string The child class name */
private $class_name = '';
/** @var array<string, array> Messages logs */
private $logs = ['success' => [], 'warning' => [], 'error' => []];
/** @var array<string> Action module settings */
private $settings = [];
/** @var array List of allowed properties */
protected static $allowed_properties = ['id', 'name', 'description', 'priority', 'configurator', 'types'];
/** @var bool Is disabled action */ /** @var bool Is disabled action */
private $disabled = false; private bool $disabled = false;
/** @var string Module id */ /** @var string Current full path */
private $id = ''; protected string $path_full = '';
/** @var string Module name */ /** @var string Current file extension */
private $name = ''; protected string $path_extension = '';
/** @var string Module description */ /** @var null|bool Current path is directory */
private $description = ''; protected ?bool $path_is_dir = null;
/** @var integer Module id */
private $priority = 500;
/** @var boolean Module has config page */
private $configurator = false;
/** @var array Module supported types */
private $types = ['plugin'];
/** /**
* Action constructor inits properties and settings of a child class. * Action constructor inits properties and settings of a child class.
*/ */
final public function __construct() 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'); $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(); $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.
*/
final public function disable()
{
$this->disabled = true;
}
/**
* Check if actio is disabled.
* *
* @return bool True on disabled * @return TaskDescriptor The task description
*/ */
final public function isDisabled() abstract protected function getProperties(): TaskDescriptor;
{
return $this->disabled;
}
/** /**
* Action initialisation function. * Action initialisation function.
@ -120,135 +84,47 @@ abstract class AbstractTask
*/ */
abstract protected function init(): bool; 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) final public function get(string $key)
{ {
if (isset($this->settings[$key])) { return $this->settings->get($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;
} }
/** /**
* Set properties of action class * Set task as disabled.
*
* @param array $properties Properties
*
* @return boolean Success
*/ */
final protected function setProperties(array $properties): bool final public function disable()
{ {
foreach ($properties as $key => $value) { $this->disabled = true;
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;
} }
/** /**
* Set one or more setting of action class * Check if task is disabled.
* *
* @param mixed $settings one or more settings * @return bool True on disabled
* @param mixed $value value for a single setting
*
* @return mixed A setting of action.
*/ */
final protected function setSettings($settings, $value = null) final public function isDisabled()
{ {
$settings = is_array($settings) ? $settings : [$settings => $value]; return $this->disabled;
foreach ($settings as $k => $v) {
$this->settings[$k] = $v;
}
return true;
} }
/** /**
* 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)) { $this->settings->save();
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'));
}
Http::redirect($url); Http::redirect($url);
return true;
} }
/** /**
@ -285,7 +161,6 @@ abstract class AbstractTask
{ {
return null; return null;
} }
//@}
/** /**
* Set in class var current module definitions. * Set in class var current module definitions.
@ -314,6 +189,10 @@ abstract class AbstractTask
$this->path_extension = $path_extension; $this->path_extension = $path_extension;
$this->path_is_dir = $path_is_dir; $this->path_is_dir = $path_is_dir;
$this->success->path($path_full);
$this->warning->path($path_full);
$this->error->path($path_full);
return true; return true;
} }
@ -374,133 +253,4 @@ abstract class AbstractTask
return null; 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');
}
//@}
} }

View file

@ -27,13 +27,16 @@ use Dotclear\Helper\Html\Form\{
Textarea Textarea
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
use Exception; use Exception;
/** /**
* Improve action module php header * Improve action module php header
*/ */
class cssheader extends AbstractTask class CssHeader extends Task
{ {
/** @var string Exemple of header */ /** @var string Exemple of header */
private static $exemple = <<<EOF private static $exemple = <<<EOF
@ -73,17 +76,20 @@ class cssheader extends AbstractTask
/** @var string Settings bloc content */ /** @var string Settings bloc content */
private $bloc_content = ''; private $bloc_content = '';
protected function getProperties(): TaskDescriptor
{
return new TaskDescriptor(
id: 'cssheader',
name: __('CSS header'),
description: __('Add or remove phpdoc header bloc from css file'),
configurator: true,
types: ['plugin', 'theme'],
priority: 340
);
}
protected function init(): bool protected function init(): bool
{ {
$this->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 = [ $this->action_bloc = [
__('Do nothing') => 0, __('Do nothing') => 0,
__('Add bloc if it does not exist') => 'create', __('Add bloc if it does not exist') => 'create',
@ -92,7 +98,7 @@ class cssheader extends AbstractTask
__('Remove existing bloc header') => 'remove', __('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 : ''; $this->bloc_content = is_string($bloc_content) ? $bloc_content : '';
return true; return true;
@ -100,13 +106,13 @@ class cssheader extends AbstractTask
public function isConfigured(): bool public function isConfigured(): bool
{ {
return !empty($this->getSetting('bloc_action')); return !empty($this->settings->get('bloc_action'));
} }
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->settings->set([
'bloc_action' => !empty($_POST['bloc_action']) ? $_POST['bloc_action'] : '', 'bloc_action' => !empty($_POST['bloc_action']) ? $_POST['bloc_action'] : '',
'bloc_content' => !empty($_POST['bloc_content']) ? $_POST['bloc_content'] : '', 'bloc_content' => !empty($_POST['bloc_content']) ? $_POST['bloc_content'] : '',
'exclude_locales' => !empty($_POST['exclude_locales']), 'exclude_locales' => !empty($_POST['exclude_locales']),
@ -121,16 +127,16 @@ class cssheader extends AbstractTask
// bloc_action // bloc_action
(new Para())->items([ (new Para())->items([
(new Label(__('Action:'), Label::OUTSIDE_LABEL_BEFORE))->for('bloc_action'), (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 // exclude_locales
(new Para())->items([ (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'), (new Label(__('Do not add bloc to files from "locales" and "libs" folder'), Label::OUTSIDE_LABEL_AFTER))->for('exclude_locales')->class('classic'),
]), ]),
// exclude_templates // exclude_templates
(new Para())->items([ (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'), (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 public function openModule(): ?bool
{ {
if (is_null(dcCore::app()->auth)) { if (is_null(dcCore::app()->auth)) {
$this->setWarning(__('Auth is not set')); $this->warning->add(__('Auth is not set'));
return null; return null;
} }
@ -165,7 +171,7 @@ class cssheader extends AbstractTask
$bloc = trim($this->bloc_content); $bloc = trim($this->bloc_content);
if (empty($bloc)) { if (empty($bloc)) {
$this->setWarning(__('bloc is empty')); $this->warning->add(__('bloc is empty'));
return null; return null;
} }
@ -195,11 +201,11 @@ class cssheader extends AbstractTask
(string) $bloc (string) $bloc
) )
); );
$this->setSuccess(__('Prepare header info')); $this->success->add(__('Prepare header info'));
return null; return null;
} catch (Exception $e) { } catch (Exception $e) {
$this->setError(__('Failed to parse bloc')); $this->error->add(__('Failed to parse bloc'));
return null; return null;
} }
@ -209,11 +215,11 @@ class cssheader extends AbstractTask
{ {
$skipped = $this->stop_scan; $skipped = $this->stop_scan;
$this->stop_scan = false; $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)
|| !empty($this->getSetting('exclude_templates')) && preg_match('/\/(tpl|default-templates)(\/.*?|)$/', $this->path_full) || !empty($this->settings->get('exclude_templates')) && preg_match('/\/(tpl|default-templates)(\/.*?|)$/', $this->path_full)
) { ) {
if (!$skipped) { if (!$skipped) {
$this->setSuccess(__('Skip directory')); $this->success->add(__('Skip directory'));
} }
$this->stop_scan = true; $this->stop_scan = true;
} }
@ -223,22 +229,22 @@ class cssheader extends AbstractTask
public function readFile(&$content): ?bool 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; return null;
} }
if (empty($this->getSetting('bloc_action'))) { if (empty($this->settings->get('bloc_action'))) {
return null; return null;
} }
$clean = $this->deleteDocBloc($content); $clean = $this->deleteDocBloc($content);
if ($this->getSetting('bloc_action') == 'remove') { if ($this->settings->get('bloc_action') == 'remove') {
$content = $clean; $content = $clean;
return null; return null;
} }
if ($content != $clean && $this->getSetting('bloc_action') == 'create') { if ($content != $clean && $this->settings->get('bloc_action') == 'create') {
return null; return null;
} }
if ($content == $clean && $this->getSetting('bloc_action') == 'replace') { if ($content == $clean && $this->settings->get('bloc_action') == 'replace') {
return null; return null;
} }
@ -264,7 +270,7 @@ class cssheader extends AbstractTask
); );
if ($count && $res) { if ($count && $res) {
$res = str_replace("\n * \n", "\n *\n", $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; return (string) $res;
@ -286,7 +292,7 @@ class cssheader extends AbstractTask
$count $count
); );
if ($count) { if ($count) {
$this->setSuccess(__('Delete old doc bloc content')); $this->succes->set(__('Delete old doc bloc content'));
} }
return (string) $res; return (string) $res;

View file

@ -18,35 +18,36 @@ use Dotclear\Helper\File\{
Files, Files,
Path Path
}; };
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
/** /**
* Improve action module Dotclear depreciated * Improve action module Dotclear depreciated
*/ */
class dcdeprecated extends AbstractTask class DcDeprecated extends Task
{ {
/** @var array Deprecated functions [filetype [pattern, deprecated, replacement, version, help link]] */ /** @var array Deprecated functions [filetype [pattern, deprecated, replacement, version, help link]] */
private $deprecated = ['php' => [], 'js' => []]; private $deprecated = ['php' => [], 'js' => []];
protected function init(): bool protected function getProperties(): TaskDescriptor
{ {
$this->setProperties([ return new TaskDescriptor(
'id' => 'dcdeprecated', id: 'dcdeprecated',
'name' => __('Dotclear deprecated'), name: __('Dotclear deprecated'),
'description' => __('Search for use of deprecated Dotclear functions'), description: __('Search for use of deprecated Dotclear functions'),
'priority' => 520, configurator: false,
'types' => ['plugin', 'theme'], types: ['plugin', 'theme'],
]); priority: 520
$this->loadDeprecatedDefinition(); );
return true;
} }
private function loadDeprecatedDefinition(): void protected function init(): bool
{ {
$path = Path::real(__DIR__ . '/dcdeprecated'); $path = Path::real(__DIR__ . '/dcdeprecated');
if (!$path || !is_dir($path) || !is_readable($path)) { if (!$path || !is_dir($path) || !is_readable($path)) {
return; return false;
} }
$files = Files::scandir($path); $files = Files::scandir($path);
@ -62,6 +63,8 @@ class dcdeprecated extends AbstractTask
$this->deprecated['js'] = array_merge($this->deprecated['js'], $tmp['js']); $this->deprecated['js'] = array_merge($this->deprecated['js'], $tmp['js']);
} }
} }
return true;
} }
public function isConfigured(): bool public function isConfigured(): bool
@ -76,7 +79,7 @@ class dcdeprecated extends AbstractTask
} }
foreach ($this->deprecated[$this->path_extension] as $d) { foreach ($this->deprecated[$this->path_extension] as $d) {
if (preg_match('/' . $d[0] . '/i', $content)) { 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]) ? '' : ' <a href="' . $d['4'] . '">' . __('Help') . '</a> ')); $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]) ? '' : ' <a href="' . $d['4'] . '">' . __('Help') . '</a> '));
} }
} }

View file

@ -27,29 +27,35 @@ use Dotclear\Helper\Html\Form\{
}; };
use Dotclear\Helper\Html\XmlTag; use Dotclear\Helper\Html\XmlTag;
use Dotclear\Helper\Text; use Dotclear\Helper\Text;
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
taskDescriptor
};
use Exception; use Exception;
/** /**
* Improve action module dcstore.xml * Improve action module dcstore.xml
*/ */
class dcstore extends AbstractTask class DcStore extends Task
{ {
/** @var string Settings dcstore zip url pattern */ /** @var string Settings dcstore zip url pattern */
private $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 protected function init(): bool
{ {
$this->setProperties([ $pattern = $this->settings->get('pattern');
'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');
$this->pattern = is_string($pattern) ? $pattern : ''; $this->pattern = is_string($pattern) ? $pattern : '';
return true; return true;
@ -57,13 +63,13 @@ class dcstore extends AbstractTask
public function isConfigured(): bool public function isConfigured(): bool
{ {
return !empty($this->getSetting('pattern')); return !empty($this->settings->get('pattern'));
} }
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save']) && !empty($_POST['dcstore_pattern'])) { 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); $this->redirect($url);
} }
@ -85,7 +91,7 @@ class dcstore extends AbstractTask
public function openModule(): ?bool public function openModule(): ?bool
{ {
$content = $this->generateXML(); $content = $this->generateXML();
if ($this->hasError()) { if (!$this->error->empty()) {
return false; return false;
} }
@ -93,9 +99,9 @@ class dcstore extends AbstractTask
try { try {
Files::putContent($this->module->get('root') . DIRECTORY_SEPARATOR . 'dcstore.xml', $content); 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) { } catch (Exception $e) {
$this->setError(__('Failed to write dcstore.xml file')); $this->error->add(__('Failed to write dcstore.xml file'));
return false; return false;
} }
@ -113,37 +119,37 @@ class dcstore extends AbstractTask
# name # name
if (empty($this->module->get('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'))); $rsp->insertNode(new XmlTag('name', $this->module->get('name')));
# version # version
if (empty($this->module->get('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'))); $rsp->insertNode(new XmlTag('version', $this->module->get('version')));
# author # author
if (empty($this->module->get('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'))); $rsp->insertNode(new XmlTag('author', $this->module->get('author')));
# desc # desc
if (empty($this->module->get('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'))); $rsp->insertNode(new XmlTag('desc', $this->module->get('desc')));
# repository # repository
if (empty($this->module->get('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
$file_pattern = $this->parseFilePattern(); $file_pattern = $this->parseFilePattern();
if (empty($file_pattern)) { 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)); $rsp->insertNode(new XmlTag('file', $file_pattern));
@ -161,14 +167,14 @@ class dcstore extends AbstractTask
} }
} }
if (empty($this->module->get('dc_min'))) { if (empty($this->module->get('dc_min'))) {
$this->setWarning(__('no minimum dotclear version')); $this->warning->add(__('no minimum dotclear version'));
} else { } else {
$rsp->insertNode(new XmlTag('da:dcmin', $this->module->get('dc_min'))); $rsp->insertNode(new XmlTag('da:dcmin', $this->module->get('dc_min')));
} }
# da details # da details
if (empty($this->module->get('details'))) { if (empty($this->module->get('details'))) {
$this->setWarning(__('no details URL')); $this->warning->add(__('no details URL'));
} else { } else {
$rsp->insertNode(new XmlTag('da:details', $this->module->get('details'))); $rsp->insertNode(new XmlTag('da:details', $this->module->get('details')));
} }
@ -183,7 +189,7 @@ class dcstore extends AbstractTask
# da support # da support
if (empty($this->module->get('support'))) { if (empty($this->module->get('support'))) {
$this->setWarning(__('no support URL')); $this->warning->add(__('no support URL'));
} else { } else {
$rsp->insertNode(new XmlTag('da:support', $this->module->get('support'))); $rsp->insertNode(new XmlTag('da:support', $this->module->get('support')));
} }

View file

@ -23,24 +23,30 @@ use Dotclear\Helper\Html\Form\{
Note, Note,
Para Para
}; };
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
/** /**
* Improve action module end of file * 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 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; return true;
} }
@ -52,7 +58,7 @@ class endoffile extends AbstractTask
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings('psr2', !empty($_POST['endoffile_psr2'])); $this->settings->set('psr2', !empty($_POST['endoffile_psr2']));
$this->redirect($url); $this->redirect($url);
} }
@ -60,7 +66,7 @@ class endoffile extends AbstractTask
(new Fieldset())->class('fieldset')->legend((new Legend(__('Contents'))))->fields([ (new Fieldset())->class('fieldset')->legend((new Legend(__('Contents'))))->fields([
// endoffile_psr2 // endoffile_psr2
(new Para())->items([ (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 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'), (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+$/'], ['/(\s*)(\?>\s*)$/', '/\n+$/'],
'', '',
$content $content
) . ($this->getSetting('psr2') ? "\n" : ''); ) . ($this->settings->get('psr2') ? "\n" : '');
if ($content != $clean) { if ($content != $clean) {
$this->setSuccess(__('Replace end of file')); $this->success->add(__('Replace end of file'));
$content = $clean; $content = $clean;
} }

View file

@ -25,12 +25,15 @@ use Dotclear\Helper\Html\Form\{
Note, Note,
Para Para
}; };
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
/** /**
* Improve action module Github shields.io * Improve action module Github shields.io
*/ */
class gitshields extends AbstractTask class GitShields extends Task
{ {
/** @var string Username of git repo */ /** @var string Username of git repo */
private $username = ''; 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)', '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 protected function init(): bool
{ {
$this->setProperties([ $username = $this->settings->get('username');
'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');
$this->username = is_string($username) ? $username : ''; $this->username = is_string($username) ? $username : '';
$this->dotaddict = (bool) $this->getSetting('dotaddict'); $this->dotaddict = (bool) $this->settings->get('dotaddict');
return true; return true;
} }
public function isConfigured(): bool public function isConfigured(): bool
{ {
return !empty($this->getSetting('username')); return !empty($this->settings->get('username'));
} }
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save']) && !empty($_POST['username'])) { if (!empty($_POST['save']) && !empty($_POST['username'])) {
$this->setSettings([ $this->settings->set([
'username' => (string) $_POST['username'], 'username' => (string) $_POST['username'],
'dotaddict' => !empty($_POST['dotaddict']), 'dotaddict' => !empty($_POST['dotaddict']),
]); ]);
@ -158,7 +164,7 @@ class gitshields extends AbstractTask
)); ));
} }
$this->blocs = $blocs; $this->blocs = $blocs;
$this->setSuccess(__('Prepare custom shield info')); $this->success->add(__('Prepare custom shield info'));
} }
private function getDotclearVersion(): string private function getDotclearVersion(): string
@ -192,7 +198,7 @@ class gitshields extends AbstractTask
$count $count
); );
if ($count && $res) { if ($count && $res) {
$this->setSuccess(__('Write new shield bloc')); $this->success->add(__('Write new shield bloc'));
} }
return (string) $res; return (string) $res;
@ -208,7 +214,7 @@ class gitshields extends AbstractTask
$count $count
); );
if ($count && $res) { if ($count && $res) {
$this->setSuccess(__('Delete old shield bloc')); $this->success->add(__('Delete old shield bloc'));
} }
return (string) $res; return (string) $res;

View file

@ -24,13 +24,16 @@ use Dotclear\Helper\Html\Form\{
Para, Para,
Select Select
}; };
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
use Exception; use Exception;
/** /**
* Improve action module license file * Improve action module license file
*/ */
class licensefile extends AbstractTask class LicenseFile extends Task
{ {
/** @var array Possible license filenames */ /** @var array Possible license filenames */
protected static $license_filenames = [ protected static $license_filenames = [
@ -45,16 +48,20 @@ class licensefile extends AbstractTask
/** @var array Action */ /** @var array Action */
private $action_full = []; 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 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 = [ $this->action_version = [
__('no version selected') => '', __('no version selected') => '',
__('gpl2 - GNU General Public License v2') => 'gpl2', __('gpl2 - GNU General Public License v2') => 'gpl2',
@ -82,7 +89,7 @@ class licensefile extends AbstractTask
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->settings->set([
'action_version' => !empty($_POST['action_version']) ? $_POST['action_version'] : '', 'action_version' => !empty($_POST['action_version']) ? $_POST['action_version'] : '',
'action_full' => !empty($_POST['action_full']) ? $_POST['action_full'] : '', 'action_full' => !empty($_POST['action_full']) ? $_POST['action_full'] : '',
]); ]);
@ -94,12 +101,12 @@ class licensefile extends AbstractTask
// action_version // action_version
(new Para())->items([ (new Para())->items([
(new Label(__('License version:'), Label::OUTSIDE_LABEL_BEFORE))->for('action_version'), (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 // action_full
(new Para())->items([ (new Para())->items([
(new Label(__('Action on file:'), Label::OUTSIDE_LABEL_BEFORE))->for('action_full'), (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(); ])->render();
@ -107,12 +114,12 @@ class licensefile extends AbstractTask
public function openModule(): ?bool public function openModule(): ?bool
{ {
if (in_array($this->getSetting('action_full'), ['remove', 'full','overwrite'])) { if (in_array($this->settings->get('action_full'), ['remove', 'full','overwrite'])) {
$this->deleteFullLicense(($this->getSetting('action_full') == 'overwrite')); $this->deleteFullLicense(($this->settings->get('action_full') == 'overwrite'));
} }
if (in_array($this->getSetting('action_full'), ['create', 'overwrite', 'full'])) { if (in_array($this->settings->get('action_full'), ['create', 'overwrite', 'full'])) {
if (empty($this->getSetting('action_version'))) { if (empty($this->settings->get('action_version'))) {
$this->setWarning(__('No full license type selected')); $this->warning->add(__('No full license type selected'));
} else { } else {
$this->writeFullLicense(); $this->writeFullLicense();
} }
@ -124,16 +131,16 @@ class licensefile extends AbstractTask
private function writeFullLicense(): ?bool private function writeFullLicense(): ?bool
{ {
try { 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)) { if (empty($full)) {
$this->setError(__('Failed to load license content')); $this->error->add(__('Failed to load license content'));
return null; return null;
} }
Files::putContent($this->module->get('root') . DIRECTORY_SEPARATOR . 'LICENSE', str_replace("\r\n", "\n", $full)); 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) { } catch (Exception $e) {
$this->setError(__('Failed to write new license file')); $this->error->add(__('Failed to write new license file'));
return null; return null;
} }
@ -148,11 +155,11 @@ class licensefile extends AbstractTask
continue; continue;
} }
if (!Files::isDeletable($this->module->get('root') . DIRECTORY_SEPARATOR . $file)) { 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)) { } 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 { } else {
$this->setSuccess(sprintf(__('Delete old license file "%s"'), $file)); $this->success->add(sprintf(__('Delete old license file "%s"'), $file));
} }
} }

View file

@ -24,45 +24,49 @@ use Dotclear\Helper\Html\Form\{
Para Para
}; };
use Dotclear\Plugin\improve\{ use Dotclear\Plugin\improve\{
AbstractTask, Task,
Core Core,
TaskDescriptor
}; };
/** /**
* Improve action module new line * 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 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; return true;
} }
public function isConfigured(): bool public function isConfigured(): bool
{ {
return !empty($this->getSetting('extensions')); return !empty($this->settings->get('extensions'));
} }
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save']) && !empty($_POST['newline_extensions'])) { if (!empty($_POST['save']) && !empty($_POST['newline_extensions'])) {
$this->setSettings( $this->settings->set(
'extensions', 'extensions',
Core::cleanExtensions($_POST['newline_extensions']) Core::cleanExtensions($_POST['newline_extensions'])
); );
$this->redirect($url); $this->redirect($url);
} }
$ext = $this->getSetting('extensions'); $ext = $this->settings->get('extensions');
if (!is_array($ext)) { if (!is_array($ext)) {
$ext = []; $ext = [];
} }
@ -81,7 +85,7 @@ class newline extends AbstractTask
public function readFile(string &$content): ?bool 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)) { if (!is_array($ext) || !in_array($this->path_extension, $ext)) {
return null; return null;
} }
@ -99,7 +103,7 @@ class newline extends AbstractTask
) )
); );
if ($content != $clean) { if ($content != $clean) {
$this->setSuccess(__('Replace bad new lines')); $this->success->add(__('Replace bad new lines'));
$content = $clean; $content = $clean;
} }

View file

@ -29,15 +29,16 @@ use Dotclear\Helper\Html\Form\{
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\improve\{ use Dotclear\Plugin\improve\{
AbstractTask, Task,
My My,
TaskDescriptor
}; };
use Exception; use Exception;
/** /**
* Improve action module PHP CS Fixer * Improve action module PHP CS Fixer
*/ */
class phpcsfixer extends AbstractTask class PhpCsFixer extends Task
{ {
/** @var array<int,string> Type of runtime errors */ /** @var array<int,string> Type of runtime errors */
protected static $errors = [ protected static $errors = [
@ -59,17 +60,20 @@ class phpcsfixer extends AbstractTask
/** @var string Settings PHP executable path */ /** @var string Settings PHP executable path */
private $phpexe_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 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(); $this->getPhpPath();
if (null !== dcCore::app()->auth?->user_prefs) { if (null !== dcCore::app()->auth?->user_prefs) {
@ -98,7 +102,7 @@ class phpcsfixer extends AbstractTask
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->settings->set([
'phpexe_path' => !empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : '', 'phpexe_path' => !empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : '',
]); ]);
$this->redirect($url); $this->redirect($url);
@ -142,18 +146,18 @@ class phpcsfixer extends AbstractTask
exec($command, $output, $error); exec($command, $output, $error);
if (empty($output)) { if (empty($output)) {
if (isset(self::$errors[$error])) { if (isset(self::$errors[$error])) {
$this->setError(self::$errors[$error]); $this->error->add(self::$errors[$error]);
return false; return false;
} }
throw new Exception('oops'); throw new Exception('oops');
} }
$this->setSuccess(sprintf('<pre>%s</pre>', implode('<br />', $output))); $this->success->add(sprintf('<pre>%s</pre>', implode('<br />', $output)));
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
$this->setError(__('Failed to run php-cs-fixer')); $this->error->add(__('Failed to run php-cs-fixer'));
return false; return false;
} }
@ -164,7 +168,7 @@ class phpcsfixer extends AbstractTask
*/ */
private function getPhpPath(): void private function getPhpPath(): void
{ {
$phpexe_path = $this->getSetting('phpexe_path'); $phpexe_path = $this->settings->get('phpexe_path');
if (!is_string($phpexe_path)) { if (!is_string($phpexe_path)) {
$phpexe_path = ''; $phpexe_path = '';
} }

View file

@ -27,13 +27,16 @@ use Dotclear\Helper\Html\Form\{
Textarea Textarea
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
use Exception; use Exception;
/** /**
* Improve action module php header * Improve action module php header
*/ */
class phpheader extends AbstractTask class PhpHeader extends Task
{ {
/** @var string Exemple of header */ /** @var string Exemple of header */
private static $exemple = <<<EOF private static $exemple = <<<EOF
@ -73,17 +76,20 @@ class phpheader extends AbstractTask
/** @var string Settings bloc content */ /** @var string Settings bloc content */
private $bloc_content = ''; private $bloc_content = '';
protected function getProperties(): TaskDescriptor
{
return new TaskDescriptor(
id: 'phpheader',
name: __('PHP header'),
description: __('Add or remove phpdoc header bloc from php file'),
configurator: true,
types: ['plugin', 'theme'],
priority: 340
);
}
protected function init(): bool protected function init(): bool
{ {
$this->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 = [ $this->action_bloc = [
__('Do nothing') => 0, __('Do nothing') => 0,
__('Add bloc if it does not exist') => 'create', __('Add bloc if it does not exist') => 'create',
@ -92,7 +98,7 @@ class phpheader extends AbstractTask
__('Remove existing bloc header') => 'remove', __('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 : ''; $this->bloc_content = is_string($bloc_content) ? $bloc_content : '';
return true; return true;
@ -100,13 +106,13 @@ class phpheader extends AbstractTask
public function isConfigured(): bool 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 public function configure($url): ?string
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->settings->set([
'bloc_action' => !empty($_POST['bloc_action']) ? $_POST['bloc_action'] : '', 'bloc_action' => !empty($_POST['bloc_action']) ? $_POST['bloc_action'] : '',
'bloc_content' => !empty($_POST['bloc_content']) ? $_POST['bloc_content'] : '', 'bloc_content' => !empty($_POST['bloc_content']) ? $_POST['bloc_content'] : '',
'remove_old' => !empty($_POST['remove_old']), 'remove_old' => !empty($_POST['remove_old']),
@ -120,16 +126,16 @@ class phpheader extends AbstractTask
// bloc_action // bloc_action
(new Para())->items([ (new Para())->items([
(new Label(__('Action:'), Label::OUTSIDE_LABEL_BEFORE))->for('bloc_action'), (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 // remove_old
(new Para())->items([ (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'), (new Label(__('Remove old style bloc header (using #)'), Label::OUTSIDE_LABEL_AFTER))->for('remove_old')->class('classic'),
]), ]),
// exclude_locales // exclude_locales
(new Para())->items([ (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'), (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 public function openModule(): ?bool
{ {
if (is_null(dcCore::app()->auth)) { if (is_null(dcCore::app()->auth)) {
$this->setWarning(__('Auth is not set')); $this->warning->add(__('Auth is not set'));
return null; return null;
} }
@ -164,7 +170,7 @@ class phpheader extends AbstractTask
$bloc = trim($this->bloc_content); $bloc = trim($this->bloc_content);
if (empty($bloc)) { if (empty($bloc)) {
$this->setWarning(__('bloc is empty')); $this->waring->set(__('bloc is empty'));
return null; return null;
} }
@ -194,11 +200,11 @@ class phpheader extends AbstractTask
(string) $bloc (string) $bloc
) )
); );
$this->setSuccess(__('Prepare header info')); $this->success->add(__('Prepare header info'));
return null; return null;
} catch (Exception $e) { } catch (Exception $e) {
$this->setError(__('Failed to parse bloc')); $this->error->add(__('Failed to parse bloc'));
return null; return null;
} }
@ -208,9 +214,9 @@ class phpheader extends AbstractTask
{ {
$skipped = $this->stop_scan; $skipped = $this->stop_scan;
$this->stop_scan = false; $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) { if (!$skipped) {
$this->setSuccess(__('Skip directory')); $this->success->add(__('Skip directory'));
} }
$this->stop_scan = true; $this->stop_scan = true;
} }
@ -220,26 +226,26 @@ class phpheader extends AbstractTask
public function readFile(&$content): ?bool 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; return null;
} }
if (!empty($this->getSetting('remove_old'))) { if (!empty($this->settings->get('remove_old'))) {
$content = $this->deleteOldBloc($content); $content = $this->deleteOldBloc($content);
} }
if (empty($this->getSetting('bloc_action'))) { if (empty($this->settings->get('bloc_action'))) {
return null; return null;
} }
$clean = $this->deleteDocBloc($content); $clean = $this->deleteDocBloc($content);
if ($this->getSetting('bloc_action') == 'remove') { if ($this->settings->get('bloc_action') == 'remove') {
$content = $clean; $content = $clean;
return null; return null;
} }
if ($content != $clean && $this->getSetting('bloc_action') == 'create') { if ($content != $clean && $this->settings->get('bloc_action') == 'create') {
return null; return null;
} }
if ($content == $clean && $this->getSetting('bloc_action') == 'replace') { if ($content == $clean && $this->settings->get('bloc_action') == 'replace') {
return null; return null;
} }
@ -265,7 +271,7 @@ class phpheader extends AbstractTask
); );
if ($count && $res) { if ($count && $res) {
$res = str_replace("\n * \n", "\n *\n", $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; return (string) $res;
@ -287,7 +293,7 @@ class phpheader extends AbstractTask
$count $count
); );
if ($count) { if ($count) {
$this->setSuccess(__('Delete old doc bloc content')); $this->success->add(__('Delete old doc bloc content'));
} }
return (string) $res; return (string) $res;
@ -309,7 +315,7 @@ class phpheader extends AbstractTask
$count $count
); );
if ($count) { if ($count) {
$this->setSuccess(__('Delete old style bloc content')); $this->success->add(__('Delete old style bloc content'));
} }
return (string) $res; return (string) $res;

View file

@ -31,15 +31,16 @@ use Dotclear\Helper\Html\Form\{
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\improve\{ use Dotclear\Plugin\improve\{
AbstractTask, Task,
My My,
TaskDescriptor
}; };
use Exception; use Exception;
/** /**
* Improve action module PHPStan * Improve action module PHPStan
*/ */
class phpstan extends AbstractTask class PhpStan extends Task
{ {
/** @var boolean User pref to use colored synthax */ /** @var boolean User pref to use colored synthax */
protected static $user_ui_colorsyntax = false; protected static $user_ui_colorsyntax = false;
@ -56,23 +57,26 @@ class phpstan extends AbstractTask
/** @var string Settings PHP executable path */ /** @var string Settings PHP executable path */
private $phpexe_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 protected function init(): bool
{ {
$this->setProperties([
'id' => 'phpstan',
'name' => __('PHPStan'),
'description' => __('Analyse php code using PHPStan'),
'priority' => 910,
'configurator' => true,
'types' => ['plugin'],
]);
$this->getPhpPath(); $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; $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 : ''; $this->ignored_vars = is_string($ignored_vars) ? $ignored_vars : '';
if (null !== dcCore::app()->auth?->user_prefs) { if (null !== dcCore::app()->auth?->user_prefs) {
@ -101,7 +105,7 @@ class phpstan extends AbstractTask
public function configure($url): ?string public function configure($url): ?string
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->settings->set([
'phpexe_path' => (!empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : ''), 'phpexe_path' => (!empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : ''),
'run_level' => (int) $_POST['run_level'], 'run_level' => (int) $_POST['run_level'],
'ignored_vars' => (!empty($_POST['ignored_vars']) ? $_POST['ignored_vars'] : ''), 'ignored_vars' => (!empty($_POST['ignored_vars']) ? $_POST['ignored_vars'] : ''),
@ -140,19 +144,19 @@ class phpstan extends AbstractTask
)->class('form-note'), )->class('form-note'),
// ignored_default // ignored_default
(new Para())->items([ (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 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'), (new Note())->text(__('See ignored errors from configuration file below.'))->class('form-note'),
// split_report // split_report
(new Para())->items([ (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 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'), (new Note())->text(__('Enable this can cause timeout.'))->class('form-note'),
// clear_cache // clear_cache
(new Para())->items([ (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 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'), (new Note())->text(__('Enable this can cause timeout.'))->class('form-note'),
@ -174,7 +178,7 @@ class phpstan extends AbstractTask
public function openModule(): bool public function openModule(): bool
{ {
if (!$this->writeConf()) { if (!$this->writeConf()) {
$this->setError(__('Failed to write phpstan configuration')); $this->error->add(__('Failed to write phpstan configuration'));
return false; return false;
} }
@ -184,27 +188,27 @@ class phpstan extends AbstractTask
public function closeFile(): ?bool public function closeFile(): ?bool
{ {
if (!$this->getSetting('split_report') if (!$this->settings->get('split_report')
|| !in_array($this->path_extension, ['php', 'in']) || !in_array($this->path_extension, ['php', 'in'])
) { ) {
return null; 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); return $clear && $this->execFixer($this->path_full);
} }
public function closeModule(): ?bool public function closeModule(): ?bool
{ {
if ($this->getSetting('split_report')) { if ($this->settings->get('split_report')) {
return null; return null;
} }
if ($this->hasError()) { if (!$this->error->empty()) {
return false; return false;
} }
$clear = $this->getSetting('clear_cache') ? $this->execClear() : true; $clear = $this->settings->get('clear_cache') ? $this->execClear() : true;
return $clear && $this->execFixer(); return $clear && $this->execFixer();
} }
@ -245,14 +249,14 @@ class phpstan extends AbstractTask
throw new Exception('oops'); throw new Exception('oops');
} }
if (count($output) < 4) { if (count($output) < 4) {
$this->setSuccess($from_clear ? __('Cache cleared') : __('No errors found')); $this->success->add($from_clear ? __('Cache cleared') : __('No errors found'));
} else { } else {
$this->setWarning(sprintf('<pre>%s</pre>', implode('<br />', $output))); $this->warning->add(sprintf('<pre>%s</pre>', implode('<br />', $output)));
} }
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
$this->setError(__('Failed to run phpstan')); $this->error->add(__('Failed to run phpstan'));
return false; return false;
} }
@ -263,7 +267,7 @@ class phpstan extends AbstractTask
*/ */
private function getPhpPath(): void private function getPhpPath(): void
{ {
$phpexe_path = $this->getSetting('phpexe_path'); $phpexe_path = $this->settings->get('phpexe_path');
if (!is_string($phpexe_path)) { if (!is_string($phpexe_path)) {
$phpexe_path = ''; $phpexe_path = '';
} }
@ -279,7 +283,7 @@ class phpstan extends AbstractTask
private function writeConf(): bool private function writeConf(): bool
{ {
$full = $this->getSetting('ignored_default') ? '' : 'full.'; $full = $this->settings->get('ignored_default') ? '' : 'full.';
$content = str_replace( $content = str_replace(
[ [
'%LEVEL%', '%LEVEL%',

View file

@ -15,12 +15,15 @@ declare(strict_types=1);
namespace Dotclear\Plugin\improve\Task; namespace Dotclear\Plugin\improve\Task;
use Dotclear\Helper\L10n; use Dotclear\Helper\L10n;
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
/** /**
* Improve action module dcstore.xml * Improve action module dcstore.xml
*/ */
class po2php extends AbstractTask class Po2Php extends Task
{ {
/** @var string License bloc */ /** @var string License bloc */
private $license = <<<EOF private $license = <<<EOF
@ -32,16 +35,20 @@ class po2php extends AbstractTask
*/ */
EOF; EOF;
protected function getProperties(): TaskDescriptor
{
return new TaskDescriptor(
id: 'po2php',
name: __('Translation files'),
description: __('Compile existing translation .po files to fresh .lang.php files'),
configurator: false,
types: ['plugin', 'theme'],
priority: 310
);
}
protected function init(): bool protected function init(): bool
{ {
$this->setProperties([
'id' => 'po2php',
'name' => __('Translation files'),
'description' => __('Compile existing translation .po files to fresh .lang.php files'),
'priority' => 310,
'types' => ['plugin', 'theme'],
]);
return true; return true;
} }
@ -57,9 +64,9 @@ class po2php extends AbstractTask
} }
if (L10n::generatePhpFileFromPo(substr($this->path_full, 0, -3), $this->license)) { 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 { } else {
$this->setError(__('Failed to compile .po file')); $this->error->add(__('Failed to compile .po file'));
} }
return true; return true;

View file

@ -14,23 +14,30 @@ declare(strict_types=1);
namespace Dotclear\Plugin\improve\Task; namespace Dotclear\Plugin\improve\Task;
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
/** /**
* Improve action module tab * 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 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; return true;
} }
@ -41,7 +48,7 @@ class tab extends AbstractTask
} }
$clean = preg_replace('/(\t)/', ' ', $content);// . "\n"; $clean = preg_replace('/(\t)/', ' ', $content);// . "\n";
if ($content != $clean) { if ($content != $clean) {
$this->setSuccess(__('Replace tabulation by spaces')); $this->success->add(__('Replace tabulation by spaces'));
$content = $clean; $content = $clean;
} }

View file

@ -29,12 +29,15 @@ use Dotclear\Helper\Html\Form\{
Note, Note,
Para Para
}; };
use Dotclear\Plugin\improve\AbstractTask; use Dotclear\Plugin\improve\{
Task,
TaskDescriptor
};
/** /**
* Improve action module zip * Improve action module zip
*/ */
class zip extends AbstractTask class Zip extends Task
{ {
/** @var array List of excluded file pattern */ /** @var array List of excluded file pattern */
public static $exclude = [ public static $exclude = [
@ -68,26 +71,29 @@ class zip extends AbstractTask
/** @var string Settings Second package filename */ /** @var string Settings Second package filename */
private $secondpack_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 protected function init(): bool
{ {
require_once implode(DIRECTORY_SEPARATOR, [__DIR__, 'zip', 'Zip.php']); require_once implode(DIRECTORY_SEPARATOR, [__DIR__, 'zip', 'Zip.php']);
$this->setProperties([ $pack_excludefiles = $this->settings->get('pack_excludefiles');
'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');
$this->pack_excludefiles = is_string($pack_excludefiles) ? $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 : ''; $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 : ''; $this->secondpack_filename = is_string($secondpack_filename) ? $secondpack_filename : '';
return true; return true;
@ -95,13 +101,13 @@ class zip extends AbstractTask
public function isConfigured(): bool 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 public function configure($url): ?string
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->settings->set([
'pack_repository' => !empty($_POST['pack_repository']) ? $_POST['pack_repository'] : '', 'pack_repository' => !empty($_POST['pack_repository']) ? $_POST['pack_repository'] : '',
'pack_filename' => !empty($_POST['pack_filename']) ? $_POST['pack_filename'] : '', 'pack_filename' => !empty($_POST['pack_filename']) ? $_POST['pack_filename'] : '',
'secondpack_filename' => !empty($_POST['secondpack_filename']) ? $_POST['secondpack_filename'] : '', 'secondpack_filename' => !empty($_POST['secondpack_filename']) ? $_POST['secondpack_filename'] : '',
@ -117,7 +123,7 @@ class zip extends AbstractTask
// pack_repository // pack_repository
(new Para())->items([ (new Para())->items([
(new Label(__('Path to repository:'), Label::OUTSIDE_LABEL_BEFORE))->for('pack_repository'), (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( (new Note())->text(sprintf(
__('Preconization: %s'), __('Preconization: %s'),
@ -129,18 +135,18 @@ class zip extends AbstractTask
// pack_filename // pack_filename
(new Para())->items([ (new Para())->items([
(new Label(__('Name of exported package:'), Label::OUTSIDE_LABEL_BEFORE))->for('pack_filename'), (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'), (new Note())->text(sprintf(__('Preconization: %s'), '%type%-%id%'))->class('form-note'),
// secondpack_filename // secondpack_filename
(new Para())->items([ (new Para())->items([
(new Label(__('Name of second exported package:'), Label::OUTSIDE_LABEL_BEFORE))->for('secondpack_filename'), (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'), (new Note())->text(sprintf(__('Preconization: %s'), '%type%-%id%-%version%'))->class('form-note'),
// pack_overwrite // pack_overwrite
(new Para())->items([ (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'), (new Label(__('Overwrite existing languages'), Label::OUTSIDE_LABEL_AFTER))->for('pack_overwrite')->class('classic'),
]), ]),
]), ]),
@ -148,12 +154,12 @@ class zip extends AbstractTask
// pack_excludefiles // pack_excludefiles
(new Para())->items([ (new Para())->items([
(new Label(__('Extra files to exclude from package:'), Label::OUTSIDE_LABEL_BEFORE))->for('pack_excludefiles'), (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'), (new Note())->text(sprintf(__('By default all these files are always removed from packages : %s'), implode(', ', self::$exclude)))->class('form-note'),
// pack_nocomment // pack_nocomment
(new Para())->items([ (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'), (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, self::$exclude,
explode(',', $this->pack_excludefiles) explode(',', $this->pack_excludefiles)
); );
$this->setSuccess(sprintf(__('Prepare excluded files "%s"'), implode(', ', $exclude))); $this->success->add(sprintf(__('Prepare excluded files "%s"'), implode(', ', $exclude)));
if (!empty($this->getSetting('pack_nocomment'))) { if (!empty($this->settings->get('pack_nocomment'))) {
zip\Zip::$remove_comment = true; 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); $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); $this->zipModule($this->secondpack_filename, $exclude);
} }
@ -198,14 +204,14 @@ class zip extends AbstractTask
foreach ($parts as $i => $part) { foreach ($parts as $i => $part) {
$parts[$i] = Files::tidyFileName($part); $parts[$i] = Files::tidyFileName($part);
} }
$path = $this->getSetting('pack_repository') . '/' . implode('/', $parts) . '.zip'; $path = $this->settings->get('pack_repository') . '/' . implode('/', $parts) . '.zip';
if (file_exists($path) && empty($this->getSetting('pack_overwrite'))) { if (file_exists($path) && empty($this->settings->get('pack_overwrite'))) {
$this->setWarning(__('Destination filename already exists')); $this->warning->add(__('Destination filename already exists'));
return; return;
} }
if (!is_dir(dirname($path)) || !is_writable(dirname($path))) { 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; return;
} }
@ -229,6 +235,6 @@ class zip extends AbstractTask
$zip->write(); $zip->write();
unset($zip); unset($zip);
$this->setSuccess(sprintf(__('Zip module into "%s"'), $path)); $this->success->add(sprintf(__('Zip module into "%s"'), $path));
} }
} }

55
src/TaskDescriptor.php Normal file
View file

@ -0,0 +1,55 @@
<?php
/**
* @brief improve, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\improve;
use dcCore;
/**
* Task description.
*/
class TaskDescriptor
{
/** @var string The priority overload settings prefix */
public const PREFIX = 'priority_';
/** @var int $priority The task priority */
public readonly int $priority;
/**
* Constructor sets all properties
*
* @param string $id The task ID
* @param string $name The task translated name
* @param string $description The task short descripton
* @param bool $configurator The task has configuration form
* @param array $types The task supported modules types
* @param int $priority The task default priority
*/
public function __construct(
public readonly string $id,
public readonly string $name,
public readonly string $description,
public readonly array $types,
public readonly bool $configurator,
int $priority = 500
) {
// Overload task priority from settings
if (!is_null(dcCore::app()->blog) && 1 < ($p = (int) dcCore::app()->blog?->settings->get(My::id())->get(self::PREFIX . $this->id))) {
$this->priority = $p;
} else {
$this->priority = abs($priority);
}
}
}

79
src/TaskMessages.php Normal file
View file

@ -0,0 +1,79 @@
<?php
/**
* @brief improve, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\improve;
/**
* Task messages group.
*/
class TaskMessages
{
/** @ var array<string,array> $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<string,array> The messages stack
*/
public function dump(): array
{
return $this->stack;
}
}

90
src/TaskSettings.php Normal file
View file

@ -0,0 +1,90 @@
<?php
/**
* @brief improve, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\improve;
use dcCore;
/**
* Task settings management.
*/
class TaskSettings
{
/** @var string The setting prefix */
public const PREFIX = 'settings_';
/** @ var array<string,mixed> $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();
}
}
}

View file

@ -15,14 +15,13 @@ declare(strict_types=1);
namespace Dotclear\Plugin\improve; namespace Dotclear\Plugin\improve;
use dcCore; use dcCore;
use Exception;
/** /**
* The Tasks stack. * The Tasks stack.
*/ */
class Tasks class Tasks
{ {
/** @var array<string,AbstractTask> $stack The tasks stack */ /** @var array<string,Task> $stack The tasks stack */
private array $stack = []; private array $stack = [];
/** /**
@ -33,21 +32,21 @@ class Tasks
# --BEHAVIOR-- improveTaskAdd: Tasks # --BEHAVIOR-- improveTaskAdd: Tasks
dcCore::app()->callBehavior('improveTaskAdd', $this); dcCore::app()->callBehavior('improveTaskAdd', $this);
uasort($this->stack, fn ($a, $b) => $a->name() <=> $b->name()); uasort($this->stack, fn ($a, $b) => $a->properties->name <=> $b->properties->name);
uasort($this->stack, fn ($a, $b) => $a->priority() <=> $b->priority()); uasort($this->stack, fn ($a, $b) => $a->properties->priority <=> $b->properties->priority);
} }
/** /**
* Add an task. * Add an task.
* *
* @param AbstractTask $task The task instance * @param Task $task The task instance
* *
* @return Tasks Self instance * @return Tasks Self instance
*/ */
public function add(AbstractTask $task): Tasks public function add(Task $task): Tasks
{ {
if (!isset($this->stack[$task->id()])) { if (!isset($this->stack[$task->properties->id])) {
$this->stack[$task->id()] = $task; $this->stack[$task->properties->id] = $task;
} }
return $this; return $this;
@ -56,7 +55,7 @@ class Tasks
/** /**
* Get all tasks. * Get all tasks.
* *
* @return array<string,AbstractTask> The tasks stack * @return array<string,Task> The tasks stack
*/ */
public function dump(): array public function dump(): array
{ {
@ -68,9 +67,9 @@ class Tasks
* *
* @param string $id The task id * @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; return $this->stack[$id] ?? null;
} }