$length) { $length -= ($calcEtcLength === true ? mb_strlen($etc) : $calcEtcLength); if (! $breakWords) { $string = preg_replace('/\s+?(\S+)?$/u', '', mb_substr($string, 0, $length + 1)); } return mb_substr($string, 0, $length) . $etc; } return $string; } /** * Инициализация wysiwyg редактора FCKEditor * @param string|null $content редактируемый контент * @param string $fieldName имя поля * @param string|int $width ширина * @param string|int $height высота * @param string $toolbarMode режим панели: average, ... * @param string $theme тема: sd * @param array $opts * @return string HTML */ public static function wysiwyg( ?string $content, string $fieldName, $width = '575px', $height = '300px', string $toolbarMode = 'average', string $theme = 'sd', array $opts = [] ): string { $opts['width'] = $opts['width'] ?? $width; $opts['theme'] = $theme ?? 'sd'; return Wysiwyg::view(Wysiwyg::TYPE_FCK, $content, null, $fieldName, $height, $opts, $toolbarMode); } /** * Инициализация TinyMCE редактора * @param string|null $content редактируемый контент * @param string $fieldName имя поля или "id поля,имя поля" * @param string $height высота редактора (px) или "100%" * @param array $opts * @param array $toolbar параметры TinyMCE * @return string|array */ public static function tinymce( ?string $content, string $fieldName, string $height = '300', array $opts = [], array $toolbar = [] ) { return Wysiwyg::view(Wysiwyg::TYPE_TINYMCE, $content, null, $fieldName, $height, $opts, $toolbar); } /** * Инициализация стандартного Wysiwyg редактора * @param string|null $content редактируемый контент * @param string $fieldName имя поля или "id поля,имя поля" * @param int|string $width ширина число или "100%" (0,false = 100%) * @param int|string $height высота число или "100%" (0,false = 100%) * @param mixed $toolbar параметры инициализации, варианты: FALSE; array(...); '{...}'; * @param string $jsName имя js объекта, для дальнейшего управления компонентом * @param array $opts * @return string */ public static function jwysiwyg( ?string $content, string $fieldName, $width = 575, $height = 300, array $toolbar = [], string $jsName = '', array $opts = [] ): string { $opts['width'] = $opts['width'] ?? $width; $opts['jsName'] = $opts['jsName'] ?? $jsName; return Wysiwyg::view(Wysiwyg::TYPE_DEFAULT, $content, null, $fieldName, $height, $opts, $toolbar); } /** * Формируем объем файла в текстовом виде, например "2 Мегабайта" * @param int $size размер в байтах * @param bool $extendedTitle true - "Мегабайт", false - "МБ" * @param string|null $lang * @return string */ public static function filesize(int $size, bool $extendedTitle = false, ?string $lang = null): string { $units = ($extendedTitle ? explode(',', _t('', 'Byte,Kilobyte,Megabyte,Gigabyte,Terabyte', [], $lang)) : explode(',', _t('', 'B,KB,MB,GB,TB', [], $lang)) ); for ($i = 0; $size > 1024; $i++) { $size /= 1024; } return round($size, 2) . ' ' . ($units[$i] ?? ''); } /** * Форматирование даты * @param mixed $datetime дата: int, string - 0000-00-00[ 00:00:00] * @param bool|array $opts параметры [format, lang, year, today, time, seconds], false => [format => false] * @return string */ public static function date($datetime, $opts = []) { if (empty($datetime)) { return ''; } if (is_string($datetime)) { if ($datetime == '0000-00-00') { return ''; } if ($datetime == '0000-00-00 00:00:00') { return ''; } $datetime = strtotime($datetime); } if (! $datetime) { return ''; } $locale = bff::locale(); if ($opts === false) { $opts = ['format' => false]; } if (! is_array($opts)) { $opts = []; } $opts = array_merge([ 'lang' => $locale->getCurrentLanguage(), 'format' => true, // использовать форматирование (Date Format) или false - полный формат 10 August 2020 (испольнутся параметры 'year' и 'today') 'year' => true, // skipYearIfCurrent опускать год, если текущий 'today' => true, // заменять день на today или yesterday и опускать месяц 'time' => false, // добавлять время 'seconds' => false, // добавлять ко времени секунды ], $opts); $lang = $opts['lang']; $format = $locale->getLanguageSettings($lang, 'date_format', $locale->dateFormatDefault()); if ($opts['format']) { if ($opts['time']) { $format .= ' %H:%M'; if ($opts['seconds']) { $format .= ':%S'; } } return strftime($format, $datetime); } $r = []; $r['d'] = strftime('%e', $datetime); $r['y'] = strftime('%Y', $datetime); $m = (int)strftime('%m', $datetime); if (in_array($lang, ['ru', 'uk'])) { # centos 7 locale Genitive Case fix https://qna.habr.com/q/38587 $r['m'] = $locale->getMonthTitle($m, $lang); } else { $r['m'] = strftime('%B', $datetime); } if ($opts['year']) { if ($r['y'] == strftime('%Y')) { $r['y'] = ''; if ($opts['today']) { if ($m == (int)strftime('%m')) { $d = strftime('%e'); if ($r['d'] == $d) { $r['m'] = ''; $r['d'] = _t('', 'Today', [], $lang); } elseif ($r['d'] == $d - 1) { $r['m'] = ''; $r['d'] = _t('', 'Yesterday', [], $lang); } } } } } $result = []; $order = $locale->getLanguageSettings($lang, 'date_order', 'dmy'); for ($i = 0; $i < 3; $i++) { if (isset($order[$i]) && ! empty($r[ $order[$i] ])) { $result[] = $r[ $order[$i] ]; } } if ($opts['time']) { $format = '%H:%M'; if ($opts['seconds']) { $format .= ':%S'; } $result[] = strftime($format, $datetime); } return join(' ', $result); } /** * Форматирование даты * @deprecated use @see tpl::date() * @param string|int $datetime дата в текстовом формате или unix-вариант * @param string $format требуемый формат @see: strftime * @return bool|string */ public static function dateFormat($datetime, string $format = '%d.%m.%Y'): string { if (empty($datetime)) { return ''; } if (is_string($datetime)) { if ($datetime == '0000-00-00') { return ''; } if ($datetime == '0000-00-00 00:00:00') { return ''; } $datetime = strtotime($datetime); } return strftime($format, $datetime); } /** * Форматируем дату к виду: "1 января 2011[, 11:20]" * @deprecated use @see tpl::date() * @param mixed $datetime дата: int, string - 0000-00-00[ 00:00:00] * @param bool $getTime добавлять время * @param bool $skipYearIfCurrent опускать год, если текущий * @param string $glue1 склейка между названием месяца и годом (если не опускается) * @param string $glue2 склейка между датой и временем (если добавляется) * @param bool $skipYear всегда опускать год * @return string */ public static function date_format2( $datetime, bool $getTime = false, bool $skipYearIfCurrent = false, string $glue1 = ' ', string $glue2 = ', ', bool $skipYear = false ): string { $months = bff::locale()->getMonthTitle(); if (! $datetime) { if (is_string($skipYearIfCurrent)) { return $skipYearIfCurrent; } return false; } if (is_int($datetime)) { $datetime = date('Y-m-j H:i:s', $datetime); } $date = func::parse_datetime($datetime); $formated = intval($date['day']) . ' ' . $months[intval($date['month'])]; # day + month if (! ($skipYear === true || ($skipYearIfCurrent === true && date('Y', time()) == $date['year']))) { $formated .= $glue1 . $date['year']; # year } if ($getTime && ! (!(int)$date['hour'] && !(int)$date['min'])) { $formated .= $glue2 . $date['hour'] . ':' . $date['min']; # hour + min } return $formated; } /** * @param string|int $datetime * @param string|null $format examples 'd.m.Y', 'd.m.Y H:i' * @param string|null $lang * @return string */ public static function date_format3($datetime, ?string $format = null, ?string $lang = null) { if (! $datetime) { return ''; } $date = func::parse_datetime($datetime); if ($format !== null) { return date($format, mktime($date['hour'], $date['min'], 0, $date['month'], $date['day'], $date['year'])); } # get now $now = []; list($now['year'], $now['month'], $now['day']) = explode(',', date('Y,m,d')); # дата позже текущей if ($now['year'] < $date['year']) { return ''; } if ($now['year'] == $date['year'] && $now['month'] == $date['month']) { if ($now['day'] == $date['day']) { return _t('', 'today', [], $lang) . " {$date['hour']}:{$date['min']}"; } elseif ($now['day'] == $date['day'] - 1) { return _t('', 'Yesterday', [], $lang) . " {$date['hour']}:{$date['min']}"; } } return "{$date['day']}.{$date['month']}.{$date['year']} в {$date['hour']}:{$date['min']}"; } /** * Формирование строки с описанием прошедшего времени от даты {$$datetime} * @param string|int $datetime дата * @param bool $getTime добавлять время * @param bool $addBack добавлять слово "назад" * @return string */ public static function date_format_spent($datetime, bool $getTime = false, bool $addBack = true): string { # локализация $lng = [ 's' => explode(';', _t('', 'second;seconds;seconds')), 'min' => explode(';', _t('', 'minute;minutes;minutes')), 'h' => explode(';', _t('', 'hour;hours;hours')), 'd' => explode(';', _t('', 'day;days;days')), 'mon' => explode(';', _t('', 'month;months;months')), 'y' => explode(';', _t('', 'year;years;years')), 'now' => _t('', 'now'), 'today' => _t('', 'today'), 'yesterday' => _t('', 'Yesterday'), 'back' => _t('', 'ago'), ]; # проверяем дату if (!$datetime) { return ''; } $dtFrom = date_create($datetime); $dtTo = date_create(); # дата позже текущей if ($dtFrom > $dtTo) { return ''; } # считаем разницу $interval = date_diff($dtFrom, $dtTo); if ($interval === false) { return ''; } $since = [ 'year' => $interval->y, 'month' => $interval->m, 'day' => $interval->d, 'hour' => $interval->h, 'min' => $interval->i, 'sec' => $interval->s, ]; $text = ''; $allowBack = true; do { # разница в год и более (X лет [X месяцев]) if ($since['year']) { $text .= $since['year'] . ' ' . static::declension($since['year'], $lng['y'], false); if ($since['month']) { $text .= ' ' . $since['month'] . ' ' . static::declension($since['month'], $lng['mon'], false); } break; } # разница в месяц и более (X месяцев [X дней]) if ($since['month']) { $text .= $since['month'] . ' ' . static::declension($since['month'], $lng['mon'], false); if ($since['day']) { $text .= ' ' . $since['day'] . ' ' . static::declension($since['day'], $lng['d'], false); } break; } # разница в день и более (X дней [X часов]) if ($since['day']) { if ($getTime) { $text .= $since['day'] . ' ' . static::declension($since['day'], $lng['d'], false); if ($since['hour'] > 0) { $text .= ' ' . $since['hour'] . ' ' . static::declension($since['hour'], $lng['h'], false); } } else { if ($since['day'] == 1) { $text = $lng['yesterday']; $allowBack = false; } else { $text .= $since['day'] . ' ' . static::declension($since['day'], $lng['d'], false); } } break; } if ($getTime) { # разница в час и более (X часов [X минут]) if ($since['hour']) { $text .= $since['hour'] . ' ' . static::declension($since['hour'], $lng['h'], false); if ($since['min']) { $text .= ' ' . $since['min'] . ' ' . static::declension($since['min'], $lng['min'], false); } break; } # разница более 3 минут (X минут) if ($since['min'] > 3) { $text = $since['min'] . ' ' . static::declension($since['min'], $lng['min'], false); } else { $text = $lng['now']; # сейчас $allowBack = false; } } else { if (intval($dtTo->format('d')) > intval($dtFrom->format('d'))) { $text = $lng['yesterday']; # сегодня } else { $text = $lng['today']; # сегодня } $allowBack = false; } } while (false); return $text . ($addBack && $allowBack ? ' ' . $lng['back'] : ''); } /** * Склонение * @param int $count число * @param array|string $forms варианты * @param bool $addCount добавлять число к результату * @param string $delimeter разделитель вариантов (в случае если $forms строка) * @param string|null $language * @return string */ public static function declension(int $count, $forms, bool $addCount = true, string $delimeter = ';', ?string $language = null): string { $count = abs($count); $forms = (is_string($forms) ? explode($delimeter, $forms) : $forms); if (empty($forms)) { $forms = ['', '', '']; } elseif (sizeof($forms) == 1) { $forms[1] = $forms[2] = $forms[0]; } elseif (sizeof($forms) == 2) { $forms[2] = $forms[1]; } $index = Lang::getLanguagePluralIndex($language ?? Lang::current(), $count); return ($addCount ? $count . ' ' : '') . ($forms[$index] ?? $forms[0]); } /** * Приводим первый символ строки к прописной (заглавной) * @param string $string * @return string */ public static function ucfirst(string $string): string { return mb_strtoupper(mb_substr($string, 0, 1)) . mb_substr($string, 1); } /** * Формирование URL в админ-панели * @deprecated use @see Admin::url() * @param string|null $event название метода * @param string|null $module название модуля * @param string|bool $escape выполнять квотирование, 'html', 'js', false - не выполнять * @return string */ public static function adminLink(?string $event, ?string $module = '', $escape = false): string { if (is_null($event)) { return Url::admin(null); } if (empty($module)) { $module = Route::controllerName(); } return HTML::escape(Url::admin($module) . '&ev=' . $event, $escape); } /** * Помечаем настройки текущей страницы в admin панели * @deprecated use {@see Admin::pageSettings()} * @param array|null $settings [key => value, ...] * @param bool $rewrite * @return array */ public static function adminPageSettings(?array $settings = null, bool $rewrite = true): array { return Admin::pageSettings($settings, $rewrite); } /** * Начало блока буферизации вывода * @return void */ public static function start() { View::start(); } /** * Конец блока буферизации вывода * @return string */ public static function stop(): string { return View::stop(); } /** * Получение значения счетчика * @param mixed $counter * @return string|mixed */ public static function counterValue($counter) { if (is_null($counter)) { return ''; } if (is_numeric($counter)) { return $counter; } if (is_callable($counter) || $counter instanceof Closure) { return call_user_func($counter); } if (is_string($counter)) { return config::get($counter, 0, TYPE_UINT); } if (is_array($counter)) { if (! empty($counter['userCounter'])) { return User::counter($counter['userCounter']); } if (isset($counter['callable'])) { $result = ''; Block::obCallable($result, $counter, function ($callable) { return call_user_func($callable); }); return $result; } } return ''; } }