update structure to php namespace (my first step in!)

This commit is contained in:
Jean-Christian Denis 2021-11-13 22:57:51 +01:00
parent c3102b3636
commit 4eba45e38f
Signed by: JcDenis
GPG key ID: 1B5B8C5B90B6C951
34 changed files with 1342 additions and 832 deletions

View file

@ -4,6 +4,9 @@ dev
- [ ] add module to check directory structure - [ ] add module to check directory structure
- [ ] add module to create full README file - [ ] add module to create full README file
- [ ] write documentation of php class - [ ] write documentation of php class
- update structure to php namespace
- update php cs fixer rules to dc2.21 / php7.4
- update phpstan to 1.1.2
0.7.1 - 2021.11.08 0.7.1 - 2021.11.08
- Fix php < 8 _ thanks @Gvx- _ closes #5 - Fix php < 8 _ thanks @Gvx- _ closes #5

View file

@ -10,23 +10,52 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
namespace plugins\improve;
if (!defined('DC_CONTEXT_ADMIN')) {
return;
}
/* dotclear */
use dcCore;
use dcPage;
use dcFavorites;
/* clearbricks */
use files;
/* php */
use ArrayObject;
/**
* Improve admin class
*
* Add menu and dashboard icons, load Improve action modules.
*/
class admin
{
public static function process(dcCore $core, ArrayObject $_menu): void
{
self::addSettingsNamespace($core);
self::addAdminBehaviors($core);
self::addAdminMenu($core, $_menu);
self::addImproveActions($core);
}
private static function addSettingsNamespace(dcCore $core): void
{
$core->blog->settings->addNamespace('improve'); $core->blog->settings->addNamespace('improve');
}
$core->addBehavior('adminDashboardFavorites', ['ImproveBehaviors', 'adminDashboardFavorites']); private static function addAdminBehaviors(dcCore $core): void
{
$core->addBehavior('improveAddAction', ['ImproveActionDcdeprecated', 'create']); $core->addBehavior('adminDashboardFavorites', __NAMESPACE__ . '\admin::adminDashboardFavorites');
$core->addBehavior('improveAddAction', ['ImproveActionDcstore', 'create']); }
$core->addBehavior('improveAddAction', ['ImproveActionEndoffile', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionGitshields', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionLicensefile', 'create']);
//$core->addBehavior('improveAddAction', ['ImproveActionLicense', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionNewline', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionPhpcsfixer', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionPhpheader', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionPhpstan', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionTab', 'create']);
$core->addBehavior('improveAddAction', ['ImproveActionZip', 'create']);
private static function addAdminMenu(dcCore $core, ArrayObject $_menu): void
{
$_menu['Plugins']->addItem( $_menu['Plugins']->addItem(
__('improve'), __('improve'),
$core->adminurl->get('admin.plugin.improve'), $core->adminurl->get('admin.plugin.improve'),
@ -34,9 +63,20 @@ $_menu['Plugins']->addItem(
preg_match('/' . preg_quote($core->adminurl->get('admin.plugin.improve')) . '(&.*)?$/', $_SERVER['REQUEST_URI']), preg_match('/' . preg_quote($core->adminurl->get('admin.plugin.improve')) . '(&.*)?$/', $_SERVER['REQUEST_URI']),
$core->auth->isSuperAdmin() $core->auth->isSuperAdmin()
); );
}
class ImproveBehaviors private static function addImproveActions(dcCore $core): void
{ {
global $__autoload;
foreach (files::scandir(prepend::getActionsDir()) as $file) {
if (is_file(prepend::getActionsDir() . $file) && '.php' == substr($file, -4)) {
$__autoload[prepend::getActionsNS() . substr($file, 0, -4)] = prepend::getActionsDir() . $file;
$core->addBehavior('improveAddAction', [prepend::getActionsNS() . substr($file, 0, -4), 'create']); /* @phpstan-ignore-line */
}
}
}
public static function adminDashboardFavorites(dcCore $core, dcFavorites $favs): void public static function adminDashboardFavorites(dcCore $core, dcFavorites $favs): void
{ {
$favs->register( $favs->register(
@ -46,8 +86,11 @@ class ImproveBehaviors
'url' => $core->adminurl->get('admin.plugin.improve'), 'url' => $core->adminurl->get('admin.plugin.improve'),
'small-icon' => dcPage::getPF('improve/icon.png'), 'small-icon' => dcPage::getPF('improve/icon.png'),
'large-icon' => dcPage::getPF('improve/icon-b.png'), 'large-icon' => dcPage::getPF('improve/icon-b.png'),
'permissions' => null 'permissions' => null,
] ]
); );
} }
} }
/* process */
admin::process($core, $_menu);

View file

@ -10,54 +10,105 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
namespace plugins\improve;
if (!defined('DC_CONTEXT_ADMIN')) { if (!defined('DC_CONTEXT_ADMIN')) {
return; return;
} }
# Check user perms /* dotclear */
use dcCore;
use adminModulesList;
use dcPage;
/* clearbricks */
use form;
/* php */
use Exception;
/**
* Admin Improve configuration class
*
* Set preference for this plugin.
*/
class config
{
/** @var dcCore $core dcCore instance */
private $core = null;
/** @var adminModulesList $list adminModulesList instance */
private $list = null;
/** @var improve $improve improve core instance */
private $improve = null;
public function __construct(dcCore $core, adminModulesList $list)
{
dcPage::checkSuper(); dcPage::checkSuper();
$improve = new Improve($core); $this->core = $core;
$this->list = $list;
$this->improve = new improve($core);
$combo_actions = []; $this->saveConfig();
foreach ($improve->modules() as $action) { $this->displayConfig();
$combo_actions[$action->name()] = $action->id(); }
}
$disabled = $improve->disabled(); private function getModules(): array
if (!empty($disabled)) { {
$combo_actions = array_merge($combo_actions, array_flip($disabled)); $modules = [];
foreach ($this->improve->modules() as $action) {
$modules[$action->name()] = $action->id();
}
$modules = array_merge($modules, array_flip($this->improve->disabled()));
return $modules;
}
private function saveConfig(): void
{
if (empty($_POST['save'])) {
return;
} }
if (!empty($_POST['save'])) {
try { try {
$pdisabled = ''; $pdisabled = '';
if (!empty($_POST['disabled'])) { if (!empty($_POST['disabled']) && is_array($_POST['disabled'])) {
$pdisabled = implode(';', $_POST['disabled']); $pdisabled = implode(';', $_POST['disabled']);
} }
$core->blog->settings->improve->put('disabled', $pdisabled); $this->core->blog->settings->improve->put('disabled', $pdisabled);
$core->blog->settings->improve->put('nodetails', !empty($_POST['nodetails'])); $this->core->blog->settings->improve->put('nodetails', !empty($_POST['nodetails']));
dcPage::addSuccessNotice(__('Configuration successfully updated')); dcPage::addSuccessNotice(__('Configuration successfully updated'));
$core->adminurl->redirect( $this->core->adminurl->redirect(
'admin.plugins', 'admin.plugins',
['module' => 'improve', 'conf' => 1, 'chk' => 1, 'redir' => $list->getRedir()] ['module' => 'improve', 'conf' => 1, 'chk' => 1, 'redir' => $this->list->getRedir()]
); );
} catch (Exception $e) { } catch (Exception $e) {
$core->error->add($e->getMessage()); $this->core->error->add($e->getMessage());
} }
} }
private function displayConfig(): void
{
echo '<div class="fieldset"><h4>' . __('List of disabled actions:') . '</h4>'; echo '<div class="fieldset"><h4>' . __('List of disabled actions:') . '</h4>';
foreach ($combo_actions as $name => $id) { foreach ($this->getModules() as $name => $id) {
echo echo
'<p><label class="classic" title="' . $id . '">' . '<p><label class="classic" title="' . $id . '">' .
form::checkbox(['disabled[]'], $id, ['checked' => isset($disabled[$id])]) . form::checkbox(['disabled[]'], $id, ['checked' => array_key_exists($id, $this->improve->disabled())]) .
__($name) . '</label></p>'; __($name) . '</label></p>';
} }
echo echo
'</div><div class="fieldset"><h4>' . __('Options') . '</h4>' . '</div><div class="fieldset"><h4>' . __('Options') . '</h4>' .
'<p><label class="classic">' . '<p><label class="classic">' .
form::checkbox('nodetails', '1', ['checked' => $core->blog->settings->improve->nodetails]) . form::checkbox('nodetails', '1', ['checked' => $this->core->blog->settings->improve->nodetails]) .
__('Hide details of rendered actions') . '</label></p>' . __('Hide details of rendered actions') . '</label></p>' .
'</div>'; '</div>';
}
}
/* process */
new config($core, $list);

View file

@ -25,6 +25,6 @@ $this->registerModule(
'type' => 'plugin', 'type' => 'plugin',
'support' => 'https://github.com/JcDenis/improve', 'support' => 'https://github.com/JcDenis/improve',
'details' => 'https://github.com/JcDenis/improve', 'details' => 'https://github.com/JcDenis/improve',
'repository' => 'https://raw.githubusercontent.com/JcDenis/improve/master/dcstore.xml' 'repository' => 'https://raw.githubusercontent.com/JcDenis/improve/master/dcstore.xml',
] ]
); );

View file

