From 558c99dd3b29b37882343e1314f6b5117fe4ad4c Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Sun, 23 Apr 2023 00:14:18 +0200 Subject: [PATCH] big code review (helper, statement, doc) --- src/Backend.php | 21 ++- src/BackendBehaviors.php | 155 ++++++++-------- src/Dater.php | 37 +++- src/Frontend.php | 28 +-- src/Install.php | 31 ++-- src/Manage.php | 34 ++-- src/ManageList.php | 65 ++++--- src/ManagePeriod.php | 63 ++++--- src/ManageVars.php | 42 ++++- src/Utils.php | 375 +++++++++++++++++++++++---------------- 10 files changed, 512 insertions(+), 339 deletions(-) diff --git a/src/Backend.php b/src/Backend.php index 2f750cd..0646c44 100644 --- a/src/Backend.php +++ b/src/Backend.php @@ -15,7 +15,6 @@ declare(strict_types=1); namespace Dotclear\Plugin\periodical; use dcAdmin; -use dcAuth; use dcCore; use dcNsProcess; use dcPage; @@ -26,9 +25,10 @@ class Backend extends dcNsProcess { static::$init == defined('DC_CONTEXT_ADMIN') && My::phpCompliant() + && !is_null(dcCore::app()->blog) && !is_null(dcCore::app()->auth) && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, ]), dcCore::app()->blog->id); return static::$init; @@ -40,6 +40,7 @@ class Backend extends dcNsProcess return false; } + // register backend behaviors dcCore::app()->addBehaviors([ 'adminBlogPreferencesFormV2' => [BackendBehaviors::class, 'adminBlogPreferencesForm'], 'adminBeforeBlogSettingsUpdate' => [BackendBehaviors::class, 'adminBeforeBlogSettingsUpdate'], @@ -50,18 +51,20 @@ class Backend extends dcNsProcess 'adminBeforePostDelete' => [BackendBehaviors::class, 'adminBeforePostDelete'], ]); - if (dcCore::app()->blog->settings->get(My::id())->get('periodical_active')) { + if (dcCore::app()->blog?->settings->get(My::id())->get('periodical_active')) { + // add backend sidebar icon dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( My::name(), - dcCore::app()->adminurl->get('admin.plugin.' . My::id()), + dcCore::app()->adminurl?->get('admin.plugin.' . My::id()), dcPage::getPF(My::id() . '/icon.svg'), - preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . My::id())) . '(&.*)?$/', $_SERVER['REQUEST_URI']), - dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, + 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_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, ]), dcCore::app()->blog->id) ); + // register bakend behaviors required user permissions dcCore::app()->addBehaviors([ 'adminDashboardFavoritesV2' => [BackendBehaviors::class, 'adminDashboardFavoritesV2'], 'adminPostHeaders' => [BackendBehaviors::class, 'adminPostHeaders'], diff --git a/src/BackendBehaviors.php b/src/BackendBehaviors.php index 625f6d1..989b688 100644 --- a/src/BackendBehaviors.php +++ b/src/BackendBehaviors.php @@ -15,14 +15,15 @@ declare(strict_types=1); namespace Dotclear\Plugin\periodical; use ArrayObject; -use cursor; -use dcAuth; use dcCore; use dcFavorites; use dcPage; use dcPostsActions; -use dcRecord; use dcSettings; +use Dotclear\Database\{ + Cursor, + MetaRecord +}; use Dotclear\Helper\Html\Form\{ Checkbox, Div, @@ -47,9 +48,9 @@ class BackendBehaviors private static array $combo_period = []; /** - * Add settings to blog preference + * Add settings to blog preference. * - * @param dcSettings $blog_settings dcSettings instance + * @param dcSettings $blog_settings dcSettings instance */ public static function adminBlogPreferencesForm(dcSettings $blog_settings): void { @@ -81,9 +82,9 @@ class BackendBehaviors } /** - * Save blog settings + * Save blog settings. * - * @param dcSettings $blog_settings dcSettings instance + * @param dcSettings $blog_settings dcSettings instance */ public static function adminBeforeBlogSettingsUpdate(dcSettings $blog_settings): void { @@ -95,7 +96,7 @@ class BackendBehaviors /** * User pref for periods columns lists. * - * @param arrayObject $cols Columns + * @param ArrayObject $cols Columns */ public static function adminColumnsLists(ArrayObject $cols): void { @@ -116,7 +117,7 @@ class BackendBehaviors /** * User pref periods filters options. * - * @param arrayObject $sorts Sort options + * @param ArrayObject $sorts Sort options */ public static function adminFiltersLists(ArrayObject $sorts): void { @@ -132,12 +133,12 @@ class BackendBehaviors /** * Add columns period to posts list header. * - * @param dcRecord $rs record instance - * @param ArrayObject $cols Columns + * @param MetaRecord $rs record instance + * @param ArrayObject $cols Columns */ - public static function adminPostListHeader(dcRecord $rs, ArrayObject $cols): void + public static function adminPostListHeader(MetaRecord $rs, ArrayObject $cols): void { - if (dcCore::app()->blog->settings->get('periodical')->get('periodical_active')) { + if (dcCore::app()->blog?->settings->get('periodical')->get('periodical_active')) { $cols['period'] = '' . __('Period') . ''; } } @@ -145,12 +146,12 @@ class BackendBehaviors /** * Add columns period to posts list values. * - * @param dcRecord $rs record instance - * @param ArrayObject $cols Columns + * @param MetaRecord $rs record instance + * @param ArrayObject $cols Columns */ - public static function adminPostListValue(dcRecord $rs, ArrayObject $cols): void + public static function adminPostListValue(MetaRecord $rs, ArrayObject $cols): void { - if (!dcCore::app()->blog->settings->get('periodical')->get('periodical_active')) { + if (!dcCore::app()->blog?->settings->get('periodical')->get('periodical_active')) { return; } @@ -158,7 +159,7 @@ class BackendBehaviors if ($r->isEmpty()) { $name = '-'; } else { - $url = dcCore::app()->adminurl->get('admin.plugin.periodical', ['part' => 'period', 'period_id' => $r->f('periodical_id')]); + $url = dcCore::app()->adminurl?->get('admin.plugin.periodical', ['part' => 'period', 'period_id' => $r->f('periodical_id')]); $name = '' . Html::escapeHTML($r->f('periodical_title')) . ''; } $cols['period'] = '' . $name . ''; @@ -167,26 +168,29 @@ class BackendBehaviors /** * Dashboard Favorites. * - * @param dcFavorites $favs Array of favorites + * @param dcFavorites $favs Array of favorites */ public static function adminDashboardFavoritesV2(dcFavorites $favs): void { + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) { + return; + } $favs->register(My::id(), [ 'title' => My::name(), '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, ]), ]); } /** - * Add javascript for toggle + * Add javascript for toggle. * - * @return string HTML head + * @return string HTML head */ public static function adminPostHeaders(): string { @@ -194,9 +198,9 @@ class BackendBehaviors } /** - * Delete relation between post and period + * Delete relation between post and period. * - * @param integer $post_id Post id + * @param int $post_id Post id */ public static function adminBeforePostDelete(int $post_id): void { @@ -204,9 +208,9 @@ class BackendBehaviors } /** - * Add actions to posts page combo + * Add actions to posts page combo. * - * @param dcPostsActions $pa dcPostsActions instance + * @param dcPostsActions $pa dcPostsActions instance */ public static function adminPostsActions(dcPostsActions $pa): void { @@ -215,10 +219,10 @@ class BackendBehaviors [self::class, 'callbackAdd'] ); - if (dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_DELETE, - dcAuth::PERMISSION_CONTENT_ADMIN, - ]), dcCore::app()->blog->id)) { + if (dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([ + dcCore::app()->auth::PERMISSION_DELETE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog?->id)) { $pa->addAction( [My::name() => [__('Remove from periodical') => 'periodical_remove']], [self::class, 'callbackRemove'] @@ -227,28 +231,28 @@ class BackendBehaviors } /** - * Posts actions callback to remove period + * Posts actions callback to remove period. * - * @param dcPostsActions $pa dcPostsActions instance - * @param ArrayObject $post _POST actions + * @param dcPostsActions $pa dcPostsActions instance + * @param ArrayObject $post _POST actions */ public static function callbackRemove(dcPostsActions $pa, ArrayObject $post): void { - # No entry + // No entry $posts_ids = $pa->getIDs(); if (empty($posts_ids)) { throw new Exception(__('No entry selected')); } - # No right - if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_DELETE, - dcAuth::PERMISSION_CONTENT_ADMIN, - ]), dcCore::app()->blog->id)) { + // No right + if (!dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([ + dcCore::app()->auth::PERMISSION_DELETE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog?->id)) { throw new Exception(__('No enough right')); } - # Remove linked period + // Remove linked period foreach ($posts_ids as $post_id) { self::delPeriod($post_id); } @@ -258,14 +262,14 @@ class BackendBehaviors } /** - * Posts actions callback to add period + * Posts actions callback to add period. * - * @param dcPostsActions $pa dcPostsActions instance - * @param ArrayObject $post _POST actions + * @param dcPostsActions $pa dcPostsActions instance + * @param ArrayObject $post _POST actions */ public static function callbackAdd(dcPostsActions $pa, ArrayObject $post): void { - # No entry + // No entry $posts_ids = $pa->getIDs(); if (empty($posts_ids)) { throw new Exception(__('No entry selected')); @@ -273,7 +277,7 @@ class BackendBehaviors //todo: check if selected posts is unpublished - # Save action + // Save action if (!empty($post['periodical'])) { foreach ($posts_ids as $post_id) { self::delPeriod($post_id); @@ -284,13 +288,13 @@ class BackendBehaviors $pa->redirect(true); } - # Display form + // Display form else { $pa->beginPage( dcPage::breadcrumb([ - Html::escapeHTML(dcCore::app()->blog->name) => '', - $pa->getCallerTitle() => $pa->getRedirection(true), - __('Add a period to this selection') => '', + Html::escapeHTML((string) dcCore::app()->blog?->name) => '', + $pa->getCallerTitle() => $pa->getRedirection(true), + __('Add a period to this selection') => '', ]) ); @@ -313,49 +317,50 @@ class BackendBehaviors } /** - * Add form to post sidebar + * Add form to post sidebar. * - * @param ArrayObject $main_items Main items - * @param ArrayObject $sidebar_items Sidebar items - * @param dcRecord $post Post record or null + * @param ArrayObject $main_items Main items + * @param ArrayObject $sidebar_items Sidebar items + * @param null|MetaRecord $post Post record or null */ - public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?dcRecord $post): void + public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?MetaRecord $post): void { - # Get existing linked period + // Get existing linked period $period = ''; if ($post !== null) { $rs = Utils::getPosts(['post_id' => $post->f('post_id')]); $period = $rs->isEmpty() ? '' : $rs->f('periodical_id'); } - # Set linked period form items + // Set linked period form items $sidebar_items['options-box']['items']['period'] = (string) self::formPeriod((int) $period)?->render(); } /** - * Save linked period + * Save linked period. * - * @param cursor $cur Current post cursor - * @param null|int $post_id Post id + * @param Cursor $cur Current post Cursor + * @param null|int $post_id Post id */ - public static function adminAfterPostSave(cursor $cur, ?int $post_id): void + public static function adminAfterPostSave(Cursor $cur, ?int $post_id): void { if (!isset($_POST['periodical']) || $post_id === null) { return; } - # Delete old linked period + // Delete old linked period self::delPeriod($post_id); - # Add new linked period + // Add new linked period self::addPeriod($post_id, (int) $_POST['periodical']); } /** - * Posts period form field + * Posts period form field. * - * @param int $period Period - * @return null|Para Period form object + * @param int $period Period + * + * @return null|Para Period form object */ private static function formPeriod(int $period = 0): ?Para { @@ -368,9 +373,9 @@ class BackendBehaviors } /** - * Combo of available periods + * Combo of available periods. * - * @return array List of period + * @return array List of period */ private static function comboPeriod(): array { @@ -392,7 +397,7 @@ class BackendBehaviors /** * Remove period from posts. * - * @param int $post_id Post id + * @param int $post_id Post id */ private static function delPeriod(int $post_id): void { @@ -400,22 +405,22 @@ class BackendBehaviors } /** - * Add period to posts + * Add period to posts. * - * @param int $post_id Post id - * @param int $period_id Period + * @param int $post_id Post id + * @param int $period_id Period */ private static function addPeriod(int $post_id, int $period_id): void { - # Get periods + // Get periods $period = Utils::getPeriods(['periodical_id' => $period_id]); - # No period + // No period if ($period->isEmpty()) { return; } - # Add relation + // Add relation Utils::addPost($period_id, $post_id); } } diff --git a/src/Dater.php b/src/Dater.php index 0b1cdf2..b1792a1 100644 --- a/src/Dater.php +++ b/src/Dater.php @@ -24,27 +24,45 @@ use Exception; class Dater { /** - * Format a date from UTC to user TZ + * Format a date from UTC to user TZ. + * + * @param string $date The date + * @param string $format The output format + * + * @return string The formated date on user timezone */ public static function fromUser(string $date, string $format = 'Y-m-d H:i:00'): string { - $d = date_create($date, new DateTimeZone(dcCore::app()->auth->getInfo('user_tz'))); + $tz = dcCore::app()->auth?->getInfo('user_tz'); + $d = date_create($date, new DateTimeZone($tz ?? 'UTC')); return $d ? date_format($d->setTimezone(new DateTimeZone('UTC')), $format) : ''; } /** - * Format a date from user TZ to UTC + * Format a date from user TZ to UTC. + * + * @param string $date The date + * @param string $format The output format + * + * @return string The formated date on UTC */ public static function toUser(string $date, string $format = 'Y-m-d\TH:i'): string { - $d = date_create($date, new DateTimeZone('UTC')); + $tz = dcCore::app()->auth?->getInfo('user_tz'); + $d = date_create($date, new DateTimeZone('UTC')); - return $d ? date_format($d->setTimezone(new DateTimeZone(dcCore::app()->auth->getInfo('user_tz'))), $format) : ''; + return $d ? date_format($d->setTimezone(new DateTimeZone($tz ?? 'UTC')), $format) : ''; } /** - * Format a date to specific TZ (UTC by default) from another format + * Format a date to specific TZ (UTC by default) from another format. + * + * @param string $date The date + * @param string $format The output format + * @param string $to_tz The output timezone + * + * @return string The formated date */ public static function toDate(int|string $date = 'now', string $format = 'Y-m-d H:i:00', string $to_tz = 'UTC'): string { @@ -56,7 +74,12 @@ class Dater } /** - * Get next timestamp from a period + * Get next timestamp from a period. + * + * @param int $ts The timestamp + * @param string $period The period (periodical string format) + * + * @return int The timestamp of next update */ public static function getNextTime(int $ts, string $period): int { diff --git a/src/Frontend.php b/src/Frontend.php index 0b239f2..3437b09 100644 --- a/src/Frontend.php +++ b/src/Frontend.php @@ -39,15 +39,19 @@ class Frontend extends dcNsProcess } dcCore::app()->addBehavior('publicBeforeDocumentV2', function (): void { + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog)) { + return; + } + try { $s = dcCore::app()->blog->settings->get(My::id()); Utils::lockUpdate(); - # Get periods + // Get periods $periods = dcCore::app()->auth->sudo([Utils::class, 'getPeriods']); - # No period + // No period if ($periods->isEmpty()) { Utils::unlockUpdate(); @@ -62,7 +66,7 @@ class Frontend extends dcNsProcess $cur_period = dcCore::app()->con->openCursor(dcCore::app()->prefix . My::TABLE_NAME); while ($periods->fetch()) { - # Check if period is ongoing + // Check if period is ongoing $cur_ts = (int) Dater::toDate($periods->f('periodical_curdt'), 'U'); $end_ts = (int) Dater::toDate($periods->f('periodical_enddt'), 'U'); @@ -83,9 +87,9 @@ class Frontend extends dcNsProcess } catch (Exception $e) { } - # If period need update + // If period need update if ($limit > 0) { - # Get posts to publish related to this period + // Get posts to publish related to this period $posts_params = []; $posts_params['periodical_id'] = $periods->f('periodical_id'); $posts_params['post_status'] = dcBlog::POST_PENDING; @@ -98,18 +102,18 @@ class Frontend extends dcNsProcess $cur_post = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcBlog::POST_TABLE_NAME); while ($posts->fetch()) { - # Publish post with right date + // Publish post with right date $cur_post->clean(); $cur_post->setField('post_status', dcBlog::POST_PUBLISHED); - # Update post date with right date + // Update post date with right date if ($s->get('periodical_upddate')) { $cur_post->setField('post_dt', Dater::toDate($last_ts, 'Y-m-d H:i:00', $posts->post_tz)); } else { $cur_post->setField('post_dt', $posts->f('post_dt')); } - # Also update post url with right date + // Also update post url with right date if ($s->get('periodical_updurl')) { $cur_post->setField('post_url', dcCore::app()->blog->getPostURL( '', @@ -124,25 +128,25 @@ class Frontend extends dcNsProcess "AND blog_id = '" . dcCore::app()->con->escapeStr(dcCore::app()->blog->id) . "' " ); - # Delete post relation to this period + // Delete post relation to this period Utils::delPost((int) $posts->f('post_id')); $last_nb++; - # Increment upddt if nb of publishing is to the max + // Increment upddt if nb of publishing is to the max if ($last_nb == $max_nb) { $last_ts = Dater::getNextTime($last_ts, $periods->f('periodical_pub_int')); $last_nb = 0; } - # --BEHAVIOR-- periodicalAfterPublishedPeriodicalEntry + // --BEHAVIOR-- periodicalAfterPublishedPeriodicalEntry dcCore::app()->callBehavior('periodicalAfterPublishedPeriodicalEntry', $posts, $periods); } dcCore::app()->blog->triggerBlog(); } } - # Update last published date of this period even if there's no post to publish + // Update last published date of this period even if there's no post to publish $cur_period->clean(); $cur_period->setField('periodical_curdt', Dater::toDate($loop_ts, 'Y-m-d H:i:00')); $cur_period->update( diff --git a/src/Install.php b/src/Install.php index 735acce..abf6771 100644 --- a/src/Install.php +++ b/src/Install.php @@ -14,9 +14,9 @@ declare(strict_types=1); namespace Dotclear\Plugin\periodical; -use dbStruct; use dcCore; use dcNsProcess; +use Dotclear\Database\Structure; use Exception; class Install extends dcNsProcess @@ -32,31 +32,30 @@ class Install extends dcNsProcess public static function process(): bool { - if (!static::$init) { + if (!static::$init || is_null(dcCore::app()->blog)) { return false; } try { - # Tables - $t = new dbStruct(dcCore::app()->con, dcCore::app()->prefix); + $t = new Structure(dcCore::app()->con, dcCore::app()->prefix); - # Table principale des sondages - $t->{My::TABLE_NAME} // @phpstan-ignore-line - ->periodical_id('bigint', 0, false) - ->blog_id('varchar', 32, false) - ->periodical_type('varchar', 32, false, "'post'") - ->periodical_title('varchar', 255, false, "''") - ->periodical_curdt('timestamp', 0, false, ' now()') - ->periodical_enddt('timestamp', 0, false, 'now()') - ->periodical_pub_int('varchar', 32, false, "'day'") - ->periodical_pub_nb('smallint', 0, false, 1) + // create database table + $t->__get(My::TABLE_NAME) + ->field('periodical_id', 'bigint', 0, false) + ->field('blog_id', 'varchar', 32, false) + ->field('periodical_type', 'varchar', 32, false, "'post'") + ->field('periodical_title', 'varchar', 255, false, "''") + ->field('periodical_curdt', 'timestamp', 0, false, ' now()') + ->field('periodical_enddt', 'timestamp', 0, false, 'now()') + ->field('periodical_pub_int', 'varchar', 32, false, "'day'") + ->field('periodical_pub_nb', 'smallint', 0, false, 1) ->primary('pk_periodical', 'periodical_id') ->index('idx_periodical_type', 'btree', 'periodical_type'); - (new dbStruct(dcCore::app()->con, dcCore::app()->prefix))->synchronize($t); + (new Structure(dcCore::app()->con, dcCore::app()->prefix))->synchronize($t); - # Settings + // set default settings $s = dcCore::app()->blog->settings->get(My::id()); $s->put('periodical_active', false, 'boolean', 'Enable extension', false, true); $s->put('periodical_upddate', true, 'boolean', 'Update post date', false, true); diff --git a/src/Manage.php b/src/Manage.php index 536f2d1..22db30b 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -15,7 +15,6 @@ declare(strict_types=1); namespace Dotclear\Plugin\periodical; use adminGenericFilter; -use dcAuth; use dcCore; use dcNsProcess; use dcPage; @@ -35,9 +34,10 @@ class Manage extends dcNsProcess { 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([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, ]), dcCore::app()->blog->id); // call period manage page @@ -54,14 +54,20 @@ class Manage extends dcNsProcess return false; } + // nullsafe + if (is_null(dcCore::app()->adminurl)) { + return false; + } + + // call period manage page if (($_REQUEST['part'] ?? 'periods') === 'period') { return ManagePeriod::process(); } - # Default values + // load default values $vars = ManageVars::init(); - # Delete periods and related posts links + // Delete periods and related posts links if ($vars->action == 'deleteperiods' && !empty($vars->periods)) { try { foreach ($vars->periods as $id) { @@ -83,7 +89,7 @@ class Manage extends dcNsProcess } } - # Delete periods related posts links (without delete periods) + // Delete periods related posts links (without delete periods) if ($vars->action == 'emptyperiods' && !empty($vars->periods)) { try { foreach ($vars->periods as $id) { @@ -116,19 +122,25 @@ class Manage extends dcNsProcess return; } + // nullsafe + if (is_null(dcCore::app()->adminurl)) { + return; + } + + // call period manage page if (($_REQUEST['part'] ?? 'periods') === 'period') { ManagePeriod::render(); return; } - # Filters + // Filters $p_filter = new adminGenericFilter(dcCore::app(), My::id()); $p_filter->add('part', 'periods'); $params = $p_filter->params(); - # Get periods + // Get periods try { $periods = Utils::getPeriods($params); $counter = Utils::getPeriods($params, true); @@ -137,7 +149,7 @@ class Manage extends dcNsProcess dcCore::app()->error->add($e->getMessage()); } - # Display + // Display dcPage::openModule( My::name(), dcPage::jsModuleLoad(My::id() . '/js/checkbox.js') . @@ -155,10 +167,10 @@ class Manage extends dcNsProcess

