From a2455b148d8452d5a6f691476592c340dfffba34 Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Mon, 24 Apr 2023 20:28:05 +0200 Subject: [PATCH] use namespace (WIP) --- src/Backend.php | 129 ++++++++++++++--------- src/BackendBehaviors.php | 217 ++++++++++++--------------------------- src/Frontend.php | 30 +++++- src/ImportExport.php | 112 ++++++++++++++++++++ src/Install.php | 152 +++++++++++++-------------- src/Manage.php | 189 +++++++++++++++++++++------------- src/ManageList.php | 31 ++++-- src/My.php | 53 ++++++++++ src/Utils.php | 176 +++++++++++++++---------------- src/Widgets.php | 65 +++++++----- 10 files changed, 674 insertions(+), 480 deletions(-) create mode 100644 src/ImportExport.php create mode 100644 src/My.php diff --git a/src/Backend.php b/src/Backend.php index da1d751..1e80a62 100644 --- a/src/Backend.php +++ b/src/Backend.php @@ -10,50 +10,87 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} - -require __DIR__ . '/_widgets.php'; - -// Admin menu -if (dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) { - dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( - __('Post widget text'), - dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)), - dcPage::getPF(basename(__DIR__) . '/icon.svg'), - preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__))) . '(&.*)?$/', $_SERVER['REQUEST_URI']), - dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_CONTENT_ADMIN]), dcCore::app()->blog->id) - ); - - dcCore::app()->addBehavior('adminDashboardFavoritesV2', ['adminPostWidgetText', 'adminDashboardFavoritesV2']); -} -dcCore::app()->addBehaviors([ - // Pref - 'adminFiltersListsV2' => ['adminPostWidgetText', 'adminFiltersListsV2'], - 'adminBlogPreferencesFormV2' => ['adminPostWidgetText', 'adminBlogPreferencesFormV2'], - 'adminBeforeBlogSettingsUpdate' => ['adminPostWidgetText', 'adminBeforeBlogSettingsUpdate'], - // Post - 'adminPostHeaders' => ['adminPostWidgetText', 'adminPostHeaders'], - 'adminPostFormItems' => ['adminPostWidgetText', 'adminPostFormItems'], - 'adminAfterPostUpdate' => ['adminPostWidgetText', 'adminAfterPostSave'], - 'adminAfterPostCreate' => ['adminPostWidgetText', 'adminAfterPostSave'], - 'adminBeforePostDelete' => ['adminPostWidgetText', 'adminBeforePostDelete'], - // Plugin "pages" - 'adminPageHeaders' => ['adminPostWidgetText', 'adminPostHeaders'], - 'adminPageFormItems' => ['adminPostWidgetText', 'adminPostFormItems'], - 'adminAfterPageUpdate' => ['adminPostWidgetText', 'adminAfterPostSave'], - 'adminAfterPageCreate' => ['adminPostWidgetText', 'adminAfterPostSave'], - 'adminBeforePageDelete' => ['adminPostWidgetText', 'adminBeforePostDelete'], -]); - -// Plugin "importExport" -if (dcCore::app()->blog->settings->get(basename(__DIR__))->get('importexport_active')) { - dcCore::app()->addBehaviors([ - 'exportFullV2' => ['adminPostWidgetText', 'exportFullV2'], - 'exportSingleV2' => ['adminPostWidgetText', 'exportSingleV2'], - 'importInitV2' => ['adminPostWidgetText', 'importInitV2'], - 'importSingleV2' => ['adminPostWidgetText', 'importSingleV2'], - 'importFullV2' => ['adminPostWidgetText', 'importFullV2'], - ]); +declare(strict_types=1); + +namespace Dotclear\Plugin\postWidgetText; + +use dcAdmin; +use dcCore; +use dcPage; +use dcNsProcess; + +class Backend extends dcNsProcess +{ + public static function init(): bool + { + static::$init = defined('DC_CONTEXT_ADMIN') + && My::phpCompliant() + && !is_null(dcCore::app()->auth) && !is_null(dcCore::app()->blog) + && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog->id); + + return static::$init; + } + + public static function process(): bool + { + if (!static::$init) { + return false; + } + + // nullsafe + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) { + return false; + } + + // backend sidebar menu icon + if (dcCore::app()->blog->settings->get(My::id())->get('active')) { + dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( + My::name(), + dcCore::app()->adminurl->get('admin.plugin.' . My::id()), + dcPage::getPF(My::id() . '/icon.svg'), + preg_match('/' . preg_quote((string) dcCore::app()->adminurl->get('admin.plugin.' . My::id())) . '(&.*)?$/', $_SERVER['REQUEST_URI']), + dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_CONTENT_ADMIN]), dcCore::app()->blog->id) + ); + // backend user dashboard favorites icon + dcCore::app()->addBehavior('adminDashboardFavoritesV2', [BackendBehaviors::class, 'adminDashboardFavoritesV2']); + } + + // backend pwt management + dcCore::app()->addBehaviors([ + // user pref + 'adminFiltersListsV2' => [BackendBehaviors::class, 'adminFiltersListsV2'], + 'adminBlogPreferencesFormV2' => [BackendBehaviors::class, 'adminBlogPreferencesFormV2'], + 'adminBeforeBlogSettingsUpdate' => [BackendBehaviors::class, 'adminBeforeBlogSettingsUpdate'], + // post + 'adminPostHeaders' => [BackendBehaviors::class, 'adminPostHeaders'], + 'adminPostFormItems' => [BackendBehaviors::class, 'adminPostFormItems'], + 'adminAfterPostUpdate' => [BackendBehaviors::class, 'adminAfterPostSave'], + 'adminAfterPostCreate' => [BackendBehaviors::class, 'adminAfterPostSave'], + 'adminBeforePostDelete' => [BackendBehaviors::class, 'adminBeforePostDelete'], + // Plugin "pages" + 'adminPageHeaders' => [BackendBehaviors::class, 'adminPostHeaders'], + 'adminPageFormItems' => [BackendBehaviors::class, 'adminPostFormItems'], + 'adminAfterPageUpdate' => [BackendBehaviors::class, 'adminAfterPostSave'], + 'adminAfterPageCreate' => [BackendBehaviors::class, 'adminAfterPostSave'], + 'adminBeforePageDelete' => [BackendBehaviors::class, 'adminBeforePostDelete'], + // widgets registration + 'initWidgets' => [Widgets::class, 'initWidgets'], + ]); + + // add plugin "importExport" features + if (!is_null(dcCore::app()->blog) && dcCore::app()->blog->settings->get(My::id())->get('importexport_active')) { + dcCore::app()->addBehaviors([ + 'exportFullV2' => [ImportExport::class, 'exportFullV2'], + 'exportSingleV2' => [ImportExport::class, 'exportSingleV2'], + 'importInitV2' => [ImportExport::class, 'importInitV2'], + 'importSingleV2' => [ImportExport::class, 'importSingleV2'], + 'importFullV2' => [ImportExport::class, 'importFullV2'], + ]); + } + + return true; + } } diff --git a/src/BackendBehaviors.php b/src/BackendBehaviors.php index d284a69..d9fa50f 100644 --- a/src/BackendBehaviors.php +++ b/src/BackendBehaviors.php @@ -10,22 +10,29 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ +declare(strict_types=1); + +namespace Dotclear\Plugin\postWidgetText; + +use ArrayObject; +use dcCore; +use dcFavorites; +use dcPage; +use dcSettings; +use Dotclear\Database\{ + Cursor, + MetaRecord +}; +use Dotclear\Helper\Html\Html; + +use form; + /** - * @ingroup DC_PLUGIN_POSTWIDGETTEXT - * @brief postWidgetText - admin methods. - * @since 2.20 + * Backend behaviors. */ -class adminPostWidgetText +class BackendBehaviors { - private static $ie_cursor; - private static $ie_pwt; - - private static function id() - { - return basename(dirname(__DIR__)); - } - - public static function sortbyCombo() + public static function sortbyCombo(): array { return [ __('Post title') => 'post_title', @@ -35,7 +42,7 @@ class adminPostWidgetText ]; } - public static function adminFiltersListsV2($sorts) + public static function adminFiltersListsV2(ArrayObject $sorts): void { $sorts['pwt'] = [ __('Post widget text'), @@ -46,7 +53,7 @@ class adminPostWidgetText ]; } - public static function adminBlogPreferencesFormV2(dcSettings $blog_settings) + public static function adminBlogPreferencesFormV2(dcSettings $blog_settings): void { echo '
@@ -54,12 +61,12 @@ class adminPostWidgetText

