diff --git a/_prepend.php b/_prepend.php
deleted file mode 100644
index e81a936..0000000
--- a/_prepend.php
+++ /dev/null
@@ -1,20 +0,0 @@
-autoload([
- 'periodical' => __DIR__ . '/inc/class.periodical.php',
- 'adminPeriodicalList' => __DIR__ . '/inc/lib.index.pager.php',
-]);
diff --git a/index.php b/index.php
deleted file mode 100644
index 40dd39f..0000000
--- a/index.php
+++ /dev/null
@@ -1,23 +0,0 @@
-auth->check(dcCore::app()->auth->makePermissions([
+ dcAuth::PERMISSION_USAGE,
+ dcAuth::PERMISSION_CONTENT_ADMIN,
+ ]), dcCore::app()->blog->id);
+
+ return static::$init;
+ }
+
+ public static function process(): bool
+ {
+ if (!static::$init) {
+ return false;
+ }
+
+ dcCore::app()->addBehaviors([
+ 'adminBlogPreferencesFormV2' => [BackendBehaviors::class, 'adminBlogPreferencesForm'],
+ 'adminBeforeBlogSettingsUpdate' => [BackendBehaviors::class, 'adminBeforeBlogSettingsUpdate'],
+ 'adminFiltersListsV2' => [BackendBehaviors::class, 'adminFiltersLists'],
+ 'adminColumnsListsV2' => [BackendBehaviors::class, 'adminColumnsLists'],
+ 'adminPostListHeaderV2' => [BackendBehaviors::class, 'adminPostListHeader'],
+ 'adminPostListValueV2' => [BackendBehaviors::class, 'adminPostListValue'],
+ 'adminBeforePostDelete' => [BackendBehaviors::class, 'adminBeforePostDelete'],
+ ]);
+
+ if (dcCore::app()->blog->settings->get(My::id())->get('periodical_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(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,
+ ]), dcCore::app()->blog->id)
+ );
+
+ dcCore::app()->addBehaviors([
+ 'adminDashboardFavoritesV2' => [BackendBehaviors::class, 'adminDashboardFavoritesV2'],
+ 'adminPostHeaders' => [BackendBehaviors::class, 'adminPostHeaders'],
+ 'adminPostsActions' => [BackendBehaviors::class, 'adminPostsActions'],
+ 'adminPostFormItems' => [BackendBehaviors::class, 'adminPostFormItems'],
+ 'adminAfterPostUpdate' => [BackendBehaviors::class, 'adminAfterPostSave'],
+ 'adminAfterPostCreate' => [BackendBehaviors::class, 'adminAfterPostSave'],
+ ]);
+ }
+
+ return true;
+ }
+}
diff --git a/src/BackendBehaviors.php b/src/BackendBehaviors.php
index 5ecf48a..8a3f96c 100644
--- a/src/BackendBehaviors.php
+++ b/src/BackendBehaviors.php
@@ -10,133 +10,55 @@
* @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);
-dcCore::app()->blog->settings->addNamespace('periodical');
+namespace Dotclear\Plugin\periodical;
-dcCore::app()->addBehavior(
- 'adminBlogPreferencesFormV2',
- ['adminPeriodical', 'adminBlogPreferencesForm']
-);
-dcCore::app()->addBehavior(
- 'adminBeforeBlogSettingsUpdate',
- ['adminPeriodical', 'adminBeforeBlogSettingsUpdate']
-);
-dcCore::app()->addBehavior(
- 'adminFiltersListsV2',
- ['adminPeriodical', 'adminFiltersLists']
-);
-dcCore::app()->addBehavior(
- 'adminColumnsListsV2',
- ['adminPeriodical', 'adminColumnsLists']
-);
-dcCore::app()->addBehavior(
- 'adminPostListHeaderV2',
- ['adminPeriodical', 'adminPostListHeader']
-);
-dcCore::app()->addBehavior(
- 'adminPostListValueV2',
- ['adminPeriodical', 'adminPostListValue']
-);
-
-if (dcCore::app()->blog->settings->periodical->periodical_active) {
- dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem(
- __('Periodical'),
- dcCore::app()->adminurl->get('admin.plugin.periodical'),
- dcPage::getPF('periodical/icon.svg'),
- preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.periodical')) . '(&.*)?$/', $_SERVER['REQUEST_URI']),
- dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
- dcAuth::PERMISSION_USAGE,
- dcAuth::PERMISSION_CONTENT_ADMIN,
- ]), dcCore::app()->blog->id)
- );
-
- dcCore::app()->addBehavior(
- 'adminDashboardFavoritesV2',
- ['adminPeriodical', 'adminDashboardFavoritesV2']
- );
- dcCore::app()->addBehavior(
- 'adminPostHeaders',
- ['adminPeriodical', 'adminPostHeaders']
- );
- dcCore::app()->addBehavior(
- 'adminPostsActions',
- ['adminPeriodical', 'adminPostsActions']
- );
- dcCore::app()->addBehavior(
- 'adminPostFormItems',
- ['adminPeriodical', 'adminPostFormItems']
- );
- dcCore::app()->addBehavior(
- 'adminAfterPostUpdate',
- ['adminPeriodical', 'adminAfterPostSave']
- );
- dcCore::app()->addBehavior(
- 'adminAfterPostCreate',
- ['adminPeriodical', 'adminAfterPostSave']
- );
-}
-
-dcCore::app()->addBehavior(
- 'adminBeforePostDelete',
- ['adminPeriodical', 'adminBeforePostDelete']
-);
+use ArrayObject;
+use cursor;
+use dcAuth;
+use dcCore;
+use dcFavorites;
+use dcPage;
+use dcPostsActions;
+use dcRecord;
+use dcSettings;
+use Exception;
+use form;
+use html;
/**
* @ingroup DC_PLUGIN_PERIODICAL
* @brief Periodical - admin methods.
* @since 2.6
*/
-class adminPeriodical
+class BackendBehaviors
{
- public static $combo_period = null;
- protected static $per = null;
-
- public static function sortbyCombo()
- {
- return [
- __('Next update') => 'periodical_curdt',
- __('End date') => 'periodical_enddt',
- __('Frequence') => 'periodical_pub_int',
- ];
- }
-
- protected static function period()
- {
- if (self::$per === null) {
- self::$per = new periodical();
- }
-
- return self::$per;
- }
+ private static array $combo_period = [];
/**
* Add settings to blog preference
*
* @param dcSettings $blog_settings dcSettings instance
*/
- public static function adminBlogPreferencesForm(dcSettings $blog_settings)
+ public static function adminBlogPreferencesForm(dcSettings $blog_settings): void
{
- $s_active = (bool) $blog_settings->periodical->periodical_active;
- $s_upddate = (bool) $blog_settings->periodical->periodical_upddate;
- $s_updurl = (bool) $blog_settings->periodical->periodical_updurl;
+ $s = $blog_settings->get('periodical');
echo
'
' . __('Periodical') . '
' .
'
' .
'
' .
'
' .
'
' .
'
' .
'
' .
'
' .
'
' .
'
' .
@@ -149,11 +71,11 @@ class adminPeriodical
*
* @param dcSettings $blog_settings dcSettings instance
*/
- public static function adminBeforeBlogSettingsUpdate(dcSettings $blog_settings)
+ public static function adminBeforeBlogSettingsUpdate(dcSettings $blog_settings): void
{
- $blog_settings->periodical->put('periodical_active', !empty($_POST['periodical_active']));
- $blog_settings->periodical->put('periodical_upddate', !empty($_POST['periodical_upddate']));
- $blog_settings->periodical->put('periodical_updurl', !empty($_POST['periodical_updurl']));
+ $blog_settings->get('periodical')->put('periodical_active', !empty($_POST['periodical_active']));
+ $blog_settings->get('periodical')->put('periodical_upddate', !empty($_POST['periodical_upddate']));
+ $blog_settings->get('periodical')->put('periodical_updurl', !empty($_POST['periodical_updurl']));
}
/**
@@ -161,10 +83,10 @@ class adminPeriodical
*
* @param arrayObject $cols Columns
*/
- public static function adminColumnsLists($cols)
+ public static function adminColumnsLists(ArrayObject $cols): void
{
- $cols['periodical'] = [
- __('Periodical'),
+ $cols[My::id()] = [
+ My::name(),
[
'curdt' => [true, __('Next update')],
'pub_int' => [true, __('Frequency')],
@@ -182,11 +104,11 @@ class adminPeriodical
*
* @param arrayObject $sorts Sort options
*/
- public static function adminFiltersLists($sorts)
+ public static function adminFiltersLists(ArrayObject $sorts): void
{
- $sorts['periodical'] = [
- __('Periodical'),
- self::sortbyCombo(),
+ $sorts[My::id()] = [
+ My::name(),
+ My::sortbyCombo(),
'periodical_curdt',
'desc',
[__('periods per page'), 10],
@@ -196,12 +118,12 @@ class adminPeriodical
/**
* Add columns period to posts list header.
*
- * @param record $rs record instance
- * @param arrayObject $cols Columns
+ * @param dcRecord $rs record instance
+ * @param ArrayObject $cols Columns
*/
- public static function adminPostListHeader($rs, $cols)
+ public static function adminPostListHeader(dcRecord $rs, ArrayObject $cols): void
{
- if (dcCore::app()->blog->settings->periodical->periodical_active) {
+ if (dcCore::app()->blog->settings->get('periodical')->get('periodical_active')) {
$cols['period'] = '
' . __('Period') . ' | ';
}
}
@@ -209,37 +131,37 @@ class adminPeriodical
/**
* Add columns period to posts list values.
*
- * @param record $rs record instance
- * @param arrayObject $cols Columns
+ * @param dcRecord $rs record instance
+ * @param ArrayObject $cols Columns
*/
- public static function adminPostListValue($rs, $cols)
+ public static function adminPostListValue(dcRecord $rs, ArrayObject $cols): void
{
- if (!dcCore::app()->blog->settings->periodical->periodical_active) {
- return null;
+ if (!dcCore::app()->blog->settings->get('periodical')->get('periodical_active')) {
+ return;
}
- $r = self::period()->getPosts(['post_id' => $rs->post_id]);
+ $r = Utils::getPosts(['post_id' => $rs->f('post_id')]);
if ($r->isEmpty()) {
$name = '-';
} else {
- $url = dcCore::app()->adminurl->get('admin.plugin.periodical', ['part' => 'period', 'period_id' => $r->periodical_id]);
- $name = '
' . html::escapeHTML($r->periodical_title) . '';
+ $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 . ' | ';
}
/**
- * Favorites.
+ * Dashboard Favorites.
*
* @param dcFavorites $favs Array of favorites
*/
- public static function adminDashboardFavoritesV2(dcFavorites $favs)
+ public static function adminDashboardFavoritesV2(dcFavorites $favs): void
{
- $favs->register('periodical', [
- 'title' => __('Periodical'),
- 'url' => dcCore::app()->adminurl->get('admin.plugin.periodical'),
- 'small-icon' => dcPage::getPF('periodical/icon.svg'),
- 'large-icon' => dcPage::getPF('periodical/icon.svg'),
+ $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,
@@ -252,9 +174,9 @@ class adminPeriodical
*
* @return string HTML head
*/
- public static function adminPostHeaders()
+ public static function adminPostHeaders(): string
{
- return dcPage::jsLoad(dcPage::getPF('periodical/js/toggle.js'));
+ return dcPage::jsModuleLoad(My::id() . '/js/toggle.js');
}
/**
@@ -262,7 +184,7 @@ class adminPeriodical
*
* @param integer $post_id Post id
*/
- public static function adminBeforePostDelete($post_id)
+ public static function adminBeforePostDelete(int $post_id): void
{
self::delPeriod($post_id);
}
@@ -272,23 +194,22 @@ class adminPeriodical
*
* @param dcPostsActions $pa dcPostsActions instance
*/
- public static function adminPostsActions(dcPostsActions $pa)
+ public static function adminPostsActions(dcPostsActions $pa): void
{
$pa->addAction(
- [__('Periodical') => [__('Add to periodical') => 'periodical_add']],
- ['adminPeriodical', 'callbackAdd']
+ [My::name() => [__('Add to periodical') => 'periodical_add']],
+ [self::class, 'callbackAdd']
);
- if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
+ if (dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
dcAuth::PERMISSION_DELETE,
dcAuth::PERMISSION_CONTENT_ADMIN,
]), dcCore::app()->blog->id)) {
- return null;
+ $pa->addAction(
+ [My::name() => [__('Remove from periodical') => 'periodical_remove']],
+ [self::class, 'callbackRemove']
+ );
}
- $pa->addAction(
- [__('Periodical') => [__('Remove from periodical') => 'periodical_remove']],
- ['adminPeriodical', 'callbackRemove']
- );
}
/**
@@ -297,7 +218,7 @@ class adminPeriodical
* @param dcPostsActions $pa dcPostsActions instance
* @param ArrayObject $post _POST actions
*/
- public static function callbackRemove(dcPostsActions $pa, ArrayObject $post)
+ public static function callbackRemove(dcPostsActions $pa, ArrayObject $post): void
{
# No entry
$posts_ids = $pa->getIDs();
@@ -318,7 +239,7 @@ class adminPeriodical
self::delPeriod($post_id);
}
- dcAdminNotices::addSuccessNotice(__('Posts have been removed from periodical.'));
+ dcPage::addSuccessNotice(__('Posts have been removed from periodical.'));
$pa->redirect(true);
}
@@ -328,7 +249,7 @@ class adminPeriodical
* @param dcPostsActions $pa dcPostsActions instance
* @param ArrayObject $post _POST actions
*/
- public static function callbackAdd(dcPostsActions $pa, ArrayObject $post)
+ public static function callbackAdd(dcPostsActions $pa, ArrayObject $post): void
{
# No entry
$posts_ids = $pa->getIDs();
@@ -342,10 +263,10 @@ class adminPeriodical
if (!empty($post['periodical'])) {
foreach ($posts_ids as $post_id) {
self::delPeriod($post_id);
- self::addPeriod($post_id, $post['periodical']);
+ self::addPeriod($post_id, (int) $post['periodical']);
}
- dcAdminNotices::addSuccessNotice(__('Posts have been added to periodical.'));
+ dcPage::addSuccessNotice(__('Posts have been added to periodical.'));
$pa->redirect(true);
}
@@ -381,52 +302,52 @@ class adminPeriodical
*
* @param ArrayObject $main_items Main items
* @param ArrayObject $sidebar_items Sidebar items
- * @param record $post Post record or null
+ * @param dcRecord $post Post record or null
*/
- public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, $post)
+ public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?dcRecord $post): void
{
# Get existing linked period
$period = '';
- if ($post) {
- $rs = self::period()->getPosts(['post_id' => $post->post_id]);
- $period = $rs->isEmpty() ? '' : $rs->periodical_id;
+ if ($post !== null) {
+ $rs = Utils::getPosts(['post_id' => $post->f('post_id')]);
+ $period = $rs->isEmpty() ? '' : $rs->f('periodical_id');
}
# Set linked period form items
- $sidebar_items['options-box']['items']['period'] = self::formPeriod($period);
+ $sidebar_items['options-box']['items']['period'] = self::formPeriod((int) $period);
}
/**
* Save linked period
*
- * @param cursor $cur Current post cursor
- * @param integer $post_id Post id
+ * @param cursor $cur Current post cursor
+ * @param null|int $post_id Post id
*/
- public static function adminAfterPostSave(cursor $cur, $post_id)
+ public static function adminAfterPostSave(cursor $cur, ?int $post_id): void
{
- if (!isset($_POST['periodical'])) {
- return null;
+ if (!isset($_POST['periodical']) || $post_id === null) {
+ return;
}
# Delete old linked period
self::delPeriod($post_id);
# Add new linked period
- self::addPeriod($post_id, $_POST['periodical']);
+ self::addPeriod($post_id, (int) $_POST['periodical']);
}
/**
* Posts period form field
*
- * @param string $period Period
- * @return null|string Period form content
+ * @param int $period Period
+ * @return string Period form content
*/
- protected static function formPeriod($period = '')
+ private static function formPeriod(int $period = 0): string
{
$combo = self::comboPeriod();
if (empty($combo)) {
- return null;
+ return '';
}
return
@@ -441,63 +362,50 @@ class adminPeriodical
*
* @return array List of period
*/
- protected static function comboPeriod()
+ private static function comboPeriod(): array
{
- if (adminPeriodical::$combo_period === null) {
- $periods = self::period()->getPeriods();
- adminPeriodical::$combo_period = [];
+ if (empty(self::$combo_period)) {
+ $periods = Utils::getPeriods();
if (!$periods->isEmpty()) {
$combo = ['-' => ''];
while ($periods->fetch()) {
- $combo[html::escapeHTML($periods->periodical_title)] = $periods->periodical_id;
+ $combo[html::escapeHTML($periods->f('periodical_title'))] = $periods->f('periodical_id');
}
- adminPeriodical::$combo_period = $combo;
+ self::$combo_period = $combo;
}
}
- return adminPeriodical::$combo_period;
+ return self::$combo_period;
}
/**
* Remove period from posts.
*
- * @param integer $post_id Post id
+ * @param int $post_id Post id
*/
- protected static function delPeriod($post_id)
+ private static function delPeriod(int $post_id): void
{
- if ($post_id === null) {
- return null;
- }
-
- $post_id = (int) $post_id;
- self::period()->delPost($post_id);
+ Utils::delPost((int) $post_id);
}
/**
* Add period to posts
*
- * @param integer $post_id Post id
- * @param array $period Period
+ * @param int $post_id Post id
+ * @param int $period_id Period
*/
- protected static function addPeriod($post_id, $period)
+ private static function addPeriod(int $post_id, int $period_id): void
{
- # Not saved
- if ($post_id === null || empty($period)) {
- return null;
- }
-
# Get periods
- $period = self::period()->getPeriods(['periodical_id' => $period]);
+ $period = Utils::getPeriods(['periodical_id' => $period_id]);
# No period
if ($period->isEmpty()) {
- return null;
+ return;
}
- $post_id = (int) $post_id;
-
# Add relation
- self::period()->addPost($period->periodical_id, $post_id);
+ Utils::addPost($period_id, $post_id);
}
}
diff --git a/src/Dater.php b/src/Dater.php
new file mode 100644
index 0000000..0b1cdf2
--- /dev/null
+++ b/src/Dater.php
@@ -0,0 +1,102 @@
+auth->getInfo('user_tz')));
+
+ return $d ? date_format($d->setTimezone(new DateTimeZone('UTC')), $format) : '';
+ }
+
+ /**
+ * Format a date from user TZ to UTC
+ */
+ public static function toUser(string $date, string $format = 'Y-m-d\TH:i'): string
+ {
+ $d = date_create($date, new DateTimeZone('UTC'));
+
+ return $d ? date_format($d->setTimezone(new DateTimeZone(dcCore::app()->auth->getInfo('user_tz'))), $format) : '';
+ }
+
+ /**
+ * Format a date to specific TZ (UTC by default) from another format
+ */
+ public static function toDate(int|string $date = 'now', string $format = 'Y-m-d H:i:00', string $to_tz = 'UTC'): string
+ {
+ $d = is_int($date) ?
+ date_create_from_format('U', (string) $date, new DateTimeZone('UTC')) :
+ date_create($date, new DateTimeZone('UTC'));
+
+ return $d ? date_format($d->setTimeZone(new DateTimeZone($to_tz)), $format) : '';
+ }
+
+ /**
+ * Get next timestamp from a period
+ */
+ public static function getNextTime(int $ts, string $period): int
+ {
+ $dt = date_create_from_format('U', (string) $ts);
+
+ if ($dt === false) {
+ return $ts;
+ }
+
+ switch($period) {
+ case 'hour':
+ $dt->modify('+1 hour');
+
+ break;
+
+ case 'halfday':
+ $dt->modify('+12 hours');
+
+ break;
+
+ case 'day':
+ $dt->modify('+1 day');
+
+ break;
+
+ case 'week':
+ $dt->modify('+1 week');
+
+ break;
+
+ case 'month':
+ $dt->modify('+1 month');
+
+ break;
+
+ default:
+
+ throw new Exception(__('Unknow frequence'));
+ }
+
+ return (int) $dt->format('U');
+ }
+}
diff --git a/src/Frontend.php b/src/Frontend.php
index b583172..0b239f2 100644
--- a/src/Frontend.php
+++ b/src/Frontend.php
@@ -10,155 +10,153 @@
* @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);
-if (!in_array(dcCore::app()->url->type, ['default', 'feed'])) {
- return null;
-}
+namespace Dotclear\Plugin\periodical;
-dcCore::app()->blog->settings->addNamespace('periodical');
-
-dcCore::app()->addBehavior(
- 'publicBeforeDocumentV2',
- ['publicPeriodical', 'publicBeforeDocument']
-);
+use dcBlog;
+use dcCore;
+use dcNsProcess;
+use Exception;
/**
- * @ingroup DC_PLUGIN_PERIODICAL
- * @brief Periodical - public methods.
- * @since 2.6
+ * Update posts from periods on frontend
*/
-class publicPeriodical
+class Frontend extends dcNsProcess
{
- /**
- * Publish periodical
- */
- public static function publicBeforeDocument()
+ public static function init(): bool
{
- try {
- $per = new periodical();
- $s = dcCore::app()->blog->settings->periodical;
+ static::$init = defined('DC_RC_PATH')
+ && in_array(dcCore::app()->url->type, ['default', 'feed']);
- $per->lockUpdate();
+ return static::$init;
+ }
- # Get periods
- $periods = dcCore::app()->auth->sudo([$per, 'getPeriods']);
-
- # No period
- if ($periods->isEmpty()) {
- $per->unlockUpdate();
-
- return null;
- }
-
- $now = dt::toUTC(time());
- $posts_order = $s->periodical_pub_order;
- if (!preg_match('/^(post_dt|post_creadt|post_id) (asc|desc)$/', $posts_order)) {
- $posts_order = 'post_dt asc';
- }
- $cur_period = dcCore::app()->con->openCursor(dcCore::app()->prefix . initPeriodical::PERIOD_TABLE_NAME);
-
- while ($periods->fetch()) {
- # Check if period is ongoing
- $cur_tz = strtotime($periods->periodical_curdt);
- $end_tz = strtotime($periods->periodical_enddt);
- $now_tz = $now + dt::getTimeOffset($periods->periodical_tz, $now);
-
- if ($cur_tz < $now_tz && $now_tz < $end_tz) {
- $last_nb = 0;
- $last_tz = $cur_tz;
-
- $max_nb = $periods->periodical_pub_nb;
- $max_tz = $end_tz < $now_tz ? $end_tz : $now_tz;
-
- # Calculate nb of posts to get
- $loop_tz = $cur_tz;
- $limit = 0;
-
- try {
- while (1) {
- if ($loop_tz > $max_tz) {
- break;
- }
- $loop_tz = $per->getNextTime($loop_tz, $periods->periodical_pub_int);
- $limit += 1;
- }
- } catch (Exception $e) {
- }
-
- # If period need update
- if ($limit > 0) {
- # Get posts to publish related to this period
- $posts_params = [];
- $posts_params['periodical_id'] = $periods->periodical_id;
- $posts_params['post_status'] = '-2';
- $posts_params['order'] = $posts_order;
- $posts_params['limit'] = $limit * $max_nb;
- $posts_params['no_content'] = true;
- $posts = dcCore::app()->auth->sudo([$per, 'getPosts'], $posts_params);
-
- if (!$posts->isEmpty()) {
- $cur_post = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcBlog::POST_TABLE_NAME);
-
- while ($posts->fetch()) {
- # Publish post with right date
- $cur_post->clean();
- $cur_post->post_status = 1;
-
- # Update post date with right date
- if ($s->periodical_upddate) {
- $cur_post->post_dt = date('Y-m-d H:i:s', $last_tz);
- $cur_post->post_tz = $periods->periodical_tz;
- } else {
- $cur_post->post_dt = $posts->post_dt;
- }
-
- # Also update post url with right date
- if ($s->periodical_updurl) {
- $cur_post->post_url = dcCore::app()->blog->getPostURL('', $cur_post->post_dt, $posts->post_title, $posts->post_id);
- }
-
- $cur_post->update(
- 'WHERE post_id = ' . $posts->post_id . ' ' .
- "AND blog_id = '" . dcCore::app()->con->escape(dcCore::app()->blog->id) . "' "
- );
-
- # Delete post relation to this period
- $per->delPost($posts->post_id);
-
- $last_nb++;
-
- # Increment upddt if nb of publishing is to the max
- if ($last_nb == $max_nb) {
- $last_tz = $per->getNextTime($last_tz, $periods->periodical_pub_int);
- $last_nb = 0;
- }
-
- # --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
- $cur_period->clean();
- $cur_period->periodical_curdt = date('Y-m-d H:i:s', $loop_tz);
- $cur_period->update(
- 'WHERE periodical_id = ' . $periods->periodical_id . ' ' .
- "AND blog_id = '" . dcCore::app()->con->escape(dcCore::app()->blog->id) . "' "
- );
- }
- }
- $per->unlockUpdate();
- } catch (Exception $e) {
- if (isset($per)) {
- $per->unlockUpdate();
- }
-
- return null;
+ public static function process(): bool
+ {
+ if (!static::$init) {
+ return false;
}
+
+ dcCore::app()->addBehavior('publicBeforeDocumentV2', function (): void {
+ try {
+ $s = dcCore::app()->blog->settings->get(My::id());
+
+ Utils::lockUpdate();
+
+ # Get periods
+ $periods = dcCore::app()->auth->sudo([Utils::class, 'getPeriods']);
+
+ # No period
+ if ($periods->isEmpty()) {
+ Utils::unlockUpdate();
+
+ return;
+ }
+
+ $now_ts = (int) Dater::toDate('now', 'U');
+ $posts_order = $s->get('periodical_pub_order');
+ if (!preg_match('/^(post_dt|post_creadt|post_id) (asc|desc)$/', $posts_order)) {
+ $posts_order = 'post_dt asc';
+ }
+ $cur_period = dcCore::app()->con->openCursor(dcCore::app()->prefix . My::TABLE_NAME);
+
+ while ($periods->fetch()) {
+ # 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');
+
+ if ($cur_ts < $now_ts && $now_ts < $end_ts) {
+ $max_nb = (int) $periods->f('periodical_pub_nb');
+ $last_nb = 0;
+ $last_ts = $loop_ts = $cur_ts;
+ $limit = 0;
+
+ try {
+ while (1) {
+ if ($loop_ts > $now_ts) {
+ break;
+ }
+ $loop_ts = Dater::getNextTime($loop_ts, $periods->f('periodical_pub_int'));
+ $limit += 1;
+ }
+ } catch (Exception $e) {
+ }
+
+ # If period need update
+ if ($limit > 0) {
+ # 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;
+ $posts_params['order'] = $posts_order;
+ $posts_params['limit'] = $limit * $max_nb;
+ $posts_params['no_content'] = true;
+ $posts = dcCore::app()->auth->sudo([Utils::class, 'getPosts'], $posts_params);
+
+ if (!$posts->isEmpty()) {
+ $cur_post = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcBlog::POST_TABLE_NAME);
+
+ while ($posts->fetch()) {
+ # Publish post with right date
+ $cur_post->clean();
+ $cur_post->setField('post_status', dcBlog::POST_PUBLISHED);
+
+ # 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
+ if ($s->get('periodical_updurl')) {
+ $cur_post->setField('post_url', dcCore::app()->blog->getPostURL(
+ '',
+ $cur_post->getField('post_dt'),
+ $posts->f('post_title'),
+ $posts->f('post_id')
+ ));
+ }
+
+ $cur_post->update(
+ 'WHERE post_id = ' . $posts->f('post_id') . ' ' .
+ "AND blog_id = '" . dcCore::app()->con->escapeStr(dcCore::app()->blog->id) . "' "
+ );
+
+ # 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
+ if ($last_nb == $max_nb) {
+ $last_ts = Dater::getNextTime($last_ts, $periods->f('periodical_pub_int'));
+ $last_nb = 0;
+ }
+
+ # --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
+ $cur_period->clean();
+ $cur_period->setField('periodical_curdt', Dater::toDate($loop_ts, 'Y-m-d H:i:00'));
+ $cur_period->update(
+ 'WHERE periodical_id = ' . $periods->f('periodical_id') . ' ' .
+ "AND blog_id = '" . dcCore::app()->con->escapeStr(dcCore::app()->blog->id) . "' "
+ );
+ }
+ }
+ Utils::unlockUpdate();
+ } catch (Exception $e) {
+ Utils::unlockUpdate();
+ }
+ });
+
+ return true;
}
}
diff --git a/src/Install.php b/src/Install.php
index c52e7f9..735acce 100644
--- a/src/Install.php
+++ b/src/Install.php
@@ -10,51 +10,64 @@
* @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\periodical;
+
+use dbStruct;
+use dcCore;
+use dcNsProcess;
+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;
}
- # Tables
- $t = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
+ public static function process(): bool
+ {
+ if (!static::$init) {
+ return false;
+ }
- # Table principale des sondages
- $t->{initPeriodical::PERIOD_TABLE_NAME}
- ->periodical_id('bigint', 0, false)
- ->blog_id('varchar', 32, false)
- ->periodical_type('varchar', 32, false, "'post'")
- ->periodical_title('varchar', 255, false, "''")
- ->periodical_tz('varchar', 128, false, "'UTC'")
- ->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)
+ try {
+ # Tables
+ $t = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
- ->primary('pk_periodical', 'periodical_id')
- ->index('idx_periodical_type', 'btree', 'periodical_type');
+ # 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)
- $ti = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
- $changes = $ti->synchronize($t);
+ ->primary('pk_periodical', 'periodical_id')
+ ->index('idx_periodical_type', 'btree', 'periodical_type');
- # Settings
- dcCore::app()->blog->settings->addNamespace(basename(__DIR__));
- $s = dcCore::app()->blog->settings->__get(basename(__DIR__));
- $s->put('periodical_active', false, 'boolean', 'Enable extension', false, true);
- $s->put('periodical_upddate', true, 'boolean', 'Update post date', false, true);
- $s->put('periodical_updurl', false, 'boolean', 'Update post url', false, true);
- $s->put('periodical_pub_order', 'post_dt asc', 'string', 'Order of publication', false, true);
+ (new dbStruct(dcCore::app()->con, dcCore::app()->prefix))->synchronize($t);
- return true;
-} catch (Exception $e) {
- dcCore::app()->error->add($e->getMessage());
+ # 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);
+ $s->put('periodical_updurl', false, 'boolean', 'Update post url', false, true);
+ $s->put('periodical_pub_order', 'post_dt asc', 'string', 'Order of publication', 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 af45c18..6f83be8 100644
--- a/src/Manage.php
+++ b/src/Manage.php
@@ -10,123 +10,172 @@
* @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\periodical;
-# Objects
-$per = new periodical();
+use adminGenericFilter;
+use dcAuth;
+use dcCore;
+use dcNsProcess;
+use dcPage;
+use Exception;
+use form;
+use http;
-# Default values
-$action = $_POST['action'] ?? '';
+/**
+ * Admin page for periods
+ */
+class Manage extends dcNsProcess
+{
+ public static function init(): bool
+ {
+ static::$init == defined('DC_CONTEXT_ADMIN')
+ && My::phpCompliant()
+ && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
+ dcAuth::PERMISSION_USAGE,
+ dcAuth::PERMISSION_CONTENT_ADMIN,
+ ]), dcCore::app()->blog->id);
-# Delete periods and related posts links
-if ($action == 'deleteperiods' && !empty($_POST['periods'])) {
- try {
- foreach ($_POST['periods'] as $id) {
- $id = (int) $id;
- $per->delPeriodPosts($id);
- $per->delPeriod($id);
+ // call period manage page
+ if (($_REQUEST['part'] ?? 'periods') === 'period') {
+ static::$init = ManagePeriod::init();
}
- dcAdminNotices::addSuccessNotice(
- __('Periods removed.')
+ return static::$init;
+ }
+
+ public static function process(): bool
+ {
+ if (!static::$init) {
+ return false;
+ }
+
+ if (($_REQUEST['part'] ?? 'periods') === 'period') {
+ return ManagePeriod::process();
+ }
+
+ # Default values
+ $vars = ManageVars::init();
+
+ # Delete periods and related posts links
+ if ($vars->action == 'deleteperiods' && !empty($vars->periods)) {
+ try {
+ foreach ($vars->periods as $id) {
+ Utils::delPeriodPosts($id);
+ Utils::delPeriod($id);
+ }
+
+ dcPage::addSuccessNotice(
+ __('Periods removed.')
+ );
+
+ if (!empty($vars->redir)) {
+ http::redirect($vars->redir);
+ } else {
+ dcCore::app()->adminurl->redirect('admin.plugin.' . My::id(), ['part' => 'periods']);
+ }
+ } catch (Exception $e) {
+ dcCore::app()->error->add($e->getMessage());
+ }
+ }
+
+ # Delete periods related posts links (without delete periods)
+ if ($vars->action == 'emptyperiods' && !empty($vars->periods)) {
+ try {
+ foreach ($vars->periods as $id) {
+ Utils::delPeriodPosts($id);
+ }
+
+ dcPage::addSuccessNotice(
+ __('Periods emptied.')
+ );
+
+ if (!empty($vars->redir)) {
+ http::redirect($vars->redir);
+ } else {
+ dcCore::app()->adminurl->redirect('admin.plugin.' . My::id(), ['part' => 'periods']);
+ }
+ } catch (Exception $e) {
+ dcCore::app()->error->add($e->getMessage());
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Renders the page.
+ */
+ public static function render(): void
+ {
+ if (!static::$init) {
+ return;
+ }
+
+ if (($_REQUEST['part'] ?? 'periods') === 'period') {
+ ManagePeriod::render();
+
+ return;
+ }
+
+ # Filters
+ $p_filter = new adminGenericFilter(dcCore::app(), My::id());
+ $p_filter->add('part', 'periods');
+
+ $params = $p_filter->params();
+
+ # Get periods
+ try {
+ $periods = Utils::getPeriods($params);
+ $counter = Utils::getPeriods($params, true);
+ $period_list = new ManageList(dcCore::app(), $periods, $counter->f(0));
+ } catch (Exception $e) {
+ dcCore::app()->error->add($e->getMessage());
+ }
+
+ # Display
+ dcPage::openModule(
+ My::name(),
+ dcPage::jsModuleLoad(My::id() . '/js/checkbox.js') .
+ $p_filter->js(dcCore::app()->adminurl->get('admin.plugin.' . My::id(), ['part' => 'periods']))
);
- if (!empty($_POST['redir'])) {
- http::redirect($_POST['redir']);
- } else {
- dcCore::app()->adminurl->redirect('admin.plugin.periodical', ['part' => 'periods']);
+ echo dcPage::breadcrumb([
+ __('Plugins') => '',
+ My::name() => '',
+ ]) .
+ dcPage::notices() .
+
+ '
+ ' . __('New period') . '
+
';
+
+ if (isset($period_list)) {
+ # Filters
+ $p_filter->display('admin.plugin.' . My::id(), form::hidden('p', My::id()) . form::hidden('part', 'periods'));
+
+ # Periods list
+ $period_list->periodDisplay(
+ $p_filter,
+ '
'
+ );
}
- } catch (Exception $e) {
- dcCore::app()->error->add($e->getMessage());
+ dcPage::helpBlock('periodical');
+
+ dcPage::closeModule();
}
}
-# Delete periods related posts links (without delete periods)
-if ($action == 'emptyperiods' && !empty($_POST['periods'])) {
- try {
- foreach ($_POST['periods'] as $id) {
- $id = (int) $id;
- $per->delPeriodPosts($id);
- }
-
- dcAdminNotices::addSuccessNotice(
- __('Periods emptied.')
- );
-
- if (!empty($_POST['redir'])) {
- http::redirect($_POST['redir']);
- } else {
- dcCore::app()->adminurl->redirect('admin.plugin.periodical', ['part' => 'periods']);
- }
- } catch (Exception $e) {
- dcCore::app()->error->add($e->getMessage());
- }
-}
-
-$combo_action = [
- __('empty periods') => 'emptyperiods',
- __('delete periods') => 'deleteperiods',
-];
-
-# Filters
-$p_filter = new adminGenericFilter(dcCore::app(), 'periodical');
-$p_filter->add('part', 'periods');
-
-$params = $p_filter->params();
-
-# Get periods
-try {
- $periods = $per->getPeriods($params);
- $counter = $per->getPeriods($params, true);
- $period_list = new adminPeriodicalList(dcCore::app(), $periods, $counter->f(0));
-} catch (Exception $e) {
- dcCore::app()->error->add($e->getMessage());
-}
-
-# Display
-echo
-'
' . __('Periodical') . '' .
-dcPage::jsLoad(dcPage::getPF('periodical/js/checkbox.js')) .
-$p_filter->js(dcCore::app()->adminurl->get('admin.plugin.periodical', ['part' => 'periods'])) .
-'' .
-'' .
-
-dcPage::breadcrumb([
- __('Plugins') => '',
- __('Periodical') => '',
-]) .
-dcPage::notices() .
-
-'
-' . __('New period') . '
-
';
-
-if (isset($period_list)) {
- # Filters
- $p_filter->display('admin.plugin.periodical', form::hidden('p', 'periodical') . form::hidden('part', 'periods'));
-
- # Periods list
- $period_list->periodDisplay(
- $p_filter,
- '
'
- );
-}
-dcPage::helpBlock('periodical');
-
-echo '';
diff --git a/src/ManageList.php b/src/ManageList.php
index ae3f7b3..8bd7492 100644
--- a/src/ManageList.php
+++ b/src/ManageList.php
@@ -10,20 +10,30 @@
* @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\periodical;
+
+use ArrayObject;
+use adminGenericFilter;
+use adminGenericList;
+use adminPostFilter;
+use dcAuth;
+use dcBlog;
+use dcCore;
+use dcPager;
+use dt;
+use html;
+use form;
/**
* @ingroup DC_PLUGIN_PERIODICAL
* @brief Periodical - admin pager methods.
* @since 2.6
*/
-class adminPeriodicalList extends adminGenericList
+class ManageList extends adminGenericList
{
- private $periodical = null;
-
- public function periodDisplay($filter, $enclose_block = '')
+ public function periodDisplay(adminGenericFilter $filter, string $enclose_block = ''): void
{
if ($this->rs->isEmpty()) {
if ($filter->show()) {
@@ -32,9 +42,8 @@ class adminPeriodicalList extends adminGenericList
echo '
' . __('No period') . '
';
}
} else {
- $this->periodical = new periodical();
- $pager = new dcPager((int) $filter->page, $this->rs_count, $filter->nb, 10);
- $pager->var_page = 'page';
+ $pager = new dcPager((int) $filter->value('page'), (int) $this->rs_count, (int) $filter->value('nb'), 10);
+ $pager->var_page = 'page';
$periods = [];
if (isset($_REQUEST['periods'])) {
@@ -58,7 +67,7 @@ class adminPeriodicalList extends adminGenericList
'enddt' => '
' . __('End date') . ' | ',
]);
- $this->userColumns('periodical', $cols);
+ $this->userColumns(My::id(), $cols);
$html_block .= '
' . implode(iterator_to_array($cols)) . '
%s%s
';
if ($enclose_block) {
@@ -69,17 +78,17 @@ class adminPeriodicalList extends adminGenericList
echo $pager->getLinks() . $blocks[0];
while ($this->rs->fetch()) {
- echo $this->periodLine(isset($periods[$this->rs->periodical_id]));
+ echo $this->periodLine(isset($periods[(int) $this->rs->f('periodical_id')]));
}
echo $blocks[1] . $blocks[2] . $pager->getLinks();
}
}
- private function periodLine($checked)
+ private function periodLine(bool $checked): string
{
- $nb_posts = $this->periodical->getPosts(['periodical_id' => $this->rs->periodical_id], true)->f(0);
- $url = dcCore::app()->adminurl->get('admin.plugin.periodical', ['part' => 'period', 'period_id' => $this->rs->periodical_id]);
+ $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 = '