From 8428191db2eb1e7f1a9adc58d65568a1ae30555f Mon Sep 17 00:00:00 2001 From: "John L. Villalovos" Date: Sun, 18 May 2025 09:36:46 -0700 Subject: [PATCH 1/3] chore: run Rector rule 'php81' on lib/Common/SmartyPage.php Applied rules: * DirNameFileConstantToDirConstantRector * TernaryToNullCoalescingRector * ClassPropertyAssignToConstructorPromotionRector * StrContainsRector * FirstClassCallableRector * NullToStrictStringFuncCallArgRector https://getrector.com/rule-detail/dir-name-file-constant-to-dir-constant-rector https://getrector.com/rule-detail/ternary-to-null-coalescing-rector https://getrector.com/rule-detail/class-property-assign-to-constructor-promotion-rector https://getrector.com/rule-detail/str-contains-rector https://getrector.com/rule-detail/first-class-callable-rector https://getrector.com/rule-detail/null-to-strict-string-func-call-arg-rector --- lib/Common/SmartyPage.php | 194 ++++++++++++++++++-------------------- 1 file changed, 94 insertions(+), 100 deletions(-) diff --git a/lib/Common/SmartyPage.php b/lib/Common/SmartyPage.php index e4e7cdbc8..950fa086e 100644 --- a/lib/Common/SmartyPage.php +++ b/lib/Common/SmartyPage.php @@ -22,11 +22,6 @@ class SmartyPage extends Smarty */ protected $Resources = null; - /** - * @var null|string - */ - protected $RootPath = null; - /** * @var bool */ @@ -35,13 +30,13 @@ class SmartyPage extends Smarty /** * * @param Resources $resources - * @param string $rootPath + * @param string $RootPath */ - public function __construct(Resources &$resources = null, $rootPath = null) + public function __construct(Resources &$resources = null, protected $RootPath = null) { parent::__construct(); - $base = dirname(__FILE__) . '/../../'; + $base = __DIR__ . '/../../'; $this->debugging = isset($_GET['debug']); $this->AddTemplateDirectory($base . 'tpl'); @@ -63,7 +58,6 @@ public function __construct(Resources &$resources = null, $rootPath = null) } $this->Resources = &$resources; - $this->RootPath = $rootPath; $this->AddTemplateDirectory($base . 'lang/' . $this->Resources->CurrentLanguage); @@ -122,53 +116,53 @@ public function FetchLocalized($templateName, bool $enforceCustomTemplate, strin protected function RegisterFunctions() { - $this->registerPlugin('function', 'translate', [$this, 'SmartyTranslate']); - $this->registerPlugin('function', 'formatdate', [$this, 'FormatDate']); - $this->registerPlugin('function', 'format_date', [$this, 'FormatDate']); - $this->registerPlugin('function', 'html_link', [$this, 'PrintLink']); - $this->registerPlugin('function', 'html_image', [$this, 'PrintImage']); - $this->registerPlugin('function', 'control', [$this, 'DisplayControl']); - $this->registerPlugin('function', 'validator', [$this, 'Validator']); - $this->registerPlugin('function', 'textbox', [$this, 'Textbox']); - $this->registerPlugin('function', 'object_html_options', [$this, 'ObjectHtmlOptions']); - $this->registerPlugin('block', 'validation_group', [$this, 'ValidationGroup']); - $this->registerPlugin('function', 'setfocus', [$this, 'SetFocus']); - $this->registerPlugin('function', 'formname', [$this, 'GetFormName']); - $this->registerPlugin('modifier', 'url2link', [$this, 'CreateUrl']); - $this->registerPlugin('function', 'pagelink', [$this, 'CreatePageLink']); - $this->registerPlugin('function', 'pagination', [$this, 'CreatePagination']); - $this->registerPlugin('function', 'js_array', [$this, 'CreateJavascriptArray']); - $this->registerPlugin('function', 'async_validator', [$this, 'AsyncValidator']); - $this->registerPlugin('function', 'fullname', [$this, 'DisplayFullName']); - $this->registerPlugin('function', 'add_querystring', [$this, 'AddQueryString']); - $this->registerPlugin('function', 'resource_image', [$this, 'GetResourceImage']); - $this->registerPlugin('modifier', 'escapequotes', [$this, 'EscapeQuotes']); - $this->registerPlugin('function', 'flush', [$this, 'Flush']); - $this->registerPlugin('function', 'jsfile', [$this, 'IncludeJavascriptFile']); - $this->registerPlugin('function', 'cssfile', [$this, 'IncludeCssFile']); - $this->registerPlugin('function', 'indicator', [$this, 'DisplayIndicator']); - $this->registerPlugin('function', 'read_only_attribute', [$this, 'ReadOnlyAttribute']); - $this->registerPlugin('function', 'csrf_token', [$this, 'CSRFToken']); - $this->registerPlugin('function', 'cancel_button', [$this, 'CancelButton']); - $this->registerPlugin('function', 'update_button', [$this, 'UpdateButton']); - $this->registerPlugin('function', 'add_button', [$this, 'AddButton']); - $this->registerPlugin('function', 'delete_button', [$this, 'DeleteButton']); - $this->registerPlugin('function', 'reset_button', [$this, 'ResetButton']); - $this->registerPlugin('function', 'filter_button', [$this, 'FilterButton']); - $this->registerPlugin('function', 'ok_button', [$this, 'OkButton']); - $this->registerPlugin('function', 'showhide_icon', [$this, 'ShowHideIcon']); - $this->registerPlugin('function', 'sort_column', [$this, 'SortColumn']); - $this->registerPlugin('function', 'formatcurrency', [$this, 'FormatCurrency']); - $this->registerPlugin('function', 'linebreak', [$this, 'LineBreak']); - $this->registerPlugin('modifier', 'urlencode', [$this, 'UrlEncode']); - $this->registerPlugin('modifier', 'explode', [$this, 'Explode']); - $this->registerPlugin('modifier', 'html_entity_decode', [$this, 'HtmlEntityDecode']); - $this->registerPlugin('modifier', 'implode', [$this, 'Implode']); - $this->registerPlugin('modifier', 'join', [$this, 'Join']); - $this->registerPlugin('modifier', 'intval', [$this, 'Intval']); - $this->registerPlugin('modifier', 'strtolower', [$this, 'Strtolower']); - $this->registerPlugin('function', 'datatable', [$this, 'CreateDataTable']); - $this->registerPlugin('function', 'datatablefilter', [$this, 'CreateDataTableFilter']); + $this->registerPlugin('function', 'translate', $this->SmartyTranslate(...)); + $this->registerPlugin('function', 'formatdate', $this->FormatDate(...)); + $this->registerPlugin('function', 'format_date', $this->FormatDate(...)); + $this->registerPlugin('function', 'html_link', $this->PrintLink(...)); + $this->registerPlugin('function', 'html_image', $this->PrintImage(...)); + $this->registerPlugin('function', 'control', $this->DisplayControl(...)); + $this->registerPlugin('function', 'validator', $this->Validator(...)); + $this->registerPlugin('function', 'textbox', $this->Textbox(...)); + $this->registerPlugin('function', 'object_html_options', $this->ObjectHtmlOptions(...)); + $this->registerPlugin('block', 'validation_group', $this->ValidationGroup(...)); + $this->registerPlugin('function', 'setfocus', $this->SetFocus(...)); + $this->registerPlugin('function', 'formname', $this->GetFormName(...)); + $this->registerPlugin('modifier', 'url2link', $this->CreateUrl(...)); + $this->registerPlugin('function', 'pagelink', $this->CreatePageLink(...)); + $this->registerPlugin('function', 'pagination', $this->CreatePagination(...)); + $this->registerPlugin('function', 'js_array', $this->CreateJavascriptArray(...)); + $this->registerPlugin('function', 'async_validator', $this->AsyncValidator(...)); + $this->registerPlugin('function', 'fullname', $this->DisplayFullName(...)); + $this->registerPlugin('function', 'add_querystring', $this->AddQueryString(...)); + $this->registerPlugin('function', 'resource_image', $this->GetResourceImage(...)); + $this->registerPlugin('modifier', 'escapequotes', $this->EscapeQuotes(...)); + $this->registerPlugin('function', 'flush', $this->Flush(...)); + $this->registerPlugin('function', 'jsfile', $this->IncludeJavascriptFile(...)); + $this->registerPlugin('function', 'cssfile', $this->IncludeCssFile(...)); + $this->registerPlugin('function', 'indicator', $this->DisplayIndicator(...)); + $this->registerPlugin('function', 'read_only_attribute', $this->ReadOnlyAttribute(...)); + $this->registerPlugin('function', 'csrf_token', $this->CSRFToken(...)); + $this->registerPlugin('function', 'cancel_button', $this->CancelButton(...)); + $this->registerPlugin('function', 'update_button', $this->UpdateButton(...)); + $this->registerPlugin('function', 'add_button', $this->AddButton(...)); + $this->registerPlugin('function', 'delete_button', $this->DeleteButton(...)); + $this->registerPlugin('function', 'reset_button', $this->ResetButton(...)); + $this->registerPlugin('function', 'filter_button', $this->FilterButton(...)); + $this->registerPlugin('function', 'ok_button', $this->OkButton(...)); + $this->registerPlugin('function', 'showhide_icon', $this->ShowHideIcon(...)); + $this->registerPlugin('function', 'sort_column', $this->SortColumn(...)); + $this->registerPlugin('function', 'formatcurrency', $this->FormatCurrency(...)); + $this->registerPlugin('function', 'linebreak', $this->LineBreak(...)); + $this->registerPlugin('modifier', 'urlencode', $this->UrlEncode(...)); + $this->registerPlugin('modifier', 'explode', $this->Explode(...)); + $this->registerPlugin('modifier', 'html_entity_decode', $this->HtmlEntityDecode(...)); + $this->registerPlugin('modifier', 'implode', $this->Implode(...)); + $this->registerPlugin('modifier', 'join', $this->Join(...)); + $this->registerPlugin('modifier', 'intval', $this->Intval(...)); + $this->registerPlugin('modifier', 'strtolower', $this->Strtolower(...)); + $this->registerPlugin('function', 'datatable', $this->CreateDataTable(...)); + $this->registerPlugin('function', 'datatablefilter', $this->CreateDataTableFilter(...)); /** * PageValidators @@ -271,7 +265,7 @@ public function FormatDate($params, $smarty) $formatted = $date->Format($format); - if (strpos($format, 'l') !== false) { + if (str_contains((string) $format, 'l')) { // correct english day name to translated day name $english_days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; $days = $this->Resources->GetDays('full'); @@ -282,10 +276,10 @@ public function FormatDate($params, $smarty) public function PrintImage($params, $smarty) { - $alt = isset($params['alt']) ? $params['alt'] : ''; - $altKey = isset($params['altKey']) ? $params['altKey'] : ''; - $width = isset($params['width']) ? $params['width'] : ''; - $height = isset($params['height']) ? $params['height'] : ''; + $alt = $params['alt'] ?? ''; + $altKey = $params['altKey'] ?? ''; + $width = $params['width'] ?? ''; + $height = $params['height'] ?? ''; $imgPath = sprintf('%simg/%s', $this->RootPath, $params['src']); $knownAttributes = ['alt', 'width', 'height', 'src', 'title', 'altKey']; @@ -324,7 +318,7 @@ public function ValidationGroup($params, $content, $smarty, &$repeat) } if (!$repeat) { - $actualContent = trim($content); + $actualContent = trim((string) $content); return empty($actualContent) ? '' : '
@@ -431,9 +425,9 @@ public function ObjectHtmlOptions($params, $smarty) $key = $params['key']; $label = $params['label']; $options = $params['options']; - $type = isset($params['type']) ? $params['type'] : 'array'; - $usemethod = isset($params['usemethod']) ? $params['usemethod'] : true; - $selected = isset($params['selected']) ? $params['selected'] : ''; + $type = $params['type'] ?? 'array'; + $usemethod = $params['usemethod'] ?? true; + $selected = $params['selected'] ?? ''; $builder = new StringBuilder(); foreach ($options as $option) { @@ -479,9 +473,9 @@ public function CreateUrl($url) return $matches[0]; } // removed trailing [.,;:] from URL - if (in_array(substr($url, -1), ['.', ',', ';', ':']) === true) { - $ret = substr($url, -1); - $url = substr($url, 0, strlen($url) - 1); + if (in_array(substr((string) $url, -1), ['.', ',', ';', ':']) === true) { + $ret = substr((string) $url, -1); + $url = substr((string) $url, 0, strlen((string) $url) - 1); } $text = $url; @@ -528,15 +522,15 @@ public function CreateUrl($url) $url = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]*)#is', $make_web_ftp_clickable_cb, - $url + (string) $url ); $url = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', $make_email_clickable_cb, - $url + (string) $url ); - $url = preg_replace("#(]+?>|>))]+?>([^>]+?)#i", "$1$3", $url); - $url = trim($url); + $url = preg_replace("#(]+?>|>))]+?>([^>]+?)#i", "$1$3", (string) $url); + $url = trim((string) $url); return $url; } @@ -618,7 +612,7 @@ public function CreatePageLink($params, $smarty) $page = $params['page']; $pageSize = $params['size']; $iscurrent = $params['iscurrent']; - $text = isset($params['text']) ? $params['text'] : $page; + $text = $params['text'] ?? $page; $newUrl = $this->ReplaceQueryString($url, QueryStringKeys::PAGE, $page); $newUrl = $this->ReplaceQueryString($newUrl, QueryStringKeys::PAGE_SIZE, $pageSize); @@ -742,8 +736,8 @@ public function ReplaceQueryString($url, $key, $value) { $newUrl = $url; - if (strpos($url, $key) === false) { // does not have variable - if (strpos($url, '?') === false) { // and does not have any query string + if (!str_contains((string) $url, (string) $key)) { // does not have variable + if (!str_contains((string) $url, '?')) { // and does not have any query string $newUrl = sprintf('%s?%s=%s', $url, $key, $value); } else { $newUrl = sprintf('%s&%s=%s', $url, $key, $value); // and has existing query string @@ -752,7 +746,7 @@ public function ReplaceQueryString($url, $key, $value) $pattern = '/(\?|&)(' . $key . '=.*)/'; $replace = '${1}' . $key . '=' . $value; - $newUrl = preg_replace($pattern, $replace, $url); + $newUrl = preg_replace($pattern, $replace, (string) $url); } return $newUrl; @@ -803,7 +797,7 @@ public function GetResourceImage($params, $smarty) { $imageUrl = Configuration::Instance()->GetKey(ConfigKeys::IMAGE_UPLOAD_URL); - if (strpos($imageUrl, 'http://') === false) { + if (!str_contains((string) $imageUrl, 'http://')) { $imageUrl = Configuration::Instance()->GetScriptUrl() . "/$imageUrl"; } @@ -841,10 +835,10 @@ public function IncludeCssFile($params, $smarty) public function DisplayIndicator($params, $smarty) { - $id = isset($params['id']) ? $params['id'] : ''; + $id = $params['id'] ?? ''; $size = isset($params['size']) ? "spinner-border-{$params['size']}" : 'spinner-border-sm'; $show = isset($params['show']) ? '' : 'd-none'; - $class = isset($params['class']) ? $params['class'] : 'indicator'; + $class = $params['class'] ?? 'indicator'; echo ""; } @@ -878,15 +872,15 @@ private function GetButtonAttributes($params) public function CancelButton($params, $smarty) { - $key = isset($params['key']) ? $params['key'] : 'Cancel'; - $class = isset($params['class']) ? $params['class'] : ''; + $key = $params['key'] ?? 'Cancel'; + $class = $params['class'] ?? ''; echo ''; } public function UpdateButton($params, $smarty) { - $key = isset($params['key']) ? $params['key'] : 'Update'; + $key = $params['key'] ?? 'Update'; $class = isset($params['class']) ? ' ' . $params['class'] . ' ' : ''; $type = isset($params['submit']) ? 'submit' : 'button'; $save = $type == 'submit' ? '' : ' save '; @@ -897,9 +891,9 @@ public function UpdateButton($params, $smarty) public function AddButton($params, $smarty) { - $key = isset($params['key']) ? $params['key'] : 'Add'; - $class = isset($params['class']) ? $params['class'] : ''; - $submit = isset($params['submit']) ? $params['submit'] : false; + $key = $params['key'] ?? 'Add'; + $class = $params['class'] ?? ''; + $submit = $params['submit'] ?? false; $type = 'button'; if ($submit) { $type = 'submit'; @@ -911,9 +905,9 @@ public function AddButton($params, $smarty) public function DeleteButton($params, $smarty) { - $key = isset($params['key']) ? $params['key'] : 'Delete'; - $class = isset($params['class']) ? $params['class'] : ''; - $submit = isset($params['submit']) ? $params['submit'] : false; + $key = $params['key'] ?? 'Delete'; + $class = $params['class'] ?? ''; + $submit = $params['submit'] ?? false; $type = 'button'; if ($submit) { $type = 'submit'; @@ -924,31 +918,31 @@ public function DeleteButton($params, $smarty) public function ResetButton($params, $smarty) { - $key = isset($params['key']) ? $params['key'] : 'Reset'; - $class = isset($params['class']) ? $params['class'] : ''; + $key = $params['key'] ?? 'Reset'; + $class = $params['class'] ?? ''; echo ''; } public function FilterButton($params, $smarty) { - $key = isset($params['key']) ? $params['key'] : 'Filter'; - $class = isset($params['class']) ? $params['class'] : ''; + $key = $params['key'] ?? 'Filter'; + $class = $params['class'] ?? ''; echo ''; } public function OkButton($params, $smarty) { - $key = isset($params['key']) ? $params['key'] : 'OK'; - $class = isset($params['class']) ? $params['class'] : ''; + $key = $params['key'] ?? 'OK'; + $class = $params['class'] ?? ''; echo ''; } public function ShowHideIcon($params, $smarty) { - $class = isset($params['class']) ? $params['class'] : ''; + $class = $params['class'] ?? ''; echo 'Show/Hide'; } @@ -976,7 +970,7 @@ public function SortColumn($params, $smarty) } if (BookedStringHelper::Contains($url, $sd)) { - $url = preg_replace("/$sd=(asc|desc)&?/", "$sd=$sortDirection&", $url); + $url = preg_replace("/$sd=(asc|desc)&?/", "$sd=$sortDirection&", (string) $url); } else { $url = $url . ($hasQueryString ? "&" : "?") . "$sd=$sortDirection"; } @@ -1014,12 +1008,12 @@ public function LineBreak($params, $smarty) public function UrlEncode($url) { - return urlencode($url); + return urlencode((string) $url); } public function Explode($separator, $string) { - return explode($separator, $string); + return explode($separator, (string) $string); } public function Implode($separator, $array) @@ -1029,7 +1023,7 @@ public function Implode($separator, $array) public function HtmlEntityDecode($string) { - return html_entity_decode($string); + return html_entity_decode((string) $string); } public function Join($sep, $array) @@ -1044,6 +1038,6 @@ public function Intval($string) public function Strtolower($string) { - return strtolower($string); + return strtolower((string) $string); } } From 1792b02847fbf24a40ed8830f989aece869fe41d Mon Sep 17 00:00:00 2001 From: "John L. Villalovos" Date: Sun, 18 May 2025 11:02:03 -0700 Subject: [PATCH 2/3] fix: Smarty deprecation issues for static methods There were deprecation errors about: "Using unregistered static method" This fixes it for classes. There are more deprecation issues about functions that need to be resolved. Closes: #363 #326 --- lib/Common/SmartyPage.php | 78 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/lib/Common/SmartyPage.php b/lib/Common/SmartyPage.php index 950fa086e..c76b17e14 100644 --- a/lib/Common/SmartyPage.php +++ b/lib/Common/SmartyPage.php @@ -62,6 +62,7 @@ public function __construct(Resources &$resources = null, protected $RootPath = $this->AddTemplateDirectory($base . 'lang/' . $this->Resources->CurrentLanguage); $this->RegisterFunctions(); + $this->RegisterClasses(); } public function AddTemplateDirectory($templateDirectory) @@ -87,7 +88,7 @@ public function FetchLocalized($templateName, bool $enforceCustomTemplate, strin $localizedPath = $langPath . $languageCode; $customTemplateName = str_replace('.tpl', '-custom.tpl', $templateName); $hasCustomTemplate = file_exists($localizedPath . '/' . $customTemplateName); - + if ($enforceCustomTemplate && !$hasCustomTemplate) { $defaultLanguageCode = Configuration::Instance()->GetKey(ConfigKeys::LANGUAGE); $defaultLocalizedPath = $langPath . $defaultLanguageCode; @@ -114,6 +115,73 @@ public function FetchLocalized($templateName, bool $enforceCustomTemplate, strin return $this->fetch($templateName); } + protected function RegisterClasses() + { + // Classes that should be registered + $classesToRegister = [ + 'Actions', + 'AutoCompleteType', + 'CalendarActions', + 'CalendarTypes', + 'CannedReport', + 'ColumnNames', + 'ConfigActions', + 'ConfigKeys', + 'ConfigSettingType', + 'CookieKeys', + 'CustomAttributeCategory', + 'CustomAttributeTypes', + 'Date', + 'DayOfWeek', + 'EmailTemplatesActions', + 'FormKeys', + 'InvitationAction', + 'ManageAccessoriesActions', + 'ManageAnnouncementsActions', + 'ManageAttributesActions', + 'ManageBlackoutsActions', + 'ManageGroupsActions', + 'ManageQuotasActions', + 'ManageReservationsActions', + 'ManageResourcesActions', + 'ManageSchedules', + 'ManageUsersActions', + 'Pages', + 'ProfileActions', + 'QueryStringKeys', + 'QuotaDuration', + 'QuotaScope', + 'QuotaUnit', + 'RepeatMonthlyType', + 'ReportActions', + 'Report_GroupBy', + 'Report_Range', + 'Report_ResultSelection', + 'Report_Usage', + 'ReservationAction', + 'ReservationConflictResolution', + 'ReservationEvent', + 'ReservationStatus', + 'ResourceStatus', + 'Schedule', + 'ScheduleLayout', + 'ScheduleStyle', + 'SeriesUpdateScope', + 'TermsOfService', + + ]; + + foreach ($classesToRegister as $className) { + try { + if (class_exists($className)) { + $this->registerClass($className, $className); + } + } catch (Exception $ex) { + error_log("Error registering $className : " . $ex->getMessage()); + } + } + } + protected function RegisterFunctions() { $this->registerPlugin('function', 'translate', $this->SmartyTranslate(...)); @@ -659,14 +727,14 @@ public function CreateDataTable($params) lengthMenu: "' . $lengthMenuText . '", zeroRecords: "' . $NoResultsFoundText . '", }, - "buttons": [ + "buttons": [ { extend: "copyHtml5", - text: "
' . $copyText . '
", + text: "
' . $copyText . '
", }, { extend: "excelHtml5", - text: "
' . $exportText . ' Excel
", + text: "
' . $exportText . ' Excel
", }, { extend: "pdfHtml5", @@ -678,7 +746,7 @@ public function CreateDataTable($params) }, { extend: "colvis", - text: "
' . $showHideText . '
", + text: "
' . $showHideText . '
", } ], "initComplete": function(settings, json) { From 28f68e2e37b96fe143be9e2107bce3462cb940ee Mon Sep 17 00:00:00 2001 From: "John L. Villalovos" Date: Sun, 18 May 2025 11:43:38 -0700 Subject: [PATCH 3/3] chore(smarty): register some additional modifiers Register some additional modifiers in Smarty. The following modifiers are now registered: * count * array_key_exists * microtime This resolves deprecation issues that were being seen. Closes: #471 --- lib/Common/SmartyPage.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/Common/SmartyPage.php b/lib/Common/SmartyPage.php index c76b17e14..55249b9fe 100644 --- a/lib/Common/SmartyPage.php +++ b/lib/Common/SmartyPage.php @@ -231,6 +231,9 @@ protected function RegisterFunctions() $this->registerPlugin('modifier', 'strtolower', $this->Strtolower(...)); $this->registerPlugin('function', 'datatable', $this->CreateDataTable(...)); $this->registerPlugin('function', 'datatablefilter', $this->CreateDataTableFilter(...)); + $this->registerPlugin('modifier', 'microtime', $this->Microtime(...)); + $this->registerPlugin('modifier', 'array_key_exists', $this->ArrayKeyExists(...)); + $this->registerPlugin('modifier', 'count', $this->Count(...)); /** * PageValidators @@ -1079,6 +1082,18 @@ public function UrlEncode($url) return urlencode((string) $url); } + public function Microtime(bool $as_float = false): string|float { + return microtime($as_float); + } + + public function ArrayKeyExists(string|int|float|bool|null $key, array $array): bool { + return array_key_exists($key, $array); + } + + public function Count(Countable|array $value, int $mode = COUNT_NORMAL): int { + return count($value, $mode); + } + public function Explode($separator, $string) { return explode($separator, (string) $string);