code review

master
Jean-Christian Paul Denis 2023-10-24 11:38:06 +02:00
parent 53f72a8748
commit de46d49d77
Signed by: JcDenis
GPG Key ID: 1B5B8C5B90B6C951
7 changed files with 176 additions and 114 deletions

View File

@ -31,14 +31,14 @@ class Alias
/** /**
* Stack of aliases. * Stack of aliases.
* *
* @var array<int, array<string, string>> $aliases * @var array<int, AliasRow> $aliases
*/ */
protected array $aliases = []; protected array $aliases = [];
/** /**
* Get aliases. * Get aliases.
* *
* @return array<int, array<string, string>> Stack of aliases * @return array<int, AliasRow> Stack of aliases
*/ */
public function getAliases(): array public function getAliases(): array
{ {
@ -46,10 +46,6 @@ class Alias
return $this->aliases; return $this->aliases;
} }
if (!App::blog()->isDefined()) {
return [];
}
$sql = new SelectStatement(); $sql = new SelectStatement();
$rs = $sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME) $rs = $sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME)
->columns([ ->columns([
@ -62,7 +58,11 @@ class Alias
->order('alias_position ASC') ->order('alias_position ASC')
->select(); ->select();
$this->aliases = is_null($rs) ? [] : $rs->rows(); if (!is_null($rs)) {
while ($rs->fetch()) {
$this->aliases[] = AliasRow::newFromRecord($rs);
}
}
return $this->aliases; return $this->aliases;
} }
@ -70,24 +70,24 @@ class Alias
/** /**
* Update aliases stack. * Update aliases stack.
* *
* @param array<int, array<string, string>> $aliases The alias stack * @param array<int, AliasRow> $aliases The alias stack
*/ */
public function updateAliases(array $aliases): void public function updateAliases(array $aliases): void
{ {
usort($aliases, fn ($a, $b) => (int) $a['alias_position'] <=> (int) $b['alias_position']); foreach ($aliases as $row) {
foreach ($aliases as $v) { if (!is_a($row, AliasRow::class)) {
if (!isset($v['alias_url']) || !isset($v['alias_destination'])) {
throw new Exception(__('Invalid aliases definitions')); throw new Exception(__('Invalid aliases definitions'));
} }
} }
usort($aliases, fn ($a, $b) => $a->position <=> $b->position);
App::con()->begin(); App::con()->begin();
try { try {
$this->deleteAliases(); $this->deleteAliases();
foreach ($aliases as $k => $v) { foreach ($aliases as $k => $alias) {
if (!empty($v['alias_url']) && !empty($v['alias_destination'])) { if (!empty($alias->url) && !empty($alias->destination)) {
$this->createAlias($v['alias_url'], $v['alias_destination'], $k + 1, !empty($v['alias_redirect'])); $this->createAlias(new AliasRow($alias->url, $alias->destination, $k + 1, $alias->redirect));
} }
} }
@ -102,19 +102,16 @@ class Alias
/** /**
* Create an alias. * Create an alias.
* *
* @param string $url The URL * @param AliasRow $alias The new Alias descriptor
* @param string $destination The destination
* @param int $position The position
* @param bool $redirect Do redirection
*/ */
public function createAlias(string $url, string $destination, int $position, bool $redirect): void public function createAlias(AliasRow $alias):void
{ {
if (!App::blog()->isDefined()) { if (!App::blog()->isDefined()) {
return; return;
} }
$url = self::removeBlogUrl($url); $url = self::removeBlogUrl($alias->url);
$destination = self::removeBlogUrl($destination); $destination = self::removeBlogUrl($alias->destination);
if (empty($url)) { if (empty($url)) {
throw new Exception(__('Alias URL is empty.')); throw new Exception(__('Alias URL is empty.'));
@ -125,10 +122,10 @@ class Alias
$cur = App::con()->openCursor(App::con()->prefix() . Alias::ALIAS_TABLE_NAME); $cur = App::con()->openCursor(App::con()->prefix() . Alias::ALIAS_TABLE_NAME);
$cur->setField('blog_id', App::blog()->id()); $cur->setField('blog_id', App::blog()->id());
$cur->setField('alias_url', (string) $url); $cur->setField('alias_url', $url);
$cur->setField('alias_destination', (string) $destination); $cur->setField('alias_destination',$destination);
$cur->setField('alias_position', abs((int) $position)); $cur->setField('alias_position', $alias->position);
$cur->setField('alias_redirect', (int) $redirect); $cur->setField('alias_redirect', (int) $alias->redirect);
$cur->insert(); $cur->insert();
} }
@ -139,10 +136,6 @@ class Alias
*/ */
public function deleteAlias(string $url): void public function deleteAlias(string $url): void
{ {
if (!App::blog()->isDefined()) {
return;
}
$sql = new DeleteStatement(); $sql = new DeleteStatement();
$sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME) $sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME)
->where('blog_id = ' . $sql->quote(App::blog()->id())) ->where('blog_id = ' . $sql->quote(App::blog()->id()))
@ -155,10 +148,6 @@ class Alias
*/ */
public function deleteAliases(): void public function deleteAliases(): void
{ {
if (!App::blog()->isDefined()) {
return;
}
$sql = new DeleteStatement(); $sql = new DeleteStatement();
$sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME) $sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME)
->where('blog_id = ' . $sql->quote(App::blog()->id())) ->where('blog_id = ' . $sql->quote(App::blog()->id()))
@ -174,6 +163,6 @@ class Alias
*/ */
public static function removeBlogUrl(string $url): string public static function removeBlogUrl(string $url): string
{ {
return App::blog()->isDefined() ? str_replace(App::blog()->url(), '', trim($url)) : trim($url); return str_replace(App::blog()->url(), '', trim($url));
} }
} }

42
src/AliasRow.php 100644
View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Dotclear\Plugin\alias;
use Dotclear\App;
use Dotclear\Database\MetaRecord;
/**
* @brief alias decriptor class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class AliasRow
{
public readonly string $url;
public readonly string $destination;
public readonly int $position;
public readonly bool $redirect;
public function __construct(?string $url, ?string $destination, null|string|int $position, null|int|string|bool $redirect)
{
$this->url = (string) $url;
$this->destination = (string) $destination;
$this->position = (int) $position;
$this->redirect = !empty($redirect);
}
public static function newFromRecord(MetaRecord $rs): AliasRow
{
return new self(
(string) $rs->field('alias_url'),
(string) $rs->field('alias_destination'),
(int) $rs->field('alias_position'),
!empty($rs->field('alias_redirect'))
);
}
}

View File

@ -6,11 +6,6 @@ namespace Dotclear\Plugin\alias;
use Dotclear\App; use Dotclear\App;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Plugin\importExport\{
FlatBackupItem,
FlatExport,
FlatImportV2
};
/** /**
* @brief alias backend class. * @brief alias backend class.
@ -36,46 +31,10 @@ class Backend extends Process
My::addBackendMenuItem(); My::addBackendMenuItem();
App::behavior()->addBehaviors([ App::behavior()->addBehaviors([
'exportFullV2' => function (FlatExport $exp): void { 'exportFullV2' => PluginImportExportBehaviors::exportFullV2(...),
$exp->exportTable(Alias::ALIAS_TABLE_NAME); 'importInitV2' => PluginImportExportBehaviors::importInitV2(...),
}, 'importFullV2' => PluginImportExportBehaviors::importFullV2(...),
'exportSingleV2' => function (FlatExport $exp, ?string $blog_id): void { 'importSingleV2' => PluginImportExportBehaviors::importSingleV2(...),
$exp->export(
'alias',
'SELECT alias_url, alias_destination, alias_position ' .
'FROM ' . App::con()->prefix() . Alias::ALIAS_TABLE_NAME . ' A ' .
"WHERE A.blog_id = '" . $blog_id . "'"
);
},
'importInitV2' => function (FlatImportV2 $bk): void {
$bk->cur_alias = App::con()->openCursor(App::con()->prefix() . Alias::ALIAS_TABLE_NAME);
$bk->alias = new Alias();
$bk->aliases = $bk->alias->getAliases();
},
'importFullV2' => function (/*bool|FlatBackupItem */$line, FlatImportV2 $bk): void {
if ($line->__name == Alias::ALIAS_TABLE_NAME) {
$bk->cur_alias->clean();
$bk->cur_alias->setField('blog_id', (string) $line->blog_id);
$bk->cur_alias->setField('alias_url', (string) $line->alias_url);
$bk->cur_alias->setField('alias_destination', (string) $line->alias_destination);
$bk->cur_alias->setField('alias_position', (int) $line->alias_position);
$bk->cur_alias->insert();
}
},
'importSingleV2' => function (/*bool|FlatBackupItem */$line, FlatImportV2 $bk): void {
if ($line->__name == Alias::ALIAS_TABLE_NAME) {
$found = false;
foreach ($bk->aliases as $v) {
if ($v['alias_url'] == $line->alias_url) {
$found = true;
}
}
if ($found) {
$bk->alias->deleteAlias($line->alias_url);
}
$bk->alias->createAlias($line->alias_url, $line->alias_destination, $line->alias_position);
}
},
]); ]);
return true; return true;

View File

@ -10,18 +10,18 @@ use Dotclear\Core\Process;
use Dotclear\Helper\Network\Http; use Dotclear\Helper\Network\Http;
/** /**
* @brief alias prepend class. * @brief alias frontend class.
* @ingroup alias * @ingroup alias
* *
* @author Olivier Meunier (author) * @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest) * @author Jean-Christian Denis (latest)
* @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 Prepend extends Process class Frontend extends Process
{ {
public static function init(): bool public static function init(): bool
{ {
return self::status(My::checkContext(My::PREPEND)); return self::status(My::checkContext(My::FRONTEND));
} }
public static function process(): bool public static function process(): bool
@ -36,19 +36,19 @@ class Prepend extends Process
$part = $args = $_SERVER['URL_REQUEST_PART']; $part = $args = $_SERVER['URL_REQUEST_PART'];
// load all Aliases // load all Aliases
foreach ((new Alias())->getAliases() as $v) { foreach ((new Alias())->getAliases() as $alias) {
// multi alias using "/url/" to "destination" // multi alias using "/url/" to "destination"
if (@preg_match('#^/.*/$#', $v['alias_url']) && @preg_match($v['alias_url'], $args)) { if (@preg_match('#^/.*/$#', $alias->url) && @preg_match($alias->url, $args)) {
$part = preg_replace($v['alias_url'], $v['alias_destination'], $args); $part = preg_replace($alias->url, $alias->destination, $args);
$found = true; $found = true;
$redir = !empty($v['alias_redirect']); $redir = !empty($alias->redirect);
break; break;
// single alias using "url" to "destination" // single alias using "url" to "destination"
} elseif ($v['alias_url'] == $args) { } elseif ($alias->url == $args) {
$part = $v['alias_destination']; $part = $alias->destination;
$found = true; $found = true;
$redir = !empty($v['alias_redirect']); $redir = !empty($alias->redirect);
break; break;
} }