'; if (isset($period_list)) { - # Filters + // Filters $p_filter->display('admin.plugin.' . My::id(), (new Hidden('p', My::id()))->render() . (new Hidden('part', 'periods'))->render()); - # Periods list + // Periods list $period_list->periodDisplay( $p_filter, '
' . diff --git a/src/ManageList.php b/src/ManageList.php index a97ee81..b5cec51 100644 --- a/src/ManageList.php +++ b/src/ManageList.php @@ -18,7 +18,6 @@ use ArrayObject; use adminGenericFilter; use adminGenericList; use adminPostFilter; -use dcAuth; use dcBlog; use dcCore; use dcPager; @@ -33,6 +32,12 @@ use Dotclear\Helper\Html\Html; */ class ManageList extends adminGenericList { + /** + * Display periods list. + * + * @param adminGenericFilter $filter The periods filter + * @param string $enclose_block The enclose block + */ public function periodDisplay(adminGenericFilter $filter, string $enclose_block = ''): void { if ($this->rs->isEmpty()) { @@ -78,45 +83,53 @@ class ManageList extends adminGenericList echo $pager->getLinks() . $blocks[0]; while ($this->rs->fetch()) { - echo $this->periodLine(isset($periods[(int) $this->rs->f('periodical_id')])); + $this->periodLine(isset($periods[(int) $this->rs->f('periodical_id')])); } echo $blocks[1] . $blocks[2] . $pager->getLinks(); } } - private function periodLine(bool $checked): string + /** + * Display a period list line. + * + * @param bool $checked Selected line + */ + private function periodLine(bool $checked): void { + $tz = dcCore::app()->auth?->getInfo('user_tz'); $nb_posts = Utils::getPosts(['periodical_id' => $this->rs->f('periodical_id')], true)->f(0); - $url = dcCore::app()->adminurl->get('admin.plugin.periodical', ['part' => 'period', 'period_id' => $this->rs->f('periodical_id')]); - - $name = '' . Html::escapeHTML($this->rs->periodical_title) . ''; - - $posts = $nb_posts ? - '' . $nb_posts . '' : - '0'; - + $url = dcCore::app()->adminurl?->get('admin.plugin.periodical', ['part' => 'period', 'period_id' => $this->rs->f('periodical_id')]); + $name = '' . Html::escapeHTML($this->rs->periodical_title) . ''; + $posts = $nb_posts ? '' . $nb_posts . '' : '0'; $interval = in_array($this->rs->f('periodical_pub_int'), My::periodCombo()) ? __((string) array_search($this->rs->f('periodical_pub_int'), My::periodCombo())) : __('Unknow frequence'); $cols = new ArrayObject([ 'check' => '' . (new Checkbox(['periods[]'], $checked))->value($this->rs->f('periodical_id'))->render() . '', 'name' => '' . $name . '', - 'curdt' => '' . Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->f('periodical_curdt'), dcCore::app()->auth->getInfo('user_tz')) . '', + 'curdt' => '' . Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->f('periodical_curdt'), $tz ?? 'UTC') . '', 'pub_int' => '' . $interval . '', 'pub_nb' => '' . $this->rs->f('periodical_pub_nb') . '', 'nbposts' => '' . $posts . '', - 'enddt' => '' . Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->f('periodical_enddt'), dcCore::app()->auth->getInfo('user_tz')) . '', + 'enddt' => '' . Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->f('periodical_enddt'), $tz ?? 'UTC') . '', ]); $this->userColumns(My::id(), $cols); - return - '' . - implode(iterator_to_array($cols)) . - ''; + echo + '' . + implode(iterator_to_array($cols)) . + ''; } + /** + * Display period posts list. + * + * @param adminPostFilter $filter The posts filter + * @param string $base_url The page base URL + * @param string $enclose_block The enclose block + */ public function postDisplay(adminPostFilter $filter, string $base_url, string $enclose_block = ''): void { $echo = ''; @@ -162,7 +175,7 @@ class ManageList extends adminGenericList echo $pager->getLinks() . $blocks[0]; while ($this->rs->fetch()) { - echo $this->postLine(isset($periodical_entries[(int) $this->rs->f('post_id')])); + $this->postLine(isset($periodical_entries[(int) $this->rs->f('post_id')])); } $img = '%1$s %1$s'; @@ -179,9 +192,14 @@ class ManageList extends adminGenericList } } - private function postLine(bool $checked): string + /** + * Display post list line. + * + * @param bool $checked Selected line + */ + private function postLine(bool $checked): void { - if (dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_CATEGORIES]), dcCore::app()->blog->id)) { + if (dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_CATEGORIES]), dcCore::app()->blog?->id)) { $cat_link = '%s'; } else { $cat_link = '%2$s'; @@ -238,6 +256,8 @@ class ManageList extends adminGenericList $attach = sprintf($img, sprintf($attach_str, $nb_media), 'attach.png'); } + $tz = dcCore::app()->auth?->getInfo('user_tz'); + $cols = [ 'check' => '' . (new Checkbox(['periodical_entries[]'], $checked))->value($this->rs->f('post_id'))->render() . '', 'title' => ' '' . $cat_title . '', 'author' => '' . $this->rs->f('user_id') . '', 'status' => '' . $img_status . ' ' . $selected . ' ' . $protected . ' ' . $attach . '', - 'create' => '' . Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->f('post_creadt'), dcCore::app()->auth->getInfo('user_tz')) . '', + 'create' => '' . Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->f('post_creadt'), $tz ?? 'UTC') . '', ]; - return '' . implode($cols) . ''; - ; + echo '' . implode($cols) . ''; } } diff --git a/src/ManagePeriod.php b/src/ManagePeriod.php index 76f98a6..5e577b2 100644 --- a/src/ManagePeriod.php +++ b/src/ManagePeriod.php @@ -15,7 +15,6 @@ declare(strict_types=1); namespace Dotclear\Plugin\periodical; use adminPostFilter; -use dcAuth; use dcCore; use dcNsProcess; use dcPage; @@ -45,9 +44,10 @@ class ManagePeriod extends dcNsProcess { 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([ - dcAuth::PERMISSION_USAGE, - dcAuth::PERMISSION_CONTENT_ADMIN, + dcCore::app()->auth::PERMISSION_USAGE, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, ]), dcCore::app()->blog->id) && ($_REQUEST['part'] ?? 'periods') === 'period'; @@ -60,21 +60,25 @@ class ManagePeriod extends dcNsProcess return false; } - # Default values + if (is_null(dcCore::app()->blog)) { + return false; + } + + // Default values $vars = ManageVars::init(); - # Get period + // Get period if ($vars->bad_period_id) { dcCore::app()->error->add(__('This period does not exist.')); } - # Set period + // Set period if ($vars->action == 'setperiod') { if ($vars->bad_period_curdt || $vars->bad_period_enddt) { dcCore::app()->error->add(__('Invalid date')); } - # Check period title and dates + // Check period title and dates $old_titles = Utils::getPeriods([ 'periodical_title' => $vars->period_title, ]); @@ -92,7 +96,7 @@ class ManagePeriod extends dcNsProcess dcCore::app()->error->add(__('Start date must be older than end date')); } - # If no error, set period + // If no error, set period if (!dcCore::app()->error->flag()) { $cur = Utils::openCursor(); $cur->setField('periodical_title', $vars->period_title); @@ -101,12 +105,12 @@ class ManagePeriod extends dcNsProcess $cur->setField('periodical_pub_int', $vars->period_pub_int); $cur->setField('periodical_pub_nb', $vars->period_pub_nb); - # Update period + // Update period if ($vars->period_id) { Utils::updPeriod($vars->period_id, $cur); self::redirect($vars->redir, $vars->period_id, '#period', __('Period successfully updated.')); - # Create period + // Create period } else { $period_id = Utils::addPeriod($cur); @@ -115,9 +119,9 @@ class ManagePeriod extends dcNsProcess } } - # Actions on related posts + // Actions on related posts if (!dcCore::app()->error->flag() && $vars->period_id && $vars->action && !empty($vars->entries)) { - # Publish posts + // Publish posts if ($vars->action == 'publish') { try { foreach ($vars->entries as $id) { @@ -131,7 +135,7 @@ class ManagePeriod extends dcNsProcess } } - # Unpublish posts + // Unpublish posts if ($vars->action == 'unpublish') { try { foreach ($vars->entries as $id) { @@ -145,7 +149,7 @@ class ManagePeriod extends dcNsProcess } } - # Remove posts from periodical + // Remove posts from periodical if ($vars->action == 'remove_post_periodical') { try { foreach ($vars->entries as $id) { @@ -171,14 +175,19 @@ class ManagePeriod extends dcNsProcess return; } - # Default values + // nullsafe + if (is_null(dcCore::app()->adminurl)) { + return; + } + + // Default values $vars = ManageVars::init(); $starting_script = ''; - # Prepare combos for posts list + // Prepare combos for posts list if ($vars->period_id > 0) { - # Filters + // Filters $post_filter = new adminPostFilter(); $post_filter->add('part', 'period'); @@ -186,7 +195,7 @@ class ManagePeriod extends dcNsProcess $params['periodical_id'] = $vars->period_id; $params['no_content'] = true; - # Get posts + // Get posts try { $posts = Utils::getPosts($params); $counter = Utils::getPosts($params, true); @@ -199,7 +208,7 @@ class ManagePeriod extends dcNsProcess $post_filter->js(dcCore::app()->adminurl->get('admin.plugin.' . My::id(), ['part' => 'period', 'period_id' => $vars->period_id], '&') . '#posts'); } - # Display + // Display dcPage::openModule( My::name(), dcPage::jsModuleLoad(My::id() . '/js/dates.js') . @@ -216,7 +225,7 @@ class ManagePeriod extends dcNsProcess ]) . dcPage::notices(); - # Period form + // Period form echo (new Div('period'))->items([ (new Text('h3', null === $vars->period_id ? __('New period') : __('Edit period'))), @@ -278,7 +287,7 @@ class ManagePeriod extends dcNsProcess echo '