@@ -67,52 +74,59 @@ class adminPostWidgetText
'; } - public static function adminBeforeBlogSettingsUpdate(dcSettings $blog_settings) + public static function adminBeforeBlogSettingsUpdate(dcSettings $blog_settings): void { - $blog_settings->get(self::id())->put('active', !empty($_POST['active'])); - $blog_settings->get(self::id())->put('importexport_active', !empty($_POST['importexport_active'])); + $blog_settings->get(My::id())->put('active', !empty($_POST['active'])); + $blog_settings->get(My::id())->put('importexport_active', !empty($_POST['importexport_active'])); } - public static function adminDashboardFavoritesV2(dcFavorites $favs) + public static function adminDashboardFavoritesV2(dcFavorites $favs): void { - $favs->register(self::id(), [ + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->adminurl)) { + return; + } + + $favs->register(My::id(), [ 'title' => __('Post widget text'), - 'url' => dcCore::app()->adminurl->get('admin.plugin.' . self::id()), - 'small-icon' => dcPage::getPF(self::id() . '/icon.svg'), - 'large-icon' => dcPage::getPF(self::id() . '/icon.svg'), + 'url' => dcCore::app()->adminurl->get('admin.plugin.' . My::id()), + 'small-icon' => dcPage::getPF(My::id() . '/icon.svg'), + 'large-icon' => dcPage::getPF(My::id() . '/icon.svg'), 'permissions' => dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, ]), ]); } - public static function adminPostHeaders() + public static function adminPostHeaders(): string { + if (is_null(dcCore::app()->auth)) { + return ''; + } + $editor = dcCore::app()->auth->getOption('editor'); return dcCore::app()->callBehavior('adminPostEditor', $editor['xhtml'], 'pwt', ['#post_wtext'], 'xhtml') . - dcPage::jsModuleLoad(self::id() . '/js/post.js'); + dcPage::jsModuleLoad(My::id() . '/js/backend.js'); } - public static function adminPostFormItems($main, $sidebar, $post) + public static function adminPostFormItems(ArrayObject $main, ArrayObject $sidebar, ?MetaRecord $post): void { # _POST fields $title = $_POST['post_wtitle'] ?? ''; $content = $_POST['post_wtext'] ?? ''; # Existing post - if ($post) { - $post_id = (int) $post->post_id; + if (!is_null($post)) { + $post_id = (int) $post->f('post_id'); - $pwt = new postWidgetText(); - $w = $pwt->getWidgets(['post_id' => $post_id]); + $w = Utils::getWidgets(['post_id' => $post_id]); # Existing widget if (!$w->isEmpty()) { - $title = $w->option_title; - $content = $w->option_content; + $title = $w->f('option_title'); + $content = $w->f('option_content'); } } @@ -121,157 +135,60 @@ class adminPostWidgetText '