@ -10,50 +10,86 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
namespace plugins\improve;
if (!defined('DC_CONTEXT_ADMIN')) { if (!defined('DC_CONTEXT_ADMIN')) {
return null; return;
} }
# -- Module specs -- /* dotclear */
use dcCore;
use dcUtils;
$dc_min = '2.19'; /* php */
$mod_id = 'improve'; use Exception;
$mod_conf = [
[ /**
* Improve install class
*
* Set default settings and version
* and manage changes on updates.
*/
class install
{
/** @var string Dotclear minimal version */
private static $dotclear_version = '2.19';
/** @var array Improve default settings */
private static $default_settings = [[
'disabled', 'disabled',
'List of hidden action modules', 'List of hidden action modules',
'tab;newline;endoffile', 'tab;newline;endoffile',
'string' 'string',
] ]];
];
# -- Nothing to change below -- public static function process(dcCore $core): ?bool
{
try { if (!self::checkModuleVersion($core)) {
# Check module version
if (version_compare(
$core->getVersion($mod_id),
$core->plugins->moduleInfo($mod_id, 'version'),
'>='
)) {
return null; return null;
} }
if (!self::checkDotclearVersion($core)) {
# Check Dotclear version
if (!method_exists('dcUtils', 'versionsCompare')
|| dcUtils::versionsCompare(DC_VERSION, $dc_min, '<', false)) {
throw new Exception(sprintf( throw new Exception(sprintf(
'%s requires Dotclear %s', '%s requires Dotclear %s',
$mod_id, 'improve',
$dc_min self::$dotclear_version
)); ));
} }
# Set module settings $core->blog->settings->addNamespace('improve');
$core->blog->settings->addNamespace($mod_id); self::update_0_8_0($core);
foreach ($mod_conf as $v) { self::putSettings($core);
$core->blog->settings->{$mod_id}->put( self::setVersion($core);
return true;
}
private static function getInstalledVersion(dcCore $core): string
{
$version = $core->getVersion('improve');
return is_string($version) ? $version : '0';
}
private static function checkModuleVersion(dcCore $core): bool
{
return version_compare(
self::getInstalledVersion($core),
$core->plugins->moduleInfo('improve', 'version'),
'<'
);
}
private static function checkDotclearVersion(dcCore $core): bool
{
return method_exists('dcUtils', 'versionsCompare')
&& dcUtils::versionsCompare(DC_VERSION, self::$dotclear_version, '>=', false);
}
private static function putSettings(dcCore $core): void
{
foreach (self::$default_settings as $v) {
$core->blog->settings->improve->put(
$v[0], $v[0],
$v[2], $v[2],
$v[3], $v[3],
@ -62,14 +98,30 @@ try {
true true
); );
} }
}
# Set module version private static function setVersion(dcCore $core): void
$core->setVersion( {
$mod_id, $core->setVersion('improve', $core->plugins->moduleInfo('improve', 'version'));
$core->plugins->moduleInfo($mod_id, 'version') }
);
return true; /** Update improve < 0.8 : action modules settings name */
private static function update_0_8_0(dcCore $core): void
{
if (version_compare(self::getInstalledVersion($core), '0.8', '<')) {
foreach ($core->blog->settings->improve->dumpGlobalSettings() as $id => $values) {
$newId = str_replace('ImproveAction', '', $id);
if ($id != $newId) {
$core->blog->settings->improve->rename($id, strtolower($newId));
}
}
}
}
}
/* process */
try {
return install::process($core);
} catch (Exception $e) { } catch (Exception $e) {
$core->error->add($e->getMessage()); $core->error->add($e->getMessage());

View file

@ -10,27 +10,38 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
namespace plugins\improve;
if (!defined('DC_RC_PATH') || !defined('DC_CONTEXT_ADMIN')) {
return; return;
} }
$improve_libs = [ /**
'Improve' => 'class.improve.php', * Improve prepend class
'ImproveAction' => 'class.improve.action.php', *
* Manage autoload and some action module helpers.
'ImproveActionDcdeprecated' => 'lib.improve.action.dcdeprecated.php', */
'ImproveActionDcstore' => 'lib.improve.action.dcstore.php', class prepend
'ImproveActionEndoffile' => 'lib.improve.action.php', {
'ImproveActionGitshields' => 'lib.improve.action.gitshields.php', public static function process(array &$__autoload): void
'ImproveActionLicensefile' => 'lib.improve.action.licensefile.php', {
'ImproveActionNewline' => 'lib.improve.action.php', foreach (['improve', 'action', 'module'] as $class) {
'ImproveActionPhpcsfixer' => 'lib.improve.action.phpcsfixer.php', $__autoload['plugins\\improve\\' . $class] = dirname(__FILE__) . '/inc/core/' . $class . '.php';
'ImproveActionPhpheader' => 'lib.improve.action.phpheader.php',
'ImproveActionPhpstan' => 'lib.improve.action.phpstan.php',
'ImproveActionTab' => 'lib.improve.action.php',
'ImproveActionZip' => 'lib.improve.action.zip.php',
'ImproveZipFileZip' => 'lib.improve.action.zip.php'
];
foreach ($improve_libs as $class => $file) {
$__autoload[$class] = dirname(__FILE__) . '/inc/' . $file;
} }
}
public static function getActionsDir(): string
{
return dirname(__FILE__) . '/inc/module/';
}
public static function getActionsNS(): string
{
return 'plugins\\improve\\module\\';
}
}
/* process */
prepend::process($__autoload);

View file

@ -10,23 +10,31 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
namespace plugins\improve;
/* dotclear */
use dcCore;
use dcPage;
/* clearbricks */
use http;
/* php */
use arrayObject;
/** /**
* @brief Plugin improve action class * Improve action class helper
* *
* Action class must extends class ImproveAction. * Action class must extends class action.
* If your class signature is myActionClass extends ImproveAction, * If your class signature is myActionClass extends plugins\improve\class\action,
* do $core->addBehavior('ImproveAddAction'), ['myClass', 'create']); * do $core->addBehavior('ImproveAddAction'), ['myClass', 'create']);
* yoru action class is automatically created, * your action class is automatically created,
* then function init() of your class wil be called. * then function init() of your class wil be called.
* One class must manage only one action. * One class must manage only one action.
*
* @package Plugin_improve
* @subpackage Action
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0-only
*/ */
abstract class ImproveAction abstract class action
{ {
/** @var dcCore dcCore instance */ /** @var dcCore dcCore instance */
protected $core; protected $core;
@ -74,16 +82,19 @@ abstract class ImproveAction
private $types = ['plugin']; private $types = ['plugin'];
/** /**
* ImproveAction constructor inits properpties and settings of a child class. * Action constructor inits properties and settings of a child class.
* *
* @param dcCore $core dcCore instance * @param dcCore $core dcCore instance
*/ */
final public function __construct(dcCore $core) final public function __construct(dcCore $core)
{ {
$this->core = $core; $this->core = $core;
$this->class_name = get_called_class(); $this->class_name = str_replace(prepend::getActionsNS(), '', get_called_class());
$settings = @unserialize($core->blog->settings->improve->get('settings_' . $this->class_name)); $settings = $core->blog->settings->improve->get('settings_' . $this->class_name);
if (null != $settings) {
$settings = unserialize($settings);
}
$this->settings = is_array($settings) ? $settings : []; $this->settings = is_array($settings) ? $settings : [];
$this->init(); $this->init();

View file

@ -10,29 +10,44 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
namespace plugins\improve;
/* dotclear */
use dcCore;
/* clearbricks */
use path;
use files;
/* php */
use arrayObject;
use Exception;
/** /**
* This class manage all actions sub-class * Improve main class
*/ */
class Improve class improve
{ {
/** @var array Allowed file extensions to open */ /** @var array Allowed file extensions to open */
public static $readfile_extensions = [ private static $readfile_extensions = [
'php', 'xml', 'js', 'css', 'csv', 'html', 'htm', 'txt', 'md' 'php', 'xml', 'js', 'css', 'csv', 'html', 'htm', 'txt', 'md',
]; ];
/** @var dcCore dcCore instance */ /** @var dcCore $core dcCore instance */
private $core; private $core;
/** @var ImproveAction[] Loaded actions modules */ /** @var array<action> $actions Loaded actions modules */
private $actions = []; private $actions = [];
/** @var array<string> Disabled actions modules */ /** @var array<string> $disabled Disabled actions modules */
private $disabled = []; private $disabled = [];
/** @var array<string, array> Logs by actions modules */ /** @var array<string, array> $logs Logs by actions modules */
private $logs = []; private $logs = [];
/** @var array<string, boolean> Has log of given type */ /** @var array<string, boolean> $has_log Has log of given type */
private $has_log = ['success' => false, 'warning' => false, 'error' => false]; private $has_log = ['success' => false, 'warning' => false, 'error' => false];
/** /**
@ -42,7 +57,6 @@ class Improve
*/ */
public function __construct(dcCore $core) public function __construct(dcCore $core)
{ {
$core->blog->settings->addNamespace('improve');
$this->core = &$core; $this->core = &$core;
$disabled = explode(';', (string) $core->blog->settings->improve->disabled); $disabled = explode(';', (string) $core->blog->settings->improve->disabled);
$list = new arrayObject(); $list = new arrayObject();
@ -51,7 +65,7 @@ class Improve
$this->core->callBehavior('improveAddAction', $list, $this->core); $this->core->callBehavior('improveAddAction', $list, $this->core);
foreach ($list as $action) { foreach ($list as $action) {
if (is_a($action, 'ImproveAction') && !isset($this->actions[$action->id()])) { if ($action instanceof action && !isset($this->actions[$action->id()])) {
if (in_array($action->id(), $disabled)) { if (in_array($action->id(), $disabled)) {
$this->disabled[$action->id()] = $action->name(); $this->disabled[$action->id()] = $action->name();
} else { } else {
@ -75,10 +89,10 @@ class Improve
return array_key_exists($type, $this->has_log) && $this->has_log[$type]; return array_key_exists($type, $this->has_log) && $this->has_log[$type];
} }
public function writeLogs(): string public function writeLogs(): int
{ {
if (empty($this->logs)) { if (empty($this->logs)) {
return ''; return 0;
} }
$cur = $this->core->con->openCursor($this->core->prefix . 'log'); $cur = $this->core->con->openCursor($this->core->prefix . 'log');
$cur->log_msg = serialize($this->logs); $cur->log_msg = serialize($this->logs);
@ -140,9 +154,9 @@ class Improve
* *
* @param string $id Module id * @param string $id Module id
* *
* @return ImproveAction ImproveAction instance * @return action action instance
*/ */
public function module(string $id): ?ImproveAction public function module(string $id): ?action
{ {
if (empty($id)) { if (empty($id)) {
return null; return null;
@ -154,7 +168,7 @@ class Improve
/** /**
* Get all loaded action modules * Get all loaded action modules
* *
* @return ImproveAction[] ImproveAction instance * @return action[] action instance
*/ */
public function modules(): array public function modules(): array
{ {
@ -174,7 +188,7 @@ class Improve
public function fixModule(string $type, string $id, array $properties, array $actions): float public function fixModule(string $type, string $id, array $properties, array $actions): float
{ {
$time_start = microtime(true); $time_start = microtime(true);
$module = ImproveDefinition::clean($type, $id, $properties); $module = module::clean($type, $id, $properties);
$workers = []; $workers = [];
foreach ($actions as $action) { foreach ($actions as $action) {
@ -324,12 +338,12 @@ class Improve
/** /**
* Sort modules by priority then name * Sort modules by priority then name
* *
* @param ImproveAction $a ImproveAction instance * @param action $a ImproveAction instance
* @param ImproveAction $b ImproveAction instance * @param action $b ImproveAction instance
* *
* @return integer Is higher * @return integer Is higher
*/ */
private function sortModules(ImproveAction $a, ImproveAction $b): int private function sortModules(action $a, action $b): int
{ {
if ($a->priority() == $b->priority()) { if ($a->priority() == $b->priority()) {
return strcasecmp($a->name(), $b->name()); return strcasecmp($a->name(), $b->name());
@ -338,176 +352,3 @@ class Improve
return $a->priority() < $b->priority() ? -1 : 1; return $a->priority() < $b->priority() ? -1 : 1;
} }
} }
class ImproveDefinition
{
/** @var array Current module properties */
private $properties = [];
/**
* Constructor
*
* @param string $type Module type, plugin or theme
* @param string $id Module id
* @param array $properties Module properties
*/
public function __construct(string $type, string $id, array $properties = [])
{
$this->loadDefine($id, $properties['root']);
$this->properties = array_merge($this->properties, self::sanitizeModule($type, $id, $properties));
}
/**
* Get module properties
*
* @return array The properties
*/
public function get(): array
{
return $this->properties;
}
/**
* Get clean properties of registered module
*
* @param string $type Module type, plugin or theme
* @param string $id Module id
* @param array $properties Module properties
*
* @return array Module properties
*/
public static function clean(string $type, string $id, array $properties): array
{
$p = new self($type, $id, $properties);
return $p->get();
}
/**
* Replicate dcModule::loadDefine
*
* @param string $id Module id
* @param string $root Module path
*
* @return boolean Success
*/
private function loadDefine(string $id, string $root): bool
{
if (file_exists($root . '/_define.php')) {
ob_start();
require $root . '/_define.php';
ob_end_clean();
}
return true;
}
/**
* Replicate dcModule::registerModule
*
* @param string $name The module name
* @param string $desc The module description
* @param string $author The module author
* @param string $version The module version
* @param string|array $properties The properties
*
* @return boolean Success
*/
private function registerModule(string $name, string $desc, string $author, string $version, $properties = []): bool
{
if (!is_array($properties)) {
$args = func_get_args();
$properties = [];
if (isset($args[4])) {
$properties['permissions'] = $args[4];
}
if (isset($args[5])) {
$properties['priority'] = (int) $args[5];
}
}
$this->properties = array_merge(
[
'permissions' => null,
'priority' => 1000,
'standalone_config' => false,
'type' => null,
'enabled' => true,
'requires' => [],
'settings' => [],
'repository' => ''
],
$properties
);
return true;
}
/**
* Replicate adminModulesList::sanitizeModule
*
* @param string $type Module type
* @param string $id Module id
* @param array $properties Module properties
*
* @return array Sanitized module properties
*/
public static function sanitizeModule(string $type, string $id, array $properties): array
{
$label = empty($properties['label']) ? $id : $properties['label'];
$name = __(empty($properties['name']) ? $label : $properties['name']);
$oname = empty($properties['name']) ? $label : $properties['name'];
return array_merge(
# Default values
[
'desc' => '',
'author' => '',
'version' => 0,
'current_version' => 0,
'root' => '',
'root_writable' => false,
'permissions' => null,
'parent' => null,
'priority' => 1000,
'standalone_config' => false,
'support' => '',
'section' => '',
'tags' => '',
'details' => '',
'sshot' => '',
'score' => 0,
'type' => null,
'requires' => [],
'settings' => [],
'repository' => '',
'dc_min' => 0
],
# Module's values
$properties,
# Clean up values
[
'id' => $id,
'sid' => self::sanitizeString($id),
'type' => $type,
'label' => $label,
'name' => $name,
'oname' => $oname,
'sname' => self::sanitizeString($name),
'sroot' => path::real($properties['root'])
]
);
}
/**
* Replicate adminModulesList::sanitizeString
*
* @param string $str String to sanitize
*
* @return string Sanitized string
*/
public static function sanitizeString(string $str): string
{
return (string) preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str));
}
}

198
inc/core/module.php Normal file
View file

@ -0,0 +1,198 @@
<?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 plugins\improve;
/* clearbricks */
use path;
/**
* Improve module helper
*
* Help to load module configuration file (_define.php)
* and gather information about it.
*/
class module
{
/** @var array Current module properties */
private $properties = [];
/**
* Constructor
*
* @param string $type Module type, plugin or theme
* @param string $id Module id
* @param array $properties Module properties
*/
public function __construct(string $type, string $id, array $properties = [])
{
$this->loadDefine($id, $properties['root']);
$this->properties = array_merge($this->properties, self::sanitizeModule($type, $id, $properties));
}
/**
* Get module properties
*
* @return array The properties
*/
public function get(): array
{
return $this->properties;
}
/**
* Get clean properties of registered module
*
* @param string $type Module type, plugin or theme
* @param string $id Module id
* @param array $properties Module properties
*
* @return array Module properties
*/
public static function clean(string $type, string $id, array $properties): array
{
$module = new self($type, $id, $properties);
return $module->get();
}
/**
* Replicate dcModule::loadDefine
*
* @param string $id Module id
* @param string $root Module path
*
* @return boolean Success
*/
private function loadDefine(string $id, string $root): bool
{
if (file_exists($root . '/_define.php')) {
ob_start();
require $root . '/_define.php';
ob_end_clean();
}
return true;
}
/**
* Replicate dcModule::registerModule
*
* @param string $name The module name
* @param string $desc The module description
* @param string $author The module author
* @param string $version The module version
* @param string|array $properties The properties
*
* @return boolean Success
* @phpstan-ignore-next-line
*/
private function registerModule(string $name, string $desc, string $author, string $version, $properties = []): bool
{
if (!is_array($properties)) {
$args = func_get_args();
$properties = [];
if (isset($args[4])) {
$properties['permissions'] = $args[4];
}
if (isset($args[5])) {
$properties['priority'] = (int) $args[5];
}
}
$this->properties = array_merge(
[
'permissions' => null,
'priority' => 1000,
'standalone_config' => false,
'type' => null,
'enabled' => true,
'requires' => [],
'settings' => [],
'repository' => '',
],
$properties
);
return true;
}
/**
* Replicate adminModulesList::sanitizeModule
*
* @param string $type Module type
* @param string $id Module id
* @param array $properties Module properties
*
* @return array Sanitized module properties
*/
public static function sanitizeModule(string $type, string $id, array $properties): array
{
$label = empty($properties['label']) ? $id : $properties['label'];
$name = __(empty($properties['name']) ? $label : $properties['name']);
$oname = empty($properties['name']) ? $label : $properties['name'];
return array_merge(
# Default values
[
'desc' => '',
'author' => '',
'version' => 0,
'current_version' => 0,
'root' => '',
'root_writable' => false,
'permissions' => null,
'parent' => null,
'priority' => 1000,
'standalone_config' => false,
'support' => '',
'section' => '',
'tags' => '',
'details' => '',
'sshot' => '',
'score' => 0,
'type' => null,
'requires' => [],
'settings' => [],
'repository' => '',
'dc_min' => 0,
],
# Module's values
$properties,
# Clean up values
[
'id' => $id,
'sid' => self::sanitizeString($id),
'type' => $type,
'label' => $label,
'name' => $name,
'oname' => $oname,
'sname' => self::sanitizeString($name),
'sroot' => path::real($properties['root']),
]
);
}
/**
* Replicate adminModulesList::sanitizeString
*
* @param string $str String to sanitize
*
* @return string Sanitized string
*/
public static function sanitizeString(string $str): string
{
return (string) preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str));
}
}

View file

@ -1,181 +0,0 @@
<?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
*/
class ImproveActionTab extends ImproveAction
{
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;
}
public function readFile(&$content): ?bool
{
if (!in_array($this->path_extension, ['php', 'md'])) {
return null;
}
$clean = preg_replace('/(\t)/', ' ', $content);// . "\n";
if ($content != $clean) {
$this->setSuccess(__('Replace tabulation by spaces'));
$content = $clean;
}
return true;
}
public function isConfigured(): bool
{
return true;
}
}
class ImproveActionNewline extends ImproveAction
{
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']
]);
/*
$ext = @unserialize($this->core->blog->settings->improve->newline_extensions);
$ext = Improve::cleanExtensions($ext);
if (!empty($ext)) {
$this->extensions = $ext;
}
*/
return true;
}
public function isConfigured(): bool
{
return !empty($this->getSetting('extensions'));
}
public function configure($url): ?string
{
if (!empty($_POST['save']) && !empty($_POST['newline_extensions'])) {
$this->setSettings(
'extensions',
Improve::cleanExtensions($_POST['newline_extensions'])
);
$this->redirect($url);
}
$ext = $this->getSetting('extensions');
if (!is_array($ext)) {
$ext = [];
}
return
'<p><label class="classic" for="newline_extensions">' .
__('List of files extension to work on:') . '<br />' .
form::field('newline_extensions', 65, 255, implode(',', $ext)) .
'</label></p><p class="form-note">' .
__('Use comma separated list of extensions without dot, recommand "php,js,xml,txt,md".') .
'</p>';
}
public function readFile(string &$content): ?bool
{
$ext = $this->getSetting('extensions');
if (!is_array($ext) || !in_array($this->path_extension, $ext)) {
return null;
}
$clean = (string) preg_replace(
'/(\n\s+\n)/',
"\n\n",
(string) preg_replace(
'/(\n\n+)/',
"\n\n",
(string) str_replace(
["\r\n", "\r"],
"\n",
$content
)
)
);
if ($content != $clean) {
$this->setSuccess(__('Replace bad new lines'));
$content = $clean;
}
return true;
}
}
class ImproveActionEndoffile extends ImproveAction
{
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;
}
public function isConfigured(): bool
{
return true;
}
public function configure($url): ?string
{
if (!empty($_POST['save'])) {
$this->setSettings('psr2', !empty($_POST['endoffile_psr2']));
$this->redirect($url);
}
return
'<p><label class="classic" for="endoffile_psr2">' .
form::checkbox('endoffile_psr2', 255, $this->getSetting('psr2')) .
__('Add a blank line to the end of file') .
'</label></p><p class="form-note">' .
__('PSR2 must have a blank line, whereas PSR12 must not.') .
'</p>';
}
public function readFile(&$content): ?bool
{
if (!in_array($this->path_extension, ['php', 'md'])) {
return null;
}
$clean = preg_replace(
['/(\s*)(\?>\s*)$/', '/\n+$/'],
'',
$content
) . ($this->getSetting('psr2') ? "\n" : '');
if ($content != $clean) {
$this->setSuccess(__('Replace end of file'));
$content = $clean;
}
return true;
}
}

View file

@ -10,7 +10,17 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionDcdeprecated extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/**
* Improve action module Dotclear depreciated
*/
class dcdeprecated extends action
{ {
/** @var array Deprecated functions [filetype [pattern, deprecated, replacement, version]] */ /** @var array Deprecated functions [filetype [pattern, deprecated, replacement, version]] */
private static $deprecated = [ private static $deprecated = [
@ -44,7 +54,7 @@ class ImproveActionDcdeprecated extends ImproveAction
['adminPostForm[^I]', 'adminPostForm', 'adminPostFormItems'], ['adminPostForm[^I]', 'adminPostForm', 'adminPostFormItems'],
['adminPostFormSidebar', 'adminPostFormSidebar', 'adminPostFormItems'], ['adminPostFormSidebar', 'adminPostFormSidebar', 'adminPostFormItems'],
['three-cols', 'three-cols', 'three-boxes', '2.6'] ['three-cols', 'three-cols', 'three-boxes', '2.6'],
], ],
'js' => [ 'js' => [
['\sstoreLocalData', 'storeLocalData', 'dotclear.storeLocalData'], ['\sstoreLocalData', 'storeLocalData', 'dotclear.storeLocalData'],
@ -55,8 +65,8 @@ class ImproveActionDcdeprecated extends ImproveAction
['\smergeDeep', 'mergeDeep', 'dotclear.mergeDeep'], ['\smergeDeep', 'mergeDeep', 'dotclear.mergeDeep'],
['\sgetCookie', 'getCookie', 'dotclear.getCookie'], ['\sgetCookie', 'getCookie', 'dotclear.getCookie'],
['\ssetCookie', 'setCookie', 'dotclear.setCookie'], ['\ssetCookie', 'setCookie', 'dotclear.setCookie'],
['\sdeleteCookie', 'deleteCookie', 'dotclear.deleteCookie'] ['\sdeleteCookie', 'deleteCookie', 'dotclear.deleteCookie'],
] ],
]; ];
protected function init(): bool protected function init(): bool
@ -66,7 +76,7 @@ class ImproveActionDcdeprecated extends ImproveAction
'name' => __('Dotclear deprecated'), 'name' => __('Dotclear deprecated'),
'description' => __('Search for use of deprecated Dotclear functions'), 'description' => __('Search for use of deprecated Dotclear functions'),
'priority' => 520, 'priority' => 520,
'types' => ['plugin', 'theme'] 'types' => ['plugin', 'theme'],
]); ]);
return true; return true;

View file

@ -10,8 +10,31 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionDcstore extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/* clearbricks */
use form;
use files;
use text;
use xmlTag;
use DOMDocument;
/* php */
use Exception;
/**
* Improve action module dcstore.xml
*/
class dcstore extends action
{ {
/** @var string Settings dcstore zip url pattern */
private $pattern = '';
protected function init(): bool protected function init(): bool
{ {
$this->setProperties([ $this->setProperties([
@ -20,9 +43,12 @@ class ImproveActionDcstore extends ImproveAction
'description' => __('Re-create dcstore.xml file according to _define.php variables'), 'description' => __('Re-create dcstore.xml file according to _define.php variables'),
'priority' => 420, 'priority' => 420,
'configurator' => true, 'configurator' => true,
'types' => ['plugin', 'theme'] 'types' => ['plugin', 'theme'],
]); ]);
$pattern = $this->getSetting('pattern');
$this->pattern = is_string($pattern) ? $pattern : '';
return true; return true;
} }
@ -42,7 +68,7 @@ class ImproveActionDcstore extends ImproveAction
'<p class="info">' . __('File will be overwritten if it exists') . '</p>' . '<p class="info">' . __('File will be overwritten if it exists') . '</p>' .
'<p><label class="classic" for="dcstore_pattern">' . '<p><label class="classic" for="dcstore_pattern">' .
__('Predictable URL to zip file on the external repository') . '<br />' . __('Predictable URL to zip file on the external repository') . '<br />' .
form::field('dcstore_pattern', 160, 255, $this->getSetting('pattern')) . '</label>' . form::field('dcstore_pattern', 160, 255, $this->pattern) . '</label>' .
'</p>' . '</p>' .
'<p class="form-note">' . '<p class="form-note">' .
sprintf(__('You can use wildcards %s'), '%author%, %type%, %id%, %version%.') . sprintf(__('You can use wildcards %s'), '%author%, %type%, %id%, %version%.') .
@ -187,25 +213,20 @@ class ImproveActionDcstore extends ImproveAction
private function parseFilePattern(): string private function parseFilePattern(): string
{ {
$str = $this->getSetting('pattern');
if (!is_string($str)) {
return '';
}
return text::tidyURL(str_replace( return text::tidyURL(str_replace(
[ [
'%type%', '%type%',
'%id%', '%id%',
'%version%', '%version%',
'%author%' '%author%',
], ],
[ [
$this->module['type'], $this->module['type'],
$this->module['id'], $this->module['id'],
$this->module['version'], $this->module['version'],
$this->module['author'] $this->module['author'],
], ],
$str $this->pattern
)); ));
} }
} }

80
inc/module/endoffile.php Normal file
View file

@ -0,0 +1,80 @@
<?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 plugins\improve\module;
/* improve */
use plugins\improve\action;
/* clearbricks */
use form;
/**
* Improve action module end of file
*/
class endoffile extends action
{
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;
}
public function isConfigured(): bool
{
return true;
}
public function configure($url): ?string
{
if (!empty($_POST['save'])) {
$this->setSettings('psr2', !empty($_POST['endoffile_psr2']));
$this->redirect($url);
}
return
'<p><label class="classic" for="endoffile_psr2">' .
form::checkbox('endoffile_psr2', 255, $this->getSetting('psr2')) .
__('Add a blank line to the end of file') .
'</label></p><p class="form-note">' .
__('PSR2 must have a blank line, whereas PSR12 must not.') .
'</p>';
}
public function readFile(&$content): ?bool
{
if (!in_array($this->path_extension, ['php', 'md'])) {
return null;
}
$clean = preg_replace(
['/(\s*)(\?>\s*)$/', '/\n+$/'],
'',
$content
) . ($this->getSetting('psr2') ? "\n" : '');
if ($content != $clean) {
$this->setSuccess(__('Replace end of file'));
$content = $clean;
}
return true;
}
}

View file

@ -10,8 +10,27 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionGitshields extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/* clearbricks */
use form;
/**
* Improve action module Github shields.io
*/
class gitshields extends action
{ {
/** @var string Username of git repo */
private $username = '';
/** @var boolean add Dotaddict shield */
private $dotaddict = false;
/** @var boolean Stop scaning files */ /** @var boolean Stop scaning files */
private $stop_scan = false; private $stop_scan = false;
@ -21,7 +40,7 @@ class ImproveActionGitshields extends ImproveAction
/** @var array Search patterns */ /** @var array Search patterns */
protected $bloc_pattern = [ protected $bloc_pattern = [
'remove' => '/\[!\[Release(.*)LICENSE\)/ms', 'remove' => '/\[!\[Release(.*)LICENSE\)/ms',
'target' => '/^([^\n]+)[\r\n|\n]{1,}/ms' 'target' => '/^([^\n]+)[\r\n|\n]{1,}/ms',
]; ];
/** @var array Shields patterns */ /** @var array Shields patterns */
@ -31,7 +50,7 @@ class ImproveActionGitshields extends ImproveAction
'issues' => '[![Issues](https://img.shields.io/github/issues/%username%/%module%)](https://github.com/%username%/%module%/issues)', 'issues' => '[![Issues](https://img.shields.io/github/issues/%username%/%module%)](https://github.com/%username%/%module%/issues)',
'dotclear' => '[![Dotclear](https://img.shields.io/badge/dotclear-v%dotclear%-blue.svg)](https://fr.dotclear.org/download)', 'dotclear' => '[![Dotclear](https://img.shields.io/badge/dotclear-v%dotclear%-blue.svg)](https://fr.dotclear.org/download)',
'dotaddict' => '[![Dotaddict](https://img.shields.io/badge/dotaddict-official-green.svg)](https://%type%s.dotaddict.org/dc2/details/%module%)', 'dotaddict' => '[![Dotaddict](https://img.shields.io/badge/dotaddict-official-green.svg)](https://%type%s.dotaddict.org/dc2/details/%module%)',
'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 init(): bool protected function init(): bool
@ -42,9 +61,13 @@ class ImproveActionGitshields extends ImproveAction
'description' => __('Add and maintain shields.io badges to the REDAME.md file'), 'description' => __('Add and maintain shields.io badges to the REDAME.md file'),
'priority' => 380, 'priority' => 380,
'configurator' => true, 'configurator' => true,
'types' => ['plugin', 'theme'] 'types' => ['plugin', 'theme'],
]); ]);
$username = $this->getSetting('username');
$this->username = is_string($username) ? $username : '';
$this->dotaddict = (bool) $this->getSetting('dotaddict');
return true; return true;
} }
@ -58,19 +81,19 @@ class ImproveActionGitshields extends ImproveAction
if (!empty($_POST['save']) && !empty($_POST['username'])) { if (!empty($_POST['save']) && !empty($_POST['username'])) {
$this->setSettings([ $this->setSettings([
'username' => (string) $_POST['username'], 'username' => (string) $_POST['username'],
'dotaddict' => !empty($_POST['dotaddict']) 'dotaddict' => !empty($_POST['dotaddict']),
]); ]);
$this->redirect($url); $this->redirect($url);
} }
return ' return '
<p><label for="username">' . __('Your Github user name :') . '</label>' . <p><label for="username">' . __('Your Github user name :') . '</label>' .
form::field('username', 60, 100, $this->getSetting('username')) . ' form::field('username', 60, 100, $this->username) . '
</p><p class="form-note">' . __('Used in your Github URL: http://github.com/username/module_id.') . '<br />' . </p><p class="form-note">' . __('Used in your Github URL: http://github.com/username/module_id.') . '<br />' .
__('If you have badges not created by this tool in the README.md file you should remove them manually.') . '</p> __('If you have badges not created by this tool in the README.md file you should remove them manually.') . '</p>
<p><label for="dotaddict">' . <p><label for="dotaddict">' .
form::checkbox('dotaddict', 1, !empty($this->getSetting('dotaddict'))) . ' ' . form::checkbox('dotaddict', 1, $this->dotaddict) . ' ' .
__('Include Dotaddict badge') . '</label> __('Include Dotaddict badge') . '</label>
</p><p class="form-note">' . __('If your plugin or theme is on Dotaddict, you can add a badge to link to its details in Dotaddict.') . '</p>'; </p><p class="form-note">' . __('If your plugin or theme is on Dotaddict, you can add a badge to link to its details in Dotaddict.') . '</p>';
} }
@ -99,7 +122,7 @@ class ImproveActionGitshields extends ImproveAction
{ {
$blocs = []; $blocs = [];
foreach ($this->bloc_content as $k => $v) { foreach ($this->bloc_content as $k => $v) {
if ($k == 'dotaddict' && empty($this->getSetting('dotaddict'))) { if ($k == 'dotaddict' && !$this->dotaddict) {
continue; continue;
} }
$blocs[$k] = trim(str_replace( $blocs[$k] = trim(str_replace(
@ -108,14 +131,14 @@ class ImproveActionGitshields extends ImproveAction
'%module%', '%module%',
'%dotclear%', '%dotclear%',
'%type%', '%type%',
"\r\n", "\n" "\r\n", "\n",
], ],
[ [
$this->getSetting('username'), $this->username,
$this->module['id'], $this->module['id'],
$dotclear = $this->getDotclearVersion(), $dotclear = $this->getDotclearVersion(),
$this->module['type'], $this->module['type'],
'', '' '', '',
], ],
$v $v
)); ));

View file

@ -10,13 +10,30 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionLicensefile extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/* clearbricks */
use form;
use files;
/* php */
use Exception;
/**
* Improve action module license file
*/
class licensefile extends action
{ {
/** @var array Possible license filenames */ /** @var array Possible license filenames */
protected static $license_filenames = [ protected static $license_filenames = [
'license', 'license',
'license.md', 'license.md',
'license.txt' 'license.txt',
]; ];
/** @var array Possible license names */ /** @var array Possible license names */
@ -33,21 +50,21 @@ class ImproveActionLicensefile extends ImproveAction
'description' => __('Add or remove full license file to module root'), 'description' => __('Add or remove full license file to module root'),
'priority' => 330, 'priority' => 330,
'configurator' => true, 'configurator' => true,
'types' => ['plugin', 'theme'] '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',
__('gpl3 - GNU General Public License v3') => 'gpl3', __('gpl3 - GNU General Public License v3') => 'gpl3',
__('lgpl3 - GNU Lesser General Public License v3') => 'lgpl3', __('lgpl3 - GNU Lesser General Public License v3') => 'lgpl3',
__('Massachusetts Institute of Technolog mit') => 'mit' __('Massachusetts Institute of Technolog mit') => 'mit',
]; ];
$this->action_full = [ $this->action_full = [
__('Do nothing') => 0, __('Do nothing') => 0,
__('Add file if it does not exist') => 'create', __('Add file if it does not exist') => 'create',
__('Add file even if it exists') => 'overwrite', __('Add file even if it exists') => 'overwrite',
__('Add file and remove others') => 'full', __('Add file and remove others') => 'full',
__('Remove license files') => 'remove' __('Remove license files') => 'remove',
]; ];
return true; return true;
@ -63,7 +80,7 @@ class ImproveActionLicensefile extends ImproveAction
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->setSettings([
'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'] : '',
]); ]);
$this->redirect($url); $this->redirect($url);
} }
@ -97,7 +114,7 @@ class ImproveActionLicensefile extends ImproveAction
private function writeFullLicense(): ?bool private function writeFullLicense(): ?bool
{ {
try { try {
$full = file_get_contents(dirname(__FILE__) . '/license/' . $this->getSetting('action_version') . '.full.txt'); $full = file_get_contents(dirname(__FILE__) . '/licensefile/' . $this->getSetting('action_version') . '.full.txt');
if (empty($full)) { if (empty($full)) {
$this->setError(__('Failed to load license content')); $this->setError(__('Failed to load license content'));

104
inc/module/newline.php Normal file
View file

@ -0,0 +1,104 @@
<?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 plugins\improve\module;
/* improve */
use plugins\improve\action;
use plugins\improve\improve;
/* clearbricks */
use form;
/**
* Improve action module new line
*/
class newline extends action
{
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'],
]);
/*
$ext = @unserialize($this->core->blog->settings->improve->newline_extensions);
$ext = Improve::cleanExtensions($ext);
if (!empty($ext)) {
$this->extensions = $ext;
}
*/
return true;
}
public function isConfigured(): bool
{
return !empty($this->getSetting('extensions'));
}
public function configure($url): ?string
{
if (!empty($_POST['save']) && !empty($_POST['newline_extensions'])) {
$this->setSettings(
'extensions',
improve::cleanExtensions($_POST['newline_extensions'])
);
$this->redirect($url);
}
$ext = $this->getSetting('extensions');
if (!is_array($ext)) {
$ext = [];
}
return
'<p><label class="classic" for="newline_extensions">' .
__('List of files extension to work on:') . '<br />' .
form::field('newline_extensions', 65, 255, implode(',', $ext)) .
'</label></p><p class="form-note">' .
__('Use comma separated list of extensions without dot, recommand "php,js,xml,txt,md".') .
'</p>';
}
public function readFile(string &$content): ?bool
{
$ext = $this->getSetting('extensions');
if (!is_array($ext) || !in_array($this->path_extension, $ext)) {
return null;
}
$clean = (string) preg_replace(
'/(\n\s+\n)/',
"\n\n",
(string) preg_replace(
'/(\n\n+)/',
"\n\n",
(string) str_replace(
["\r\n", "\r"],
"\n",
$content
)
)
);
if ($content != $clean) {
$this->setSuccess(__('Replace bad new lines'));
$content = $clean;
}
return true;
}
}

View file

@ -10,7 +10,28 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionPhpcsfixer extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/* dotclear */
use dcPage;
/* clearbricks */
use html;
use form;
use path;
/* php */
use Exception;
/**
* Improve action module PHP CS Fixer
*/
class phpcsfixer extends action
{ {
/** @var array<int,string> Type of runtime errors */ /** @var array<int,string> Type of runtime errors */
protected static $errors = [ protected static $errors = [
@ -20,7 +41,7 @@ class ImproveActionPhpcsfixer extends ImproveAction
8 => 'Some files need fixing (only in dry-run mode).', 8 => 'Some files need fixing (only in dry-run mode).',
16 => 'Configuration error of the application.', 16 => 'Configuration error of the application.',
32 => 'Configuration error of a Fixer.', 32 => 'Configuration error of a Fixer.',
64 => 'Exception raised within the application' 64 => 'Exception raised within the application',
]; ];
/** @var boolean User pref to use colored synthax */ /** @var boolean User pref to use colored synthax */
@ -40,7 +61,7 @@ class ImproveActionPhpcsfixer extends ImproveAction
'description' => __('Fix PSR coding style using Php CS Fixer'), 'description' => __('Fix PSR coding style using Php CS Fixer'),
'priority' => 920, 'priority' => 920,
'configurator' => true, 'configurator' => true,
'types' => ['plugin', 'theme'] 'types' => ['plugin', 'theme'],
]); ]);
$this->getPhpPath(); $this->getPhpPath();
@ -70,11 +91,11 @@ class ImproveActionPhpcsfixer extends ImproveAction
{ {
if (!empty($_POST['save'])) { if (!empty($_POST['save'])) {
$this->setSettings([ $this->setSettings([
'phpexe_path' => !empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : '' 'phpexe_path' => !empty($_POST['phpexe_path']) ? $_POST['phpexe_path'] : '',
]); ]);
$this->redirect($url); $this->redirect($url);
} }
$content = (string) file_get_contents(dirname(__FILE__) . '/libs/dc.phpcsfixer.rules.php'); $content = (string) file_get_contents(dirname(__FILE__) . '/phpcsfixer/phpcsfixer.rules.php');
return return
'<p><label class="classic" for="phpexe_path">' . '<p><label class="classic" for="phpexe_path">' .
@ -89,11 +110,11 @@ class ImproveActionPhpcsfixer extends ImproveAction
'<p>' . form::textarea('file_content', 120, 60, [ '<p>' . form::textarea('file_content', 120, 60, [
'default' => html::escapeHTML($content), 'default' => html::escapeHTML($content),
'class' => 'maximal', 'class' => 'maximal',
'extra_html' => 'readonly="true"' 'extra_html' => 'readonly="true"',
]) . '</p>' . ]) . '</p>' .
( (
!self::$user_ui_colorsyntax ? '' : !self::$user_ui_colorsyntax ? '' :
dcPage::jsLoad(dcPage::getPF('improve/inc/lib.improve.action.phpcsfixer.js')) . dcPage::jsLoad(dcPage::getPF('improve/inc/module/phpcsfixer/phpcsfixer.improve.js')) .
dcPage::jsRunCodeMirror('editor', 'file_content', 'dotclear', self::$user_ui_colorsyntax_theme) dcPage::jsRunCodeMirror('editor', 'file_content', 'dotclear', self::$user_ui_colorsyntax_theme)
); );
} }
@ -101,7 +122,7 @@ class ImproveActionPhpcsfixer extends ImproveAction
public function closeModule(): ?bool public function closeModule(): ?bool
{ {
$command = sprintf( $command = sprintf(
'%sphp %s/libs/php-cs-fixer.phar fix %s --config=%s/libs/dc.phpcsfixer.rules.php --using-cache=no', '%sphp %s/phpcsfixer/libs/php-cs-fixer.phar fix %s --config=%s/phpcsfixer/phpcsfixer.rules.php --using-cache=no',
$this->phpexe_path, $this->phpexe_path,
dirname(__FILE__), dirname(__FILE__),
$this->module['sroot'], $this->module['sroot'],

View file

@ -1,23 +1,26 @@
<?php <?php
/** @phpstan-ignore-next-line */
$finder = PhpCsFixer\Finder::create() $finder = PhpCsFixer\Finder::create()
->exclude('node_modules') ->exclude('node_modules')
->exclude('vendor') ->exclude('vendor')
->exclude('libs') ->exclude('libs')
->in(__DIR__); ->in(__DIR__);
/** @phpstan-ignore-next-line */
$config = new PhpCsFixer\Config(); $config = new PhpCsFixer\Config();
/* @phpstan-ignore-next-line */
return $config return $config
->setRules([ ->setRules([
'@PSR12' => true, '@PSR12' => true,
'@PHP74Migration' => true,
'array_indentation' => true, 'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => [ 'binary_operator_spaces' => [
'default' => 'align_single_space_minimal', 'default' => 'align_single_space_minimal',
'operators' => [ 'operators' => [
'=>' => 'align_single_space_minimal', '=>' => 'align_single_space_minimal',
] ],
], ],
'blank_line_before_statement' => true, 'blank_line_before_statement' => true,
'braces' => ['allow_single_line_closure' => true], 'braces' => ['allow_single_line_closure' => true],
@ -33,15 +36,10 @@ return $config
'no_unused_imports' => true, 'no_unused_imports' => true,
'no_useless_else' => true, 'no_useless_else' => true,
'no_useless_return' => true, 'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'normalize_index_brace' => true,
'phpdoc_indent' => true, 'phpdoc_indent' => true,
'phpdoc_to_comment' => true, 'phpdoc_to_comment' => true,
'phpdoc_trim' => true, 'phpdoc_trim' => true,
'return_type_declaration' => ['space_before' => 'none'],
'single_quote' => true, 'single_quote' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline' => false,
'trim_array_spaces' => true, 'trim_array_spaces' => true,
]) ])
->setFinder($finder); ->setFinder($finder);

View file

@ -10,7 +10,24 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionPhpheader extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/* clearbricks */
use form;
use html;
/* php */
use Exception;
/**
* Improve action module php header
*/
class phpheader extends action
{ {
/** @var string Exemple of header */ /** @var string Exemple of header */
private static $exemple = <<<EOF private static $exemple = <<<EOF
@ -35,7 +52,7 @@ EOF;
'%user_cn%', '%user_cn%',
'%user_name%', '%user_name%',
'%user_email%', '%user_email%',
'%user_url%' '%user_url%',
]; ];
/** @var array Allowed action for header */ /** @var array Allowed action for header */
@ -58,7 +75,7 @@ EOF;
'description' => __('Add or remove phpdoc header bloc from php file'), 'description' => __('Add or remove phpdoc header bloc from php file'),
'priority' => 340, 'priority' => 340,
'configurator' => true, 'configurator' => true,
'types' => ['plugin', 'theme'] 'types' => ['plugin', 'theme'],
]); ]);
$this->action_bloc = [ $this->action_bloc = [
@ -66,7 +83,7 @@ EOF;
__('Add bloc if it does not exist') => 'create', __('Add bloc if it does not exist') => 'create',
__('Add and overwrite bloc') => 'overwrite', __('Add and overwrite bloc') => 'overwrite',
__('Overwrite bloc only if it exists') => 'replace', __('Overwrite bloc only if it exists') => 'replace',
__('Remove existing bloc header') => 'remove' __('Remove existing bloc header') => 'remove',
]; ];
$bloc_content = $this->getSetting('bloc_content'); $bloc_content = $this->getSetting('bloc_content');
@ -87,7 +104,7 @@ EOF;
'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']),
'exclude_locales' => !empty($_POST['exclude_locales']) 'exclude_locales' => !empty($_POST['exclude_locales']),
]); ]);
$this->redirect($url); $this->redirect($url);
} }
@ -148,7 +165,7 @@ EOF;
$this->core->auth->getInfo('user_cn'), $this->core->auth->getInfo('user_cn'),
$this->core->auth->getinfo('user_name'), $this->core->auth->getinfo('user_name'),
$this->core->auth->getInfo('user_email'), $this->core->auth->getInfo('user_email'),
$this->core->auth->getInfo('user_url') $this->core->auth->getInfo('user_url'),
], ],
(string) $bloc (string) $bloc
) )

