From b62c9623776edf78389d075cb3de2c9a0f261345 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sat, 24 Aug 2024 00:07:59 -0400 Subject: [PATCH 01/13] Make date display in consistently across manager components Adds a new centralized formatting class for datetime data, adjusting various classes to make use of the new formatters. --- .../data/transport.core.system_settings.php | 18 +++ core/lexicon/en/default.inc.php | 1 + core/lexicon/en/setting.inc.php | 6 + .../Processors/Browser/Directory/GetFiles.php | 16 +- core/src/Revolution/Processors/Processor.php | 117 +++++++++----- .../Revolution/Processors/Resource/Data.php | 68 +++++--- .../Processors/Resource/Event/GetList.php | 43 ++--- .../Processors/Resource/Trash/GetList.php | 9 ++ .../Processors/Security/Message/GetList.php | 15 +- .../Processors/Security/Profile/Get.php | 13 +- .../Processors/Security/Profile/Update.php | 24 ++- .../Processors/Security/User/Get.php | 20 ++- .../Processors/Security/User/GetOnline.php | 15 +- .../User/GetRecentlyEditedResources.php | 30 ++-- .../Processors/Security/User/Validation.php | 143 +++++++++-------- .../System/ActiveResource/GetList.php | 16 +- .../System/Dashboard/Widget/Feed.php | 22 ++- .../src/Revolution/Utilities/modFormatter.php | 147 ++++++++++++++++++ core/src/Revolution/modX.php | 24 +++ .../modext/sections/system/file/edit.js | 4 +- .../modext/widgets/media/modx.browser.js | 7 +- .../resource/modx.panel.resource.data.js | 38 +---- .../resource/modx.panel.resource.schedule.js | 8 +- .../modx.grid.user.recent.resource.js | 1 - .../default/system/file/edit.class.php | 9 ++ .../default/dashboard/onlineusers.tpl | 4 +- 26 files changed, 572 insertions(+), 246 deletions(-) create mode 100644 core/src/Revolution/Utilities/modFormatter.php diff --git a/_build/data/transport.core.system_settings.php b/_build/data/transport.core.system_settings.php index a34f938f995..7a54d35138d 100644 --- a/_build/data/transport.core.system_settings.php +++ b/_build/data/transport.core.system_settings.php @@ -993,6 +993,24 @@ 'area' => 'manager', 'editedon' => null, ], '', true, true); +$settings['manager_datetime_separator'] = $xpdo->newObject(modSystemSetting::class); +$settings['manager_datetime_separator']->fromArray([ + 'key' => 'manager_datetime_separator', + 'value' => ', ', + 'xtype' => 'textfield', + 'namespace' => 'core', + 'area' => 'manager', + 'editedon' => null, +], '', true, true); +$settings['manager_datetime_empty_value'] = $xpdo->newObject(modSystemSetting::class); +$settings['manager_datetime_empty_value']->fromArray([ + 'key' => 'manager_datetime_empty_value', + 'value' => '—', + 'xtype' => 'textfield', + 'namespace' => 'core', + 'area' => 'manager', + 'editedon' => null, +], '', true, true); $settings['manager_direction'] = $xpdo->newObject(modSystemSetting::class); $settings['manager_direction']->fromArray([ 'key' => 'manager_direction', diff --git a/core/lexicon/en/default.inc.php b/core/lexicon/en/default.inc.php index 58145332f7f..77e5ad354af 100644 --- a/core/lexicon/en/default.inc.php +++ b/core/lexicon/en/default.inc.php @@ -510,6 +510,7 @@ $_lang['untitled_tv'] = 'Untitled tv'; $_lang['untitled_weblink'] = 'Untitled weblink'; $_lang['untitled_symlink'] = 'Untitled symlink'; +$_lang['unedited'] = 'Unedited'; $_lang['unknown'] = 'Unknown'; $_lang['unsaved_changes'] = 'There are unsaved changes. Are you sure you want to leave this page?'; $_lang['update'] = 'Update'; diff --git a/core/lexicon/en/setting.inc.php b/core/lexicon/en/setting.inc.php index 03cf9c14fa8..3045ee95c88 100644 --- a/core/lexicon/en/setting.inc.php +++ b/core/lexicon/en/setting.inc.php @@ -219,6 +219,12 @@ $_lang['setting_date_timezone'] = 'Default Time Zone'; $_lang['setting_date_timezone_desc'] = 'Controls the default timezone setting for PHP date functions, if not empty. If empty and the PHP date.timezone ini setting is not set in your environment, UTC will be assumed.'; +$_lang['manager_datetime_empty_value'] = 'Datetime Empty Value'; +$_lang['manager_datetime_empty_value_desc'] = 'The text (if any) that will show in grids and forms when a datetime field’s value has not been set. (Default: “–” [a single en dash])'; + +$_lang['manager_datetime_separator'] = 'Datetime Separator'; +$_lang['manager_datetime_separator_desc'] = 'When the date and time are shown as a combined element, these characters will be used to visually seapate them. (Default: “, ” [comma and space])'; + $_lang['setting_debug'] = 'Debug'; $_lang['setting_debug_desc'] = 'Controls turning debugging on/off in MODX and/or sets the PHP error_reporting level. \'\' = use current error_reporting, \'0\' = false (error_reporting = 0), \'1\' = true (error_reporting = -1), or any valid error_reporting value (as an integer).'; diff --git a/core/src/Revolution/Processors/Browser/Directory/GetFiles.php b/core/src/Revolution/Processors/Browser/Directory/GetFiles.php index 90a8aa692fc..f081d2cf742 100644 --- a/core/src/Revolution/Processors/Browser/Directory/GetFiles.php +++ b/core/src/Revolution/Processors/Browser/Directory/GetFiles.php @@ -1,4 +1,5 @@ source->getObjectsInContainer($dir); - return $this->source->hasErrors() - ? $this->failure($this->source->getErrors(), []) - : $this->outputArray($list); + if ($this->source->hasErrors()) { + return $this->failure($this->source->getErrors(), []); + } + + $formatter = new modFormatter($this->modx); + foreach ($list as $i => $file) { + $list[$i]['lastmod'] = $formatter->formatManagerDateTime($file['lastmod']); + } + + return $this->outputArray($list); } } diff --git a/core/src/Revolution/Processors/Processor.php b/core/src/Revolution/Processors/Processor.php index 79565241fe7..4b58e2d5aa2 100644 --- a/core/src/Revolution/Processors/Processor.php +++ b/core/src/Revolution/Processors/Processor.php @@ -1,4 +1,5 @@ modx =& $modx; $this->setProperties($properties); } @@ -55,7 +64,8 @@ public function __construct(modX $modx,array $properties = []) { * @param string $path The absolute path * @return void */ - public function setPath($path) { + public function setPath($path) + { $this->path = $path; } @@ -66,9 +76,10 @@ public function setPath($path) { * * @return void */ - public function setProperties($properties, $merge = true) { + public function setProperties($properties, $merge = true) + { unset($properties['HTTP_MODAUTH']); - $this->properties = $merge ? array_merge($this->properties,$properties) : $properties; + $this->properties = $merge ? array_merge($this->properties, $properties) : $properties; } /** @@ -76,7 +87,8 @@ public function setProperties($properties, $merge = true) { * @param string $key * @return void */ - public function unsetProperty($key) { + public function unsetProperty($key) + { unset($this->properties[$key]); } @@ -85,7 +97,10 @@ public function unsetProperty($key) { * * @return boolean */ - public function checkPermissions() { return true; } + public function checkPermissions() + { + return true; + } /** * Can be used to provide custom methods prior to processing. Return true to tell MODX that the Processor @@ -93,14 +108,18 @@ public function checkPermissions() { return true; } * * @return boolean */ - public function initialize() { return true; } + public function initialize() + { + return true; + } /** * Load a collection of Language Topics for this processor. * Override this in your derivative class to provide the array of topics to load. * @return array */ - public function getLanguageTopics() { + public function getLanguageTopics() + { return []; } @@ -110,8 +129,9 @@ public function getLanguageTopics() { * @param mixed $object * @return array|string */ - public function success($msg = '',$object = null) { - return $this->modx->error->success($msg,$object); + public function success($msg = '', $object = null) + { + return $this->modx->error->success($msg, $object); } /** @@ -120,15 +140,17 @@ public function success($msg = '',$object = null) { * @param mixed $object * @return array|string */ - public function failure($msg = '',$object = null) { - return $this->modx->error->failure($msg,$object); + public function failure($msg = '', $object = null) + { + return $this->modx->error->failure($msg, $object); } /** * Return whether or not the processor has errors * @return boolean */ - public function hasErrors() { + public function hasErrors() + { return $this->modx->error->hasError(); } @@ -138,8 +160,9 @@ public function hasErrors() { * @param string $message * @return void */ - public function addFieldError($key,$message = '') { - $this->modx->error->addField($key,$message); + public function addFieldError($key, $message = '') + { + $this->modx->error->addField($key, $message); } /** @@ -152,9 +175,10 @@ public function addFieldError($key,$message = '') { * @param array $properties An array of properties being run with the processor * @return Processor The class specified by $className */ - public static function getInstance(modX $modx,$className,$properties = []) { + public static function getInstance(modX $modx, $className, $properties = []) + { /** @var Processor $processor */ - $processor = new $className($modx,$properties); + $processor = new $className($modx, $properties); return $processor; } @@ -170,7 +194,8 @@ abstract public function process(); * Run the processor, returning a ProcessorResponse object. * @return ProcessorResponse */ - public function run() { + public function run() + { if (!$this->checkPermissions()) { $o = $this->failure($this->modx->lexicon('permission_denied_processor', array( 'action' => preg_replace('/[^\w\-_\/]+/i', '', $this->getProperty('action')), @@ -189,7 +214,7 @@ public function run() { $o = $this->process(); } } - $response = new ProcessorResponse($this->modx,$o); + $response = new ProcessorResponse($this->modx, $o); return $response; } @@ -199,8 +224,9 @@ public function run() { * @param mixed $default * @return mixed */ - public function getProperty($k,$default = null) { - return array_key_exists($k,$this->properties) ? $this->properties[$k] : $default; + public function getProperty($k, $default = null) + { + return array_key_exists($k, $this->properties) ? $this->properties[$k] : $default; } /** @@ -210,7 +236,8 @@ public function getProperty($k,$default = null) { * @param mixed $v * @return void */ - public function setProperty($k,$v) { + public function setProperty($k, $v) + { $this->properties[$k] = $v; } @@ -222,11 +249,12 @@ public function setProperty($k,$v) { * @param boolean $force * @return int|null */ - public function setCheckbox($k,$force = false) { + public function setCheckbox($k, $force = false) + { $v = null; if ($force || isset($this->properties[$k])) { $v = empty($this->properties[$k]) || $this->properties[$k] === 'false' ? 0 : 1; - $this->setProperty($k,$v); + $this->setProperty($k, $v); } return $v; } @@ -235,7 +263,8 @@ public function setCheckbox($k,$force = false) { * Get an array of properties for this processor * @return array */ - public function getProperties() { + public function getProperties() + { return $this->properties; } @@ -245,8 +274,9 @@ public function getProperties() { * @param array $properties * @return array The newly merged properties array */ - public function setDefaultProperties(array $properties = []) { - $this->properties = array_merge($properties,$this->properties); + public function setDefaultProperties(array $properties = []) + { + $this->properties = array_merge($properties, $this->properties); return $this->properties; } @@ -261,8 +291,11 @@ public function setDefaultProperties(array $properties = []) { * @param mixed $count The total number of objects. Used for pagination. * @return string The JSON output. */ - public function outputArray(array $array,$count = false) { - if ($count === false) { $count = count($array); } + public function outputArray(array $array, $count = false) + { + if ($count === false) { + $count = count($array); + } $output = json_encode([ 'success' => true, 'total' => $count, @@ -270,7 +303,7 @@ public function outputArray(array $array,$count = false) { ], JSON_INVALID_UTF8_SUBSTITUTE); if ($output === false) { - $this->modx->log(modX::LOG_LEVEL_ERROR, 'Processor failed creating output array due to JSON error '.json_last_error()); + $this->modx->log(modX::LOG_LEVEL_ERROR, 'Processor failed creating output array due to JSON error ' . json_last_error()); return json_encode(['success' => false]); } return $output; @@ -286,7 +319,8 @@ public function outputArray(array $array,$count = false) { * @param mixed $data The PHP data to be converted. * @return string The extended JSON-encoded string. */ - public function toJSON($data) { + public function toJSON($data) + { if (is_array($data)) { array_walk_recursive($data, [&$this, '_encodeLiterals']); } @@ -300,12 +334,15 @@ public function toJSON($data) { * @param mixed &$value A reference to the value to be encoded if it is identified as a literal. * @param integer|string $key The array key corresponding to the value. */ - protected function _encodeLiterals(&$value, $key) { + protected function _encodeLiterals(&$value, $key) + { if (is_string($value)) { /* properly handle common literal structures */ - if (strpos($value, 'function(') === 0 + if ( + strpos($value, 'function(') === 0 || strpos($value, 'new Function(') === 0 - || strpos($value, 'Ext.') === 0) { + || strpos($value, 'Ext.') === 0 + ) { $value = '@@' . base64_encode($value) . '@@'; } } @@ -318,11 +355,14 @@ protected function _encodeLiterals(&$value, $key) { * @param string $string The JSON-encoded string with encoded literals. * @return string The JSON-encoded string with literals restored. */ - protected function _decodeLiterals($string) { + protected function _decodeLiterals($string) + { $pattern = '/"@@(.*?)@@"/'; $string = preg_replace_callback( $pattern, - function ($matches) { return base64_decode($matches[1]); }, + function ($matches) { + return base64_decode($matches[1]); + }, $string ); return $string; @@ -335,7 +375,8 @@ function ($matches) { return base64_decode($matches[1]); }, * @param string $separator The separator for each event response * @return string The processed response. */ - public function processEventResponse($response,$separator = "\n") { + public function processEventResponse($response, $separator = "\n") + { if (is_array($response)) { $result = false; foreach ($response as $msg) { diff --git a/core/src/Revolution/Processors/Resource/Data.php b/core/src/Revolution/Processors/Resource/Data.php index c600d2cc827..e3d029d3e84 100644 --- a/core/src/Revolution/Processors/Resource/Data.php +++ b/core/src/Revolution/Processors/Resource/Data.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); $id = $this->getProperty('id', false); - if (empty($id)) return $this->modx->lexicon('resource_err_ns'); + if (empty($id)) { + return $this->modx->lexicon('resource_err_ns'); + } $c = $this->modx->newQuery(modResource::class); $c->select([ $this->modx->getSelectColumns(modResource::class, 'modResource'), @@ -88,7 +93,7 @@ public function getCacheSource() $buffer = $this->modx->cacheManager->get($this->resource->getCacheKey(), [ xPDO::OPT_CACHE_KEY => $this->modx->getOption('cache_resource_key', null, 'resource'), xPDO::OPT_CACHE_HANDLER => $this->modx->getOption('cache_resource_handler', null, $this->modx->getOption(xPDO::OPT_CACHE_HANDLER)), - xPDO::OPT_CACHE_FORMAT => (integer)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), + xPDO::OPT_CACHE_FORMAT => (int)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), ]); if ($buffer) { $buffer = $buffer['resource']['_content']; @@ -98,29 +103,46 @@ public function getCacheSource() public function getChanges(array $resourceArray) { - $emptyDate = '0000-00-00 00:00:00'; - $resourceArray['pub_date'] = !empty($resourceArray['pub_date']) && $resourceArray['pub_date'] != $emptyDate ? $resourceArray['pub_date'] : $this->modx->lexicon('none'); - $resourceArray['unpub_date'] = !empty($resourceArray['unpub_date']) && $resourceArray['unpub_date'] != $emptyDate ? $resourceArray['unpub_date'] : $this->modx->lexicon('none'); + $unknownUser = '(' . $this->modx->lexicon('unknown') . ')'; $resourceArray['status'] = $resourceArray['published'] ? $this->modx->lexicon('resource_published') : $this->modx->lexicon('resource_unpublished'); - $server_offset_time = floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600; - $format = $this->modx->getOption('manager_date_format') . ' ' . $this->modx->getOption('manager_time_format'); - $resourceArray['createdon_adjusted'] = date($format, strtotime($this->resource->get('createdon')) + $server_offset_time); - $resourceArray['createdon_by'] = $this->resource->get('creator'); - if (!empty($resourceArray['editedon']) && $resourceArray['editedon'] != $emptyDate) { - $resourceArray['editedon_adjusted'] = date($format, strtotime($this->resource->get('editedon')) + $server_offset_time); - $resourceArray['editedon_by'] = $this->resource->get('editor'); - } else { - $resourceArray['editedon_adjusted'] = $this->modx->lexicon('none'); - $resourceArray['editedon_by'] = $this->modx->lexicon('none'); - } - if (!empty($resourceArray['publishedon']) && $resourceArray['publishedon'] != $emptyDate) { - $resourceArray['publishedon_adjusted'] = date($format, strtotime($this->resource->get('publishedon')) + $server_offset_time); - $resourceArray['publishedon_by'] = $this->resource->get('publisher'); - } else { - $resourceArray['publishedon_adjusted'] = $this->modx->lexicon('none'); - $resourceArray['publishedon_by'] = $this->modx->lexicon('none'); - } + $resourceArray['createdon_by'] = $this->resource->get('creator') ?: $unknownUser; + $resourceArray['createdon_adjusted'] = $this->formatter->getFormattedResourceDate( + $this->resource->get('createdon'), + 'created', + false + ); + $resourceArray['editedon_adjusted'] = $this->formatter->getFormattedResourceDate( + $this->resource->get('editedon'), + 'edited', + false + ); + $resourceArray['editedon_by'] = in_array($resourceArray['editedon'], $this->formatter->managerDateEmptyValues) + ? '(' . $this->modx->lexicon('unedited') . ')' + : $this->resource->get('editor') + ; + + $resourceArray['pub_date'] = $this->formatter->getFormattedResourceDate( + $resourceArray['pub_date'], + 'publish', + false + ); + $resourceArray['unpub_date'] = $this->formatter->getFormattedResourceDate( + $resourceArray['unpub_date'], + 'unpublish', + false + ); + $resourceArray['publishedon_adjusted'] = $this->formatter->getFormattedResourceDate( + $this->resource->get('publishedon'), + 'published', + false + ); + $publisher = $this->resource->get('publisher') ?: $unknownUser; + $resourceArray['publishedon_by'] = in_array($resourceArray['publishedon'], $this->formatter->managerDateEmptyValues) + ? '(' . $this->modx->lexicon('unpublished') . ')' + : $publisher + ; + return $resourceArray; } } diff --git a/core/src/Revolution/Processors/Resource/Event/GetList.php b/core/src/Revolution/Processors/Resource/Event/GetList.php index c89c1ea4f3b..277eade75f5 100644 --- a/core/src/Revolution/Processors/Resource/Event/GetList.php +++ b/core/src/Revolution/Processors/Resource/Event/GetList.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); $this->setDefaultProperties([ 'start' => 0, 'limit' => 10, 'mode' => 'pub_date', - 'dir' => 'ASC', - 'timeFormat' => '%a %b %d, %Y %H:%M', - 'offset' => floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600, + 'dir' => 'ASC' ]); return true; } @@ -55,7 +56,9 @@ public function process() $list = []; /** @var modResource $resource */ foreach ($data['results'] as $resource) { - if (!$resource->checkPolicy('view')) continue; + if (!$resource->checkPolicy('view')) { + continue; + } $resourceArray = $this->prepareRow($resource); if (!empty($resourceArray)) { $list[] = $resourceArray; @@ -94,25 +97,27 @@ public function getData() */ public function prepareRow(xPDOObject $object) { - $timeFormat = $this->getProperty('timeFormat', '%a %b %d, %Y'); - $offset = $this->getProperty('offset', 0); - $objectArray = $object->toArray(); + unset($objectArray['content']); + /* + Note that editor grids will not make use of the empty value; without doing some + refactoring of the MODx's datetime component, the field definition for this component + type must specify "date" as its field type and, by doing this, any formatting defined + below will be lost. + */ + $pubDate = $object->get('pub_date'); + $objectArray['pub_date'] = in_array($pubDate, $this->managerDateEmptyValues) + ? $this->managerDateEmptyDisplay + : $this->formatter->formatManagerDateTime($pubDate, 'combined', true) + ; - if (!in_array($object->get('pub_date'), ['', '1969-12-31 00:00:00'])) { - $pubDate = strtotime($object->get('pub_date')) + $offset; - $objectArray['pub_date'] = strftime($timeFormat, $pubDate); - } else { - $objectArray['pub_date'] = ''; - } + $unpubDate = $object->get('unpub_date'); + $objectArray['unpub_date'] = in_array($unpubDate, $this->managerDateEmptyValues) + ? $this->managerDateEmptyDisplay + : $this->formatter->formatManagerDateTime($unpubDate, 'combined', true) + ; - if (!in_array($object->get('unpub_date'), ['', '1969-12-31 00:00:00'])) { - $unpubDate = strtotime($object->get('unpub_date')) + $offset; - $objectArray['unpub_date'] = strftime($timeFormat, $unpubDate); - } else { - $objectArray['unpub_date'] = ''; - } return $objectArray; } } diff --git a/core/src/Revolution/Processors/Resource/Trash/GetList.php b/core/src/Revolution/Processors/Resource/Trash/GetList.php index b53838d3da7..86c2dc19ea1 100644 --- a/core/src/Revolution/Processors/Resource/Trash/GetList.php +++ b/core/src/Revolution/Processors/Resource/Trash/GetList.php @@ -13,6 +13,7 @@ use MODX\Revolution\modContext; use MODX\Revolution\Processors\Model\GetListProcessor; +use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modResource; use MODX\Revolution\modUser; use PDO; @@ -39,6 +40,12 @@ class GetList extends GetListProcessor public $permission = 'view'; + public function initialize() + { + $this->formatter = new modFormatter($this->modx); + return parent::initialize(); + } + /** * @param xPDOQuery $c * @return xPDOQuery @@ -192,6 +199,8 @@ public function prepareRow(xPDOObject $object) $objectArray['cls'] = implode(' ', $cls); + $objectArray['deletedon'] = $this->formatter->formatManagerDateTime($objectArray['deletedon']); + return $objectArray; } } diff --git a/core/src/Revolution/Processors/Security/Message/GetList.php b/core/src/Revolution/Processors/Security/Message/GetList.php index 4746f3e842e..0c8735ee263 100644 --- a/core/src/Revolution/Processors/Security/Message/GetList.php +++ b/core/src/Revolution/Processors/Security/Message/GetList.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); + return parent::initialize(); + } + /** * @param xPDOQuery $c * @return xPDOQuery @@ -78,7 +86,7 @@ public function prepareQueryAfterCount(xPDOQuery $c) 'recipient_username' => 'Recipient.username', 'recipient_fullname' => 'RecipientProfile.fullname' ]); - + return $c; } @@ -89,6 +97,11 @@ public function prepareQueryAfterCount(xPDOQuery $c) public function prepareRow(xPDOObject $object) { $objectArray = $object->toArray(); + + if (array_key_exists('date_sent', $objectArray)) { + $objectArray['date_sent'] = $this->formatter->formatManagerDateTime($objectArray['date_sent']); + } + $objectArray['sender_name'] = $object->get('sender_fullname') . " ({$object->get('sender_username')})"; $objectArray['recipient_name'] = $object->get('recipient_fullname') . " ({$object->get('recipient_username')})"; $objectArray['read'] = $object->get('read') ? true : false; diff --git a/core/src/Revolution/Processors/Security/Profile/Get.php b/core/src/Revolution/Processors/Security/Profile/Get.php index 59775bbe45d..089aa1066ec 100644 --- a/core/src/Revolution/Processors/Security/Profile/Get.php +++ b/core/src/Revolution/Processors/Security/Profile/Get.php @@ -1,4 +1,5 @@ user) { return $this->modx->lexicon('user_err_not_found'); } + $this->formatter = new modFormatter($this->modx); return true; } @@ -67,12 +70,10 @@ public function process() $userArray = array_merge($profile->toArray(), $userArray); } - $userArray['dob'] = !empty($userArray['dob']) ? date('m/d/Y', $userArray['dob']) : ''; - $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date('m/d/Y h:i A', - $userArray['blockeduntil']) : ''; - $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date('m/d/Y h:i A', - $userArray['blockedafter']) : ''; - $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? date('m/d/Y', $userArray['lastlogin']) : ''; + $userArray['dob'] = !empty($userArray['dob']) ? date('Y-m-d', $userArray['dob']) : ''; + $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockeduntil']) : ''; + $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockedafter']) : ''; + $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? $this->formatter->formatManagerDateTime($userArray['lastlogin']) : ''; unset($userArray['password'], $userArray['cachepwd'], $userArray['sessionid'], $userArray['salt']); return $this->success('', $userArray); diff --git a/core/src/Revolution/Processors/Security/Profile/Update.php b/core/src/Revolution/Processors/Security/Profile/Update.php index cd7337fd57e..2bd7dab1b3b 100644 --- a/core/src/Revolution/Processors/Security/Profile/Update.php +++ b/core/src/Revolution/Processors/Security/Profile/Update.php @@ -1,4 +1,5 @@ profile === null) { return $this->modx->lexicon('user_profile_err_not_found'); } - + $this->formatter = new modFormatter($this->modx); return true; } @@ -89,6 +90,11 @@ public function process() return $this->success($this->modx->lexicon('success'), $this->profile->toArray()); } + /* + TBD: Ultimately this Update class should be using the Validation class + that the main User class does ... for both the dob property in prepare() + and the password properties in validate() below + */ public function prepare() { $properties = $this->getProperties(); @@ -96,12 +102,18 @@ public function prepare() /* format and set data */ $dob = $this->getProperty('dob'); if (!empty($dob)) { - $properties['dob'] = strtotime($dob); + $date = \DateTimeImmutable::createFromFormat($this->formatter->managerDateFormat, $dob); + if ($date === false) { + $this->addFieldError('dob', $this->modx->lexicon('user_err_not_specified_dob')); + } else { + $properties['dob'] = $date->getTimestamp(); + } } $this->profile->fromArray($properties); } - public function validate() { + public function validate() + { if ($this->getProperty('newpassword') !== 'false') { $oldPassword = $this->getProperty('password_old'); $newPassword = $this->getProperty('password_new'); @@ -113,10 +125,10 @@ public function validate() { } if (empty($newPassword) || strlen($newPassword) < $this->modx->getOption('password_min_length', null, 8)) { $this->addFieldError('password_new', $this->modx->lexicon('user_err_password_too_short')); - } else if (!preg_match('/^[^\'\x3c\x3e\(\);\x22\x7b\x7d\x2f\x5c]+$/', $newPassword)) { + } elseif (!preg_match('/^[^\'\x3c\x3e\(\);\x22\x7b\x7d\x2f\x5c]+$/', $newPassword)) { $this->addFieldError('password_new', $this->modx->lexicon('user_err_password_invalid')); } - if (empty($confirmPassword) || strcmp($newPassword,$confirmPassword) != 0) { + if (empty($confirmPassword) || strcmp($newPassword, $confirmPassword) != 0) { $this->addFieldError('password_confirm', $this->modx->lexicon('user_err_password_no_match')); } } diff --git a/core/src/Revolution/Processors/Security/User/Get.php b/core/src/Revolution/Processors/Security/User/Get.php index fa746b8ea94..7218ea5c868 100644 --- a/core/src/Revolution/Processors/Security/User/Get.php +++ b/core/src/Revolution/Processors/Security/User/Get.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); + return parent::initialize(); + } + /** * @throws \xPDO\xPDOException */ @@ -91,13 +99,11 @@ public function cleanup() $userArray = array_merge($profile->toArray(), $userArray); } - $userArray['dob'] = !empty($userArray['dob']) ? date('m/d/Y', $userArray['dob']) : ''; - $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date('Y-m-d H:i:s', - $userArray['blockeduntil']) : ''; - $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date('Y-m-d H:i:s', - $userArray['blockedafter']) : ''; - $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? date($this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), - $userArray['lastlogin']) : ''; + $userArray['dob'] = !empty($userArray['dob']) ? date('Y-m-d', $userArray['dob']) : ''; + $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockeduntil']) : ''; + $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockedafter']) : ''; + $userArray['createdon'] = $this->formatter->formatManagerDateTime($userArray['createdon']); + $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? $this->formatter->formatManagerDateTime($userArray['lastlogin']) : ''; unset($userArray['password'], $userArray['cachepwd'], $userArray['sessionid'], $userArray['salt']); return $this->success('', $userArray); diff --git a/core/src/Revolution/Processors/Security/User/GetOnline.php b/core/src/Revolution/Processors/Security/User/GetOnline.php index 6d0023855f9..fc67327ef4e 100644 --- a/core/src/Revolution/Processors/Security/User/GetOnline.php +++ b/core/src/Revolution/Processors/Security/User/GetOnline.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); + return parent::initialize(); + } + /** * @param xPDOQuery $c * @return xPDOQuery @@ -70,9 +78,14 @@ public function prepareRow(xPDOObject $object) { $row = $object->toArray(); + $row['occurred_date'] = $this->formatter->formatManagerDateTime($row['occurred'], 'date'); + $row['occurred_time'] = $this->formatter->formatManagerDateTime($row['occurred'], 'time'); + $row['occurred'] = $this->formatter->formatManagerDateTime($row['occurred']); + /** @var modUser $user */ if ($user = $object->getOne('User')) { - $row = array_merge($row, + $row = array_merge( + $row, $user->get(['username']), $user->Profile->get(['fullname', 'email']), ['photo' => $user->getPhoto(64, 64)] diff --git a/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php b/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php index d1dd77078d0..62401f26115 100644 --- a/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php +++ b/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php @@ -1,4 +1,5 @@ setDefaultProperties(['limit' => 10]); - + $this->formatter = new modFormatter($this->modx); $this->classKeys = $this->modx->getDescendants(modResource::class); $this->classKeys[] = modResource::class; return parent::initialize(); } - /** * Filter resources by user * @param xPDOQuery $c @@ -96,27 +97,20 @@ public function prepareRow(xPDOObject $object) $resourceArray = $resource->get(['id','pagetitle','description','published','deleted','context_key', 'createdon', 'editedon']); $resourceArray['pagetitle'] = htmlspecialchars($resourceArray['pagetitle'], ENT_QUOTES, $this->modx->getOption('modx_charset', null, 'UTF-8')); - $dateFormat = $this->modx->getOption('manager_date_format'); - $timeFormat = $this->modx->getOption('manager_time_format'); - - $createdon = new \DateTimeImmutable($resourceArray['createdon']); - $resourceArray['createdon_date'] = $createdon->format($dateFormat); - $resourceArray['createdon_time'] = $createdon->format($timeFormat); - - $resourceArray['editedon_date'] = $resourceArray['createdon_date']; - $resourceArray['editedon_time'] = $resourceArray['createdon_time']; - - if (!empty($resourceArray['editedon'])) { - $editedon = new \DateTimeImmutable($resourceArray['editedon']); - $resourceArray['editedon_date'] = $editedon->format($dateFormat); - $resourceArray['editedon_time'] = $editedon->format($timeFormat); - } + $editedon = !empty($resourceArray['editedon']) ? $resourceArray['editedon'] : $resourceArray['createdon'] ; + $isUnedited = $editedon === $resourceArray['createdon']; + $resourceArray['createdon_date'] = $this->formatter->formatManagerDateTime($resourceArray['createdon'], 'date'); + $resourceArray['createdon_time'] = $this->formatter->formatManagerDateTime($resourceArray['createdon'], 'time'); + $resourceArray['editedon_date'] = $isUnedited ? $resourceArray['createdon_date'] : $this->formatter->formatManagerDateTime($editedon, 'date'); + $resourceArray['editedon_time'] = $isUnedited ? $resourceArray['createdon_time'] : $this->formatter->formatManagerDateTime($editedon, 'time'); + $row['occurred'] = $this->formatter->formatManagerDateTime($row['occurred']); $row = array_merge($row, $resourceArray); /** @var modUser $user */ if ($user = $object->getOne('User')) { - $row = array_merge($row, + $row = array_merge( + $row, $user->get(['username']), $user->Profile->get(['fullname', 'email']), ['photo' => $user->getPhoto(64, 64)] diff --git a/core/src/Revolution/Processors/Security/User/Validation.php b/core/src/Revolution/Processors/Security/User/Validation.php index bb789ef763d..d0661b33eec 100644 --- a/core/src/Revolution/Processors/Security/User/Validation.php +++ b/core/src/Revolution/Processors/Security/User/Validation.php @@ -1,4 +1,5 @@ processor =& $processor; $this->modx =& $processor->modx; $this->user =& $user; $this->profile =& $profile; + $this->formatter = new modFormatter($this->modx); } - public function validate() { + public function validate() + { $this->checkUsername(); $this->checkPassword(); $this->checkEmail(); @@ -50,57 +57,60 @@ public function validate() { return !$this->processor->hasErrors(); } - public function checkUsername() { + public function checkUsername() + { $username = $this->processor->getProperty('username'); if (empty($username)) { - $this->processor->addFieldError('username',$this->modx->lexicon('user_err_not_specified_username')); + $this->processor->addFieldError('username', $this->modx->lexicon('user_err_not_specified_username')); } elseif (!preg_match('/^[^\'\\x3c\\x3e\\(\\);\\x22]+$/', $username)) { - $this->processor->addFieldError('username',$this->modx->lexicon('user_err_username_invalid')); - } else if (!empty($username)) { + $this->processor->addFieldError('username', $this->modx->lexicon('user_err_username_invalid')); + } elseif (!empty($username)) { if ($this->alreadyExists($username)) { - $this->processor->addFieldError('username',$this->modx->lexicon('user_err_already_exists')); + $this->processor->addFieldError('username', $this->modx->lexicon('user_err_already_exists')); } - $this->user->set('username',$username); + $this->user->set('username', $username); } } - public function alreadyExists($name) { - return $this->modx->getCount(modUser::class, - [ + public function alreadyExists($name) + { + return $this->modx->getCount( + modUser::class, + [ 'username' => $name, 'id:!=' => $this->user->get('id'), - ] - ) > 0; + ] + ) > 0; } - public function checkPassword() { - $newPassword = $this->processor->getProperty('newpassword',null); + public function checkPassword() + { + $newPassword = $this->processor->getProperty('newpassword', null); $id = $this->processor->getProperty('id'); - $passwordGenerationMethod = $this->processor->getProperty('passwordgenmethod','g'); + $passwordGenerationMethod = $this->processor->getProperty('passwordgenmethod', 'g'); if ($passwordGenerationMethod !== 'user_email_specify' && ($newPassword !== null && $newPassword != 'false' || empty($id))) { - $passwordNotifyMethod = $this->processor->getProperty('passwordnotifymethod',null); + $passwordNotifyMethod = $this->processor->getProperty('passwordnotifymethod', null); if (empty($passwordNotifyMethod)) { - $this->processor->addFieldError('password_notify_method',$this->modx->lexicon('user_err_not_specified_notification_method')); + $this->processor->addFieldError('password_notify_method', $this->modx->lexicon('user_err_not_specified_notification_method')); } - if ($passwordGenerationMethod == 'g') { $autoPassword = $this->user->generatePassword(); $this->user->set('password', $autoPassword); - $this->processor->newPassword= $autoPassword; + $this->processor->newPassword = $autoPassword; } else { $specifiedPassword = $this->processor->getProperty('specifiedpassword'); $confirmPassword = $this->processor->getProperty('confirmpassword'); if (empty($specifiedPassword)) { - $this->processor->addFieldError('specifiedpassword',$this->modx->lexicon('user_err_not_specified_password')); + $this->processor->addFieldError('specifiedpassword', $this->modx->lexicon('user_err_not_specified_password')); } elseif ($specifiedPassword != $confirmPassword) { - $this->processor->addFieldError('confirmpassword',$this->modx->lexicon('user_err_password_no_match')); + $this->processor->addFieldError('confirmpassword', $this->modx->lexicon('user_err_password_no_match')); } elseif (strlen($specifiedPassword) < $this->modx->getOption('password_min_length', null, 8, true)) { - $this->processor->addFieldError('specifiedpassword',$this->modx->lexicon('user_err_password_too_short')); + $this->processor->addFieldError('specifiedpassword', $this->modx->lexicon('user_err_password_too_short')); } elseif (!preg_match('/^[^\'\x3c\x3e\(\);\x22\x7b\x7d\x2f\x5c]+$/', $specifiedPassword)) { $this->processor->addFieldError('specifiedpassword', $this->modx->lexicon('user_err_password_invalid')); } else { - $this->user->set('password',$specifiedPassword); + $this->user->set('password', $specifiedPassword); $this->processor->newPassword = $specifiedPassword; } } @@ -108,88 +118,93 @@ public function checkPassword() { return $this->processor->newPassword; } - public function checkEmail() { + public function checkEmail() + { $email = $this->processor->getProperty('email'); if (empty($email)) { - $this->processor->addFieldError('email',$this->modx->lexicon('user_err_not_specified_email')); + $this->processor->addFieldError('email', $this->modx->lexicon('user_err_not_specified_email')); } - if (!$this->modx->getOption('allow_multiple_emails',null,true)) { + if (!$this->modx->getOption('allow_multiple_emails', null, true)) { /** @var modUserProfile $emailExists */ $emailExists = $this->modx->getObject(modUserProfile::class, ['email' => $email]); if ($emailExists) { if ($emailExists->get('internalKey') != $this->processor->getProperty('id')) { - $this->processor->addFieldError('email',$this->modx->lexicon('user_err_already_exists_email')); + $this->processor->addFieldError('email', $this->modx->lexicon('user_err_already_exists_email')); } } } return $email; } - public function checkPhone() { + public function checkPhone() + { $phone = $this->processor->getProperty('phone'); if (!empty($phone)) { - if ($this->modx->getOption('clean_phone_number',null,false)) { - $phone = str_replace(' ','',$phone); - $phone = str_replace('-','',$phone); - $phone = str_replace('(','',$phone); - $phone = str_replace(')','',$phone); - $phone = str_replace('+','',$phone); - $this->processor->setProperty('phone',$phone); - $this->profile->set('phone',$phone); + if ($this->modx->getOption('clean_phone_number', null, false)) { + $phone = str_replace(' ', '', $phone); + $phone = str_replace('-', '', $phone); + $phone = str_replace('(', '', $phone); + $phone = str_replace(')', '', $phone); + $phone = str_replace('+', '', $phone); + $this->processor->setProperty('phone', $phone); + $this->profile->set('phone', $phone); } } } - public function checkCellPhone() { + public function checkCellPhone() + { $phone = $this->processor->getProperty('mobilephone'); if (!empty($phone)) { - if ($this->modx->getOption('clean_phone_number',null,false)) { - $phone = str_replace(' ','',$phone); - $phone = str_replace('-','',$phone); - $phone = str_replace('(','',$phone); - $phone = str_replace(')','',$phone); - $phone = str_replace('+','',$phone); - $this->processor->setProperty('mobilephone',$phone); - $this->profile->set('mobilephone',$phone); + if ($this->modx->getOption('clean_phone_number', null, false)) { + $phone = str_replace(' ', '', $phone); + $phone = str_replace('-', '', $phone); + $phone = str_replace('(', '', $phone); + $phone = str_replace(')', '', $phone); + $phone = str_replace('+', '', $phone); + $this->processor->setProperty('mobilephone', $phone); + $this->profile->set('mobilephone', $phone); } } } - public function checkBirthDate() { + public function checkBirthDate() + { $birthDate = $this->processor->getProperty('dob'); if (!empty($birthDate)) { - $birthDate = strtotime($birthDate); - if (false === $birthDate) { - $this->processor->addFieldError('dob',$this->modx->lexicon('user_err_not_specified_dob')); + $date = \DateTimeImmutable::createFromFormat($this->formatter->managerDateFormat, $birthDate); + if ($date === false) { + $this->processor->addFieldError('dob', $this->modx->lexicon('user_err_not_specified_dob')); } - $this->processor->setProperty('dob',$birthDate); - $this->profile->set('dob',$birthDate); + $birthDate = $date->getTimestamp(); + $this->processor->setProperty('dob', $birthDate); + $this->profile->set('dob', $birthDate); } } - public function checkBlocked() { + public function checkBlocked() + { /* blocked until */ $blockedUntil = $this->processor->getProperty('blockeduntil'); if (!empty($blockedUntil)) { - $blockedUntil = str_replace('-','/',$blockedUntil); + $blockedUntil = str_replace('-', '/', $blockedUntil); if (!$blockedUntil = strtotime($blockedUntil)) { - $this->processor->addFieldError('blockeduntil',$this->modx->lexicon('user_err_not_specified_blockeduntil')); + $this->processor->addFieldError('blockeduntil', $this->modx->lexicon('user_err_not_specified_blockeduntil')); } - $this->processor->setProperty('blockeduntil',$blockedUntil); - $this->profile->set('blockeduntil',$blockedUntil); + $this->processor->setProperty('blockeduntil', $blockedUntil); + $this->profile->set('blockeduntil', $blockedUntil); } /* blocked after */ $blockedAfter = $this->processor->getProperty('blockedafter'); if (!empty($blockedAfter)) { - $blockedAfter = str_replace('-','/',$blockedAfter); + $blockedAfter = str_replace('-', '/', $blockedAfter); if (!$blockedAfter = strtotime($blockedAfter)) { - $this->processor->addFieldError('blockedafter',$this->modx->lexicon('user_err_not_specified_blockedafter')); + $this->processor->addFieldError('blockedafter', $this->modx->lexicon('user_err_not_specified_blockedafter')); } - $this->processor->setProperty('blockedafter',$blockedAfter); - $this->profile->set('blockedafter',$blockedAfter); + $this->processor->setProperty('blockedafter', $blockedAfter); + $this->profile->set('blockedafter', $blockedAfter); } } - } diff --git a/core/src/Revolution/Processors/System/ActiveResource/GetList.php b/core/src/Revolution/Processors/System/ActiveResource/GetList.php index 599b292e39b..b367027accd 100644 --- a/core/src/Revolution/Processors/System/ActiveResource/GetList.php +++ b/core/src/Revolution/Processors/System/ActiveResource/GetList.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); $this->setDefaultProperties([ - 'dateFormat' => '%b %d, %Y %I:%M %p', + 'dateFormat' => '', ]); return $initialized; } @@ -100,7 +103,12 @@ public function prepareRow(xPDOObject $object) 'editedon', 'username', ]); - $objectArray['editedon'] = strftime($this->getProperty('dateFormat'), strtotime($object->get('editedon'))); + $customFormat = $this->getProperty('dateFormat'); + $editedOn = $object->get('editedon'); + $objectArray['editedon'] = !empty($customFormat) + ? $this->formatter->formatManagerDateTime($editedOn, '', false, true, $customFormat) + : $this->formatter->formatManagerDateTime($editedOn) + ; return $objectArray; } diff --git a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php index 8db6d363b05..5ed0b3b07c2 100644 --- a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php +++ b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); + return parent::initialize(); + } + /** * @return array|mixed|string */ @@ -74,18 +82,21 @@ public function loadFeed($url) $feed->handle_content_type(); if ($feed->error()) { - $this->modx->log(modX::LOG_LEVEL_ERROR, - is_array($feed->error()) ? print_r($feed->error(), true) : $feed->error()); + $this->modx->log( + modX::LOG_LEVEL_ERROR, + is_array($feed->error()) ? print_r($feed->error(), true) : $feed->error() + ); } $output = []; /** @var SimplePie_Item $item */ foreach ($feed->get_items() as $item) { + $date = $item->get_date('Y-m-d H:i:s'); $output[] = $this->getFileChunk('dashboard/rssitem.tpl', [ 'title' => $item->get_title(), 'description' => $item->get_description(), 'link' => $item->get_permalink(), - 'pubdate' => $item->get_date(), + 'pubdate' => $this->formatter->formatManagerDateTime($date), ]); } @@ -103,8 +114,7 @@ public function getFileChunk($tpl, array $placeholders = []) $file = $tpl; if (!file_exists($file)) { - $file = $this->modx->getOption('manager_path') . 'templates/' . $this->modx->getOption('manager_theme', - null, 'default') . '/' . $tpl; + $file = $this->modx->getOption('manager_path') . 'templates/' . $this->modx->getOption('manager_theme', null, 'default') . '/' . $tpl; } if (!file_exists($file)) { $file = $this->modx->getOption('manager_path') . 'templates/default/' . $tpl; @@ -126,7 +136,7 @@ public function getFileChunk($tpl, array $placeholders = []) * * @return array The proxy configuration. */ - private function buildProxyOptions() + private function buildProxyOptions() { $config = []; $proxyHost = $this->modx->getOption('proxy_host', null, ''); diff --git a/core/src/Revolution/Utilities/modFormatter.php b/core/src/Revolution/Utilities/modFormatter.php new file mode 100644 index 00000000000..837a664ff1d --- /dev/null +++ b/core/src/Revolution/Utilities/modFormatter.php @@ -0,0 +1,147 @@ +modx =& $modx; + $this->managerDateFormat = $this->modx->getOption('manager_date_format', null, 'Y-m-d', true); + $this->managerTimeFormat = $this->modx->getOption('manager_time_format', null, 'H:i', true); + $this->managerDateEmptyDisplay = $this->modx->getOption('manager_datetime_empty_value', null, '–', true); + } + + /** + * Provides final formatted output of a date, time, or combination of the two, based on system settings + * @param string|int $value The value to transform (must be a unix timestamp or mysql-format string) + * @param string $outputStyle Controls whether the output should be date only, time only, or a combination of the two + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param bool $useAlternateFormat Whether to override the system settings' format with a custom one + * @param string $alternateFormat The custom format to use when overriding the system one + * @return string The formatted date + */ + public function formatManagerDateTime($value, string $outputStyle = 'combined', bool $useOffset = false, bool $useAlternateFormat = false, string $alternateFormat = ''): string + { + $offset = floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600; + $managerDateTimeSeparator = $this->modx->getOption('manager_datetime_separator', null, ', ', true); + + if (!modX::isValidTimestamp($value)) { + // If not a timestamp integer, expecting mysql-formatted value + $dateTime = \DateTimeImmutable::createFromFormat($this->managerDateHiddenFormat, $value); + if ($dateTime === false) { + $msg = "Attempting to convert the string “{$value}” to a timestamp, but the given value is invalid."; + $this->modx->log(modX::LOG_LEVEL_WARN, $msg); + return 0; + } + $value = $dateTime->getTimestamp(); + } + + $value = $useOffset ? $value + $offset : $value ; + + if ($useAlternateFormat && !empty($alternateFormat)) { + return date($alternateFormat, $value); + } + + switch ($outputStyle) { + case 'combined': + $format = $this->managerDateFormat . $managerDateTimeSeparator . $this->managerTimeFormat; + break; + case 'date': + $format = $this->managerDateFormat; + break; + case 'time': + $format = $this->managerTimeFormat; + break; + // no default + } + + return date($format, $value); + } + + /** + * Formats a Resource-related date when applicable and includes localized default text to + * represent conditions where a date is not present + * + * @param string|int $value The source date value to format + * @param string $whichDate One of five identifiers specifying the type of date being formatted + * @param bool $useStandardEmptyValue Whether to use the default empty value defined in the system settings + * @return string The formatted date or relevant text indicating an empty date value + */ + public function getFormattedResourceDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string + { + if ($useStandardEmptyValue) { + $emptyValue = $this->managerDateEmptyDisplay; + } else { + switch ($whichDate) { + case 'edited': + $emptyValue = $this->modx->lexicon('unedited'); + break; + case 'publish': + case 'unpublish': + $emptyValue = $this->modx->lexicon('notset'); + break; + case 'published': + $emptyValue = $this->modx->lexicon('unpublished'); + break; + default: + $emptyValue = $this->modx->lexicon('unknown'); + } + $emptyValue = '(' . $emptyValue . ')'; + } + return in_array($value, $this->managerDateEmptyValues) + ? $emptyValue + : $this->formatManagerDateTime($value, 'combined', true) + ; + } +} diff --git a/core/src/Revolution/modX.php b/core/src/Revolution/modX.php index f12942d0a93..2e5476250c1 100644 --- a/core/src/Revolution/modX.php +++ b/core/src/Revolution/modX.php @@ -2987,4 +2987,28 @@ public function _postProcess() { } $this->invokeEvent('OnWebPageComplete'); } + + /** + * Determine whether the passed value is a unix timestamp and, optionally, whether it is within + * a specified range + * @param string|int $value The timestamp to test + * @param bool $limitStart Optional minimum timestamp value that will validate + * @param bool $limitEnd Optional maximum timestamp value that will validate + * @return bool + */ + public static function isValidTimestamp($value, $limitStart = false, $limitEnd = false): bool + { + // Check that value represents an integer (signed or unsigned) + if (!preg_match('/^-?[1-9][0-9]*$/', $value)) { + return false; + } + $value = (int)$value; + if (!($value <= PHP_INT_MAX && $value >= ~PHP_INT_MAX)) { + return false; + } + if (($limitStart !== false && $value < (int)$limitStart) || ($limitEnd !== false && $value > (int)$limitEnd)) { + return false; + } + return true; + } } diff --git a/manager/assets/modext/sections/system/file/edit.js b/manager/assets/modext/sections/system/file/edit.js index 80995229128..d5d994dfd43 100644 --- a/manager/assets/modext/sections/system/file/edit.js +++ b/manager/assets/modext/sections/system/file/edit.js @@ -111,14 +111,14 @@ MODx.panel.EditFile = function(config) { ,name: 'last_accessed' ,id: 'modx-file-last-accessed' ,anchor: '100%' - ,value: MODx.util.Format.dateFromTimestamp(config.record.last_accessed) + ,value: config.record.last_accessed },{ xtype: 'statictextfield' ,fieldLabel: _('file_last_modified') ,name: 'last_modified' ,id: 'modx-file-last-modified' ,anchor: '100%' - ,value: MODx.util.Format.dateFromTimestamp(config.record.last_modified) + ,value: config.record.last_modified },{ xtype: 'textarea' ,hideLabel: true diff --git a/manager/assets/modext/widgets/media/modx.browser.js b/manager/assets/modext/widgets/media/modx.browser.js index 67cb98113a0..4208711d9a8 100644 --- a/manager/assets/modext/widgets/media/modx.browser.js +++ b/manager/assets/modext/widgets/media/modx.browser.js @@ -43,7 +43,7 @@ MODx.browser.View = function(config) { {name: 'name', sortType: Ext.data.SortTypes.asUCString} ,'cls','url','relativeUrl','fullRelativeUrl','image','original_width','original_height','image_width','image_height','thumb','thumb_width','thumb_height','pathname','pathRelative','ext','disabled','preview' ,{name: 'size', type: 'float'} - ,{name: 'lastmod', type: 'date', dateFormat: 'timestamp'} + ,'lastmod' ,'menu', 'visibility' ] ,baseParams: { @@ -393,7 +393,6 @@ Ext.extend(MODx.browser.View,MODx.DataView,{ data.sizeString = data.size != 0 ? formatSize(data.size) : 0; data.imageSizeString = data.preview != 0 ? data.original_width + "x" + data.original_height + "px": 0; data.imageSizeString = data.imageSizeString === "xpx" ? 0 : data.imageSizeString; - data.dateString = !Ext.isEmpty(data.lastmod) ? new Date(data.lastmod).format(MODx.config.manager_date_format + " " + MODx.config.manager_time_format) : 0; this.lookup[data.name] = data; return data; } @@ -460,9 +459,9 @@ Ext.extend(MODx.browser.View,MODx.DataView,{ ,' '+_('image_size')+':' ,' {imageSizeString}' ,' ' - ,' ' + ,' ' ,' '+_('file_last_modified')+':' - ,' {dateString}' + ,' {lastmod}' ,' ' ,' ' ,' '+_('visibility')+':' diff --git a/manager/assets/modext/widgets/resource/modx.panel.resource.data.js b/manager/assets/modext/widgets/resource/modx.panel.resource.data.js index ea57402aace..e9889b13e64 100644 --- a/manager/assets/modext/widgets/resource/modx.panel.resource.data.js +++ b/manager/assets/modext/widgets/resource/modx.panel.resource.data.js @@ -2,8 +2,7 @@ MODx.panel.ResourceData = function(config) { config = config || {}; var df = { border: false - ,msgTarget: 'side' - ,width: 300 + ,anchor: '100%' }; Ext.applyIf(config,{ url: MODx.config.connector_url @@ -27,119 +26,99 @@ MODx.panel.ResourceData = function(config) { name: 'context_key' ,fieldLabel: _('context') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'alias' ,fieldLabel: _('resource_alias') ,description: _('resource_alias_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'template_name' ,fieldLabel: _('resource_template') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'pagetitle' ,fieldLabel: _('resource_pagetitle') ,description: _('resource_pagetitle_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'longtitle' ,fieldLabel: _('resource_longtitle') ,description: _('resource_longtitle_help') ,xtype: 'statictextfield' - ,anchor: '100%' ,value: _('notset') },{ name: 'description' ,fieldLabel: _('resource_description') ,description: _('resource_description_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'introtext' ,fieldLabel: _('resource_summary') ,description: _('resource_summary_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'content' ,fieldLabel: _('resource_content') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'published' ,fieldLabel: _('resource_published') ,description: _('resource_published_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'deleted' ,fieldLabel: _('deleted') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'publishedon' ,fieldLabel: _('resource_publishedon') ,description: _('resource_publishedon_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'pub_date' ,fieldLabel: _('resource_publishdate') ,description: _('resource_publishdate_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'unpub_date' ,fieldLabel: _('resource_unpublishdate') ,description: _('resource_unpublishdate_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'hidemenu' ,fieldLabel: _('resource_hide_from_menus') ,description: _('resource_hide_from_menus_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'menutitle' ,fieldLabel: _('resource_menutitle') ,description: _('resource_menutitle_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'menuindex' ,fieldLabel: _('resource_menuindex') ,description: _('resource_menuindex_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'link_attributes' ,fieldLabel: _('resource_link_attributes') ,description: _('resource_link_attributes_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'class_key' ,fieldLabel: _('class_key') ,description: _('resource_class_key_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'content_type' ,fieldLabel: _('resource_content_type') ,description: _('resource_content_type_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'isfolder' ,fieldLabel: _('resource_folder') ,description: _('resource_folder_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'show_in_tree' ,fieldLabel: _('resource_show_in_tree') @@ -163,7 +142,6 @@ MODx.panel.ResourceData = function(config) { ,fieldLabel: _('resource_uri_override') ,description: _('resource_uri_override_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'uri' ,fieldLabel: _('resource_uri') @@ -175,31 +153,26 @@ MODx.panel.ResourceData = function(config) { ,fieldLabel: _('resource_parent') ,description: _('resource_parent_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'content_dispo' ,fieldLabel: _('resource_contentdispo') ,description: _('resource_contentdispo_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'richtext' ,fieldLabel: _('resource_richtext') ,description: _('resource_richtext_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'searchable' ,fieldLabel: _('resource_searchable') ,description: _('resource_searchable_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'cacheable' ,fieldLabel: _('resource_cacheable') ,description: _('resource_cacheable_help') ,xtype: 'staticboolean' - ,anchor: '100%' }] },{ title: _('changes') @@ -213,7 +186,6 @@ MODx.panel.ResourceData = function(config) { ,items: [{ name: 'createdon_adjusted' ,fieldLabel: _('resource_createdon') - ,anchor: '100%' },{ name: 'createdon_by' ,fieldLabel: _('resource_createdby') @@ -221,22 +193,17 @@ MODx.panel.ResourceData = function(config) { },{ name: 'publishedon_adjusted' ,fieldLabel: _('resource_publishedon') - ,anchor: '100%' },{ name: 'publishedon_by' ,fieldLabel: _('resource_publishedby') - ,anchor: '100%' },{ name: 'editedon_adjusted' ,fieldLabel: _('resource_editedon') - ,anchor: '100%' },{ name: 'editedon_by' ,fieldLabel: _('resource_editedby') - ,anchor: '100%' },{ xtype: 'modx-grid-manager-log' - ,anchor: '100%' ,preventRender: true ,formpanel: 'modx-panel-manager-log' ,baseParams: { @@ -297,8 +264,7 @@ Ext.extend(MODx.panel.ResourceData,MODx.FormPanel,{ } ,listeners: { 'success': {fn:function(r) { - if (r.object.pub_date == '0') { r.object.pub_date = ''; } - if (r.object.unpub_date == '0') { r.object.unpub_date = ''; } + r.object.publishedon = r.object.publishedon_adjusted; Ext.get('modx-resource-header').update(Ext.util.Format.htmlEncode(r.object.pagetitle)); this.getForm().setValues(r.object); this.fireEvent('ready'); diff --git a/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js b/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js index 13fc9227bf5..4be9016330f 100644 --- a/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js +++ b/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js @@ -57,7 +57,7 @@ MODx.grid.ResourceSchedule = function(config) { ,'pagetitle' ,'class_key' ,{name: 'pub_date', type: 'date'} - ,{name: 'unpub_date', type:'date'} + ,{name: 'unpub_date', type: 'date'} ,'menu' ] ,showActionsColumn: false @@ -88,7 +88,7 @@ MODx.grid.ResourceSchedule = function(config) { ,timeFormat: MODx.config.manager_time_format ,ctCls: 'x-datetime-inline-editor' } - ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format) + ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + MODx.config.manager_datetime_separator + MODx.config.manager_time_format) },{ header: _('unpublish_date') ,dataIndex: 'unpub_date' @@ -99,7 +99,7 @@ MODx.grid.ResourceSchedule = function(config) { ,timeFormat: MODx.config.manager_time_format ,ctCls: 'x-datetime-inline-editor' } - ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format) + ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + MODx.config.manager_datetime_separator + MODx.config.manager_time_format) }] ,tbar: [{ text: _('showing_pub') @@ -108,7 +108,7 @@ MODx.grid.ResourceSchedule = function(config) { ,enableToggle: true ,tooltip: _('click_to_change') ,id: 'btn-toggle' - ,cls:'primary-button' + ,cls: 'primary-button' }] }); MODx.grid.ResourceSchedule.superclass.constructor.call(this,config); diff --git a/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js b/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js index cb749b53652..a64f3929cde 100644 --- a/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js +++ b/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js @@ -37,7 +37,6 @@ MODx.grid.RecentlyEditedResourcesByUser = function(config) { },{ header: _('editedon') ,dataIndex: 'occurred' - ,renderer : Ext.util.Format.dateRenderer(dateFormat) },{ header: _('published') ,dataIndex: 'published' diff --git a/manager/controllers/default/system/file/edit.class.php b/manager/controllers/default/system/file/edit.class.php index 42ce2e85543..fdb3c6c67c2 100644 --- a/manager/controllers/default/system/file/edit.class.php +++ b/manager/controllers/default/system/file/edit.class.php @@ -1,4 +1,5 @@ modx); + if (!empty($this->fileRecord['last_accessed'])) { + $this->fileRecord['last_accessed'] = $formatter->formatManagerDateTime($this->fileRecord['last_accessed']); + } + if (!empty($this->fileRecord['last_modified'])) { + $this->fileRecord['last_modified'] = $formatter->formatManagerDateTime($this->fileRecord['last_modified']); + } $this->canSave = true; $placeholders['fa'] = $this->fileRecord; diff --git a/manager/templates/default/dashboard/onlineusers.tpl b/manager/templates/default/dashboard/onlineusers.tpl index 3831a516074..1fba0446044 100644 --- a/manager/templates/default/dashboard/onlineusers.tpl +++ b/manager/templates/default/dashboard/onlineusers.tpl @@ -28,8 +28,8 @@ -
{$record.occurred|date_format:'%B %d, %Y'}
-
{$record.occurred|date_format:'%H:%M'}
+
{$record.occurred_date}
+
{$record.occurred_time}
{$record.action} From 3a4c3e1033c63eb3c05f0432ccc1682112045ebc Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sat, 24 Aug 2024 16:19:30 -0400 Subject: [PATCH 02/13] Minor corrections and additions Applied formatter to system settings processor and made a few other corrections to previously-committed code. --- core/lexicon/en/default.inc.php | 1 + .../Processors/Resource/Event/GetList.php | 8 ++-- .../System/ActiveResource/GetList.php | 4 +- .../Processors/System/Settings/GetList.php | 42 ++++++++++++------- .../src/Revolution/Utilities/modFormatter.php | 12 +++++- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/core/lexicon/en/default.inc.php b/core/lexicon/en/default.inc.php index 77e5ad354af..93a8896ba0b 100644 --- a/core/lexicon/en/default.inc.php +++ b/core/lexicon/en/default.inc.php @@ -97,6 +97,7 @@ $_lang['data_err_load'] = 'Error loading data.'; $_lang['date'] = 'Date'; $_lang['datechanged'] = 'Date changed'; +$_lang['datetime_conversion_err_invalid_mysql_format'] = 'Attempted to convert the value “[[+value]]” to a timestamp, but the the value is not in the required mysql format (Y-m-d H:i:s).'; $_lang['db_header'] = 'Database tables'; $_lang['db_info_mysql'] = 'If a table has an overhead, you may optimize it by clicking on the link in the Overhead column.'; $_lang['delete'] = 'Delete'; diff --git a/core/src/Revolution/Processors/Resource/Event/GetList.php b/core/src/Revolution/Processors/Resource/Event/GetList.php index 277eade75f5..ddb3a5a21af 100644 --- a/core/src/Revolution/Processors/Resource/Event/GetList.php +++ b/core/src/Revolution/Processors/Resource/Event/GetList.php @@ -107,14 +107,14 @@ public function prepareRow(xPDOObject $object) below will be lost. */ $pubDate = $object->get('pub_date'); - $objectArray['pub_date'] = in_array($pubDate, $this->managerDateEmptyValues) - ? $this->managerDateEmptyDisplay + $objectArray['pub_date'] = in_array($pubDate, $this->formatter->managerDateEmptyValues) + ? $this->formatter->managerDateEmptyDisplay : $this->formatter->formatManagerDateTime($pubDate, 'combined', true) ; $unpubDate = $object->get('unpub_date'); - $objectArray['unpub_date'] = in_array($unpubDate, $this->managerDateEmptyValues) - ? $this->managerDateEmptyDisplay + $objectArray['unpub_date'] = in_array($unpubDate, $this->formatter->managerDateEmptyValues) + ? $this->formatter->managerDateEmptyDisplay : $this->formatter->formatManagerDateTime($unpubDate, 'combined', true) ; diff --git a/core/src/Revolution/Processors/System/ActiveResource/GetList.php b/core/src/Revolution/Processors/System/ActiveResource/GetList.php index b367027accd..9cd3da61d49 100644 --- a/core/src/Revolution/Processors/System/ActiveResource/GetList.php +++ b/core/src/Revolution/Processors/System/ActiveResource/GetList.php @@ -24,8 +24,8 @@ * @param integer $limit (optional) The number of records to limit to. Defaults to 10. * @param string $sort (optional) The column to sort by. Defaults to name. * @param string $dir (optional) The direction of the sort. Defaults to ASC. - * @param string $dateFormat (optional) The strftime date format to format the - * editedon date to. Defaults to the manager's combined date, separator, and time format settings. + * @param string $dateFormat (optional) The datetime format to format the editedon date to. + * Defaults to the manager's combined date, separator, and time format settings. * @package MODX\Revolution\Processors\System\ActiveResource */ class GetList extends GetListProcessor diff --git a/core/src/Revolution/Processors/System/Settings/GetList.php b/core/src/Revolution/Processors/System/Settings/GetList.php index 6e855d70e4b..df0b7ec833a 100644 --- a/core/src/Revolution/Processors/System/Settings/GetList.php +++ b/core/src/Revolution/Processors/System/Settings/GetList.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); $this->setDefaultProperties([ 'key' => false, 'namespace' => false, 'area' => false, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), + 'dateFormat' => '' ]); return $initialized; @@ -113,9 +116,14 @@ public function prepareRow(xPDOObject $object) $k = 'setting_' . $settingArray['key']; /* if 3rd party setting, load proper text, fallback to english */ - $this->modx->lexicon->load('en:' . $object->get('namespace') . ':default', - 'en:' . $object->get('namespace') . ':setting'); - $this->modx->lexicon->load($object->get('namespace') . ':default', $object->get('namespace') . ':setting'); + $this->modx->lexicon->load( + 'en:' . $object->get('namespace') . ':default', + 'en:' . $object->get('namespace') . ':setting' + ); + $this->modx->lexicon->load( + $object->get('namespace') . ':default', + $object->get('namespace') . ':setting' + ); /* get translated area text */ if ($this->modx->lexicon->exists('area_' . $object->get('area'))) { @@ -145,19 +153,25 @@ public function prepareRow(xPDOObject $object) } else { $settingArray['name'] = $settingArray['name_trans']; } - $settingArray['key'] = htmlspecialchars($settingArray['key'], ENT_QUOTES, - $this->modx->getOption('modx_charset', null, 'UTF-8')); - $settingArray['name_trans'] = htmlspecialchars($settingArray['name_trans'], ENT_QUOTES, - $this->modx->getOption('modx_charset', null, 'UTF-8')); + $settingArray['key'] = htmlspecialchars( + $settingArray['key'], + ENT_QUOTES, + $this->modx->getOption('modx_charset', null, 'UTF-8') + ); + $settingArray['name_trans'] = htmlspecialchars( + $settingArray['name_trans'], + ENT_QUOTES, + $this->modx->getOption('modx_charset', null, 'UTF-8') + ); $settingArray['oldkey'] = $settingArray['key']; - $settingArray['editedon'] = in_array($object->get('editedon'), [ - '-001-11-30 00:00:00', - '-1-11-30 00:00:00', - '0000-00-00 00:00:00', - null - ]) ? '' : date($this->getProperty('dateFormat'), strtotime($object->get('editedon'))); + $customFormat = $this->getProperty('dateFormat'); + $editedOn = $object->get('editedon'); + $settingArray['editedon'] = !empty($customFormat) + ? $this->formatter->formatManagerDateTime($editedOn, '', false, true, $customFormat) + : $this->formatter->formatManagerDateTime($editedOn) + ; return $settingArray; } diff --git a/core/src/Revolution/Utilities/modFormatter.php b/core/src/Revolution/Utilities/modFormatter.php index 837a664ff1d..1b5a8923971 100644 --- a/core/src/Revolution/Utilities/modFormatter.php +++ b/core/src/Revolution/Utilities/modFormatter.php @@ -46,7 +46,15 @@ class modFormatter /** * @var array $managerDateEmptyValues A list of possible values representing an empty date */ - public $managerDateEmptyValues = ['', '1969-12-31 00:00:00', '0000-00-00 00:00:00', 0]; + public $managerDateEmptyValues = [ + '', + '-001-11-30 00:00:00', + '-1-11-30 00:00:00', + '1969-12-31 00:00:00', + '0000-00-00 00:00:00', + 0, + null + ]; /** * @var string $managerDateEmptyDisplay The text (if any) to show for empty dates @@ -80,7 +88,7 @@ public function formatManagerDateTime($value, string $outputStyle = 'combined', // If not a timestamp integer, expecting mysql-formatted value $dateTime = \DateTimeImmutable::createFromFormat($this->managerDateHiddenFormat, $value); if ($dateTime === false) { - $msg = "Attempting to convert the string “{$value}” to a timestamp, but the given value is invalid."; + $msg = $this->modx->lexicon('datetime_conversion_err_invalid_mysql_format', ['value' => $value]); $this->modx->log(modX::LOG_LEVEL_WARN, $msg); return 0; } From ff0c24308fe2bf7dcfdc5125fe9da33b0399270d Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 25 Aug 2024 02:05:22 -0400 Subject: [PATCH 03/13] Fix rss feed date format and missing lexicon in resource data page --- core/src/Revolution/Processors/Resource/Data.php | 2 +- .../Revolution/Processors/System/Dashboard/Widget/Feed.php | 2 +- manager/assets/modext/widgets/modx.panel.welcome.js | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/Revolution/Processors/Resource/Data.php b/core/src/Revolution/Processors/Resource/Data.php index e3d029d3e84..6093b78215a 100644 --- a/core/src/Revolution/Processors/Resource/Data.php +++ b/core/src/Revolution/Processors/Resource/Data.php @@ -37,7 +37,7 @@ public function checkPermissions() public function getLanguageTopics() { - return ['resource']; + return ['resource', 'manager_log']; } public function initialize() diff --git a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php index 5ed0b3b07c2..0de3d34eac1 100644 --- a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php +++ b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php @@ -96,7 +96,7 @@ public function loadFeed($url) 'title' => $item->get_title(), 'description' => $item->get_description(), 'link' => $item->get_permalink(), - 'pubdate' => $this->formatter->formatManagerDateTime($date), + 'pubdate' => $this->formatter->formatManagerDateTime($date) ]); } diff --git a/manager/assets/modext/widgets/modx.panel.welcome.js b/manager/assets/modext/widgets/modx.panel.welcome.js index 5210d3e4afc..56f0d81591b 100644 --- a/manager/assets/modext/widgets/modx.panel.welcome.js +++ b/manager/assets/modext/widgets/modx.panel.welcome.js @@ -91,10 +91,6 @@ Ext.extend(MODx.panel.Welcome, MODx.Panel, { else if (response.message.length > 0) { container.innerHTML = '

' + MODx.util.safeHtml(response.message) + '

'; } - var datestamps = Ext.select(".date_stamp", container); - datestamps.each(function (el) { - el.dom.innerText = new Date(el.dom.innerText).format(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format); - }); }, scope: this } ,failure: { From 850c2e546cb15b73a7317087c25829bdc7e752e8 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 25 Aug 2024 02:06:29 -0400 Subject: [PATCH 04/13] Update data.class.php Should have included this with the last commit --- manager/controllers/default/resource/data.class.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/manager/controllers/default/resource/data.class.php b/manager/controllers/default/resource/data.class.php index 39614ebfb4b..887fb1965c2 100644 --- a/manager/controllers/default/resource/data.class.php +++ b/manager/controllers/default/resource/data.class.php @@ -1,4 +1,5 @@ modx->cacheManager->get($this->resource->getCacheKey(), [ xPDO::OPT_CACHE_KEY => $this->modx->getOption('cache_resource_key', null, 'resource'), xPDO::OPT_CACHE_HANDLER => $this->modx->getOption('cache_resource_handler', null, $this->modx->getOption(xPDO::OPT_CACHE_HANDLER)), - xPDO::OPT_CACHE_FORMAT => (integer)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), + xPDO::OPT_CACHE_FORMAT => (int)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), ]); if ($buffer) { $placeholders['buffer'] = htmlspecialchars($buffer['resource']['_content']); @@ -115,9 +116,9 @@ public function process(array $scriptProperties = []) $placeholders['_ctx'] = $this->resource->get('context_key'); return $placeholders; + return ''; } - /** * @return string */ @@ -160,7 +161,7 @@ public function getTemplateFile() */ public function getLanguageTopics() { - return ['resource']; + return ['resource', 'manager_log']; } From a11c54c0b6d03168776469de786c7f078002a3e7 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 25 Aug 2024 22:49:43 -0400 Subject: [PATCH 05/13] Convert Lexicons date display --- .../Processors/Workspace/Lexicon/GetList.php | 9 ++++++--- .../assets/modext/workspace/lexicon/lexicon.grid.js | 11 +++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php index f2e874e510f..6fe237b16fe 100644 --- a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php @@ -13,6 +13,7 @@ use MODX\Revolution\modLexiconEntry; use MODX\Revolution\Processors\Processor; +use MODX\Revolution\Utilities\modFormatter; /** * Gets a list of lexicon entries @@ -65,6 +66,7 @@ public function initialize() if ($this->getProperty('topic') === '') { $this->setProperty('topic', 'default'); } + $this->formatter = new modFormatter($this->modx); return true; } @@ -143,8 +145,8 @@ function parseArray($needle, array $haystack = []) 'namespace' => $this->getProperty('namespace'), 'topic' => $this->getProperty('topic'), 'language' => $this->getProperty('language'), - 'createdon' => null, - 'editedon' => null, + 'createdon' => $this->formatter->managerDateEmptyDisplay, + 'editedon' => $this->formatter->managerDateEmptyDisplay, 'overridden' => 0, ]; /* if override in db, load */ @@ -153,7 +155,8 @@ function parseArray($needle, array $haystack = []) $entryArray[$k] = $v; // array_merge very slow inside loop, don't use it here } - $entryArray['editedon'] = strtotime($entryArray['editedon']) ?: strtotime($entryArray['createdon']); + $entryArray['editedon'] = $this->formatter->formatManagerDateTime($entryArray['editedon']) ?: $this->formatter->formatManagerDateTime($entryArray['createdon']); + $entryArray['overridden'] = 1; } $list[] = $entryArray; diff --git a/manager/assets/modext/workspace/lexicon/lexicon.grid.js b/manager/assets/modext/workspace/lexicon/lexicon.grid.js index 7d7d5440d10..6b074fa3c78 100644 --- a/manager/assets/modext/workspace/lexicon/lexicon.grid.js +++ b/manager/assets/modext/workspace/lexicon/lexicon.grid.js @@ -49,7 +49,6 @@ MODx.grid.Lexicon = function(config = {}) { header: _('last_modified') ,dataIndex: 'editedon' ,width: 125 - ,renderer: this._renderLastModDate }] ,tbar: { cls: 'has-nested-filters', @@ -236,12 +235,12 @@ Ext.extend(MODx.grid.Lexicon,MODx.grid.Grid,{ } } + /** + * @deprecated since 3.0.5. To be removed in future release. Datetime formatting + * now handled in back end processors to provide uniform display across components. + */ ,_renderLastModDate: function(value) { - if (Ext.isEmpty(value)) { - return '—'; - } - - return new Date(value*1000).format(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format); + return value; } ,loadWindow2: function(btn,e,o) { From 539c3c6afbf1d41b4aab84f558bb70ed14b3132d Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 25 Aug 2024 22:50:47 -0400 Subject: [PATCH 06/13] Update modFormatter.php Include empty date display value in early return --- core/src/Revolution/Utilities/modFormatter.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/Revolution/Utilities/modFormatter.php b/core/src/Revolution/Utilities/modFormatter.php index 1b5a8923971..6bcc95c6d54 100644 --- a/core/src/Revolution/Utilities/modFormatter.php +++ b/core/src/Revolution/Utilities/modFormatter.php @@ -53,6 +53,7 @@ class modFormatter '1969-12-31 00:00:00', '0000-00-00 00:00:00', 0, + '0', null ]; @@ -81,6 +82,10 @@ public function __construct(modX $modx) */ public function formatManagerDateTime($value, string $outputStyle = 'combined', bool $useOffset = false, bool $useAlternateFormat = false, string $alternateFormat = ''): string { + if (in_array($value, $this->managerDateEmptyValues)) { + return $this->managerDateEmptyDisplay; + } + $offset = floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600; $managerDateTimeSeparator = $this->modx->getOption('manager_datetime_separator', null, ', ', true); From 3fae011484fd5e9a2444ab1bb16237188f1be778 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 26 Aug 2024 02:05:45 -0400 Subject: [PATCH 07/13] Packages related updates Applies formatter to this object type --- .../Processors/Workspace/Packages/Get.php | 32 ++++++------ .../Processors/Workspace/Packages/GetList.php | 46 +++++++++-------- .../Workspace/Packages/Version/GetList.php | 50 +++++++++++-------- .../src/Revolution/Utilities/modFormatter.php | 36 ++++++++++++- .../assets/modext/workspace/package.grid.js | 13 ++--- .../package/package.versions.grid.js | 13 ++--- 6 files changed, 112 insertions(+), 78 deletions(-) diff --git a/core/src/Revolution/Processors/Workspace/Packages/Get.php b/core/src/Revolution/Processors/Workspace/Packages/Get.php index 9243a103980..da4c3148202 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/Get.php +++ b/core/src/Revolution/Processors/Workspace/Packages/Get.php @@ -1,4 +1,5 @@ modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); - $this->dateFormat = $this->getProperty('dateFormat', - $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format')); + $this->formatter = new modFormatter($this->modx); return parent::initialize(); } @@ -83,19 +81,17 @@ public function getMetadata() */ public function formatDates(array $packageArray) { - $updated = $this->object->get('updated'); - if ($updated !== '0000-00-00 00:00:00' && $updated !== null) { - $packageArray['updated'] = date($this->dateFormat, strtotime($updated)); - } else { - $packageArray['updated'] = ''; - } - $packageArray['created'] = date($this->dateFormat, strtotime($this->object->get('created'))); - $installed = $this->object->get('installed'); - if ($installed === null || $installed === '0000-00-00 00:00:00') { - $packageArray['installed'] = null; - } else { - $packageArray['installed'] = date($this->dateFormat, strtotime($installed)); - } + $packageArray['created'] = $this->formatter->getFormattedPackageDate($this->object->get('created')); + $packageArray['installed'] = $this->formatter->getFormattedPackageDate( + $this->object->get('installed'), + 'installed', + false + ); + $packageArray['updated'] = $this->formatter->getFormattedPackageDate( + $this->object->get('updated'), + 'updated', + false + ); return $packageArray; } } diff --git a/core/src/Revolution/Processors/Workspace/Packages/GetList.php b/core/src/Revolution/Processors/Workspace/Packages/GetList.php index a48d48c1af7..c01ab34f047 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Packages/GetList.php @@ -1,4 +1,5 @@ modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); + $this->formatter = new modFormatter($this->modx); $this->setDefaultProperties([ 'start' => 0, 'limit' => 10, 'workspace' => 1, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), 'query' => '', ]); return true; @@ -141,20 +143,18 @@ public function getVersionInfo(array $packageArray) */ public function formatDates(array $packageArray) { - if ($packageArray['updated'] !== '0000-00-00 00:00:00' && $packageArray['updated'] !== null) { - $packageArray['updated'] = utf8_encode(date($this->getProperty('dateFormat'), - strtotime($packageArray['updated']))); - } else { - $packageArray['updated'] = ''; - } - $packageArray['created'] = utf8_encode(date($this->getProperty('dateFormat'), - strtotime($packageArray['created']))); - if ($packageArray['installed'] === null || $packageArray['installed'] === '0000-00-00 00:00:00') { - $packageArray['installed'] = null; - } else { - $packageArray['installed'] = utf8_encode(date($this->getProperty('dateFormat'), - strtotime($packageArray['installed']))); - } + $packageArray['created'] = $this->formatter->getFormattedPackageDate($packageArray['created']); + $packageArray['installed'] = $this->formatter->getFormattedPackageDate( + $packageArray['installed'], + 'installed', + false + ); + $packageArray['updated'] = $this->formatter->getFormattedPackageDate( + $packageArray['updated'], + 'updated', + false + ); + return $packageArray; } @@ -197,9 +197,16 @@ public function checkForUpdates(modTransportPackage $package, array $packageArra if ($package->get('provider') > 0 && $this->modx->getOption('auto_check_pkg_updates', null, false)) { $updateCacheKey = 'mgr/providers/updates/' . $package->get('provider') . '/' . $package->get('signature'); $updateCacheOptions = [ - xPDO::OPT_CACHE_KEY => $this->modx->cacheManager->getOption('cache_packages_key', null, 'packages'), - xPDO::OPT_CACHE_HANDLER => $this->modx->cacheManager->getOption('cache_packages_handler', null, - $this->modx->cacheManager->getOption(xPDO::OPT_CACHE_HANDLER)), + xPDO::OPT_CACHE_KEY => $this->modx->cacheManager->getOption( + 'cache_packages_key', + null, + 'packages' + ), + xPDO::OPT_CACHE_HANDLER => $this->modx->cacheManager->getOption( + 'cache_packages_handler', + null, + $this->modx->cacheManager->getOption(xPDO::OPT_CACHE_HANDLER) + ) ]; $updates = $this->modx->cacheManager->get($updateCacheKey, $updateCacheOptions); if (empty($updates)) { @@ -220,8 +227,7 @@ public function checkForUpdates(modTransportPackage $package, array $packageArra } else { $updates = ['count' => count($updates)]; } - $this->modx->cacheManager->set($updateCacheKey, $updates, $this->updatesCacheExpire, - $updateCacheOptions); + $this->modx->cacheManager->set($updateCacheKey, $updates, $this->updatesCacheExpire, $updateCacheOptions); } } } diff --git a/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php b/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php index d8d332e233f..00fa665cc2d 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php @@ -1,4 +1,5 @@ modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); + $this->formatter = new modFormatter($this->modx); $this->setDefaultProperties([ 'limit' => 10, 'start' => 0, 'workspace' => 1, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), 'signature' => false, ]); return parent::initialize(); @@ -57,8 +59,11 @@ public function getData() 'package_name' => urldecode($this->getProperty('package_name', $signatureArray[0])), ]; $limit = $this->getProperty('limit'); - $pkgList = $this->modx->call(modTransportPackage::class, 'listPackageVersions', - [&$this->modx, $criteria, $limit > 0 ? $limit : 0, $this->getProperty('start')]); + $pkgList = $this->modx->call( + modTransportPackage::class, + 'listPackageVersions', + [&$this->modx, $criteria, $limit > 0 ? $limit : 0, $this->getProperty('start')] + ); $data['results'] = $pkgList['collection']; $data['total'] = $pkgList['total']; return $data; @@ -110,19 +115,18 @@ public function parseVersion(modTransportPackage $package, array $packageArray) */ public function formatDates(modTransportPackage $package, array $packageArray) { - $updated = $package->get('updated'); - if ($updated !== '0000-00-00 00:00:00' && $updated !== null) { - $packageArray['updated'] = date($this->getProperty('dateFormat'), strtotime($updated)); - } else { - $packageArray['updated'] = ''; - } - $packageArray['created'] = date($this->getProperty('dateFormat'), strtotime($package->get('created'))); - $installed = $package->get('installed'); - if ($installed === null || $installed === '0000-00-00 00:00:00') { - $packageArray['installed'] = null; - } else { - $packageArray['installed'] = date($this->getProperty('dateFormat'), strtotime($installed)); - } + $packageArray['created'] = $this->formatter->getFormattedPackageDate($package->get('created')); + $packageArray['installed'] = $this->formatter->getFormattedPackageDate( + $package->get('installed'), + 'installed', + false + ); + $packageArray['updated'] = $this->formatter->getFormattedPackageDate( + $package->get('updated'), + 'updated', + false + ); + return $packageArray; } @@ -137,8 +141,11 @@ public function getMetaData(modTransportPackage $package, array $packageArray) if (!empty($metadata)) { foreach ($metadata as $row) { if (!empty($row['name']) && $row['name'] === 'description') { - $packageArray['readme'] = str_replace([PHP_EOL, '

'], ['', '
'], - nl2br($row['text'])); + $packageArray['readme'] = str_replace( + [PHP_EOL, '

'], + ['', '
'], + nl2br($row['text']) + ); break; } } @@ -147,8 +154,11 @@ public function getMetaData(modTransportPackage $package, array $packageArray) $transport = $package->getTransport(); if ($transport) { $packageArray['readme'] = $transport->getAttribute('readme'); - $packageArray['readme'] = str_replace([PHP_EOL, '

'], ['', '
'], - nl2br($packageArray['readme'])); + $packageArray['readme'] = str_replace( + [PHP_EOL, '

'], + ['', '
'], + nl2br($packageArray['readme']) + ); } } unset($packageArray['attributes'], $packageArray['metadata'], $packageArray['manifest']); diff --git a/core/src/Revolution/Utilities/modFormatter.php b/core/src/Revolution/Utilities/modFormatter.php index 6bcc95c6d54..f2163890694 100644 --- a/core/src/Revolution/Utilities/modFormatter.php +++ b/core/src/Revolution/Utilities/modFormatter.php @@ -124,10 +124,10 @@ public function formatManagerDateTime($value, string $outputStyle = 'combined', /** * Formats a Resource-related date when applicable and includes localized default text to - * represent conditions where a date is not present + * represent conditions where a date is not present or applicable * * @param string|int $value The source date value to format - * @param string $whichDate One of five identifiers specifying the type of date being formatted + * @param string $whichDate An identifier specifying the type of date being formatted * @param bool $useStandardEmptyValue Whether to use the default empty value defined in the system settings * @return string The formatted date or relevant text indicating an empty date value */ @@ -157,4 +157,36 @@ public function getFormattedResourceDate($value, string $whichDate = 'created', : $this->formatManagerDateTime($value, 'combined', true) ; } + + /** + * Formats a Package-related date when applicable and includes localized default text to + * represent conditions where a date is not present or applicable + * + * @param string|int $value The source date value to format + * @param string $whichDate An identifier specifying the type of date being formatted + * @param bool $useStandardEmptyValue Whether to use the default empty value defined in the system settings + * @return string The formatted date or relevant text indicating an empty date value + */ + public function getFormattedPackageDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string + { + if ($useStandardEmptyValue) { + $emptyValue = $this->managerDateEmptyDisplay; + } else { + switch ($whichDate) { + case 'installed': + $emptyValue = $this->modx->lexicon('not_installed'); + break; + case 'updated': + $emptyValue = $this->modx->lexicon('not_updated'); + break; + default: + $emptyValue = $this->modx->lexicon('unknown'); + } + $emptyValue = '(' . $emptyValue . ')'; + } + return in_array($value, $this->managerDateEmptyValues) + ? $emptyValue + : $this->formatManagerDateTime($value, 'combined', true) + ; + } } diff --git a/manager/assets/modext/workspace/package.grid.js b/manager/assets/modext/workspace/package.grid.js index c25d19b2098..3914fb4080b 100644 --- a/manager/assets/modext/workspace/package.grid.js +++ b/manager/assets/modext/workspace/package.grid.js @@ -211,16 +211,11 @@ Ext.extend(MODx.grid.Package,MODx.grid.Grid,{ return this.mainColumnTpl.apply(values); } - ,dateColumnRenderer: function(d,c) { - switch(d) { - case '': - case null: - c.css = 'not-installed'; - return _('not_installed'); - default: - c.css = ''; - return _('installed_on',{'time':d}); + ,dateColumnRenderer: function(value, metaData) { + if (Ext.isEmpty(value) || value.includes(_('not_installed'))) { + metaData.css = 'not-installed'; } + return value; } ,onClick: function(e){ diff --git a/manager/assets/modext/workspace/package/package.versions.grid.js b/manager/assets/modext/workspace/package/package.versions.grid.js index 0223981dd67..eac7118d076 100644 --- a/manager/assets/modext/workspace/package/package.versions.grid.js +++ b/manager/assets/modext/workspace/package/package.versions.grid.js @@ -41,16 +41,11 @@ MODx.grid.PackageVersions = function(config) { }; Ext.extend(MODx.grid.PackageVersions,MODx.grid.Grid,{ - _rins: function(d,c) { - switch(d) { - case '': - case null: - c.css = 'not-installed'; - return _('not_installed'); - default: - c.css = ''; - return d; + _rins: function(value, metaData) { + if (Ext.isEmpty(value) || value.includes(_('not_installed'))) { + metaData.css = 'not-installed'; } + return value; } ,removePriorVersion: function(btn,e) { From c5523bb3ee0685140692ef28ff6f991b621f60f3 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 26 Aug 2024 02:07:26 -0400 Subject: [PATCH 08/13] Additional updates (Finding areas I'd missed updating in earlier commits) --- core/lexicon/en/workspace.inc.php | 1 + .../Processors/System/Log/GetList.php | 18 ++++++++++++------ .../Processors/Workspace/Lexicon/GetList.php | 10 +++++----- .../widgets/system/modx.grid.manager.log.js | 2 ++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/core/lexicon/en/workspace.inc.php b/core/lexicon/en/workspace.inc.php index 324f3477390..96a314c9489 100644 --- a/core/lexicon/en/workspace.inc.php +++ b/core/lexicon/en/workspace.inc.php @@ -60,6 +60,7 @@ $_lang['newest_additions'] = 'Newest Additions'; $_lang['no_preview'] = 'No Preview'; $_lang['not_installed'] = 'Not Installed'; +$_lang['not_updated'] = 'Not Updated'; $_lang['package'] = 'Package'; $_lang['package_add'] = 'New Package'; $_lang['package_already_downloaded'] = 'Package already downloaded'; diff --git a/core/src/Revolution/Processors/System/Log/GetList.php b/core/src/Revolution/Processors/System/Log/GetList.php index e20a4b4d097..84feec8272e 100644 --- a/core/src/Revolution/Processors/System/Log/GetList.php +++ b/core/src/Revolution/Processors/System/Log/GetList.php @@ -1,4 +1,5 @@ formatter = new modFormatter($this->modx); $this->setDefaultProperties([ 'limit' => 20, 'start' => 0, @@ -61,7 +64,7 @@ public function initialize() 'actionType' => false, 'dateStart' => false, 'dateEnd' => false, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), + 'dateFormat' => '', ]); return true; } @@ -185,8 +188,8 @@ public function prepareLog(modManagerLog $log) // Action is prefixed with a namespace, assume we need to load a package $exp = explode('.', $logArray['action']); $ns = $exp[0]; - $path = $this->modx->getOption("{$ns}.core_path", null, - $this->modx->getOption('core_path') . "components/{$ns}/") . 'model/'; + $nsCorePath = $this->modx->getOption('core_path') . "components/{$ns}/"; + $path = $this->modx->getOption("{$ns}.core_path", null, $nsCorePath) . 'model/'; $this->modx->addPackage($ns, $path); } if (!empty($logArray['classKey']) && !empty($logArray['item'])) { @@ -204,7 +207,11 @@ public function prepareLog(modManagerLog $log) } else { $logArray['name'] = $log->get('item'); } - $logArray['occurred'] = date($this->getProperty('dateFormat'), strtotime($logArray['occurred'])); + $customFormat = $this->getProperty('dateFormat'); + $logArray['occurred'] = !empty($customFormat) + ? $this->formatter->formatManagerDateTime($logArray['occurred'], '', false, true, $customFormat) + : $this->formatter->formatManagerDateTime($logArray['occurred']) + ; return $logArray; } @@ -245,8 +252,7 @@ public function getNameField($classKey) case modUserSetting::class: $field = 'key'; break; - default: - break; + // no default } return $field; } diff --git a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php index 6fe237b16fe..0c130223b5e 100644 --- a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php @@ -139,14 +139,15 @@ function parseArray($needle, array $haystack = []) /* loop through */ $list = []; foreach ($entries as $name => $value) { + $editedOn = null; $entryArray = [ 'name' => $name, 'value' => $value, 'namespace' => $this->getProperty('namespace'), 'topic' => $this->getProperty('topic'), 'language' => $this->getProperty('language'), - 'createdon' => $this->formatter->managerDateEmptyDisplay, - 'editedon' => $this->formatter->managerDateEmptyDisplay, + 'createdon' => null, + 'editedon' => null, 'overridden' => 0, ]; /* if override in db, load */ @@ -154,11 +155,10 @@ function parseArray($needle, array $haystack = []) foreach ($dbEntries[$name] as $k => $v) { $entryArray[$k] = $v; // array_merge very slow inside loop, don't use it here } - - $entryArray['editedon'] = $this->formatter->formatManagerDateTime($entryArray['editedon']) ?: $this->formatter->formatManagerDateTime($entryArray['createdon']); - + $editedOn = $entryArray['editedon'] ?: $entryArray['createdon'] ; $entryArray['overridden'] = 1; } + $entryArray['editedon'] = $this->formatter->formatManagerDateTime($editedOn); $list[] = $entryArray; } diff --git a/manager/assets/modext/widgets/system/modx.grid.manager.log.js b/manager/assets/modext/widgets/system/modx.grid.manager.log.js index 8a0b549defd..82088d5cb05 100644 --- a/manager/assets/modext/widgets/system/modx.grid.manager.log.js +++ b/manager/assets/modext/widgets/system/modx.grid.manager.log.js @@ -75,6 +75,7 @@ MODx.panel.ManagerLog = function(config) { ,name: 'dateStart' ,allowBlank: true ,anchor: '100%' + ,format: MODx.config.manager_date_format ,listeners: { 'select': {fn: this.filter, scope: this} ,'render': {fn:this._addEnterKeyHandler} @@ -85,6 +86,7 @@ MODx.panel.ManagerLog = function(config) { ,name: 'dateEnd' ,allowBlank: true ,anchor: '100%' + ,format: MODx.config.manager_date_format ,listeners: { 'select': {fn: this.filter, scope: this} ,'render': {fn:this._addEnterKeyHandler} From 2c45cb61bf64b472942e083509ec1f5a8fa06367 Mon Sep 17 00:00:00 2001 From: Jan Peca Date: Fri, 6 Sep 2024 16:18:20 +0200 Subject: [PATCH 09/13] Adjust the formatter --- .../modManagerDateFormatter.php} | 115 ++++++++++-------- .../Processors/Browser/Directory/GetFiles.php | 7 +- core/src/Revolution/Processors/Processor.php | 6 - .../Revolution/Processors/Resource/Data.php | 22 ++-- .../Processors/Resource/Event/GetList.php | 18 ++- .../Processors/Resource/Trash/GetList.php | 10 +- .../Processors/Security/Message/GetList.php | 10 +- .../Processors/Security/Profile/Get.php | 14 ++- .../Processors/Security/Profile/Update.php | 17 +-- .../Processors/Security/User/Get.php | 16 +-- .../Processors/Security/User/GetOnline.php | 16 +-- .../User/GetRecentlyEditedResources.php | 19 +-- .../Processors/Security/User/Validation.php | 13 +- .../System/ActiveResource/GetList.php | 12 +- .../System/Dashboard/Widget/Feed.php | 10 +- .../Processors/System/Log/GetList.php | 14 ++- .../Processors/System/Settings/GetList.php | 12 +- .../Processors/Workspace/Lexicon/GetList.php | 8 +- .../Processors/Workspace/Packages/Get.php | 12 +- .../Processors/Workspace/Packages/GetList.php | 12 +- .../Workspace/Packages/Version/GetList.php | 12 +- core/src/Revolution/modX.php | 3 + .../default/system/file/edit.class.php | 9 +- 23 files changed, 210 insertions(+), 177 deletions(-) rename core/src/Revolution/{Utilities/modFormatter.php => Formatter/modManagerDateFormatter.php} (68%) diff --git a/core/src/Revolution/Utilities/modFormatter.php b/core/src/Revolution/Formatter/modManagerDateFormatter.php similarity index 68% rename from core/src/Revolution/Utilities/modFormatter.php rename to core/src/Revolution/Formatter/modManagerDateFormatter.php index f2163890694..89459593e71 100644 --- a/core/src/Revolution/Utilities/modFormatter.php +++ b/core/src/Revolution/Formatter/modManagerDateFormatter.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace MODX\Revolution\Utilities; +namespace MODX\Revolution\Formatter; use MODX\Revolution\modX; @@ -18,7 +18,7 @@ * * @package MODX\Revolution */ -class modFormatter +class modManagerDateFormatter { /** * A reference to the modX object. @@ -31,22 +31,22 @@ class modFormatter /** * @var string $managerDateFormat The php datetime format for dates, as defined in the system settings */ - public $managerDateFormat = ''; + protected string $managerDateFormat = ''; /** * @var string $managerTimeFormat The php datetime format for times, as defined in the system settings */ - public $managerTimeFormat = ''; + protected string $managerTimeFormat = ''; /** * @var string $managerDateHiddenFormat Standard mysql format required for date transformations */ - public $managerDateHiddenFormat = 'Y-m-d H:i:s'; + protected string $managerDateHiddenFormat = 'Y-m-d H:i:s'; /** * @var array $managerDateEmptyValues A list of possible values representing an empty date */ - public $managerDateEmptyValues = [ + protected array $managerDateEmptyValues = [ '', '-001-11-30 00:00:00', '-1-11-30 00:00:00', @@ -60,7 +60,7 @@ class modFormatter /** * @var string $managerDateEmptyDisplay The text (if any) to show for empty dates */ - public $managerDateEmptyDisplay = ''; + private $managerDateEmptyDisplay = ''; public function __construct(modX $modx) @@ -71,23 +71,16 @@ public function __construct(modX $modx) $this->managerDateEmptyDisplay = $this->modx->getOption('manager_datetime_empty_value', null, '–', true); } - /** - * Provides final formatted output of a date, time, or combination of the two, based on system settings - * @param string|int $value The value to transform (must be a unix timestamp or mysql-format string) - * @param string $outputStyle Controls whether the output should be date only, time only, or a combination of the two - * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation - * @param bool $useAlternateFormat Whether to override the system settings' format with a custom one - * @param string $alternateFormat The custom format to use when overriding the system one - * @return string The formatted date - */ - public function formatManagerDateTime($value, string $outputStyle = 'combined', bool $useOffset = false, bool $useAlternateFormat = false, string $alternateFormat = ''): string + public function isEmpty($value) { - if (in_array($value, $this->managerDateEmptyValues)) { - return $this->managerDateEmptyDisplay; - } + return in_array($value, $this->managerDateEmptyValues); + } - $offset = floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600; - $managerDateTimeSeparator = $this->modx->getOption('manager_datetime_separator', null, ', ', true); + protected function parseValue($value, bool $useOffset = false): ?int + { + if ($this->isEmpty($value)) { + return null; + } if (!modX::isValidTimestamp($value)) { // If not a timestamp integer, expecting mysql-formatted value @@ -100,28 +93,58 @@ public function formatManagerDateTime($value, string $outputStyle = 'combined', $value = $dateTime->getTimestamp(); } - $value = $useOffset ? $value + $offset : $value ; + $value = (int)$value; - if ($useAlternateFormat && !empty($alternateFormat)) { - return date($alternateFormat, $value); + if (!$useOffset) { + return $value; } - switch ($outputStyle) { - case 'combined': - $format = $this->managerDateFormat . $managerDateTimeSeparator . $this->managerTimeFormat; - break; - case 'date': - $format = $this->managerDateFormat; - break; - case 'time': - $format = $this->managerTimeFormat; - break; - // no default + $offset = floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600; + + return $value + $offset; + } + + /** + * Format DateTime with a custom format + * @param string|int $value The value to transform (must be a unix timestamp or mysql-format string) + * @param string $format The custom format to use when formatting the $value + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @return string The formatted date + */ + public function format($value, string $format, bool $useOffset = false, string $emptyValue = null): string + { + $value = $this->parseValue($value, $useOffset); + + if ($value === null) { + return $emptyValue === null ? $this->managerDateEmptyDisplay : $emptyValue; } return date($format, $value); } + public function formatHidden($value): string + { + return $this->format($value, $this->managerDateHiddenFormat, false, ''); + } + + public function formatDate($value, bool $useOffset = false, string $emptyValue = null): string + { + return $this->format($value, $this->managerDateFormat, $useOffset, $emptyValue); + } + + public function formatTime($value, bool $useOffset = false, string $emptyValue = null): string + { + return $this->format($value, $this->managerTimeFormat, $useOffset, $emptyValue); + } + + public function formatDateTime($value, bool $useOffset = false, string $emptyValue = null): string + { + $managerDateTimeSeparator = $this->modx->getOption('manager_datetime_separator', null, ', ', true); + $format = $this->managerDateFormat . $managerDateTimeSeparator . $this->managerTimeFormat; + + return $this->format($value, $format, $useOffset, $emptyValue); + } + /** * Formats a Resource-related date when applicable and includes localized default text to * represent conditions where a date is not present or applicable @@ -131,10 +154,10 @@ public function formatManagerDateTime($value, string $outputStyle = 'combined', * @param bool $useStandardEmptyValue Whether to use the default empty value defined in the system settings * @return string The formatted date or relevant text indicating an empty date value */ - public function getFormattedResourceDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string + public function formatResourceDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string { if ($useStandardEmptyValue) { - $emptyValue = $this->managerDateEmptyDisplay; + $emptyValue = null; } else { switch ($whichDate) { case 'edited': @@ -152,10 +175,8 @@ public function getFormattedResourceDate($value, string $whichDate = 'created', } $emptyValue = '(' . $emptyValue . ')'; } - return in_array($value, $this->managerDateEmptyValues) - ? $emptyValue - : $this->formatManagerDateTime($value, 'combined', true) - ; + + return $this->formatDateTime($value, true, $emptyValue); } /** @@ -167,10 +188,10 @@ public function getFormattedResourceDate($value, string $whichDate = 'created', * @param bool $useStandardEmptyValue Whether to use the default empty value defined in the system settings * @return string The formatted date or relevant text indicating an empty date value */ - public function getFormattedPackageDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string + public function formatPackageDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string { if ($useStandardEmptyValue) { - $emptyValue = $this->managerDateEmptyDisplay; + $emptyValue = null; } else { switch ($whichDate) { case 'installed': @@ -184,9 +205,7 @@ public function getFormattedPackageDate($value, string $whichDate = 'created', b } $emptyValue = '(' . $emptyValue . ')'; } - return in_array($value, $this->managerDateEmptyValues) - ? $emptyValue - : $this->formatManagerDateTime($value, 'combined', true) - ; + + return $this->formatDateTime($value, true, $emptyValue); } } diff --git a/core/src/Revolution/Processors/Browser/Directory/GetFiles.php b/core/src/Revolution/Processors/Browser/Directory/GetFiles.php index f081d2cf742..2bd2550ca5b 100644 --- a/core/src/Revolution/Processors/Browser/Directory/GetFiles.php +++ b/core/src/Revolution/Processors/Browser/Directory/GetFiles.php @@ -11,8 +11,8 @@ namespace MODX\Revolution\Processors\Browser\Directory; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\Processors\Browser\Browser; -use MODX\Revolution\Utilities\modFormatter; /** * Gets all files in a directory @@ -50,9 +50,10 @@ public function process() return $this->failure($this->source->getErrors(), []); } - $formatter = new modFormatter($this->modx); + /** @var modManagerDateFormatter $formatter */ + $formatter = $this->modx->services->get(modManagerDateFormatter::class); foreach ($list as $i => $file) { - $list[$i]['lastmod'] = $formatter->formatManagerDateTime($file['lastmod']); + $list[$i]['lastmod'] = $formatter->formatDateTime($file['lastmod']); } return $this->outputArray($list); diff --git a/core/src/Revolution/Processors/Processor.php b/core/src/Revolution/Processors/Processor.php index 4b58e2d5aa2..50e19f02d57 100644 --- a/core/src/Revolution/Processors/Processor.php +++ b/core/src/Revolution/Processors/Processor.php @@ -41,12 +41,6 @@ abstract class Processor */ public $permission = ''; - /** - * An instance of modFormatter, which is set from the child processors that use it - * @var modFormatter $formatter - */ - public $formatter = null; - /** * Creates a modProcessor object. * diff --git a/core/src/Revolution/Processors/Resource/Data.php b/core/src/Revolution/Processors/Resource/Data.php index 6093b78215a..547a2e117b2 100644 --- a/core/src/Revolution/Processors/Resource/Data.php +++ b/core/src/Revolution/Processors/Resource/Data.php @@ -11,11 +11,11 @@ namespace MODX\Revolution\Processors\Resource; -use MODX\Revolution\Processors\Processor; -use MODX\Revolution\Utilities\modFormatter; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modResource; use MODX\Revolution\modTemplate; use MODX\Revolution\modUser; +use MODX\Revolution\Processors\Processor; use xPDO\Cache\xPDOCacheManager; use xPDO\xPDO; @@ -30,6 +30,8 @@ class Data extends Processor /** @var modResource $resource */ public $resource; + private modManagerDateFormatter $formatter; + public function checkPermissions() { return $this->modx->hasPermission('view'); @@ -42,7 +44,7 @@ public function getLanguageTopics() public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $id = $this->getProperty('id', false); if (empty($id)) { return $this->modx->lexicon('resource_err_ns'); @@ -107,38 +109,38 @@ public function getChanges(array $resourceArray) $resourceArray['status'] = $resourceArray['published'] ? $this->modx->lexicon('resource_published') : $this->modx->lexicon('resource_unpublished'); $resourceArray['createdon_by'] = $this->resource->get('creator') ?: $unknownUser; - $resourceArray['createdon_adjusted'] = $this->formatter->getFormattedResourceDate( + $resourceArray['createdon_adjusted'] = $this->formatter->formatResourceDate( $this->resource->get('createdon'), 'created', false ); - $resourceArray['editedon_adjusted'] = $this->formatter->getFormattedResourceDate( + $resourceArray['editedon_adjusted'] = $this->formatter->formatResourceDate( $this->resource->get('editedon'), 'edited', false ); - $resourceArray['editedon_by'] = in_array($resourceArray['editedon'], $this->formatter->managerDateEmptyValues) + $resourceArray['editedon_by'] = $this->formatter->isEmpty($resourceArray['editedon']) ? '(' . $this->modx->lexicon('unedited') . ')' : $this->resource->get('editor') ; - $resourceArray['pub_date'] = $this->formatter->getFormattedResourceDate( + $resourceArray['pub_date'] = $this->formatter->formatResourceDate( $resourceArray['pub_date'], 'publish', false ); - $resourceArray['unpub_date'] = $this->formatter->getFormattedResourceDate( + $resourceArray['unpub_date'] = $this->formatter->formatResourceDate( $resourceArray['unpub_date'], 'unpublish', false ); - $resourceArray['publishedon_adjusted'] = $this->formatter->getFormattedResourceDate( + $resourceArray['publishedon_adjusted'] = $this->formatter->formatResourceDate( $this->resource->get('publishedon'), 'published', false ); $publisher = $this->resource->get('publisher') ?: $unknownUser; - $resourceArray['publishedon_by'] = in_array($resourceArray['publishedon'], $this->formatter->managerDateEmptyValues) + $resourceArray['publishedon_by'] = $this->formatter->isEmpty($resourceArray['publishedon']) ? '(' . $this->modx->lexicon('unpublished') . ')' : $publisher ; diff --git a/core/src/Revolution/Processors/Resource/Event/GetList.php b/core/src/Revolution/Processors/Resource/Event/GetList.php index ddb3a5a21af..a6c5dc0d736 100644 --- a/core/src/Revolution/Processors/Resource/Event/GetList.php +++ b/core/src/Revolution/Processors/Resource/Event/GetList.php @@ -11,9 +11,9 @@ namespace MODX\Revolution\Processors\Resource\Event; -use MODX\Revolution\Processors\Processor; -use MODX\Revolution\Utilities\modFormatter; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modResource; +use MODX\Revolution\Processors\Processor; use xPDO\Om\xPDOObject; /** @@ -28,6 +28,8 @@ */ class GetList extends Processor { + private modManagerDateFormatter $formatter; + public function checkPermissions() { return $this->modx->hasPermission('view_document'); @@ -40,7 +42,7 @@ public function getLanguageTopics() public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'start' => 0, 'limit' => 10, @@ -107,16 +109,10 @@ public function prepareRow(xPDOObject $object) below will be lost. */ $pubDate = $object->get('pub_date'); - $objectArray['pub_date'] = in_array($pubDate, $this->formatter->managerDateEmptyValues) - ? $this->formatter->managerDateEmptyDisplay - : $this->formatter->formatManagerDateTime($pubDate, 'combined', true) - ; + $objectArray['pub_date'] = $this->formatter->formatDateTime($pubDate, true); $unpubDate = $object->get('unpub_date'); - $objectArray['unpub_date'] = in_array($unpubDate, $this->formatter->managerDateEmptyValues) - ? $this->formatter->managerDateEmptyDisplay - : $this->formatter->formatManagerDateTime($unpubDate, 'combined', true) - ; + $objectArray['unpub_date'] = $this->formatter->formatDateTime($unpubDate,true); return $objectArray; } diff --git a/core/src/Revolution/Processors/Resource/Trash/GetList.php b/core/src/Revolution/Processors/Resource/Trash/GetList.php index 86c2dc19ea1..79234f46ac6 100644 --- a/core/src/Revolution/Processors/Resource/Trash/GetList.php +++ b/core/src/Revolution/Processors/Resource/Trash/GetList.php @@ -11,11 +11,11 @@ namespace MODX\Revolution\Processors\Resource\Trash; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modContext; -use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modResource; use MODX\Revolution\modUser; +use MODX\Revolution\Processors\Model\GetListProcessor; use PDO; use xPDO\Om\xPDOObject; use xPDO\Om\xPDOQuery; @@ -40,9 +40,11 @@ class GetList extends GetListProcessor public $permission = 'view'; + private modManagerDateFormatter $formatter; + public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return parent::initialize(); } @@ -199,7 +201,7 @@ public function prepareRow(xPDOObject $object) $objectArray['cls'] = implode(' ', $cls); - $objectArray['deletedon'] = $this->formatter->formatManagerDateTime($objectArray['deletedon']); + $objectArray['deletedon'] = $this->formatter->formatDateTime($objectArray['deletedon']); return $objectArray; } diff --git a/core/src/Revolution/Processors/Security/Message/GetList.php b/core/src/Revolution/Processors/Security/Message/GetList.php index 0c8735ee263..19b18d93742 100644 --- a/core/src/Revolution/Processors/Security/Message/GetList.php +++ b/core/src/Revolution/Processors/Security/Message/GetList.php @@ -11,11 +11,11 @@ namespace MODX\Revolution\Processors\Security\Message; -use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modUser; use MODX\Revolution\modUserMessage; use MODX\Revolution\modUserProfile; +use MODX\Revolution\Processors\Model\GetListProcessor; use xPDO\Om\xPDOObject; use xPDO\Om\xPDOQuery; @@ -34,9 +34,11 @@ class GetList extends GetListProcessor public $permission = 'messages'; public $defaultSortField = 'date_sent'; + private modManagerDateFormatter $formatter; + public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return parent::initialize(); } @@ -99,7 +101,7 @@ public function prepareRow(xPDOObject $object) $objectArray = $object->toArray(); if (array_key_exists('date_sent', $objectArray)) { - $objectArray['date_sent'] = $this->formatter->formatManagerDateTime($objectArray['date_sent']); + $objectArray['date_sent'] = $this->formatter->formatDateTime($objectArray['date_sent']); } $objectArray['sender_name'] = $object->get('sender_fullname') . " ({$object->get('sender_username')})"; diff --git a/core/src/Revolution/Processors/Security/Profile/Get.php b/core/src/Revolution/Processors/Security/Profile/Get.php index 089aa1066ec..5ab425f6a8f 100644 --- a/core/src/Revolution/Processors/Security/Profile/Get.php +++ b/core/src/Revolution/Processors/Security/Profile/Get.php @@ -11,12 +11,12 @@ namespace MODX\Revolution\Processors\Security\Profile; -use MODX\Revolution\Processors\Processor; -use MODX\Revolution\Utilities\modFormatter; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modUser; use MODX\Revolution\modUserGroup; use MODX\Revolution\modUserGroupMember; use MODX\Revolution\modUserGroupRole; +use MODX\Revolution\Processors\Processor; /** * Get a user profile @@ -28,6 +28,8 @@ class Get extends Processor /** @var modUser $user */ public $user; + private modManagerDateFormatter $formatter; + /** * @return bool */ @@ -53,7 +55,7 @@ public function initialize() if (!$this->user) { return $this->modx->lexicon('user_err_not_found'); } - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return true; } @@ -71,9 +73,9 @@ public function process() } $userArray['dob'] = !empty($userArray['dob']) ? date('Y-m-d', $userArray['dob']) : ''; - $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockeduntil']) : ''; - $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockedafter']) : ''; - $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? $this->formatter->formatManagerDateTime($userArray['lastlogin']) : ''; + $userArray['blockeduntil'] = $this->formatter->formatHidden($userArray['blockeduntil']); + $userArray['blockedafter'] = $this->formatter->formatHidden($userArray['blockedafter']); + $userArray['lastlogin'] = $this->formatter->formatDateTime($userArray['lastlogin'], false, ''); unset($userArray['password'], $userArray['cachepwd'], $userArray['sessionid'], $userArray['salt']); return $this->success('', $userArray); diff --git a/core/src/Revolution/Processors/Security/Profile/Update.php b/core/src/Revolution/Processors/Security/Profile/Update.php index 2bd7dab1b3b..68d96cc9c85 100644 --- a/core/src/Revolution/Processors/Security/Profile/Update.php +++ b/core/src/Revolution/Processors/Security/Profile/Update.php @@ -11,10 +11,9 @@ namespace MODX\Revolution\Processors\Security\Profile; -use MODX\Revolution\Processors\Processor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modUser; use MODX\Revolution\modUserProfile; +use MODX\Revolution\Processors\Processor; /** * Update a user profile @@ -50,7 +49,6 @@ public function initialize() if ($this->profile === null) { return $this->modx->lexicon('user_profile_err_not_found'); } - $this->formatter = new modFormatter($this->modx); return true; } @@ -90,11 +88,6 @@ public function process() return $this->success($this->modx->lexicon('success'), $this->profile->toArray()); } - /* - TBD: Ultimately this Update class should be using the Validation class - that the main User class does ... for both the dob property in prepare() - and the password properties in validate() below - */ public function prepare() { $properties = $this->getProperties(); @@ -102,13 +95,15 @@ public function prepare() /* format and set data */ $dob = $this->getProperty('dob'); if (!empty($dob)) { - $date = \DateTimeImmutable::createFromFormat($this->formatter->managerDateFormat, $dob); - if ($date === false) { + $parsedDob = strtotime($dob); + + if ($parsedDob === false) { $this->addFieldError('dob', $this->modx->lexicon('user_err_not_specified_dob')); } else { - $properties['dob'] = $date->getTimestamp(); + $properties['dob'] = $parsedDob; } } + $this->profile->fromArray($properties); } diff --git a/core/src/Revolution/Processors/Security/User/Get.php b/core/src/Revolution/Processors/Security/User/Get.php index 7218ea5c868..98e86362546 100644 --- a/core/src/Revolution/Processors/Security/User/Get.php +++ b/core/src/Revolution/Processors/Security/User/Get.php @@ -11,12 +11,12 @@ namespace MODX\Revolution\Processors\Security\User; -use MODX\Revolution\Processors\Model\GetProcessor; -use MODX\Revolution\Utilities\modFormatter; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modUser; use MODX\Revolution\modUserGroup; use MODX\Revolution\modUserGroupMember; use MODX\Revolution\modUserGroupRole; +use MODX\Revolution\Processors\Model\GetProcessor; /** * Get a user @@ -30,9 +30,11 @@ class Get extends GetProcessor public $permission = 'view_user'; public $objectType = 'user'; + private modManagerDateFormatter $formatter; + public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return parent::initialize(); } @@ -100,10 +102,10 @@ public function cleanup() } $userArray['dob'] = !empty($userArray['dob']) ? date('Y-m-d', $userArray['dob']) : ''; - $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockeduntil']) : ''; - $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date($this->formatter->managerDateHiddenFormat, $userArray['blockedafter']) : ''; - $userArray['createdon'] = $this->formatter->formatManagerDateTime($userArray['createdon']); - $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? $this->formatter->formatManagerDateTime($userArray['lastlogin']) : ''; + $userArray['blockeduntil'] = $this->formatter->formatHidden($userArray['blockeduntil']); + $userArray['blockedafter'] = $this->formatter->formatHidden($userArray['blockedafter']); + $userArray['createdon'] = $this->formatter->formatDateTime($userArray['createdon']); + $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? $this->formatter->formatDateTime($userArray['lastlogin']) : ''; unset($userArray['password'], $userArray['cachepwd'], $userArray['sessionid'], $userArray['salt']); return $this->success('', $userArray); diff --git a/core/src/Revolution/Processors/Security/User/GetOnline.php b/core/src/Revolution/Processors/Security/User/GetOnline.php index fc67327ef4e..b60d3cbd54d 100644 --- a/core/src/Revolution/Processors/Security/User/GetOnline.php +++ b/core/src/Revolution/Processors/Security/User/GetOnline.php @@ -13,14 +13,14 @@ use DateInterval; use DateTime; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modManagerLog; -use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modUser; use MODX\Revolution\modUserGroup; +use MODX\Revolution\Processors\Model\GetListProcessor; use PDO; -use xPDO\Om\xPDOQuery; use xPDO\Om\xPDOObject; +use xPDO\Om\xPDOQuery; /** * Gets a list of all users who are online @@ -32,9 +32,11 @@ class GetOnline extends GetListProcessor public $defaultSortField = 'occurred'; public $defaultSortDirection = 'desc'; + private modManagerDateFormatter $formatter; + public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return parent::initialize(); } @@ -78,9 +80,9 @@ public function prepareRow(xPDOObject $object) { $row = $object->toArray(); - $row['occurred_date'] = $this->formatter->formatManagerDateTime($row['occurred'], 'date'); - $row['occurred_time'] = $this->formatter->formatManagerDateTime($row['occurred'], 'time'); - $row['occurred'] = $this->formatter->formatManagerDateTime($row['occurred']); + $row['occurred_date'] = $this->formatter->formatDate($row['occurred']); + $row['occurred_time'] = $this->formatter->formatTime($row['occurred']); + $row['occurred'] = $this->formatter->formatDateTime($row['occurred']); /** @var modUser $user */ if ($user = $object->getOne('User')) { diff --git a/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php b/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php index 62401f26115..f2a8955cb4e 100644 --- a/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php +++ b/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php @@ -11,13 +11,12 @@ namespace MODX\Revolution\Processors\Security\User; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modManagerLog; -use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modResource; use MODX\Revolution\modUser; use MODX\Revolution\modUserGroup; -use PDO; +use MODX\Revolution\Processors\Model\GetListProcessor; use xPDO\Om\xPDOObject; use xPDO\Om\xPDOQuery; @@ -39,13 +38,15 @@ class GetRecentlyEditedResources extends GetListProcessor public $defaultSortDirection = 'DESC'; protected $classKeys = []; + private modManagerDateFormatter $formatter; + /** * @return bool|null|string */ public function initialize() { $this->setDefaultProperties(['limit' => 10]); - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->classKeys = $this->modx->getDescendants(modResource::class); $this->classKeys[] = modResource::class; @@ -99,11 +100,11 @@ public function prepareRow(xPDOObject $object) $editedon = !empty($resourceArray['editedon']) ? $resourceArray['editedon'] : $resourceArray['createdon'] ; $isUnedited = $editedon === $resourceArray['createdon']; - $resourceArray['createdon_date'] = $this->formatter->formatManagerDateTime($resourceArray['createdon'], 'date'); - $resourceArray['createdon_time'] = $this->formatter->formatManagerDateTime($resourceArray['createdon'], 'time'); - $resourceArray['editedon_date'] = $isUnedited ? $resourceArray['createdon_date'] : $this->formatter->formatManagerDateTime($editedon, 'date'); - $resourceArray['editedon_time'] = $isUnedited ? $resourceArray['createdon_time'] : $this->formatter->formatManagerDateTime($editedon, 'time'); - $row['occurred'] = $this->formatter->formatManagerDateTime($row['occurred']); + $resourceArray['createdon_date'] = $this->formatter->formatDate($resourceArray['createdon']); + $resourceArray['createdon_time'] = $this->formatter->formatTime($resourceArray['createdon']); + $resourceArray['editedon_date'] = $isUnedited ? $resourceArray['createdon_date'] : $this->formatter->formatDate($editedon); + $resourceArray['editedon_time'] = $isUnedited ? $resourceArray['createdon_time'] : $this->formatter->formatTime($editedon); + $row['occurred'] = $this->formatter->formatDateTime($row['occurred']); $row = array_merge($row, $resourceArray); diff --git a/core/src/Revolution/Processors/Security/User/Validation.php b/core/src/Revolution/Processors/Security/User/Validation.php index d0661b33eec..a4150431a43 100644 --- a/core/src/Revolution/Processors/Security/User/Validation.php +++ b/core/src/Revolution/Processors/Security/User/Validation.php @@ -11,11 +11,10 @@ namespace MODX\Revolution\Processors\Security\User; -use MODX\Revolution\Processors\ModelProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modUser; use MODX\Revolution\modUserProfile; use MODX\Revolution\modX; +use MODX\Revolution\Processors\ModelProcessor; /** * Handles common validation for user processors @@ -32,8 +31,6 @@ class Validation public $user; /** @var modUserProfile $profile */ public $profile; - /** @var modFormatter $formatter */ - public $formatter; public function __construct(ModelProcessor &$processor, modUser &$user, modUserProfile &$profile) { @@ -41,7 +38,6 @@ public function __construct(ModelProcessor &$processor, modUser &$user, modUserP $this->modx =& $processor->modx; $this->user =& $user; $this->profile =& $profile; - $this->formatter = new modFormatter($this->modx); } public function validate() @@ -173,11 +169,10 @@ public function checkBirthDate() { $birthDate = $this->processor->getProperty('dob'); if (!empty($birthDate)) { - $date = \DateTimeImmutable::createFromFormat($this->formatter->managerDateFormat, $birthDate); - if ($date === false) { - $this->processor->addFieldError('dob', $this->modx->lexicon('user_err_not_specified_dob')); + $birthDate = strtotime($birthDate); + if (false === $birthDate) { + $this->processor->addFieldError('dob',$this->modx->lexicon('user_err_not_specified_dob')); } - $birthDate = $date->getTimestamp(); $this->processor->setProperty('dob', $birthDate); $this->profile->set('dob', $birthDate); } diff --git a/core/src/Revolution/Processors/System/ActiveResource/GetList.php b/core/src/Revolution/Processors/System/ActiveResource/GetList.php index 9cd3da61d49..564e405e8b1 100644 --- a/core/src/Revolution/Processors/System/ActiveResource/GetList.php +++ b/core/src/Revolution/Processors/System/ActiveResource/GetList.php @@ -11,10 +11,10 @@ namespace MODX\Revolution\Processors\System\ActiveResource; -use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modResource; use MODX\Revolution\modUser; +use MODX\Revolution\Processors\Model\GetListProcessor; use xPDO\Om\xPDOObject; use xPDO\Om\xPDOQuery; @@ -36,6 +36,8 @@ class GetList extends GetListProcessor public $defaultSortField = 'editedon'; public $defaultSortDirection = 'DESC'; + private modManagerDateFormatter $formatter; + /** * @return bool */ @@ -59,7 +61,7 @@ public function getLanguageTopics() public function initialize() { $initialized = parent::initialize(); - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'dateFormat' => '', ]); @@ -106,8 +108,8 @@ public function prepareRow(xPDOObject $object) $customFormat = $this->getProperty('dateFormat'); $editedOn = $object->get('editedon'); $objectArray['editedon'] = !empty($customFormat) - ? $this->formatter->formatManagerDateTime($editedOn, '', false, true, $customFormat) - : $this->formatter->formatManagerDateTime($editedOn) + ? $this->formatter->format($editedOn, $customFormat) + : $this->formatter->formatDateTime($editedOn) ; return $objectArray; diff --git a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php index 0de3d34eac1..d32f6acb58b 100644 --- a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php +++ b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php @@ -11,10 +11,10 @@ namespace MODX\Revolution\Processors\System\Dashboard\Widget; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modChunk; -use MODX\Revolution\Processors\Processor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modX; +use MODX\Revolution\Processors\Processor; use SimplePie_Item; use xPDO\xPDO; @@ -26,9 +26,11 @@ */ class Feed extends Processor { + private modManagerDateFormatter $formatter; + public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return parent::initialize(); } @@ -96,7 +98,7 @@ public function loadFeed($url) 'title' => $item->get_title(), 'description' => $item->get_description(), 'link' => $item->get_permalink(), - 'pubdate' => $this->formatter->formatManagerDateTime($date) + 'pubdate' => $this->formatter->formatDateTime($date) ]); } diff --git a/core/src/Revolution/Processors/System/Log/GetList.php b/core/src/Revolution/Processors/System/Log/GetList.php index 84feec8272e..6558be5951b 100644 --- a/core/src/Revolution/Processors/System/Log/GetList.php +++ b/core/src/Revolution/Processors/System/Log/GetList.php @@ -11,14 +11,13 @@ namespace MODX\Revolution\Processors\System\Log; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modCategory; use MODX\Revolution\modContext; use MODX\Revolution\modContextSetting; use MODX\Revolution\modDocument; -use MODX\Revolution\modMenu; -use MODX\Revolution\Processors\Processor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modManagerLog; +use MODX\Revolution\modMenu; use MODX\Revolution\modResource; use MODX\Revolution\modStaticResource; use MODX\Revolution\modSymLink; @@ -27,6 +26,7 @@ use MODX\Revolution\modUser; use MODX\Revolution\modUserSetting; use MODX\Revolution\modWebLink; +use MODX\Revolution\Processors\Processor; use xPDO\Om\xPDOObject; /** @@ -41,6 +41,8 @@ */ class GetList extends Processor { + private modManagerDateFormatter $formatter; + /** * @return bool */ @@ -54,7 +56,7 @@ public function checkPermissions() */ public function initialize() { - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'limit' => 20, 'start' => 0, @@ -209,8 +211,8 @@ public function prepareLog(modManagerLog $log) } $customFormat = $this->getProperty('dateFormat'); $logArray['occurred'] = !empty($customFormat) - ? $this->formatter->formatManagerDateTime($logArray['occurred'], '', false, true, $customFormat) - : $this->formatter->formatManagerDateTime($logArray['occurred']) + ? $this->formatter->format($logArray['occurred'], $customFormat) + : $this->formatter->formatDateTime($logArray['occurred']) ; return $logArray; diff --git a/core/src/Revolution/Processors/System/Settings/GetList.php b/core/src/Revolution/Processors/System/Settings/GetList.php index df0b7ec833a..d00ba0309dc 100644 --- a/core/src/Revolution/Processors/System/Settings/GetList.php +++ b/core/src/Revolution/Processors/System/Settings/GetList.php @@ -11,10 +11,10 @@ namespace MODX\Revolution\Processors\System\Settings; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modNamespace; -use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\modSystemSetting; +use MODX\Revolution\Processors\Model\GetListProcessor; use xPDO\Om\xPDOObject; use xPDO\Om\xPDOQuery; @@ -35,13 +35,15 @@ class GetList extends GetListProcessor public $permission = 'settings'; public $defaultSortField = 'key'; + private modManagerDateFormatter $formatter; + /** * @return bool */ public function initialize() { $initialized = parent::initialize(); - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'key' => false, 'namespace' => false, @@ -169,8 +171,8 @@ public function prepareRow(xPDOObject $object) $customFormat = $this->getProperty('dateFormat'); $editedOn = $object->get('editedon'); $settingArray['editedon'] = !empty($customFormat) - ? $this->formatter->formatManagerDateTime($editedOn, '', false, true, $customFormat) - : $this->formatter->formatManagerDateTime($editedOn) + ? $this->formatter->format($editedOn, $customFormat) + : $this->formatter->formatDateTime($editedOn) ; return $settingArray; diff --git a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php index 0c130223b5e..39ac2efb410 100644 --- a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php @@ -11,9 +11,9 @@ namespace MODX\Revolution\Processors\Workspace\Lexicon; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modLexiconEntry; use MODX\Revolution\Processors\Processor; -use MODX\Revolution\Utilities\modFormatter; /** * Gets a list of lexicon entries @@ -26,6 +26,8 @@ */ class GetList extends Processor { + private modManagerDateFormatter $formatter; + /** * @return bool */ @@ -66,7 +68,7 @@ public function initialize() if ($this->getProperty('topic') === '') { $this->setProperty('topic', 'default'); } - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return true; } @@ -158,7 +160,7 @@ function parseArray($needle, array $haystack = []) $editedOn = $entryArray['editedon'] ?: $entryArray['createdon'] ; $entryArray['overridden'] = 1; } - $entryArray['editedon'] = $this->formatter->formatManagerDateTime($editedOn); + $entryArray['editedon'] = $this->formatter->formatDateTime($editedOn); $list[] = $entryArray; } diff --git a/core/src/Revolution/Processors/Workspace/Packages/Get.php b/core/src/Revolution/Processors/Workspace/Packages/Get.php index da4c3148202..ec13fd43382 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/Get.php +++ b/core/src/Revolution/Processors/Workspace/Packages/Get.php @@ -11,8 +11,8 @@ namespace MODX\Revolution\Processors\Workspace\Packages; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\Processors\Model\GetProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\Transport\modTransportPackage; use MODX\Revolution\Transport\modTransportProvider; use xPDO\Transport\xPDOTransport; @@ -37,13 +37,15 @@ class Get extends GetProcessor /** @var modTransportPackage $object */ public $object; + private modManagerDateFormatter $formatter; + /** * @return bool */ public function initialize() { $this->modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return parent::initialize(); } @@ -81,13 +83,13 @@ public function getMetadata() */ public function formatDates(array $packageArray) { - $packageArray['created'] = $this->formatter->getFormattedPackageDate($this->object->get('created')); - $packageArray['installed'] = $this->formatter->getFormattedPackageDate( + $packageArray['created'] = $this->formatter->formatPackageDate($this->object->get('created')); + $packageArray['installed'] = $this->formatter->formatPackageDate( $this->object->get('installed'), 'installed', false ); - $packageArray['updated'] = $this->formatter->getFormattedPackageDate( + $packageArray['updated'] = $this->formatter->formatPackageDate( $this->object->get('updated'), 'updated', false diff --git a/core/src/Revolution/Processors/Workspace/Packages/GetList.php b/core/src/Revolution/Processors/Workspace/Packages/GetList.php index c01ab34f047..b0e040a47be 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Packages/GetList.php @@ -11,8 +11,8 @@ namespace MODX\Revolution\Processors\Workspace\Packages; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\Transport\modTransportPackage; use MODX\Revolution\Transport\modTransportProvider; use xPDO\Om\xPDOObject; @@ -44,13 +44,15 @@ class GetList extends GetListProcessor /** @var array $providerCache */ public $providerCache = []; + private modManagerDateFormatter $formatter; + /** * @return bool */ public function initialize() { $this->modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'start' => 0, 'limit' => 10, @@ -143,13 +145,13 @@ public function getVersionInfo(array $packageArray) */ public function formatDates(array $packageArray) { - $packageArray['created'] = $this->formatter->getFormattedPackageDate($packageArray['created']); - $packageArray['installed'] = $this->formatter->getFormattedPackageDate( + $packageArray['created'] = $this->formatter->formatPackageDate($packageArray['created']); + $packageArray['installed'] = $this->formatter->formatPackageDate( $packageArray['installed'], 'installed', false ); - $packageArray['updated'] = $this->formatter->getFormattedPackageDate( + $packageArray['updated'] = $this->formatter->formatPackageDate( $packageArray['updated'], 'updated', false diff --git a/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php b/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php index 00fa665cc2d..b32b184dff6 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php @@ -11,8 +11,8 @@ namespace MODX\Revolution\Processors\Workspace\Packages\Version; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\Processors\Model\GetListProcessor; -use MODX\Revolution\Utilities\modFormatter; use MODX\Revolution\Transport\modTransportPackage; use xPDO\Om\xPDOObject; use xPDO\Transport\xPDOTransport; @@ -30,13 +30,15 @@ class GetList extends GetListProcessor public $permission = 'packages'; public $languageTopics = ['workspace']; + private modManagerDateFormatter $formatter; + /** * @return bool */ public function initialize() { $this->modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); - $this->formatter = new modFormatter($this->modx); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'limit' => 10, 'start' => 0, @@ -115,13 +117,13 @@ public function parseVersion(modTransportPackage $package, array $packageArray) */ public function formatDates(modTransportPackage $package, array $packageArray) { - $packageArray['created'] = $this->formatter->getFormattedPackageDate($package->get('created')); - $packageArray['installed'] = $this->formatter->getFormattedPackageDate( + $packageArray['created'] = $this->formatter->formatPackageDate($package->get('created')); + $packageArray['installed'] = $this->formatter->formatPackageDate( $package->get('installed'), 'installed', false ); - $packageArray['updated'] = $this->formatter->getFormattedPackageDate( + $packageArray['updated'] = $this->formatter->formatPackageDate( $package->get('updated'), 'updated', false diff --git a/core/src/Revolution/modX.php b/core/src/Revolution/modX.php index 2e5476250c1..db899c786de 100644 --- a/core/src/Revolution/modX.php +++ b/core/src/Revolution/modX.php @@ -13,6 +13,7 @@ use Exception; use GuzzleHttp\Client; use GuzzleHttp\Psr7\HttpFactory; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\Services\Container; use MODX\Revolution\Error\modError; use MODX\Revolution\Error\modErrorHandler; @@ -584,6 +585,8 @@ public function initialize($contextKey= 'web', $options = null) { $this->services->add('registry', new modRegistry($this)); $this->registry = $this->services->get('registry'); + $this->services->add(modManagerDateFormatter::class, fn() => new modManagerDateFormatter($this)); + if (!$this->getOption(xPDO::OPT_SETUP)) { $this->invokeEvent( 'OnMODXInit', diff --git a/manager/controllers/default/system/file/edit.class.php b/manager/controllers/default/system/file/edit.class.php index fdb3c6c67c2..60de7d64891 100644 --- a/manager/controllers/default/system/file/edit.class.php +++ b/manager/controllers/default/system/file/edit.class.php @@ -9,11 +9,11 @@ * files found in the top-level directory of this distribution. */ +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modManagerController; use MODX\Revolution\modSystemEvent; use MODX\Revolution\Sources\modFileMediaSource; use MODX\Revolution\Sources\modMediaSource; -use MODX\Revolution\Utilities\modFormatter; /** * Loads the edit file page @@ -106,12 +106,13 @@ public function process(array $scriptProperties = []) return false; } - $formatter = new modFormatter($this->modx); + /** @var modManagerDateFormatter $formatter */ + $formatter = $this->modx->services->get(modManagerDateFormatter::class); if (!empty($this->fileRecord['last_accessed'])) { - $this->fileRecord['last_accessed'] = $formatter->formatManagerDateTime($this->fileRecord['last_accessed']); + $this->fileRecord['last_accessed'] = $formatter->formatDateTime($this->fileRecord['last_accessed']); } if (!empty($this->fileRecord['last_modified'])) { - $this->fileRecord['last_modified'] = $formatter->formatManagerDateTime($this->fileRecord['last_modified']); + $this->fileRecord['last_modified'] = $formatter->formatDateTime($this->fileRecord['last_modified']); } $this->canSave = true; From eedb80fa287ae5eaa050846ef49907fe4590749c Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 24 Sep 2024 09:16:46 -0400 Subject: [PATCH 10/13] Update modManagerDateFormatter.php Add/tweak method documentation; make nullable string more explicit in method signatures --- .../Formatter/modManagerDateFormatter.php | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/core/src/Revolution/Formatter/modManagerDateFormatter.php b/core/src/Revolution/Formatter/modManagerDateFormatter.php index 89459593e71..415226081f3 100644 --- a/core/src/Revolution/Formatter/modManagerDateFormatter.php +++ b/core/src/Revolution/Formatter/modManagerDateFormatter.php @@ -76,6 +76,13 @@ public function isEmpty($value) return in_array($value, $this->managerDateEmptyValues); } + /** + * Calculates the Unix timestamp for a valid date/time-related value, + * applying the system-specified server offset if applicable + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @return int|null The calculated timestamp + */ protected function parseValue($value, bool $useOffset = false): ?int { if ($this->isEmpty($value)) { @@ -105,13 +112,14 @@ protected function parseValue($value, bool $useOffset = false): ?int } /** - * Format DateTime with a custom format - * @param string|int $value The value to transform (must be a unix timestamp or mysql-format string) + * Transforms a date/time-related value using the specified DateTime format + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) * @param string $format The custom format to use when formatting the $value * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty * @return string The formatted date */ - public function format($value, string $format, bool $useOffset = false, string $emptyValue = null): string + public function format($value, string $format, bool $useOffset = false, ?string $emptyValue = null): string { $value = $this->parseValue($value, $useOffset); @@ -122,22 +130,49 @@ public function format($value, string $format, bool $useOffset = false, string $ return date($format, $value); } + /** + * Transforms a date/time-related value according to the DateTime system format used for hidden values + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @return string The formatted date + */ public function formatHidden($value): string { return $this->format($value, $this->managerDateHiddenFormat, false, ''); } - public function formatDate($value, bool $useOffset = false, string $emptyValue = null): string + /** + * Transforms a date/time-related value into the specified date-only DateTime format + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty + * @return string The formatted date + */ + public function formatDate($value, bool $useOffset = false, ?string $emptyValue = null): string { return $this->format($value, $this->managerDateFormat, $useOffset, $emptyValue); } - public function formatTime($value, bool $useOffset = false, string $emptyValue = null): string + /** + * Transforms a date/time-related value into the specified time-only DateTime format + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty + * @return string The formatted date + */ + public function formatTime($value, bool $useOffset = false, ?string $emptyValue = null): string { return $this->format($value, $this->managerTimeFormat, $useOffset, $emptyValue); } - public function formatDateTime($value, bool $useOffset = false, string $emptyValue = null): string + /** + * Transforms a date/time-related value into the specified DateTime format showing + * both date and time, including an optional system-specified separator + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty + * @return string The formatted date + */ + public function formatDateTime($value, bool $useOffset = false, ?string $emptyValue = null): string { $managerDateTimeSeparator = $this->modx->getOption('manager_datetime_separator', null, ', ', true); $format = $this->managerDateFormat . $managerDateTimeSeparator . $this->managerTimeFormat; From 615049454d7d5abfd9e7877230790250932f383e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 24 Sep 2024 09:17:33 -0400 Subject: [PATCH 11/13] Update GetList.php Applies new modManagerDateFormatter to Context settings --- .../Processors/Context/Setting/GetList.php | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/core/src/Revolution/Processors/Context/Setting/GetList.php b/core/src/Revolution/Processors/Context/Setting/GetList.php index dc8e42429f0..b0188677d6e 100644 --- a/core/src/Revolution/Processors/Context/Setting/GetList.php +++ b/core/src/Revolution/Processors/Context/Setting/GetList.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'key' => false, 'namespace' => false, 'area' => false, + 'dateFormat' => '' ]); - $this->dateFormat = $this->modx->getOption('manager_date_format') . ', ' - . $this->modx->getOption('manager_time_format'); - return $initialized; } @@ -110,8 +111,10 @@ public function prepareRow(xPDOObject $object) $k = 'setting_' . $settingArray['key']; /* if 3rd party setting, load proper text, fallback to english */ - $this->modx->lexicon->load('en:' . $object->get('namespace') . ':default', - 'en:' . $object->get('namespace') . ':setting'); + $this->modx->lexicon->load( + 'en:' . $object->get('namespace') . ':default', + 'en:' . $object->get('namespace') . ':setting' + ); $this->modx->lexicon->load($object->get('namespace') . ':default', $object->get('namespace') . ':setting'); /* get translated area text */ @@ -128,8 +131,10 @@ public function prepareRow(xPDOObject $object) $settingArray['description_trans'] = $this->modx->lexicon($k . '_desc'); $settingArray['description'] = $k . '_desc'; } else { - $this->modx->log(modX::LOG_LEVEL_DEBUG, - '[' . __METHOD__ . '] lexicon entry for ' . $k . '_desc not found'); + $this->modx->log( + modX::LOG_LEVEL_DEBUG, + '[' . __METHOD__ . '] lexicon entry for ' . $k . '_desc not found' + ); $settingArray['description_trans'] = !empty($settingArray['description']) ? $settingArray['description'] : ''; } } else { @@ -148,10 +153,12 @@ public function prepareRow(xPDOObject $object) $settingArray['oldkey'] = $settingArray['key']; - $settingArray['editedon'] = in_array( - $object->get('editedon'), - ['-001-11-30 00:00:00', '-1-11-30 00:00:00', '0000-00-00 00:00:00', null] - ) ? '' : date($this->dateFormat, strtotime($object->get('editedon'))); + $customFormat = $this->getProperty('dateFormat'); + $editedOn = $object->get('editedon'); + $settingArray['editedon'] = !empty($customFormat) + ? $this->formatter->format($editedOn, $customFormat) + : $this->formatter->formatDateTime($editedOn) + ; return $settingArray; } From 10a3a37b3d68daad7ed31da03582ccd2c2e9f94e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 1 Oct 2024 20:30:59 -0400 Subject: [PATCH 12/13] Update modManagerDateFormatter.php Make requested changes and add a few more prop/method type declarations --- .../Formatter/modManagerDateFormatter.php | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/core/src/Revolution/Formatter/modManagerDateFormatter.php b/core/src/Revolution/Formatter/modManagerDateFormatter.php index 415226081f3..06c88485f64 100644 --- a/core/src/Revolution/Formatter/modManagerDateFormatter.php +++ b/core/src/Revolution/Formatter/modManagerDateFormatter.php @@ -24,7 +24,7 @@ class modManagerDateFormatter * A reference to the modX object. * @var modX $modx */ - public $modx = null; + protected ?modX $modx = null; // DATE FORMATTER PROPERTIES @@ -60,7 +60,7 @@ class modManagerDateFormatter /** * @var string $managerDateEmptyDisplay The text (if any) to show for empty dates */ - private $managerDateEmptyDisplay = ''; + private string $managerDateEmptyDisplay = ''; public function __construct(modX $modx) @@ -71,7 +71,7 @@ public function __construct(modX $modx) $this->managerDateEmptyDisplay = $this->modx->getOption('manager_datetime_empty_value', null, '–', true); } - public function isEmpty($value) + public function isEmpty($value): bool { return in_array($value, $this->managerDateEmptyValues); } @@ -192,24 +192,23 @@ public function formatDateTime($value, bool $useOffset = false, ?string $emptyVa public function formatResourceDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string { if ($useStandardEmptyValue) { - $emptyValue = null; - } else { - switch ($whichDate) { - case 'edited': - $emptyValue = $this->modx->lexicon('unedited'); - break; - case 'publish': - case 'unpublish': - $emptyValue = $this->modx->lexicon('notset'); - break; - case 'published': - $emptyValue = $this->modx->lexicon('unpublished'); - break; - default: - $emptyValue = $this->modx->lexicon('unknown'); - } - $emptyValue = '(' . $emptyValue . ')'; + return $this->formatDateTime($value, true, null); + } + switch ($whichDate) { + case 'edited': + $emptyValue = $this->modx->lexicon('unedited'); + break; + case 'publish': + case 'unpublish': + $emptyValue = $this->modx->lexicon('notset'); + break; + case 'published': + $emptyValue = $this->modx->lexicon('unpublished'); + break; + default: + $emptyValue = $this->modx->lexicon('unknown'); } + $emptyValue = '(' . $emptyValue . ')'; return $this->formatDateTime($value, true, $emptyValue); } From 3b3a0cc84be3058f6a13a438e8539e71bc75317d Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 1 Oct 2024 20:43:23 -0400 Subject: [PATCH 13/13] Update modManagerDateFormatter.php Implement requested change missed in previous commit --- .../Formatter/modManagerDateFormatter.php | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/core/src/Revolution/Formatter/modManagerDateFormatter.php b/core/src/Revolution/Formatter/modManagerDateFormatter.php index 06c88485f64..b89a0fa421a 100644 --- a/core/src/Revolution/Formatter/modManagerDateFormatter.php +++ b/core/src/Revolution/Formatter/modManagerDateFormatter.php @@ -225,20 +225,19 @@ public function formatResourceDate($value, string $whichDate = 'created', bool $ public function formatPackageDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string { if ($useStandardEmptyValue) { - $emptyValue = null; - } else { - switch ($whichDate) { - case 'installed': - $emptyValue = $this->modx->lexicon('not_installed'); - break; - case 'updated': - $emptyValue = $this->modx->lexicon('not_updated'); - break; - default: - $emptyValue = $this->modx->lexicon('unknown'); - } - $emptyValue = '(' . $emptyValue . ')'; + return $this->formatDateTime($value, true, null); } + switch ($whichDate) { + case 'installed': + $emptyValue = $this->modx->lexicon('not_installed'); + break; + case 'updated': + $emptyValue = $this->modx->lexicon('not_updated'); + break; + default: + $emptyValue = $this->modx->lexicon('unknown'); + } + $emptyValue = '(' . $emptyValue . ')'; return $this->formatDateTime($value, true, $emptyValue); }