' . '' . - form::field('post_wtitle', 20, 255, html::escapeHTML($title), 'maximal') . + form::field('post_wtitle', 20, 255, Html::escapeHTML($title), 'maximal') . '

' . '

' . '' . - form::textarea('post_wtext', 50, 5, html::escapeHTML($content)) . + form::textarea('post_wtext', 50, 5, Html::escapeHTML($content)) . '

' . ''; } - public static function adminAfterPostSave($cur, $post_id) + public static function adminAfterPostSave(Cursor $cur, int $post_id): void { - $post_id = (int) $post_id; - # _POST fields $title = $_POST['post_wtitle'] ?? ''; $content = $_POST['post_wtext'] ?? ''; - # Object - $pwt = new postWidgetText(); - # Get existing widget - $w = $pwt->getWidgets(['post_id' => $post_id]); + $w = Utils::getWidgets(['post_id' => (int) $post_id]); # If new content is empty, delete old existing widget if (empty($title) && empty($content) && !$w->isEmpty()) { - $pwt->delWidget($w->option_id); + Utils::delWidget((int) $w->f('option_id')); } # If new content is not empty if (!empty($title) || !empty($content)) { - $wcur = $pwt->openCursor(); - $wcur->post_id = $post_id; - $wcur->option_type = self::id(); - $wcur->option_lang = $cur->post_lang; - $wcur->option_format = $cur->post_format; - $wcur->option_title = $title; - $wcur->option_content = $content; + $wcur = Utils::openCursor(); + $wcur->setField('post_id', (int) $post_id); + $wcur->setField('option_type', My::id()); + $wcur->setField('option_lang', $cur->getField('post_lang')); + $wcur->setField('option_format', $cur->getField('post_format')); + $wcur->setField('option_title', $title); + $wcur->setField('option_content', $content); # Create widget if ($w->isEmpty()) { - $id = $pwt->addWidget($wcur); + $id = Utils::addWidget($wcur); } # Upddate widget else { - $pwt->updWidget($w->option_id, $wcur); + Utils::updWidget($w->f('option_id'), $wcur); } } } - public static function adminBeforePostDelete($post_id) + public static function adminBeforePostDelete(int $post_id): void { - $post_id = (int) $post_id; - - # Object - $pwt = new postWidgetText(); - # Get existing widget - $w = $pwt->getWidgets(['post_id' => $post_id]); + $w = Utils::getWidgets(['post_id' => (int) $post_id]); # If new content is empty, delete old existing widget if (!$w->isEmpty()) { - $pwt->delWidget($w->option_id); - } - } - - public static function exportSingleV2($exp, $blog_id) - { - $exp->export( - self::id(), - 'SELECT option_type, option_content, ' . - 'option_content_xhtml, W.post_id ' . - 'FROM ' . dcCore::app()->prefix . initPostWidgetText::PWT_TABLE_NAME . ' W ' . - 'LEFT JOIN ' . dcCore::app()->prefix . dcBlog::POST_TABLE_NAME . ' P ' . - 'ON P.post_id = W.post_id ' . - "WHERE P.blog_id = '" . $blog_id . "' " . - "AND W.option_type = '" . dcCore::app()->con->escape(self::id()) . "' " - ); - } - - public static function exportFullV2($exp) - { - $exp->export( - self::id(), - 'SELECT option_type, option_content, ' . - 'option_content_xhtml, W.post_id ' . - 'FROM ' . dcCore::app()->prefix . initPostWidgetText::PWT_TABLE_NAME . ' W ' . - 'LEFT JOIN ' . dcCore::app()->prefix . dcBlog::POST_TABLE_NAME . ' P ' . - 'ON P.post_id = W.post_id ' . - "WHERE W.option_type = '" . dcCore::app()->con->escape(self::id()) . "' " - ); - } - - public static function importInitV2($bk) - { - self::$ie_cursor = dcCore::app()->con->openCursor( - dcCore::app()->prefix . initPostWidgetText::PWT_TABLE_NAME - ); - self::$ie_pwt = new postWidgetText(); - } - - public static function importSingleV2($line, $bk) - { - if ($line->__name == self::id() - && isset($bk->old_ids['post'][(int) $line->post_id]) - ) { - $line->post_id = $bk->old_ids['post'][(int) $line->post_id]; - - $exists = self::$ie_pwt->getWidgets([ - 'post_id' => $line->post_id, - ]); - - if ($exists->isEmpty()) { - self::$ie_cursor->clean(); - - self::$ie_cursor->post_id = (int) $line->post_id; - self::$ie_cursor->option_type = (string) $line->option_type; - self::$ie_cursor->option_lang = (string) $line->option_lang; - self::$ie_cursor->option_format = (string) $line->option_format; - self::$ie_cursor->option_content = (string) $line->option_content; - self::$ie_cursor->option_content_xhtml = (string) $line->option_content_xhtml; - - self::$ie_pwt->addWidget( - self::$ie_cursor - ); - } - } - } - - public static function importFullV2($line, $bk) - { - if ($line->__name == self::id()) { - $exists = self::$ie_pwt->getWidgets([ - 'post_id' => $line->post_id, - ]); - - if ($exists->isEmpty()) { - self::$ie_cursor->clean(); - - self::$ie_cursor->post_id = (int) $line->post_id; - self::$ie_cursor->option_type = (string) $line->option_type; - self::$ie_cursor->option_format = (string) $line->option_format; - self::$ie_cursor->option_content = (string) $line->option_content; - self::$ie_cursor->option_content = (string) $line->option_content; - self::$ie_cursor->option_content_xhtml = (string) $line->option_content_xhtml; - - self::$ie_pwt->addWidget( - self::$ie_cursor - ); - } + Utils::delWidget($w->f('option_id')); } } } diff --git a/src/Frontend.php b/src/Frontend.php index 95729b9..d12699b 100644 --- a/src/Frontend.php +++ b/src/Frontend.php @@ -10,8 +10,30 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return null; -} +declare(strict_types=1); -require __DIR__ . '/_widgets.php'; +namespace Dotclear\Plugin\postWidgetText; + +use dcCore; +use dcNsProcess; + +class Frontend extends dcNsProcess +{ + public static function init(): bool + { + static::$init = My::phpCompliant(); + + return static::$init; + } + + public static function process(): bool + { + if (!static::$init) { + return false; + } + + dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initWidgets']); + + return true; + } +} diff --git a/src/ImportExport.php b/src/ImportExport.php new file mode 100644 index 0000000..2f46b85 --- /dev/null +++ b/src/ImportExport.php @@ -0,0 +1,112 @@ +export( + My::id(), + 'SELECT option_type, option_content, ' . + 'option_content_xhtml, W.post_id ' . + 'FROM ' . dcCore::app()->prefix . My::TABLE_NAME . ' W ' . + 'LEFT JOIN ' . dcCore::app()->prefix . dcBlog::POST_TABLE_NAME . ' P ' . + 'ON P.post_id = W.post_id ' . + "WHERE P.blog_id = '" . $blog_id . "' " . + "AND W.option_type = '" . dcCore::app()->con->escapeStr((string) My::id()) . "' " + ); + } + + public static function exportFullV2($exp) + { + $exp->export( + My::id(), + 'SELECT option_type, option_content, ' . + 'option_content_xhtml, W.post_id ' . + 'FROM ' . dcCore::app()->prefix . My::TABLE_NAME . ' W ' . + 'LEFT JOIN ' . dcCore::app()->prefix . dcBlog::POST_TABLE_NAME . ' P ' . + 'ON P.post_id = W.post_id ' . + "WHERE W.option_type = '" . dcCore::app()->con->escapeStr((string) My::id()) . "' " + ); + } + + public static function importInitV2($bk) + { + self::$ie_cursor = dcCore::app()->con->openCursor( + dcCore::app()->prefix . My::TABLE_NAME + ); + } + + public static function importSingleV2($line, $bk) + { + if ($line->__name == My::id() + && isset($bk->old_ids['post'][(int) $line->post_id]) + ) { + $line->post_id = $bk->old_ids['post'][(int) $line->post_id]; + + $exists = Utils::getWidgets([ + 'post_id' => $line->post_id, + ]); + + if ($exists->isEmpty()) { + self::$ie_cursor->clean(); + + self::$ie_cursor->post_id = (int) $line->post_id; + self::$ie_cursor->option_type = (string) $line->option_type; + self::$ie_cursor->option_lang = (string) $line->option_lang; + self::$ie_cursor->option_format = (string) $line->option_format; + self::$ie_cursor->option_content = (string) $line->option_content; + self::$ie_cursor->option_content_xhtml = (string) $line->option_content_xhtml; + + Utils::addWidget( + self::$ie_cursor + ); + } + } + } + + public static function importFullV2($line, $bk) + { + if ($line->__name == My::id()) { + $exists = Utils::getWidgets([ + 'post_id' => $line->post_id, + ]); + + if ($exists->isEmpty()) { + self::$ie_cursor->clean(); + + self::$ie_cursor->post_id = (int) $line->post_id; + self::$ie_cursor->option_type = (string) $line->option_type; + self::$ie_cursor->option_format = (string) $line->option_format; + self::$ie_cursor->option_content = (string) $line->option_content; + self::$ie_cursor->option_content = (string) $line->option_content; + self::$ie_cursor->option_content_xhtml = (string) $line->option_content_xhtml; + + Utils::addWidget( + self::$ie_cursor + ); + } + } + } +} diff --git a/src/Install.php b/src/Install.php index b97de70..4c1856c 100644 --- a/src/Install.php +++ b/src/Install.php @@ -10,90 +10,82 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -try { - // check installed version - if (!dcCore::app()->newVersion( - basename(__DIR__), - dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version') - )) { - return null; +namespace Dotclear\Plugin\postWidgetText; + +use dcCore; +use dcNsProcess; +use Dotclear\Database\Structure; +use Exception; + +class Install extends dcNsProcess +{ + public static function init(): bool + { + static::$init = defined('DC_CONTEXT_ADMIN') + && My::phpCompliant() + && dcCore::app()->newVersion(My::id(), dcCore::app()->plugins->moduleInfo(My::id(), 'version')); + + return static::$init; } - // Table is the same for plugins pollsFactory, postTask, postWidgetText - $st = new dbStruct(dcCore::app()->con, dcCore::app()->prefix); - $st->{initPostWidgetText::PWT_TABLE_NAME} - ->option_id('bigint', 0, false) - ->post_id('bigint', 0, false) - ->option_creadt('timestamp', 0, false, 'now()') - ->option_upddt('timestamp', 0, false, 'now()') - ->option_type('varchar', 32, false, "''") - ->option_format('varchar', 32, false, "'xhtml'") - ->option_lang('varchar', 5, true, null) - ->option_title('varchar', 255, true, null) - ->option_content('text', 0, true, null) - ->option_content_xhtml('text', 0, false) - - ->index('idx_post_option_option', 'btree', 'option_id') - ->index('idx_post_option_post', 'btree', 'post_id') - ->index('idx_post_option_type', 'btree', 'option_type'); - - $si = new dbStruct(dcCore::app()->con, dcCore::app()->prefix); - $changes = $si->synchronize($st); - - $current = dcCore::app()->getVersion(basename(__DIR__)); - - // Update settings id, ns - if ($current && version_compare($current, '2022.12.23', '<=')) { - $record = dcCore::app()->con->select( - 'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' . - "WHERE setting_ns = 'postwidgettext' " - ); - - while ($record->fetch()) { - if (preg_match('/^postwidgettext_(.*?)$/', $record->setting_id, $match)) { - $cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME); - $cur->setting_id = $match[1]; - $cur->setting_ns = basename(__DIR__); - $cur->update( - "WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'postwidgettext' " . - 'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escape($record->blog_id) . "' ")) - ); - } + public static function process(): bool + { + if (!static::$init) { + return false; } - } else { - // Settings - dcCore::app()->blog->settings->get(basename(__DIR__))->put( - 'active', - true, - 'boolean', - 'post widget text plugin enabled', - false, - true - ); - dcCore::app()->blog->settings->get(basename(__DIR__))->put( - 'importexport_active', - true, - 'boolean', - 'activate import/export behaviors', - false, - true - ); - } - # Transfert records from old table to the new one - if (dcCore::app()->getVersion(basename(__DIR__)) !== null - && version_compare(dcCore::app()->getVersion(basename(__DIR__)), '0.5', '<') - ) { - require_once __DIR__ . '/inc/patch.0.5.php'; - } + // nullsafe + if (is_null(dcCore::app()->blog)) { + return false; + } - return true; -} catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); + try { + // Table is the same for plugins pollsFactory, postTask, postWidgetText + $s = new Structure(dcCore::app()->con, dcCore::app()->prefix); + $s->__get(My::TABLE_NAME) + ->field('option_id', 'bigint', 0, false) + ->field('post_id', 'bigint', 0, false) + ->field('option_creadt', 'timestamp', 0, false, 'now()') + ->field('option_upddt', 'timestamp', 0, false, 'now()') + ->field('option_type', 'varchar', 32, false, "''") + ->field('option_format', 'varchar', 32, false, "'xhtml'") + ->field('option_lang', 'varchar', 5, true, null) + ->field('option_title', 'varchar', 255, true, null) + ->field('option_content', 'text', 0, true, null) + ->field('option_content_xhtml', 'text', 0, false) + + ->index('idx_post_option_option', 'btree', 'option_id') + ->index('idx_post_option_post', 'btree', 'post_id') + ->index('idx_post_option_type', 'btree', 'option_type'); + + (new Structure(dcCore::app()->con, dcCore::app()->prefix))->synchronize($s); + + // Settings + $s = dcCore::app()->blog->settings->get(My::id()); + $s->put( + 'active', + true, + 'boolean', + 'post widget text plugin enabled', + false, + true + ); + $s->put( + 'importexport_active', + true, + 'boolean', + 'activate import/export behaviors', + false, + true + ); + + return true; + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + + return false; + } + } } - -return false; diff --git a/src/Manage.php b/src/Manage.php index 78e72cb..6840b0c 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -10,84 +10,129 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -dcPage::check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, -])); +namespace Dotclear\Plugin\postWidgetText; -$pwt = new postWidgetText(); +use dcAdminFilters; +use adminGenericFilterV2; +use dcCore; +use dcNsProcess; +use dcPage; +use Dotclear\Helper\Network\Http; +use Exception; -# Delete widgets -if (!empty($_POST['save']) && !empty($_POST['widgets'])) { - try { - foreach ($_POST['widgets'] as $k => $id) { - $id = (int) $id; - $pwt->delWidget($id); +use form; + +class Manage extends dcNsProcess +{ + public static function init(): bool + { + static::$init = defined('DC_CONTEXT_ADMIN') + && My::phpCompliant() + && !is_null(dcCore::app()->auth) && !is_null(dcCore::app()->blog) + && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog->id); + + return static::$init; + } + + public static function process(): bool + { + if (!static::$init) { + return false; } - dcAdminNotices::addSuccessNotice( - __('Posts widgets successfully delete.') + // nullsafe check + if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) { + return false; + } + + # Delete widgets + if (!empty($_POST['save']) && !empty($_POST['widgets'])) { + try { + foreach ($_POST['widgets'] as $k => $id) { + Utils::delWidget((int) $id); + } + + dcPage::addSuccessNotice( + __('Posts widgets successfully delete.') + ); + if (!empty($_POST['redir'])) { + Http::redirect($_POST['redir']); + } else { + dcCore::app()->adminurl->redirect('admin.plugin.' . My::id()); + } + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + } + + return true; + } + + public static function render(): void + { + if (!static::$init) { + return; + } + + // nullsafe check + if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) { + return; + } + + # filters + $filter = new adminGenericFilterV2('pwt'); + $filter->add(dcAdminFilters::getPageFilter()); + $params = $filter->params(); + + # Get posts with text widget + try { + $posts = Utils::getWidgets($params); + $counter = Utils::getWidgets($params, true); + $posts_list = new ManageList($posts, $counter->f(0)); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + $posts_list = null; + } + + // display + dcPage::openModule( + My::name(), + dcPage::jsPageTabs() . + dcPage::jsModuleLoad(My::id() . '/js/manage.js') . + $filter->js(dcCore::app()->adminurl->get('admin.plugin.' . My::id()) . '#record') ); - if (!empty($_POST['redir'])) { - http::redirect($_POST['redir']); - } else { - dcCore::app()->adminurl->redirect('admin.plugin.' . basename(__DIR__)); + + echo + dcPage::breadcrumb([ + __('Plugins') => '', + My::name() => '', + ]) . + dcPage::notices(); + + if ($posts_list) { + $filter->display('admin.plugin.' . My::id(), form::hidden('p', My::id())); + + $posts_list->display( + (int) $filter->value('page'), + (int) $filter->value('nb'), + '
' . + '%s' . + '
' . + '

' . + '

' . + '

' . + dcCore::app()->adminurl->getHiddenFormFields('admin.plugin.' . My::id(), array_merge(['p' => My::id()], $filter->values(true))) . + dcCore::app()->formNonce() . + '
' . + '
' + ); } - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); + + dcPage::closeModule(); } } - -# filters -$filter = new adminGenericFilter(dcCore::app(), 'pwt'); -$filter->add(dcAdminFilters::getPageFilter()); -$params = $filter->params(); - -# Get posts with text widget -try { - $posts = $pwt->getWidgets($params); - $counter = $pwt->getWidgets($params, true); - $posts_list = new listPostWidgetText(dcCore::app(), $posts, $counter->f(0)); -} catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - $posts_list = null; -} - -# Display -echo ' -' . __('Post widget text') . '' . -dcPage::jsModuleLoad(basename(__DIR__) . '/js/index.js') . -$filter->js(dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__))) . ' - -' . - -dcPage::breadcrumb([ - __('Plugins') => '', - __('Posts widgets') => '', -]) . -dcPage::notices(); - -if ($posts_list) { - $filter->display('admin.plugin.' . basename(__DIR__), form::hidden('p', basename(__DIR__))); - - $posts_list->display( - $filter->page, - $filter->nb, - '
' . - '%s' . - '
' . - '

' . - '

' . - '

' . - dcCore::app()->adminurl->getHiddenFormFields('admin.plugin.' . basename(__DIR__), array_merge(['p' => basename(__DIR__)], $filter->values(true))) . - dcCore::app()->formNonce() . - '
' . - '
' - ); -} - -echo ''; diff --git a/src/ManageList.php b/src/ManageList.php index 9f33a0b..cf52dd4 100644 --- a/src/ManageList.php +++ b/src/ManageList.php @@ -10,24 +10,33 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); + +namespace Dotclear\Plugin\postWidgetText; + +use adminGenericListV2; +use context; +use dcCore; +use dcPager; +use Dotclear\Helper\Date; +use Dotclear\Helper\Html\Html; + +use form; /** * @ingroup DC_PLUGIN_POSTWIDGETTEXT * @brief postWidgetText - admin list methods. * @since 2.6 */ -class listPostWidgetText extends adminGenericList +class ManageList extends adminGenericListV2 { - public function display($page, $nb_per_page, $enclose = '') + public function display(int $page, int $nb_per_page, string $enclose = ''): void { if ($this->rs->isEmpty()) { - return '

' . __('No widget') . '

'; + echo '

' . __('No widget') . '

'; } - $pager = new dcPager($page, $this->rs_count, $nb_per_page, 10); + $pager = new dcPager($page, (int) $this->rs_count, $nb_per_page, 10); $pager->html_prev = $this->html_prev; $pager->html_next = $this->html_next; $pager->var_page = 'page'; @@ -45,7 +54,7 @@ class listPostWidgetText extends adminGenericList ''; while ($this->rs->fetch()) { - $w_title = html::escapeHTML($this->rs->option_title); + $w_title = Html::escapeHTML($this->rs->option_title); if ($w_title == '') { $w_title = '' . context::global_filters( $this->rs->option_content, @@ -75,14 +84,14 @@ class listPostWidgetText extends adminGenericList $this->rs->post_type, $this->rs->post_id ) . '#post-wtext-form">' . - html::escapeHTML($this->rs->post_title) . + Html::escapeHTML($this->rs->post_title) . '' . - '' . dt::dt2str( + '' . Date::dt2str( __('%Y-%m-%d %H:%M'), $this->rs->post_dt ) . '' . '' . $w_title . '' . - '' . dt::dt2str( + '' . Date::dt2str( __('%Y-%m-%d %H:%M'), $this->rs->option_upddt ) . '' . diff --git a/src/My.php b/src/My.php new file mode 100644 index 0000000..5f6fe7c --- /dev/null +++ b/src/My.php @@ -0,0 +1,53 @@ +plugins->moduleInfo(self::id(), 'name')); + } + + /** + * Check php version + */ + public static function phpCompliant(): bool + { + return version_compare(phpversion(), self::PHP_MIN, '>='); + } +} diff --git a/src/Utils.php b/src/Utils.php index 128a1f7..f904425 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -10,55 +10,37 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return null; -} +declare(strict_types=1); + +namespace Dotclear\Plugin\postWidgetText; + +use dcCore; +use Dotclear\Database\{ + Cursor, + MetaRecord, + Structure +}; + +use Exception; /** * @ingroup DC_PLUGIN_POSTWIDGETTEXT * @brief postWidgetText - admin and public methods. * @since 2.6 */ -class postWidgetText +class Utils { - public $con; - private $table; - private $blog; - - public function __construct() + public static function openCursor(): Cursor { - $this->con = dcCore::app()->con; - $this->table = dcCore::app()->prefix . initPostWidgetText::PWT_TABLE_NAME; - $this->blog = dcCore::app()->con->escape(dcCore::app()->blog->id); + return dcCore::app()->con->openCursor(dcCore::app()->prefix . My::TABLE_NAME); } - public function tableName() + public static function getWidgets(array $params, bool $count_only = false): MetaRecord { - return $this->table; - } + if (is_null(dcCore::app()->blog)) { + throw new Exception('blog is not set'); + } - public function openCursor() - { - return $this->con->openCursor($this->table); - } - - public function lockTable() - { - $this->con->writeLock($this->table); - } - - public function unlockTable() - { - $this->con->unlock(); - } - - public function triggerBlog() - { - dcCore::app()->blog->triggerBlog(); - } - - public function getWidgets($params, $count_only = false) - { if (!isset($params['columns'])) { $params['columns'] = []; } @@ -75,15 +57,15 @@ class postWidgetText if (!isset($params['from'])) { $params['from'] = ''; } - $params['join'] = 'LEFT JOIN ' . $this->table . ' W ON P.post_id=W.post_id '; + $params['join'] = 'LEFT JOIN ' . dcCore::app()->prefix . My::TABLE_NAME . ' W ON P.post_id=W.post_id '; if (!isset($params['sql'])) { $params['sql'] = ''; } if (isset($params['option_type'])) { - $params['sql'] .= "AND W.option_type = '" . $this->con->escape($params['option_type']) . "' "; + $params['sql'] .= "AND W.option_type = '" . dcCore::app()->con->escapeStr((string) $params['option_type']) . "' "; } else { - $params['sql'] .= "AND W.option_type = '" . $this->con->escape(basename(dirname(__DIR__))) . "' "; + $params['sql'] .= "AND W.option_type = '" . dcCore::app()->con->escapeStr((string) My::id()) . "' "; } unset($params['option_type']); if (!isset($params['post_type'])) { @@ -93,51 +75,59 @@ class postWidgetText return dcCore::app()->blog->getPosts($params, $count_only); } - public function addWidget($cur) + public static function addWidget(Cursor $cur): int { + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog)) { + throw new Exception('blog is not set'); + } + if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, - ]), $this->blog)) { + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog->id)) { throw new Exception(__('You are not allowed to create an entry text widget')); } if ($cur->post_id == '') { throw new Exception('No such entry ID'); } - $this->lockTable(); + dcCore::app()->con->writeLock(dcCore::app()->prefix . My::TABLE_NAME); try { - $rs = $this->con->select( + $rs = dcCore::app()->con->select( 'SELECT MAX(option_id) ' . - 'FROM ' . $this->table + 'FROM ' . dcCore::app()->prefix . My::TABLE_NAME ); $cur->option_id = (int) $rs->f(0) + 1; $cur->option_creadt = date('Y-m-d H:i:s'); $cur->option_upddt = date('Y-m-d H:i:s'); - $this->getWidgetContent($cur, $cur->option_id); + self::getWidgetContent($cur, (int) $cur->option_id); $cur->insert(); - $this->unlockTable(); + dcCore::app()->con->unlock(); } catch (Exception $e) { - $this->unlockTable(); + dcCore::app()->con->unlock(); throw $e; } - $this->triggerBlog(); + dcCore::app()->blog->triggerBlog(); - return $cur->option_id; + return (int) $cur->option_id; } - public function updWidget($id, &$cur) + public static function updWidget(int $id, Cursor $cur): void { + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog)) { + throw new Exception('blog is not set'); + } + if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, - ]), $this->blog)) { + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog->id)) { throw new Exception(__('You are not allowed to update entries text widget')); } @@ -147,17 +137,17 @@ class postWidgetText throw new Exception(__('No such ID')); } - $this->getWidgetContent($cur, $id); + self::getWidgetContent($cur, $id); $cur->option_upddt = date('Y-m-d H:i:s'); - if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_CONTENT_ADMIN]), $this->blog)) { + if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_CONTENT_ADMIN]), dcCore::app()->blog->id)) { $params['option_id'] = $id; - $params['user_id'] = $this->con->escape(dcCore::app()->auth->userID()); + $params['user_id'] = dcCore::app()->con->escapeStr((string) dcCore::app()->auth->userID()); $params['no_content'] = true; $params['limit'] = 1; - $rs = $this->getWidgets($params); + $rs = self::getWidgets($params); if ($rs->isEmpty()) { throw new Exception(__('You are not allowed to delete this entry text widget')); @@ -165,65 +155,52 @@ class postWidgetText } $cur->update('WHERE option_id = ' . $id . ' '); - $this->triggerBlog(); + dcCore::app()->blog->triggerBlog(); } - public function delWidget($id, $type = '') + public static function delWidget(int $id, ?string $type = null): void { + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog)) { + throw new Exception('blog is not set'); + } + if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_DELETE, - dcAuth::PERMISSION_CONTENT_ADMIN, - ]), $this->blog)) { + dcCore::app()->auth::PERMISSION_DELETE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog->id)) { throw new Exception(__('You are not allowed to delete entries text widget')); } $id = (int) $id; - $type ??= basename(__DIR__); + $type ??= My::id(); if (empty($id)) { throw new Exception(__('No such ID')); } - if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_CONTENT_ADMIN]), $this->blog)) { + if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_CONTENT_ADMIN]), dcCore::app()->blog->id)) { $params['option_id'] = $id; - $params['user_id'] = $this->con->escape(dcCore::app()->auth->userID()); + $params['user_id'] = dcCore::app()->con->escapeStr((string) dcCore::app()->auth->userID()); $params['no_content'] = true; $params['limit'] = 1; - $rs = $this->getWidgets($params); + $rs = self::getWidgets($params); if ($rs->isEmpty()) { throw new Exception(__('You are not allowed to delete this entry text widget')); } } - $this->con->execute( - 'DELETE FROM ' . $this->table . ' ' . + dcCore::app()->con->execute( + 'DELETE FROM ' . dcCore::app()->prefix . My::TABLE_NAME . ' ' . 'WHERE option_id = ' . $id . ' ' . - "AND option_type = '" . $this->con->escape($type) . "' " + "AND option_type = '" . dcCore::app()->con->escapeStr((string) $type) . "' " ); - $this->triggerBlog(); + dcCore::app()->blog->triggerBlog(); } - private function getWidgetContent(&$cur, $option_id) - { - $option_content = $cur->option_content; - $option_content_xhtml = $cur->option_content_xhtml; - - $this->setWidgetContent( - $option_id, - $cur->option_format, - $cur->option_lang, - $option_content, - $option_content_xhtml - ); - - $cur->option_content = $option_content; - $cur->option_content_xhtml = $option_content_xhtml; - } - - public function setWidgetContent($option_id, $format, $lang, &$content, &$content_xhtml) + public static function setWidgetContent(int $option_id, string $format, string $lang, ?string &$content, ?string &$content_xhtml): void { if ($format == 'wiki') { dcCore::app()->initWikiPost(); @@ -250,4 +227,21 @@ class postWidgetText 'content_xhtml' => &$content_xhtml, ]); } + + private static function getWidgetContent(Cursor $cur, int $option_id): void + { + $option_content = $cur->option_content; + $option_content_xhtml = $cur->option_content_xhtml; + + self::setWidgetContent( + $option_id, + $cur->option_format, + $cur->option_lang, + $option_content, + $option_content_xhtml + ); + + $cur->option_content = $option_content; + $cur->option_content_xhtml = $option_content_xhtml; + } } diff --git a/src/Widgets.php b/src/Widgets.php index 39ea547..f53d3ea 100644 --- a/src/Widgets.php +++ b/src/Widgets.php @@ -10,26 +10,34 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return null; -} +declare(strict_types=1); -dcCore::app()->addBehavior('initWidgets', ['postWidgetTextWidget', 'init']); +namespace Dotclear\Plugin\postWidgetText; + +use dcCore; +use Dotclear\Helper\Html\Html; +use Dotclear\Plugin\widgets\WidgetsStack; +use Dotclear\Plugin\widgets\WidgetsElement; /** * @ingroup DC_PLUGIN_POSTWIDGETTEXT * @brief postWidgetText - admin and public widget methods. * @since 2.6 */ -class postWidgetTextWidget +class Widgets { - public static function init($w) + /** + * Widget initialisation. + * + * @param WidgetsStack $w WidgetsStack instance + */ + public static function initWidgets(WidgetsStack $w): void { $w ->create( basename(__DIR__), __('Post widget text'), - ['postWidgetTextWidget', 'display'], + [self::class, 'parseWidget'], null, __('Add a widget with a text related to an entry') ) @@ -51,41 +59,46 @@ class postWidgetTextWidget ->addOffline(); } - public static function display($w) + /** + * Parse widget. + * + * @param WidgetsElement $w WidgetsElement instance + */ + public static function parseWidget(WidgetsElement $w): string { - if ($w->offline - || !dcCore::app()->blog->settings->get(basename(__DIR__))->get('active') + if (is_null(dcCore::app()->blog) + || is_null(dcCore::app()->ctx) + || $w->__get('offline') + || !dcCore::app()->blog->settings->get(My::id())->get('active') || !dcCore::app()->ctx->exists('posts') - || !dcCore::app()->ctx->__get('posts')->post_id + || !dcCore::app()->ctx->__get('posts')->f('post_id') ) { - return null; + return ''; } - $title = $w->title ?: null; + $title = $w->__get('title') ?: null; $content = ''; - $pwt = new postWidgetText(); - $rs = $pwt->getWidgets(['post_id' => dcCore::app()->ctx->__get('posts')->post_id]); - + $rs = Utils::getWidgets(['post_id' => dcCore::app()->ctx->__get('posts')->f('post_id')]); if ($rs->isEmpty()) { - return null; + return ''; } - if ('' != $rs->option_title) { - $title = $rs->option_title; + if ('' != $rs->f('option_title')) { + $title = $rs->f('option_title'); } - if ('' != $rs->option_content_xhtml) { - $content = $rs->option_content_xhtml; + if ('' != $rs->f('option_content_xhtml')) { + $content = $rs->f('option_content_xhtml'); } - if ('' == $content && $w->excerpt) { - $content = dcCore::app()->ctx->__get('posts')->post_excerpt_xhtml; + if ('' == $content && $w->__get('excerpt')) { + $content = dcCore::app()->ctx->__get('posts')->f('post_excerpt_xhtml'); } return $w->renderDiv( - $w->content_only, - basename(__DIR__) . ' ' . $w->class, + (bool) $w->__get('content_only'), + My::id() . ' ' . $w->__get('class'), '', - ($title ? $w->renderTitle(html::escapeHTML($title)) : '') . $content + ($title ? $w->renderTitle(Html::escapeHTML($title)) : '') . $content ); } }