' . __('Entries linked to this period') . '

'; - # Filters + // Filters $post_filter->display( ['admin.plugin.periodical', '#posts'], dcCore::app()->adminurl->getHiddenFormFields('admin.plugin.periodical', [ @@ -287,7 +296,7 @@ class ManagePeriod extends dcNsProcess ]) ); - # Posts list + // Posts list $post_list->postDisplay( $post_filter, $base_url, @@ -319,6 +328,14 @@ class ManagePeriod extends dcNsProcess dcPage::closeModule(); } + /** + * Do a Http redirection. + * + * @param string $redir Previous redirection + * @param int $id The period ID + * @param string $tab The page tab + * @param string $msg The notice message + */ private static function redirect(string $redir, int $id, string $tab, string $msg): void { dcPage::addSuccessNotice($msg); @@ -326,7 +343,7 @@ class ManagePeriod extends dcNsProcess if (!empty($redir)) { Http::redirect($redir); } else { - dcCore::app()->adminurl->redirect('admin.plugin.' . My::id(), ['part' => 'period', 'period_id' => $id], $tab); + dcCore::app()->adminurl?->redirect('admin.plugin.' . My::id(), ['part' => 'period', 'period_id' => $id], $tab); } } } diff --git a/src/ManageVars.php b/src/ManageVars.php index d59e256..fb53860 100644 --- a/src/ManageVars.php +++ b/src/ManageVars.php @@ -19,26 +19,51 @@ namespace Dotclear\Plugin\periodical; */ class ManageVars { - /** - * @var ManageVars self instance - */ - private static $container; + /** @var ManageVars $container Self instance */ + private static ManageVars $container; + /** @var string $action The post form action */ public readonly string $action; + + /** @var string $redir The post form redirection */ public readonly string $redir; + + /** @var array $periods The post form periods */ public readonly array $periods; + + /** @var array $entries The post form entries */ public readonly array $entries; + /** @var null|int $period_id The post form period id */ public readonly ?int $period_id; + + /** @var string $period_title The psort form period title */ public readonly string $period_title; + + /** @var int $period_pub_nb The post form period publication number */ public readonly int $period_pub_nb; + + /** @var string $period_pub_int The post form period publication interval */ public readonly string $period_pub_int; + + /** @var string $period_curdt The post form period current date */ public readonly string $period_curdt; + + /** @var string $period_curdt The post form period end date */ public readonly string $period_enddt; + + /** @var bool $bad_period_id Is period ID wrong */ public readonly bool $bad_period_id; + + /** @var bool $bad_period_curdt Is period current date wrong */ public readonly bool $bad_period_curdt; + + /** @var bool $bad_period_enddt Is period end date wrong */ public readonly bool $bad_period_enddt; + /** + * Constructor check and sets default post form values. + */ protected function __construct() { $this->action = $_POST['action'] ?? ''; @@ -71,7 +96,7 @@ class ManageVars $bad_period_curdt = false; $bad_period_enddt = false; - # period values from record + // period values from record if (!empty($_REQUEST['period_id'])) { $rs = Utils::getPeriods([ 'periodical_id' => $_REQUEST['period_id'], @@ -88,7 +113,7 @@ class ManageVars } } - # period values from POST + // period values from POST if (!empty($_POST['period_title'])) { $period_title = $_POST['period_title']; } @@ -129,6 +154,11 @@ class ManageVars $this->bad_period_enddt = $bad_period_enddt; } + /** + * Get self instance. + * + * @return ManageVars Self instance + */ public static function init(): ManageVars { if (!(self::$container instanceof self)) { diff --git a/src/Utils.php b/src/Utils.php index 8fa5c77..edf21ef 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -14,18 +14,27 @@ declare(strict_types=1); namespace Dotclear\Plugin\periodical; -use cursor; -use dcAuth; +use ArrayObject; use dcBlog; use dcCore; use dcMeta; -use dcRecord; -use Dotclear\Helper\File\Files; -use Dotclear\Helper\File\Path; +use Dotclear\Database\{ + Cursor, + MetaRecord +}; +use Dotclear\Database\Statement\{ + DeleteStatement, + JoinStatement, + SelectStatement +}; +use Dotclear\Helper\File\{ + Files, + Path +}; use Exception; /** - * Manage records + * Manage periodical records */ class Utils { @@ -33,105 +42,127 @@ class Utils private static $lock = null; /** - * Get escaped blog id + * Get periodical table cursor. + * + * @return Cursor The periodical table cursor */ - private static function blog(): string - { - return dcCore::app()->con->escapeStr(dcCore::app()->blog->id); - } - - /** - * Get escaped periodical full table name - */ - private static function table(): string - { - return dcCore::app()->con->escapeStr(dcCore::app()->prefix . My::TABLE_NAME); - } - - /** - * Get periodical table cursor - */ - public static function openCursor(): cursor + public static function openCursor(): Cursor { return dcCore::app()->con->openCursor(dcCore::app()->prefix . My::TABLE_NAME); } /** - * Get periods + * Get periods. + * + * @param array|ArrayObject $params Parameters + * @param bool $count_only Only counts results + * @param SelectStatement $ext_sql Optional SelectStatement instance + * + * @return MetaRecord A record with some more capabilities */ - public static function getPeriods(array $params = [], bool $count_only = false): dcRecord + public static function getPeriods(array|ArrayObject $params = [], bool $count_only = false, ?SelectStatement $ext_sql = null): MetaRecord { - if ($count_only) { - $q = 'SELECT count(T.periodical_id) '; - } else { - $q = 'SELECT T.periodical_id, T.periodical_type, '; + $params = new ArrayObject($params); + $sql = $ext_sql ? clone $ext_sql : new SelectStatement(); + if ($count_only) { + $sql->column($sql->count($sql->unique('T.periodical_id'))); + } else { if (!empty($params['columns']) && is_array($params['columns'])) { - $q .= implode(', ', $params['columns']) . ', '; + $sql->columns($params['columns']); } - $q .= 'T.periodical_title, ' . - 'T.periodical_curdt, T.periodical_enddt, ' . - 'T.periodical_pub_int, T.periodical_pub_nb '; + $sql->columns([ + 'T.periodical_title', + 'T.periodical_curdt', + 'T.periodical_enddt', + 'T.periodical_pub_int', + 'T.periodical_pub_nb', + + ]); } - $q .= 'FROM ' . self::table() . ' T '; + $sql->from($sql->as(dcCore::app()->prefix . My::TABLE_NAME, 'T'), false, true); + + if (!empty($params['join'])) { + $sql->join($params['join']); + } if (!empty($params['from'])) { - $q .= $params['from'] . ' '; + $sql->from($params['from']); + } + + if (!empty($params['where'])) { + $sql->where($params['where']); + $sql->and('P.blog_id = ' . $sql->quote((string) dcCore::app()->blog?->id)); + } else { + $sql->where('P.blog_id = ' . $sql->quote((string) dcCore::app()->blog?->id)); } - $q .= "WHERE T.blog_id = '" . self::blog() . "' "; if (isset($params['periodical_type'])) { - if (is_array($params['periodical_type']) && !empty($params['periodical_type'])) { - $q .= 'AND T.periodical_type ' . dcCore::app()->con->in($params['periodical_type']); - } elseif ($params['periodical_type'] != '') { - $q .= "AND T.periodical_type = '" . dcCore::app()->con->escapeStr($params['periodical_type']) . "' "; + if (is_array($params['periodical_type']) || !empty($params['periodical_type'])) { + $sql->and('T.periodical_type ' . $sql->in($params['periodical_type'])); } } else { - $q .= "AND T.periodical_type = 'post' "; + $sql->and("T.periodical_type = 'post' "); } + if (!empty($params['periodical_id'])) { if (is_array($params['periodical_id'])) { array_walk($params['periodical_id'], function ($v) { if ($v !== null) { $v = (int) $v; } }); } else { $params['periodical_id'] = [(int) $params['periodical_id']]; } - $q .= 'AND T.periodical_id ' . dcCore::app()->con->in($params['periodical_id']); - } - if (!empty($params['periodical_title'])) { - $q .= "AND T.periodical_title = '" . dcCore::app()->con->escapeStr($params['periodical_title']) . "' "; - } - if (!empty($params['sql'])) { - $q .= $params['sql'] . ' '; - } - if (!$count_only) { - if (!empty($params['order'])) { - $q .= 'ORDER BY ' . dcCore::app()->con->escapeStr($params['order']) . ' '; - } else { - $q .= 'ORDER BY T.periodical_id ASC '; - } - } - if (!$count_only && !empty($params['limit'])) { - $q .= dcCore::app()->con->limit($params['limit']); + $sql->and('T.periodical_id ' . $sql->in($params['periodical_id'])); } - return new dcRecord(dcCore::app()->con->select($q)); + if (!empty($params['periodical_title'])) { + $sql->and('T.periodical_title = ' . $sql->quote($params['periodical_title'])); + } + + if (!empty($params['sql'])) { + $sql->sql($params['sql']); + } + + if (!$count_only) { + if (!empty($params['order'])) { + $sql->order($sql->escape($params['order'])); + } else { + $sql->order('T.periodical_id ASC'); + } + } + + if (!$count_only && !empty($params['limit'])) { + $sql->limit($params['limit']); + } + + $rs = $sql->select(); + + return is_null($rs) ? MetaRecord::newFromArray([]) : $rs; } /** - * Add a period + * Add a period. + * + * @param Cursor $cur The period cursor + * + * @return int The new period ID */ - public static function addPeriod(cursor $cur): int + public static function addPeriod(Cursor $cur): int { - dcCore::app()->con->writeLock(self::table()); + dcCore::app()->con->writeLock(dcCore::app()->prefix . My::TABLE_NAME); try { - $id = dcCore::app()->con->select( - 'SELECT MAX(periodical_id) FROM ' . self::table() - )->f(0) + 1; + // get next id + $sql = new SelectStatement(); + $rs = $sql->from(dcCore::app()->prefix . My::TABLE_NAME) + ->column($sql->max('periodical_id')) + ->select(); + $id = is_null($rs) || $rs->isEmpty() ? 1 : (int) $rs->f(0) + 1; + + // insert $cur->setField('periodical_id', $id); - $cur->setField('blog_id', self::blog()); + $cur->setField('blog_id', (string) dcCore::app()->blog?->id); $cur->setField('periodical_type', 'post'); $cur->insert(); dcCore::app()->con->unlock(); @@ -141,51 +172,57 @@ class Utils throw $e; } - return (int) $cur->getField('periodical_id'); + return $id; } /** - * Update a period + * Update a period. + * + * @param int $period_id The period ID + * @param Cursor $cur The period cursor */ - public static function updPeriod(int $period_id, cursor $cur): void + public static function updPeriod(int $period_id, Cursor $cur): void { $cur->update( - "WHERE blog_id = '" . self::blog() . "' " . + "WHERE blog_id = '" . dcCore::app()->con->escapeStr((string) dcCore::app()->blog?->id) . "' " . 'AND periodical_id = ' . $period_id . ' ' ); } /** - * Delete a period + * Delete a period. + * + * @param int $period_id The period ID */ public static function delPeriod(int $period_id): void { - $params = []; - $params['periodical_id'] = $period_id; - $params['post_status'] = ''; - $rs = self::getPosts($params); + $rs = self::getPosts([ + 'periodical_id' => $period_id, + 'post_status' => '', + ]); if (!$rs->isEmpty()) { throw new Exception('Periodical is not empty'); } - dcCore::app()->con->execute( - 'DELETE FROM ' . self::table() . ' ' . - "WHERE blog_id = '" . self::blog() . "' " . - 'AND periodical_id = ' . $period_id . ' ' - ); + $sql = new DeleteStatement(); + $sql->from(dcCore::app()->prefix . My::TABLE_NAME) + ->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog?->id)) + ->and('periodical_id = ' . $period_id) + ->delete(); } /** - * Remove all posts related to a period + * Remove all posts related to a period. + * + * @param int $period_id The period ID */ public static function delPeriodPosts(int $period_id): void { - $params = []; - $params['post_status'] = ''; - $params['periodical_id'] = $period_id; - - $rs = self::getPosts($params); + $rs = self::getPosts([ + 'post_status' => '', + 'periodical_id' => $period_id, + ]); if ($rs->isEmpty()) { return; @@ -196,48 +233,59 @@ class Utils $ids[] = $rs->f('post_id'); } - if (empty($ids)) { - return; - } - - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->prefix . dcMeta::META_TABLE_NAME . ' ' . - "WHERE meta_type = '" . My::META_TYPE . "' " . - 'AND post_id ' . dcCore::app()->con->in($ids) - ); + $sql = new DeleteStatement(); + $sql->from(dcCore::app()->prefix . dcMeta::META_TABLE_NAME) + ->where('meta_type = ' . $sql->quote(My::META_TYPE)) + ->and('post_id ' . $sql->in($ids)) + ->delete(); } /** - * Get posts related to periods + * Get posts related to periods. + * + * @param array|ArrayObject $params Parameters + * @param bool $count_only Only counts results + * @param SelectStatement $ext_sql Optional SelectStatement instance + * + * @return MetaRecord A record with some more capabilities */ - public static function getPosts(array $params = [], bool $count_only = false): dcRecord + public static function getPosts(array|ArrayObject $params = [], bool $count_only = false, ?SelectStatement $ext_sql = null): MetaRecord { - if (!isset($params['columns'])) { - $params['columns'] = []; - } - if (!isset($params['from'])) { - $params['from'] = ''; - } - if (!isset($params['join'])) { - $params['join'] = ''; - } + $params = new ArrayObject($params); + $sql = $ext_sql ? clone $ext_sql : new SelectStatement(); + if (!isset($params['sql'])) { $params['sql'] = ''; } - $params['columns'][] = 'T.periodical_id'; - $params['columns'][] = 'T.periodical_title'; - $params['columns'][] = 'T.periodical_type'; - $params['columns'][] = 'T.periodical_curdt'; - $params['columns'][] = 'T.periodical_enddt'; - $params['columns'][] = 'T.periodical_pub_int'; - $params['columns'][] = 'T.periodical_pub_nb'; + $sql + ->columns([ + 'T.periodical_id', + 'T.periodical_title', + 'T.periodical_type', + 'T.periodical_curdt', + 'T.periodical_enddt', + 'T.periodical_pub_int', + 'T.periodical_pub_nb', - $params['join'] .= 'LEFT JOIN ' . dcCore::app()->prefix . dcMeta::META_TABLE_NAME . ' R ON P.post_id = R.post_id '; - $params['join'] .= 'LEFT JOIN ' . self::table() . ' T ON CAST(T.periodical_id as char) = CAST(R.meta_id as char) '; - - $params['sql'] .= "AND R.meta_type = '" . My::META_TYPE . "' "; - $params['sql'] .= "AND T.periodical_type = 'post' "; + ]) + ->join( + (new JoinStatement()) + ->left() + ->from($sql->as(dcCore::app()->prefix . dcMeta::META_TABLE_NAME, 'R')) + ->on('P.post_id = R.post_id') + ->statement() + ) + ->join( + (new JoinStatement()) + ->left() + ->from($sql->as(dcCore::app()->prefix . My::TABLE_NAME, 'T')) + ->on('CAST(T.periodical_id as char) = CAST(R.meta_id as char)') + ->statement() + ) + ->and('R.meta_type = ' . $sql->quote(My::META_TYPE)) + ->and("T.periodical_type = 'post' ") + ; if (!empty($params['periodical_id'])) { if (is_array($params['periodical_id'])) { @@ -249,30 +297,39 @@ class Utils } else { $params['periodical_id'] = [(int) $params['periodical_id']]; } - $params['sql'] .= 'AND T.periodical_id ' . dcCore::app()->con->in($params['periodical_id']); + $sql->and('T.periodical_id ' . $sql->in($params['periodical_id'])); unset($params['periodical_id']); } - if (dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) { + if (dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_ADMIN]), dcCore::app()->blog?->id)) { if (isset($params['post_status'])) { if ($params['post_status'] != '') { - $params['sql'] .= 'AND P.post_status = ' . (int) $params['post_status'] . ' '; + $sql->and('P.post_status = ' . (int) $params['post_status']); } unset($params['post_status']); } } else { - $params['sql'] .= 'AND P.post_status = ' . dcBlog::POST_PENDING . ' '; + $sql->and('P.post_status = ' . dcBlog::POST_PENDING); } - return dcCore::app()->blog->getPosts($params, $count_only); + $rs = dcCore::app()->blog?->getPosts($params, $count_only, $sql); + + return is_null($rs) ? MetaRecord::newFromArray([]) : $rs; } /** - * Add post to a period + * Add post to a period. + * + * @param int $period_id The period ID + * @param int $post_id The post ID */ public static function addPost(int $period_id, int $post_id): void { - # Check if exists - $rs = self::getPosts(['post_id' => $post_id, 'periodical_id' => $period_id]); + // Check if exists + $rs = self::getPosts([ + 'post_id' => $post_id, + 'periodical_id' => $period_id, + ]); + if (!$rs->isEmpty()) { return; } @@ -294,25 +351,31 @@ class Utils } /** - * Remove a post from periods + * Remove a post from periods. + * + * @param int $post_id The post ID */ public static function delPost(int $post_id): void { - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->prefix . dcMeta::META_TABLE_NAME . ' ' . - "WHERE meta_type = '" . My::META_TYPE . "' " . - "AND post_id = '" . $post_id . "' " - ); + $sql = new DeleteStatement(); + $sql->from(dcCore::app()->prefix . dcMeta::META_TABLE_NAME) + ->where('meta_type = ' . $sql->quote(My::META_TYPE)) + ->and('post_id = ' . $post_id) + ->delete(); } /** - * Remove all posts without pending status from periodical + * Remove all posts without pending status from periodical. + * + * @param null|int $period_id The optionnal period ID */ public static function cleanPosts(?int $period_id = null): void { - $params = []; - $params['post_status'] = ''; - $params['sql'] = 'AND post_status != ' . dcBlog::POST_PENDING . ' '; + // hack post status of dcBlog::getPost() + $params = [ + 'post_status' => '', + 'sql' => 'AND post_status != ' . dcBlog::POST_PENDING . ' ', + ]; if ($period_id !== null) { $params['periodical_id'] = $period_id; } @@ -327,15 +390,11 @@ class Utils $ids[] = (int) $rs->f('post_id'); } - if (empty($ids)) { - return; - } - - dcCore::app()->con->execute( - 'DELETE FROM ' . dcCore::app()->prefix . dcMeta::META_TABLE_NAME . ' ' . - "WHERE meta_type = '" . My::META_TYPE . "' " . - 'AND post_id ' . dcCore::app()->con->in($ids) - ); + $sql = new DeleteStatement(); + $sql->from(dcCore::app()->prefix . dcMeta::META_TABLE_NAME) + ->where('meta_type = ' . $sql->quote(My::META_TYPE)) + ->and('post_id ' . $sql->in($ids)) + ->delete(); } /** @@ -344,16 +403,16 @@ class Utils public static function lockUpdate(): bool { try { - # Need flock function + // Need flock function if (!function_exists('flock')) { throw new Exception("Can't call php function named flock"); } - # Cache writable ? + // Cache writable ? if (!is_writable(DC_TPL_CACHE)) { throw new Exception("Can't write in cache fodler"); } - # Set file path - $f_md5 = md5(self::blog()); + // Set file path + $f_md5 = md5((string) dcCore::app()->blog?->id); $cached_file = sprintf( '%s/%s/%s/%s/%s.txt', DC_TPL_CACHE, @@ -362,16 +421,16 @@ class Utils substr($f_md5, 2, 2), $f_md5 ); - # Real path + // Real path $cached_file = Path::real($cached_file, false); if (is_bool($cached_file)) { throw new Exception("Can't write in cache fodler"); } - # Make dir + // Make dir if (!is_dir(dirname($cached_file))) { Files::makeDir(dirname($cached_file), true); } - # Make file + // Make file if (!file_exists($cached_file)) { !$fp = @fopen($cached_file, 'w'); if ($fp === false) { @@ -380,11 +439,11 @@ class Utils fwrite($fp, '1', strlen('1')); fclose($fp); } - # Open file + // Open file if (!($fp = @fopen($cached_file, 'r+'))) { throw new Exception("Can't open file"); } - # Lock file + // Lock file if (!flock($fp, LOCK_EX)) { throw new Exception("Can't lock file"); } @@ -401,7 +460,9 @@ class Utils */ public static function unlockUpdate(): void { - @fclose(self::$lock); - self::$lock = null; + if (!is_null(self::$lock)) { + @fclose(self::$lock); + self::$lock = null; + } } }