View File

@ -51,13 +51,22 @@ class Manage extends Process
return true; return true;
} }
$alias = new Alias(); $utils = new Alias();
$aliases = $alias->getAliases(); $aliases = $utils->getAliases();
# Update aliases # Update aliases
if (isset($_POST['a']) && is_array($_POST['a'])) { if (isset($_POST['a']) && is_array($_POST['a'])) {
try { try {
$alias->updateAliases($_POST['a']); $stack = [];
foreach($_POST['a'] as $alias) {
$stack[] = new AliasRow(
$alias['alias_url'] ?? '',
$alias['alias_destination'] ?? '',
(int) ($alias['alias_position'] ?? 0),
!empty($alias['alias_redirect']),
);
}
$utils->updateAliases($stack);
Notices::addSuccessNotice(__('Aliases successfully updated.')); Notices::addSuccessNotice(__('Aliases successfully updated.'));
My::redirect(); My::redirect();
} catch (Exception $e) { } catch (Exception $e) {
@ -68,7 +77,7 @@ class Manage extends Process
# New alias # New alias
if (isset($_POST['alias_url'])) { if (isset($_POST['alias_url'])) {
try { try {
$alias->createAlias($_POST['alias_url'], $_POST['alias_destination'], count($aliases) + 1, !empty($_POST['alias_redirect'])); $utils->createAlias(new AliasRow($_POST['alias_url'], $_POST['alias_destination'], count($aliases) + 1, !empty($_POST['alias_redirect'])));
Notices::addSuccessNotice(__('Alias successfully created.')); Notices::addSuccessNotice(__('Alias successfully created.'));
My::redirect(); My::redirect();
} catch (Exception $e) { } catch (Exception $e) {
@ -85,8 +94,7 @@ class Manage extends Process
return; return;
} }
$alias = new Alias(); $aliases = (new Alias())->getAliases();
$aliases = $alias->getAliases();
Page::openModule(My::name()); Page::openModule(My::name());
@ -104,11 +112,11 @@ class Manage extends Process
(new Form(My::id() . '_form'))->method('post')->action(App::backend()->getPageURL())->fields([ (new Form(My::id() . '_form'))->method('post')->action(App::backend()->getPageURL())->fields([
(new Para())->class('field')->items([ (new Para())->class('field')->items([
(new Label(__('Alias URL:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_url'), (new Label(__('Alias URL:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_url'),
(new Input('alias_url'))->size(50)->maxlenght(255), (new Input('alias_url'))->size(50)->maxlength(255),
]), ]),
(new Para())->class('field')->items([ (new Para())->class('field')->items([
(new Label(__('Alias destination:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_destination'), (new Label(__('Alias destination:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_destination'),
(new Input('alias_destination'))->size(50)->maxlenght(255), (new Input('alias_destination'))->size(50)->maxlength(255),
]), ]),
(new Note())->class('form-note')->text(sprintf(__('Do not put blog URL "%s" in fields.'), App::blog()->url())), (new Note())->class('form-note')->text(sprintf(__('Do not put blog URL "%s" in fields.'), App::blog()->url())),
(new Para())->items([ (new Para())->items([
@ -152,17 +160,17 @@ class Manage extends Process
'</tr>' . '</tr>' .
'</thead><tbody>'; '</thead><tbody>';
foreach ($aliases as $k => $v) { foreach ($aliases as $k => $alias) {
echo echo
'<tr class="line" id="l_' . $k . '">' . '<tr class="line" id="l_' . $k . '">' .
'<td class="minimal">' . '<td class="minimal">' .
(new Input(['a[' . $k . '][alias_url]']))->size(50)->maxlenght(255)->value(Html::escapeHTML($v['alias_url']))->render() . '</td>' . (new Input(['a[' . $k . '][alias_url]']))->size(50)->maxlength(255)->value(Html::escapeHTML($alias->url))->render() . '</td>' .
'<td class="minimal">' . '<td class="minimal">' .
(new Input(['a[' . $k . '][alias_destination]']))->size(50)->maxlenght(255)->value(Html::escapeHTML($v['alias_destination']))->render() . '</td>' . (new Input(['a[' . $k . '][alias_destination]']))->size(50)->maxlength(255)->value(Html::escapeHTML($alias->destination))->render() . '</td>' .
'<td class="minimal">' . '<td class="minimal">' .
(new Number(['a[' . $k . '][alias_position]']))->min(1)->max(count($aliases))->default((int) $v['alias_position'])->class('position')->title(sprintf(__('position of %s'), Html::escapeHTML($v['alias_url'])))->render() . '</td>' . (new Number(['a[' . $k . '][alias_position]']))->min(1)->max(count($aliases))->default($alias->position)->class('position')->title(sprintf(__('position of %s'), Html::escapeHTML($alias->url)))->render() . '</td>' .
'<td class="maximal">' . '<td class="maximal">' .
(new Checkbox(['a[' . $k . '][alias_redirect]'], (bool) $v['alias_redirect']))->title(sprintf(__('visible redirection to %s'), Html::escapeHTML(App::blog()->url() . $v['alias_destination'])))->render() . '</td>' . (new Checkbox(['a[' . $k . '][alias_redirect]'], $alias->redirect))->title(sprintf(__('visible redirection to %s'), Html::escapeHTML(App::blog()->url() . $alias->destination)))->render() . '</td>' .
'</tr>'; '</tr>';
} }

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Dotclear\Plugin\alias; namespace Dotclear\Plugin\alias;
use Dotclear\App;
use Dotclear\Module\MyPlugin; use Dotclear\Module\MyPlugin;
/** /**
@ -17,15 +16,5 @@ use Dotclear\Module\MyPlugin;
*/ */
class My extends MyPlugin class My extends MyPlugin
{ {
public static function checkCustomContext(int $context): ?bool // Use default permissions
{
return match ($context) {
My::BACKEND, My::MANAGE, My::MENU => App::task()->checkContext('BACKEND')
&& App::auth()->check(App::auth()->makePermissions([
App::auth()::PERMISSION_ADMIN,
]), App::blog()->id()),
default => null,
};
}
} }

View File

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace Dotclear\Plugin\alias;
use Dotclear\App;
use Dotclear\Database\Statement\SelectStatement;
use Dotclear\Plugin\importExport\{
FlatBackupItem,
FlatExport,
FlatImportV2
};
/**
* @brief alias plugin importExport features class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class PluginImportExportBehaviors
{
public static function exportFullV2(FlatExport $exp): void
{
$exp->exportTable(Alias::ALIAS_TABLE_NAME);
}
public static function exportSingleV2(FlatExport $exp, ?string $blog_id): void
{
$sql = new SelectStatement();
$sql->columns(['alias_url', 'alias_destination', 'alias_position', 'alias_redirect'])
->from($sql->as(App::con()->prefix() . Alias::ALIAS_TABLE_NAME, 'A'))
->where('blog_id = ' . $sql->quote((string) $blog_id));
$exp->export('alias', $sql->statement());
}
public static function importInitV2(FlatImportV2 $bk): void
{
$bk->__set('cur_alias', App::con()->openCursor(App::con()->prefix() . Alias::ALIAS_TABLE_NAME));
$bk->__set('alias', new Alias());
$bk->__set('aliases', $bk->__get('alias')->getAliases());
}
public static function importFullV2(bool|FlatBackupItem $line, FlatImportV2 $bk): void
{
if (!is_bool($line) && $line->__name == Alias::ALIAS_TABLE_NAME) {
$bk->__get('cur_alias')->clean();
$bk->__get('cur_alias')->setField('blog_id', (string) $line->f('blog_id'));
$bk->__get('cur_alias')->setField('alias_url', (string) $line->f('alias_url'));
$bk->__get('cur_alias')->setField('alias_destination', (string) $line->f('alias_destination'));
$bk->__get('cur_alias')->setField('alias_position', (int) $line->f('alias_position'));
$bk->__get('cur_alias')->setField('alias_redirect', (int) $line->f('alias_redirect'));
$bk->__get('cur_alias')->insert();
}
}
public static function importSingleV2(bool|FlatBackupItem $line, FlatImportV2 $bk): void
{
if (!is_bool($line) && $line->__name == Alias::ALIAS_TABLE_NAME) {
$found = false;
foreach ($bk->__get('aliases') as $alias) {
if ($alias->url == $line->f('alias_url')) {
$found = true;
}
}
if ($found) {
$bk->__get('alias')->deleteAlias($line->f('alias_url'));
}
$bk->__get('alias')->createAlias(new AliasRow($line->f('alias_url'), $line->f('alias_destination'), $line->f('alias_position'), $line->f('alias_redirect')));
}
}
}