View file

@ -10,7 +10,28 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionPhpstan extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/* dotclear */
use dcPage;
/* clearbricks */
use html;
use form;
use path;
/* php */
use Exception;
/**
* Improve action module PHPStan
*/
class phpstan extends action
{ {
/** @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;
@ -35,7 +56,7 @@ class ImproveActionPhpstan extends ImproveAction
'description' => __('Analyse php code using PHPStan'), 'description' => __('Analyse php code using PHPStan'),
'priority' => 910, 'priority' => 910,
'configurator' => true, 'configurator' => true,
'types' => ['plugin'] 'types' => ['plugin'],
]); ]);
$this->getPhpPath(); $this->getPhpPath();
@ -74,11 +95,11 @@ class ImproveActionPhpstan extends ImproveAction
'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'] : ''),
'split_report' => !empty($_POST['split_report']) 'split_report' => !empty($_POST['split_report']),
]); ]);
$this->redirect($url); $this->redirect($url);
} }
$content = (string) file_get_contents(dirname(__FILE__) . '/libs/dc.phpstan.rules.conf'); $content = (string) file_get_contents(dirname(__FILE__) . '/phpstan/phpstan.rules.conf');
return return
'<p class="info">' . __('You must enable improve details to view analyse results !') . '</p>' . '<p class="info">' . __('You must enable improve details to view analyse results !') . '</p>' .
@ -108,11 +129,11 @@ class ImproveActionPhpstan extends ImproveAction
'<p>' . form::textarea('file_content', 120, 14, [ '<p>' . form::textarea('file_content', 120, 14, [
'default' => html::escapeHTML($content), 'default' => html::escapeHTML($content),
'class' => 'maximal', 'class' => 'maximal',
'extra_html' => 'readonly="true"' 'extra_html' => 'readonly="true"',
]) . '</p>' . ]) . '</p>' .
( (
!self::$user_ui_colorsyntax ? '' : !self::$user_ui_colorsyntax ? '' :
dcPage::jsLoad(dcPage::getPF('improve/inc/lib.improve.action.phpstan.js')) . dcPage::jsLoad(dcPage::getPF('improved/inc/module/phpstan/phpstan.improve.js')) .
dcPage::jsRunCodeMirror('editor', 'file_content', 'dotclear', self::$user_ui_colorsyntax_theme) dcPage::jsRunCodeMirror('editor', 'file_content', 'dotclear', self::$user_ui_colorsyntax_theme)
); );
} }
@ -158,7 +179,7 @@ class ImproveActionPhpstan extends ImproveAction
} }
$command = sprintf( $command = sprintf(
'%sphp %s/libs/phpstan.phar analyse ' . $path . '--configuration=%s', '%sphp %s/phpstan/libs/phpstan.phar analyse ' . $path . '--configuration=%s',
$this->phpexe_path, $this->phpexe_path,
dirname(__FILE__), dirname(__FILE__),
DC_VAR . '/phpstan.neon' DC_VAR . '/phpstan.neon'
@ -179,6 +200,7 @@ class ImproveActionPhpstan extends ImproveAction
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
$this->setError(__('Failed to run phpstan')); $this->setError(__('Failed to run phpstan'));
pdump($e);
return false; return false;
} }
@ -210,15 +232,15 @@ class ImproveActionPhpstan extends ImproveAction
'%LEVEL%', '%LEVEL%',
'%MODULE_ROOT%', '%MODULE_ROOT%',
'%DC_ROOT%', '%DC_ROOT%',
'%BOOTSTRAP_ROOT%' '%BOOTSTRAP_ROOT%',
], ],
[ [
$this->run_level, $this->run_level,
$this->module['sroot'], $this->module['sroot'],
DC_ROOT, DC_ROOT,
dirname(__FILE__) . '/libs/' dirname(__FILE__) . '/phpstan',
], ],
(string) file_get_contents(dirname(__FILE__) . '/libs/dc.phpstan.rules.conf') (string) file_get_contents(dirname(__FILE__) . '/phpstan/phpstan.rules.conf')
); );
$ignored = explode(';', $this->ignored_vars); $ignored = explode(';', $this->ignored_vars);

View file

@ -14,7 +14,7 @@ parameters:
- %MODULE_ROOT%/*/libs/* - %MODULE_ROOT%/*/libs/*
bootstrapFiles: bootstrapFiles:
- %BOOTSTRAP_ROOT%dc.phpstan.bootstrap.php - %BOOTSTRAP_ROOT%/phpstan.bootstrap.php
fileExtensions: fileExtensions:
- php - php

56
inc/module/tab.php Normal file
View file

@ -0,0 +1,56 @@
<?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 plugins\improve\module;
/* improve */
use plugins\improve\action;
/**
* Improve action module tab
*/
class tab extends action
{
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;
}
public function readFile(&$content): ?bool
{
if (!in_array($this->path_extension, ['php', 'md'])) {
return null;
}
$clean = preg_replace('/(\t)/', ' ', $content);// . "\n";
if ($content != $clean) {
$this->setSuccess(__('Replace tabulation by spaces'));
$content = $clean;
}
return true;
}
public function isConfigured(): bool
{
return true;
}
}

View file

@ -10,7 +10,23 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class ImproveActionZip extends ImproveAction declare(strict_types=1);
namespace plugins\improve\module;
/* improve */
use plugins\improve\action;
/* clearbricks */
use form;
use path;
use files;
use fileZip;
/**
* Improve action module zip
*/
class zip extends action
{ {
/** @var array List of excluded file pattern */ /** @var array List of excluded file pattern */
public static $exclude = [ public static $exclude = [
@ -23,7 +39,7 @@ class ImproveActionZip extends ImproveAction
'CVS', 'CVS',
'.DS_Store', '.DS_Store',
'Thumbs.db', 'Thumbs.db',
'_disabled' '_disabled',
]; ];
/** @var array Replacement wildcards */ /** @var array Replacement wildcards */
@ -32,7 +48,7 @@ class ImproveActionZip extends ImproveAction
'%id%', '%id%',
'%version%', '%version%',
'%author%', '%author%',
'%time%' '%time%',
]; ];
/** @var string Settings Excluded files */ /** @var string Settings Excluded files */
@ -52,7 +68,7 @@ class ImproveActionZip extends ImproveAction
'description' => __('Compress module into a ready to install package'), 'description' => __('Compress module into a ready to install package'),
'priority' => 980, 'priority' => 980,
'configurator' => true, 'configurator' => true,
'types' => ['plugin', 'theme'] 'types' => ['plugin', 'theme'],
]); ]);
$pack_excludefiles = $this->getSetting('pack_excludefiles'); $pack_excludefiles = $this->getSetting('pack_excludefiles');
@ -81,7 +97,7 @@ class ImproveActionZip extends ImproveAction
'secondpack_filename' => !empty($_POST['secondpack_filename']) ? $_POST['secondpack_filename'] : '', 'secondpack_filename' => !empty($_POST['secondpack_filename']) ? $_POST['secondpack_filename'] : '',
'pack_overwrite' => !empty($_POST['pack_overwrite']), 'pack_overwrite' => !empty($_POST['pack_overwrite']),
'pack_excludefiles' => !empty($_POST['pack_excludefiles']) ? $_POST['pack_excludefiles'] : '', 'pack_excludefiles' => !empty($_POST['pack_excludefiles']) ? $_POST['pack_excludefiles'] : '',
'pack_nocomment' => !empty($_POST['pack_nocomment']) 'pack_nocomment' => !empty($_POST['pack_nocomment']),
]); ]);
$this->redirect($url); $this->redirect($url);
} }
@ -143,7 +159,7 @@ class ImproveActionZip extends ImproveAction
); );
$this->setSuccess(sprintf(__('Prepare excluded files "%s"'), implode(', ', $exclude))); $this->setSuccess(sprintf(__('Prepare excluded files "%s"'), implode(', ', $exclude)));
if (!empty($this->getSetting('pack_nocomment'))) { if (!empty($this->getSetting('pack_nocomment'))) {
ImproveZipFileZip::$remove_comment = true; zipFileZip::$remove_comment = true;
$this->setSuccess(__('Prepare comment removal')); $this->setSuccess(__('Prepare comment removal'));
} }
if (!empty($this->getSetting('pack_filename'))) { if (!empty($this->getSetting('pack_filename'))) {
@ -165,7 +181,7 @@ class ImproveActionZip extends ImproveAction
$this->module['id'], $this->module['id'],
$this->module['version'], $this->module['version'],
$this->module['author'], $this->module['author'],
time() time(),
], ],
$file $file
); );
@ -186,7 +202,7 @@ class ImproveActionZip extends ImproveAction
} }
@set_time_limit(300); @set_time_limit(300);
$fp = fopen($path, 'wb'); $fp = fopen($path, 'wb');
$zip = new ImproveZipFileZip($fp); $zip = new zipFileZip($fp);
foreach ($exclude as $e) { foreach ($exclude as $e) {
$e = '#(^|/)(' . str_replace( $e = '#(^|/)(' . str_replace(
['.', '*'], ['.', '*'],
@ -208,7 +224,7 @@ class ImproveActionZip extends ImproveAction
} }
} }
class ImproveZipFileZip extends fileZip class zipFileZip extends fileZip
{ {
/** @var boolean Should remove comments from files */ /** @var boolean Should remove comments from files */
public static $remove_comment = false; public static $remove_comment = false;

282
index.php
View file

@ -10,179 +10,259 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
namespace plugins\improve;
if (!defined('DC_CONTEXT_ADMIN')) { if (!defined('DC_CONTEXT_ADMIN')) {
return; return;
} }
/* dotclear */
use dcCore;
use dcPage;
use dcThemes;
use dcUtils;
/* clearbricks */
use html;
use form;
/* php */
use Exception;
/**
* Improve page class
*
* Display page and configure modules
* and launch action.
*/
class index
{
/** @var dcCore $core dcCore instance */
private $core = null;
/** @var improve $improve improve core instance */
private $improve = null;
/** @var string $type Current module(s) type */
private $type = 'plugin';
/** @var string $module Current module id */
private $module = '-';
/** @var action|null $action Current action module */
private $action = null;
public function __construct(dcCore $core)
{
dcPage::checkSuper(); dcPage::checkSuper();
$improve = new Improve($core); $this->core = $core;
$this->improve = new improve($core);
$this->type = $this->getType();
$this->module = $this->getModule();
$this->action = $this->getAction();
$show_filters = false; $this->doAction();
$type = $_REQUEST['type'] ?? 'plugin'; $this->displayPage();
$preferences = @unserialize($core->blog->settings->improve->preferences);
if (!is_array($preferences)) {
$preferences = [];
} }
$preferences = array_merge(['plugin' => [], 'theme' => []], $preferences);
private function getType(): string
{
return $_REQUEST['type'] ?? 'plugin';
}
private function getModule(): string
{
$module = $_REQUEST['module'] ?? '';
if (!in_array($module, $this->comboModules())) {
$module = '-';
}
return $module;
}
private function getAction(): ?action
{
return empty($_REQUEST['config']) ? null : $this->improve->module($_REQUEST['config']);
}
private function getPreference(): array
{
try {
if (!empty($this->type)) {
$preferences = unserialize($this->core->blog->settings->improve->preferences);
if (is_array($preferences)) {
return array_key_exists($this->type, $preferences) ? $preferences[$this->type] : [];
}
}
} catch (Exception $e) {
}
return [];
}
private function setPreferences(): void
{
if (!empty($_POST['save_preferences'])) { if (!empty($_POST['save_preferences'])) {
$preferences[$type] = []; $preferences[$this->type] = [];
if (!empty($_POST['actions'])) { if (!empty($_POST['actions'])) {
foreach ($improve->modules() as $action) { foreach ($this->improve->modules() as $action) {
if (in_array($type, $action->types()) && in_array($action->id(), $_POST['actions'])) { if (in_array($this->type, $action->types()) && in_array($action->id(), $_POST['actions'])) {
$preferences[$type][] = $action->id(); $preferences[$this->type][] = $action->id();
} }
} }
} }
$core->blog->settings->improve->put('preferences', serialize($preferences), 'string', null, true, true); $this->core->blog->settings->improve->put('preferences', serialize($preferences), 'string', null, true, true);
dcPage::addSuccessNotice(__('Configuration successfully updated')); dcPage::addSuccessNotice(__('Configuration successfully updated'));
} }
}
$allow_distrib = (bool) $core->blog->settings->improve->allow_distrib; private function comboModules(): array
{
$allow_distrib = (bool) $this->core->blog->settings->improve->allow_distrib;
$official = [ $official = [
'plugin' => explode(',', DC_DISTRIB_PLUGINS), 'plugin' => explode(',', DC_DISTRIB_PLUGINS),
'theme' => explode(',', DC_DISTRIB_THEMES) 'theme' => explode(',', DC_DISTRIB_THEMES),
]; ];
if (!isset($core->themes)) { if (!isset($this->core->themes)) {
$core->themes = new dcThemes($core); $this->core->themes = new dcThemes($this->core);
$core->themes->loadModules($core->blog->themes_path, null); $this->core->themes->loadModules($this->core->blog->themes_path, null);
} }
$combo_modules = []; $combo_modules = [];
$modules = $type == 'plugin' ? $core->plugins->getModules() : $core->themes->getModules(); $modules = $this->type == 'plugin' ? $this->core->plugins->getModules() : $this->core->themes->getModules();
foreach ($modules as $id => $m) { foreach ($modules as $id => $m) {
if (!$m['root_writable'] || !$allow_distrib && in_array($id, $official[$type])) { if (!$m['root_writable'] || !$allow_distrib && in_array($id, $official[$this->type])) {
continue; continue;
} }
$combo_modules[__($m['name'])] = $id; $combo_modules[__($m['name'])] = $id;
} }
dcUtils::lexicalKeySort($combo_modules); dcUtils::lexicalKeySort($combo_modules);
$combo_modules = array_merge([__('Select a module') => '-'], $combo_modules);
$module = $_REQUEST['module'] ?? ''; return array_merge([__('Select a module') => '-'], $combo_modules);
if (!in_array($module, $combo_modules)) {
$module = '-';
} }
private function doAction(): void
{
if (!empty($_POST['fix'])) { if (!empty($_POST['fix'])) {
if (empty($_POST['actions'])) { if (empty($_POST['actions'])) {
dcPage::addWarningNotice(__('No action selected')); dcPage::addWarningNotice(__('No action selected'));
} elseif ($module == '-') { } elseif ($this->module == '-') {
dcPage::addWarningNotice(__('No module selected')); dcPage::addWarningNotice(__('No module selected'));
} else { } else {
try { try {
$time = $improve->fixModule( $time = $this->improve->fixModule(
$type, $this->type,
$module, $this->module,
$type == 'plugin' ? $core->plugins->getModules($module) : $core->themes->getModules($module), $this->type == 'plugin' ? $this->core->plugins->getModules($this->module) : $this->core->themes->getModules($this->module),
$_POST['actions'] $_POST['actions']
); );
$log_id = $improve->writeLogs(); $log_id = $this->improve->writeLogs();
$core->blog->triggerBlog(); $this->core->blog->triggerBlog();
if ($improve->hasLog('error')) { if ($this->improve->hasLog('error')) {
$notice = ['type' => 'error', 'msg' => __('Fix of "%s" complete in %s secondes with errors')]; $notice = ['type' => 'error', 'msg' => __('Fix of "%s" complete in %s secondes with errors')];
} elseif ($improve->hasLog('warning')) { } elseif ($this->improve->hasLog('warning')) {
$notice = ['type' => 'warning', 'msg' => __('Fix of "%s" complete in %s secondes with warnings')]; $notice = ['type' => 'warning', 'msg' => __('Fix of "%s" complete in %s secondes with warnings')];
} elseif ($improve->hasLog('success')) { } elseif ($this->improve->hasLog('success')) {
$notice = ['type' => 'success', 'msg' => __('Fix of "%s" complete in %s secondes')]; $notice = ['type' => 'success', 'msg' => __('Fix of "%s" complete in %s secondes')];
} else { } else {
$notice = ['type' => 'success', 'msg' => __('Fix of "%s" complete in %s secondes without messages')]; $notice = ['type' => 'success', 'msg' => __('Fix of "%s" complete in %s secondes without messages')];
} }
dcPage::addNotice($notice['type'], sprintf($notice['msg'], $module, $time)); dcPage::addNotice($notice['type'], sprintf($notice['msg'], $this->module, $time));
$core->adminurl->redirect('admin.plugin.improve', ['type' => $type, 'module' => $module, 'upd' => $log_id]); $this->core->adminurl->redirect('admin.plugin.improve', ['type' => $this->type, 'module' => $this->module, 'upd' => $log_id]);
} catch (Exception $e) { } catch (Exception $e) {
$core->error->add($e->getMessage()); $this->core->error->add($e->getMessage());
}
} }
} }
} }
$action = null; private function displayPage(): void
$header = ''; {
$breadcrumb = []; $bc = empty($_REQUEST['config']) ?
if (!empty($_REQUEST['config'])) { ($this->type == 'theme' ? __('Themes actions') : __('Plugins actions')) :
$breadcrumb = [ __('Configure module');
__('Configure module') => ''
];
if (null !== ($action = $improve->module($_REQUEST['config']))) {
$header = $action->header();
}
} else {
$breadcrumb[$type == 'theme' ? __('Themes actions') : __('Plugins actions')] = '';
}
# display header
echo '<html><head><title>' . __('improve') . '</title>' . echo '<html><head><title>' . __('improve') . '</title>' .
dcPage::jsLoad(dcPage::getPF('improve/js/index.js')) . dcPage::jsLoad(dcPage::getPF('improve/js/index.js')) .
$header . ($this->action === null ? '' : $this->action->header()) .
'</head><body>' . '</head><body>' .
dcPage::breadcrumb(array_merge([ dcPage::notices() .
dcPage::breadcrumb([
__('Plugins') => '', __('Plugins') => '',
__('improve') => '' __('improve') => '',
], $breadcrumb)) . $bc => '',
dcPage::notices(); ]);
# Menu list
if (empty($_REQUEST['config'])) { if (empty($_REQUEST['config'])) {
echo $this->displayActions();
'<form method="get" action="' . $core->adminurl->get('admin.plugin.improve') . '" id="improve_menu">' . } else {
'<p class="anchor-nav"><label for="type" class="classic">' . __('Goto:') . ' </label>' . $this->displayConfigurator();
form::combo('type', [__('Plugins') => 'plugin', __('Themes') => 'theme'], $type) . ' ' .
'<input type="submit" value="' . __('Ok') . '" />' .
form::hidden('p', 'improve') . '</p>' .
'</form>';
} }
if (!empty($_REQUEST['config'])) { echo '</body></html>';
$back_url = $_REQUEST['redir'] ?? $core->adminurl->get('admin.plugin.improve', ['type' => $type]); }
if (null !== $action) { private function displayConfigurator(): void
$redir = $_REQUEST['redir'] ?? $core->adminurl->get('admin.plugin.improve', ['type' => $type, 'config' => $action->id()]); {
$res = $action->configure($redir); $back_url = $_REQUEST['redir'] ?? $this->core->adminurl->get('admin.plugin.improve', ['type' => $this->type]);
echo ' if (null === $this->action) {
<h3>' . sprintf(__('Configure module "%s"'), $action->name()) . '</h3>
<p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>
<p class="info">' . html::escapeHTML($action->description()) . '</p>
<form action="' . $core->adminurl->get('admin.plugin.improve') . '" method="post" id="form-actions">' .
(empty($res) ? '<p class="message">' . __('Nothing to configure') . '</p>' : $res) . '
<p class="clear"><input type="submit" name="save" value="' . __('Save') . '" />' .
form::hidden('type', $type) .
form::hidden('config', $action->id()) .
form::hidden('redir', $redir) .
$core->formNonce() . '</p>' .
'</form>';
} else {
echo ' echo '
<p class="warning">' . __('Unknow module') . '</p> <p class="warning">' . __('Unknow module') . '</p>
<p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>'; <p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>';
}
} else { } else {
$redir = $_REQUEST['redir'] ?? $this->core->adminurl->get('admin.plugin.improve', ['type' => $this->type, 'config' => $this->action->id()]);
$res = $this->action->configure($redir);
echo '
<h3>' . sprintf(__('Configure module "%s"'), $this->action->name()) . '</h3>
<p><a class="back" href="' . $back_url . '">' . __('Back') . '</a></p>
<p class="info">' . html::escapeHTML($this->action->description()) . '</p>
<form action="' . $this->core->adminurl->get('admin.plugin.improve') . '" method="post" id="form-actions">' .
(empty($res) ? '<p class="message">' . __('Nothing to configure') . '</p>' : $res) . '
<p class="clear"><input type="submit" name="save" value="' . __('Save') . '" />' .
form::hidden('type', $this->type) .
form::hidden('config', $this->action->id()) .
form::hidden('redir', $redir) .
$this->core->formNonce() . '</p>' .
'</form>';
}
}
private function displayActions(): void
{
echo
'<form method="get" action="' . $this->core->adminurl->get('admin.plugin.improve') . '" id="improve_menu">' .
'<p class="anchor-nav"><label for="type" class="classic">' . __('Goto:') . ' </label>' .
form::combo('type', [__('Plugins') => 'plugin', __('Themes') => 'theme'], $this->type) . ' ' .
'<input type="submit" value="' . __('Ok') . '" />' .
form::hidden('p', 'improve') . '</p>' .
'</form>';
$combo_modules = $this->comboModules();
if (count($combo_modules) == 1) { if (count($combo_modules) == 1) {
echo '<p class="message">' . __('No module to manage') . '</p>'; echo '<p class="message">' . __('No module to manage') . '</p>';
} else { } else {
echo '<form action="' . $core->adminurl->get('admin.plugin.improve') . '" method="post" id="form-actions">' . echo '<form action="' . $this->core->adminurl->get('admin.plugin.improve') . '" method="post" id="form-actions">' .
'<table><caption class="hidden">' . __('Actions') . '</caption><thead><tr>' . '<table><caption class="hidden">' . __('Actions') . '</caption><thead><tr>' .
'<th colspan="2" class="first">' . __('Action') . '</td>' . '<th colspan="2" class="first">' . __('Action') . '</td>' .
'<th scope="col">' . __('Description') . '</td>' . '<th scope="col">' . __('Description') . '</td>' .
'<th scope="col">' . __('Configuration') . '</td>' . '<th scope="col">' . __('Configuration') . '</td>' .
(DC_DEBUG ? '<th scope="col">' . __('Priority') . '</td>' : '') . (DC_DEBUG ? '<th scope="col">' . __('Priority') . '</td>' : '') . /* @phpstan-ignore-line */
'</tr></thead><tbody>'; '</tr></thead><tbody>';
foreach ($improve->modules() as $action) { foreach ($this->improve->modules() as $action) {
if (!in_array($type, $action->types())) { if (!in_array($this->type, $action->types())) {
continue; continue;
} }
echo echo
'<tr class="line' . ($action->isConfigured() ? '' : ' offline') . '">' . '<tr class="line' . ($action->isConfigured() ? '' : ' offline') . '">' .
'<td class="minimal">' . form::checkbox( '<td class="minimal">' . form::checkbox(
['actions[]', ['actions[]',
'action_' . $action->id()], 'action_' . $action->id(), ],
$action->id(), $action->id(),
in_array($action->id(), $preferences[$type]) && $action->isConfigured(), in_array($action->id(), $this->getPreference()) && $action->isConfigured(),
'', '',
'', '',
!$action->isConfigured() !$action->isConfigured()
@ -193,10 +273,10 @@ if (!empty($_REQUEST['config'])) {
'<td class="maximal">' . $action->description() . '</td>' . '<td class="maximal">' . $action->description() . '</td>' .
'<td class="minimal nowrap modules">' . ( '<td class="minimal nowrap modules">' . (
false === $action->configurator() ? '' : false === $action->configurator() ? '' :
'<a class="module-config" href="' . $core->adminurl->get('admin.plugin.improve', ['type' => $type, 'config' => $action->id()]) . '<a class="module-config" href="' . $this->core->adminurl->get('admin.plugin.improve', ['type' => $this->type, 'config' => $action->id()]) .
'" title="' . sprintf(__("Configure action '%s'"), $action->name()) . '">' . __('Configure') . '</a>' '" title="' . sprintf(__("Configure action '%s'"), $action->name()) . '">' . __('Configure') . '</a>'
) . '</td>' . ) . '</td>' .
(DC_DEBUG ? '<td class="minimal"><span class="debug">' . $action->priority() . '</span></td>' : '') . (DC_DEBUG ? '<td class="minimal"><span class="debug">' . $action->priority() . '</span></td>' : '') . /* @phpstan-ignore-line */
'</tr>'; '</tr>';
} }
@ -206,17 +286,17 @@ if (!empty($_REQUEST['config'])) {
form::checkbox('save_preferences', 1, !empty($_POST['save_preferences'])) . form::checkbox('save_preferences', 1, !empty($_POST['save_preferences'])) .
__('Save fields selection as preference') . '</label></p> __('Save fields selection as preference') . '</label></p>
<p class="col right"><label for="module" class="classic">' . __('Select a module:') . ' </label>' . <p class="col right"><label for="module" class="classic">' . __('Select a module:') . ' </label>' .
form::combo('module', $combo_modules, $module) . form::combo('module', $combo_modules, $this->module) .
' <input type="submit" name="fix" value="' . __('Fix it') . '" />' . ' <input type="submit" name="fix" value="' . __('Fix it') . '" />' .
form::hidden(['type'], $type) . form::hidden(['type'], $this->type) .
$core->formNonce() . ' $this->core->formNonce() . '
</p> </p>
</div> </div>
<br class="clear" /> <br class="clear" />
</form>'; </form>';
if (!empty($_REQUEST['upd']) && !$core->blog->settings->improve->nodetails) { if (!empty($_REQUEST['upd']) && !$this->core->blog->settings->improve->nodetails) {
$logs = $improve->parseLogs($_REQUEST['upd']); $logs = $this->improve->parseLogs((int) $_REQUEST['upd']);
if (!empty($logs)) { if (!empty($logs)) {
echo '<div class="fieldset"><h4>' . __('Details') . '</h4>'; echo '<div class="fieldset"><h4>' . __('Details') . '</h4>';
@ -225,11 +305,13 @@ if (!empty($_REQUEST['config'])) {
foreach ($types as $type => $tools) { foreach ($types as $type => $tools) {
echo '<div class="' . $type . '"><ul>'; echo '<div class="' . $type . '"><ul>';
foreach ($tools as $tool => $msgs) { foreach ($tools as $tool => $msgs) {
$a = $improve->module($tool); $a = $this->improve->module($tool);
echo '<li>' . ($a !== null ? $a->name() : 'unknow') . '<ul>'; if (null !== $a) {
echo '<li>' . $a->name() . '<ul>';
foreach ($msgs as $msg) { foreach ($msgs as $msg) {
echo '<li>' . $msg . '</li>'; echo '<li>' . $msg . '</li>';
} }
}
echo '</ul></li>'; echo '</ul></li>';
} }
echo '</ul></div>'; echo '</ul></div>';
@ -241,5 +323,7 @@ if (!empty($_REQUEST['config'])) {
} }
} }
} }
}
echo '</body></html>'; /* process */
new index($core);

View file

@ -1,9 +1,9 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: improve 0.6\n" "Project-Id-Version: improve 0.7.3\n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: 2021-11-07T17:50:41+00:00\n" "PO-Revision-Date: 2021-11-13T21:51:37+00:00\n"
"Last-Translator: Jean-Christian Denis\n" "Last-Translator: Jean-Christian Denis\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -94,6 +94,21 @@ msgstr "Lien de détail non défini"
msgid "no support URL" msgid "no support URL"
msgstr "Lien de support non défini" msgstr "Lien de support non défini"
msgid "End of files"
msgstr "Fin de fichiers"
msgid "Remove php tag and empty lines from end of files"
msgstr "Supprimer le tag PHP et les lignes vides de fin de fichiers"
msgid "Add a blank line to the end of file"
msgstr "Ajouter une ligne vide en fin de fichier"
msgid "PSR2 must have a blank line, whereas PSR12 must not."
msgstr "PSR2 doit avoir une ligne vide, alors que PSR12 non."
msgid "Replace end of file"
msgstr "Remplacer les fins de fichiers"
msgid "Shields badges" msgid "Shields badges"
msgstr "Badges Shields.io" msgstr "Badges Shields.io"
@ -175,15 +190,6 @@ msgstr "Impossible de supprimer l'ancien fichier de licence (%s)"
msgid "Delete old license file \"%s\"" msgid "Delete old license file \"%s\""
msgstr "Effacer l'ancien fichier de Licence \"%s\"" msgstr "Effacer l'ancien fichier de Licence \"%s\""
msgid "Tabulations"
msgstr "Tabulations"
msgid "Replace tabulation by four space in php files"
msgstr "Remplace les tabulation par quatre espaces dans les fichiers php"
msgid "Replace tabulation by spaces"
msgstr "Remplacer les tabulations"
msgid "Newlines" msgid "Newlines"
msgstr "Retour à la ligne" msgstr "Retour à la ligne"
@ -199,21 +205,6 @@ msgstr "Utiliser une liste d'extensions séparé par des virgules et sans le poi
msgid "Replace bad new lines" msgid "Replace bad new lines"
msgstr "Remplacer les retours à la ligne" msgstr "Remplacer les retours à la ligne"
msgid "End of files"
msgstr "Fin de fichiers"
msgid "Remove php tag and empty lines from end of files"
msgstr "Supprimer le tag PHP et les lignes vides de fin de fichiers"
msgid "Add a blank line to the end of file"
msgstr "Ajouter une ligne vide en fin de fichier"
msgid "PSR2 must have a blank line, whereas PSR12 must not."
msgstr "PSR2 doit avoir une ligne vide, alors que PSR12 non."
msgid "Replace end of file"
msgstr "Remplacer les fins de fichiers"
msgid "Fix PSR coding style using Php CS Fixer" msgid "Fix PSR coding style using Php CS Fixer"
msgstr "Corrige le style du code suivant les règles PSR en utilisant Php CS Fixer" msgstr "Corrige le style du code suivant les règles PSR en utilisant Php CS Fixer"
@ -262,9 +253,6 @@ msgstr "Contenu du bloc :"
msgid "Do not put structural elements to the begining of lines." msgid "Do not put structural elements to the begining of lines."
msgstr "Ne pas mettre d'élément de structure en début de ligne" msgstr "Ne pas mettre d'élément de structure en début de ligne"
msgid "Skip directory"
msgstr "Ignorer le répertoire"
msgid "bloc is empty" msgid "bloc is empty"
msgstr "le bloc est vide" msgstr "le bloc est vide"
@ -274,6 +262,9 @@ msgstr "Préparer les informations d'entête"
msgid "Failed to parse bloc" msgid "Failed to parse bloc"
msgstr "Impossible de préparer le bloc" msgstr "Impossible de préparer le bloc"
msgid "Skip directory"
msgstr "Ignorer le répertoire"
msgid "Write new doc bloc content" msgid "Write new doc bloc content"
msgstr "Ecrire le nouveau contenu de bloc" msgstr "Ecrire le nouveau contenu de bloc"
@ -286,6 +277,9 @@ msgstr "Effacer l'ancien contenu de type ancien"
msgid "Analyse php code using PHPStan" msgid "Analyse php code using PHPStan"
msgstr "Analyse le code PHP en utilisant PHPStan" msgstr "Analyse le code PHP en utilisant PHPStan"
msgid "You must enable improve details to view analyse results !"
msgstr "Vous devez activer l'affichage des détails de l'analyse dans les paramètres d'improve."
msgid "Level:" msgid "Level:"
msgstr "Niveau :" msgstr "Niveau :"
@ -307,12 +301,27 @@ msgstr "Scinder le rapport par fichier plutôt qu'un seul à la fin."
msgid "Enable this can cause timeout." msgid "Enable this can cause timeout."
msgstr "Activer ceci peut causer de Timeout." msgstr "Activer ceci peut causer de Timeout."
msgid "You must enable improve details to view analyse results !" msgid "PHPStan configuration file:"
msgstr "Vous devez activer l'affichage des détails de l'analyse dans les paramètres d'improve." msgstr "Fichier de configuration de PHPStan :"
msgid "Failed to write phpstan configuration"
msgstr "Impossible d'écrire la configuration de PHPStan"
msgid "No errors found" msgid "No errors found"
msgstr "Aucune erreur trouvé" msgstr "Aucune erreur trouvé"
msgid "Failed to run phpstan"
msgstr "Impossible d'exécuter PHPStan"
msgid "Tabulations"
msgstr "Tabulations"
msgid "Replace tabulation by four space in php files"
msgstr "Remplace les tabulation par quatre espaces dans les fichiers php"
msgid "Replace tabulation by spaces"
msgstr "Remplacer les tabulations"
msgid "Zip module" msgid "Zip module"
msgstr "Zipper le module" msgstr "Zipper le module"
@ -388,17 +397,17 @@ msgstr "Fixe de \"%s\" complété en %s secondes"
msgid "Fix of \"%s\" complete in %s secondes without messages" msgid "Fix of \"%s\" complete in %s secondes without messages"
msgstr "Fixe de \"%s\" complété en %s secondes sans message" msgstr "Fixe de \"%s\" complété en %s secondes sans message"
msgid "Configure module"
msgstr "Configurer le module"
msgid "Themes actions" msgid "Themes actions"
msgstr "Actions sur les thèmes" msgstr "Actions sur les thèmes"
msgid "Plugins actions" msgid "Plugins actions"
msgstr "Actions sur les plugins" msgstr "Actions sur les plugins"
msgid "Themes" msgid "Configure module"
msgstr "Thèmes" msgstr "Configurer le module"
msgid "Unknow module"
msgstr "Module inconnu"
msgid "Configure module \"%s\"" msgid "Configure module \"%s\""
msgstr "Configurer le module \"%s\"" msgstr "Configurer le module \"%s\""
@ -406,8 +415,8 @@ msgstr "Configurer le module \"%s\""
msgid "Nothing to configure" msgid "Nothing to configure"
msgstr "Rien à configurer" msgstr "Rien à configurer"
msgid "Unknow module" msgid "Themes"
msgstr "Module inconnu" msgstr "Thèmes"
msgid "No module to manage" msgid "No module to manage"
msgstr "Aucun module à gérer" msgstr "Aucun module à gérer"
@ -418,6 +427,9 @@ msgstr "Priorité"
msgid "Configure action '%s'" msgid "Configure action '%s'"
msgstr "Configurer l'action \"%s\"" msgstr "Configurer l'action \"%s\""
msgid "Configure"
msgstr "Configurer"
msgid "Save fields selection as preference" msgid "Save fields selection as preference"
msgstr "Enregistrer la sélection comme préférence" msgstr "Enregistrer la sélection comme préférence"