Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Language.php
<?php

namespace XF;

use
XF\Db\AbstractAdapter;

use function
array_key_exists, count, floatval, is_array, is_null;

class
Language implements \ArrayAccess
{
    protected
$id;
    protected
$options = [
       
'title' => '',
       
'language_code' => '',
       
'date_format' => 'M j, Y',
       
'time_format' => 'g:i A',
       
'currency_format' => '{symbol}{value}',
       
'decimal_point' => '.',
       
'thousands_separator' => ',',
       
'text_direction' => 'LTR',
       
'week_start' => 0,
       
'label_separator' => ':',
       
'comma_separator' => ', ',
       
'ellipsis' => '...',
       
'parenthesis_open' => '(',
       
'parenthesis_close' => ')',
       
'user_selectable' => true
   
];

    protected static
$modifierMap = [
       
':' => 'label_separator',
       
',' => 'comma_separator',
       
'...' => 'ellipsis',
       
'(' => 'parenthesis_open',
       
')' => 'parenthesis_close'
   
];

   
/**
     * @var Db\AbstractAdapter
     */
   
protected $db;

    protected
$groupPath;

   
/**
     * @var array
     */
   
protected $phraseCache = [];
    protected
$phrasesToLoad = [];
    protected
$groupsCached = [];

   
/**
     * @var \DateTime
     */
   
protected $date;

    protected
$dayStartTimestamps = null;

   
/**
     * Translate a numeric day of the week to representation that will be used in phrases.
     *
     * @var array
     */
   
protected $dowTranslation = [
       
0 => 'sunday',
       
1 => 'monday',
       
2 => 'tuesday',
       
3 => 'wednesday',
       
4 => 'thursday',
       
5 => 'friday',
       
6 => 'saturday'
   
];

    public function
__construct($id, array $options, AbstractAdapter $db, $groupPath, array $phrases = null)
    {
        if (isset(
$options['phrase_cache']))
        {
           
$cache = $options['phrase_cache'];
            if (
is_array($cache) && $phrases === null)
            {
               
$phrases = $cache;
            }
            unset(
$options['phrase_cache']);
        }

       
$this->id = $id;
       
$this->options = array_merge($this->options, $options);
       
$this->options['language_code'] = $this->getLanguageCode();

       
$this->db = $db;
       
$this->groupPath = $groupPath;

        if (
is_array($phrases))
        {
           
$this->phraseCache = $phrases;
        }

       
$this->date = new \DateTime('now', new \DateTimeZone('UTC'));
    }

    public function
getId()
    {
        return
$this->id;
    }

    public function
phrase($name, array $params = [], $preLoad = true, $allowHtml = true)
    {
       
$effectiveName = $this->getEffectivePhraseName($name);

        if (
$preLoad
           
&& !isset($this->phraseCache[$effectiveName])
            && !isset(
$this->phrasesToLoad[$effectiveName])
            &&
strpos($effectiveName, '.') === false
       
)
        {
           
$this->phrasesToLoad[$effectiveName] = true;
        }

        return new
Phrase($this, $name, $params, $allowHtml);
    }

    public function
renderPhrase($name, array $params = [], $context = 'html', array $options = [])
    {
       
$options = array_replace([
           
'fallback' => null,
           
'fallbackRaw' => false,
           
'nameOnInvalid' => true
       
], $options);

       
$name = $this->getEffectivePhraseName($name, $prefixes, $suffixes);

       
$text = $this->getPhraseText($name);
        if (
$text === false)
        {
           
// phrase not found
           
if ($options['fallback'] !== null)
            {
                if (
$options['fallbackRaw'])
                {
                   
$text = $options['fallback'];
                }
                else
                {
                   
$text = \XF::escapeString($options['fallback'], $context);
                }
            }
            else if (
$options['nameOnInvalid'])
            {
               
$text = \XF::escapeString($name, $context);
            }
            else
            {
               
// if not returning anything, don't apply any prefixes/suffixes
               
return '';
            }
        }
        else if (
$params)
        {
           
$text = preg_replace_callback('/\{([a-z0-9_-]+)\}/i', function(array $match) use ($params, $context)
            {
               
$paramName = $match[1];

                if (!
array_key_exists($paramName, $params))
                {
                    return
$match[0];
                }

               
$param = $params[$paramName];
                if (
$param instanceof Phrase)
                {
                    return
$param->render($context);
                }
                else
                {
                    return \
XF::escapeString($param, $context);
                }
            },
$text);
        }

        if (
$prefixes)
        {
           
$text = implode('', $prefixes) . $text;
        }
        if (
$suffixes)
        {
           
// we process these right to left so invert them
           
$suffixes = array_reverse($suffixes);
           
$text .= implode('', $suffixes);
        }

        return
$text;
    }

    protected function
getEffectivePhraseName(string $name, &$prefixes = [], &$suffixes = []): string
   
{
       
// Process phrase name prefixes/suffixes.
        // Note that there is very similar code in XF\Template\Compiler\Func\Phrase. It should correspond.
       
$prefixes = [];
       
$suffixes = [];

        if (
$name[0] == '(')
        {
           
$prefixes[] = $this->options['parenthesis_open'];
           
$name = substr($name, 1);
        }

        do
        {
           
$matchedSuffix = false;

            if (
substr($name, -3) == '...')
            {
               
$suffixes[] = $this->options['ellipsis'];
               
$name = substr($name, 0, -3);
               
$matchedSuffix = true;
            }
            else
            {
               
$lastChar = substr($name, -1);
                switch (
$lastChar)
                {
                    case
':':
                    case
',':
                    case
')':
                    case
'(':
                        if (isset(
self::$modifierMap[$lastChar]))
                        {
                           
$suffixes[] = $this->options[self::$modifierMap[$lastChar]];
                        }
                       
$matchedSuffix = true;
                       
$name = substr($name, 0, -1);
                        break;
                }
            }
        }
        while (
$matchedSuffix);

        return
$name;
    }

    public function
getPhraseText($name)
    {
        if (isset(
$this->phraseCache[$name]))
        {
            return
$this->phraseCache[$name];
        }

       
$parts = explode('.', $name, 2);
        if (isset(
$parts[1]) && $this->loadPhraseGroup($parts[0]))
        {
           
// group has been cached so everything should be in it - if it's not, it's invalid
           
if (!isset($this->phraseCache[$name]))
            {
               
$this->phraseCache[$name] = false;
            }

            return
$this->phraseCache[$name];
        }

       
$this->phrasesToLoad[$name] = true;
       
$this->loadPhrases();

        if (!isset(
$this->phraseCache[$name]))
        {
           
$this->phraseCache[$name] = false;
        }

        return
$this->phraseCache[$name];
    }

    protected function
loadPhraseGroup($group)
    {
        if (isset(
$this->groupsCached[$group]))
        {
            return
$this->groupsCached[$group];
        }

        if (
preg_match('/[^a-z0-9_]/i', $group))
        {
            throw new \
InvalidArgumentException("Phrase group $group is not a valid format");
        }

       
$file = $this->groupPath . "/l$this->id/$group.php";

        try
        {
           
$phrases = @include($file);
        }
        catch (\
Throwable $e)
        {
           
$phrases = false;
        }

        if (
is_array($phrases))
        {
           
$this->phraseCache = array_merge($this->phraseCache, $phrases);
           
$this->groupsCached[$group] = true;
        }
        else
        {
           
$this->groupsCached[$group] = false;
        }

        return
$this->groupsCached[$group];
    }

    protected function
getPhraseCacheRaw($name)
    {
        if (isset(
$this->phraseCache[$name]))
        {
            return
$this->phraseCache[$name];
        }
        else
        {
            return
$name;
        }
    }

    public function
cachePhrase($name, $value)
    {
       
$this->phraseCache[$name] = $value;
    }

    public function
cachePhrases(array $phrases)
    {
       
$this->phraseCache = array_merge($this->phraseCache, $phrases);
    }

    public function
uncachePhrase($name)
    {
        if (
strpos($name, '.') === false)
        {
            unset(
$this->phraseCache[$name]);
        }
    }

    public function
isGroupCached($group)
    {
        return isset(
$this->groupsCached[$group]);
    }

    public function
uncacheGroup($group)
    {
        unset(
$this->groupsCached[$group]);
    }

    public function
requirePhrases(array $phrases)
    {
        foreach (
$phrases AS $name)
        {
            if (!isset(
$this->phraseCache[$name])
                && !isset(
$this->phrasesToLoad[$name])
                &&
strpos($name, '.') === false
           
)
            {
               
$this->phrasesToLoad[$name] = true;
            }
        }
    }

    protected function
loadPhrases()
    {
        if (!
$this->phrasesToLoad)
        {
            return;
        }

       
$phrases = $this->db->fetchPairs("
            SELECT title, phrase_text
            FROM xf_phrase_compiled
            WHERE language_id = ?
                AND title IN ("
. $this->db->quote(array_keys($this->phrasesToLoad)) . ")
        "
, $this->id);

        foreach (
$phrases AS $title => $text)
        {
           
$this->phraseCache[$title] = $text;
        }

       
$this->phrasesToLoad = [];
    }

    public function
getTitle()
    {
        return
$this->options['title'];
    }

    public function
getLanguageCode()
    {
        return
$this->options['language_code'];
    }

    public function
getTextDirection()
    {
        return
$this->options['text_direction'];
    }

    public function
isRtl()
    {
        return (
$this->options['text_direction'] == 'RTL');
    }

    public function
isUsable(\XF\Entity\User $user)
    {
        if (
$this->options['user_selectable'])
        {
            return
true;
        }

        return
$user->is_admin ? true : false;
    }

   
#[\ReturnTypeWillChange]
   
public function offsetGet($key)
    {
        return
$this->options[$key];
    }

    public function
__get($key)
    {
        return
$this->offsetGet($key);
    }

   
#[\ReturnTypeWillChange]
   
public function offsetExists($key)
    {
        return isset(
$this->options[$key]);
    }

    public function
__isset($key)
    {
        return
$this->offsetExists($key);
    }

   
#[\ReturnTypeWillChange]
   
public function offsetSet($key, $value)
    {
        throw new \
LogicException("Language object cannot be written to.");
    }

   
#[\ReturnTypeWillChange]
   
public function offsetUnset($key)
    {
        throw new \
LogicException("Language object cannot be written to.");
    }

    public function
setTimeZone($tz)
    {
        if (!(
$tz instanceof \DateTimeZone))
        {
            try
            {
               
$tz = new \DateTimeZone($tz);
            }
            catch (\
Exception $e)
            {
                return
false;
            }
        }

       
$this->date->setTimezone($tz);
        return
true;
    }

   
/**
     * @return \DateTimeZone
     */
   
public function getTimeZone()
    {
        return
$this->date->getTimezone();
    }

    protected function
formatDateTime(\DateTime $date, $format)
    {
        if (!
$date)
        {
           
$date = $this->date;
        }

       
$dateParts = explode('|', $date->format('j|w|W|n|Y|G|i|s|S'));
        list(
$dayOfMonth, $dayOfWeek, $weekOfYear, $month, $year, $hour, $minute, $second, $ordinalSuffix) = $dateParts;

       
$output = '';

       
$formatters = str_split($format);
       
$formatterCount = count($formatters);
        for (
$i = 0; $i < $formatterCount; $i++)
        {
           
$identifier = $formatters[$i];

            switch (
$identifier)
            {
               
// day of month
               
case 'd': $output .= sprintf('%02d', $dayOfMonth); break;
                case
'j': $output .= $dayOfMonth; break;

               
// day of week
               
case 'D': $output .= $this->getPhraseCacheRaw('day_' . $this->dowTranslation[$dayOfWeek] . '_short'); break;
                case
'l': $output .= $this->getPhraseCacheRaw('day_' . $this->dowTranslation[$dayOfWeek]); break;

               
// week
               
case 'w': $output .= $dayOfWeek; break;
                case
'W': $output .= $weekOfYear; break;

               
// month
               
case 'm': $output .= sprintf('%02d', $month); break;
                case
'n': $output .= $month; break;
                case
'F': $output .= $this->getPhraseCacheRaw('month_' . $month); break;
                case
'M': $output .= $this->getPhraseCacheRaw('month_' . $month . '_short'); break;

               
// year
               
case 'Y': $output .= $year; break;
                case
'y': $output .= substr($year, 2); break;

               
// am/pm
               
case 'a': $output .= $this->getPhraseCacheRaw(($hour >= 12 ? 'time_pm_lower' : 'time_am_lower')); break;
                case
'A': $output .= $this->getPhraseCacheRaw(($hour >= 12 ? 'time_pm_upper' : 'time_am_upper')); break;

               
// hour
               
case 'H': $output .= sprintf('%02d', $hour); break;
                case
'h': $output .= sprintf('%02d', $hour % 12 ? $hour % 12 : 12); break;
                case
'G': $output .= $hour; break;
                case
'g': $output .= ($hour % 12 ? $hour % 12 : 12); break;

               
// minute
               
case 'i': $output .= $minute; break;

               
// second
               
case 's': $output .= $second; break;

               
// ordinal
               
case 'S': $output .= $ordinalSuffix; break;

                case
'\\':
                   
$i++;
                    if (
$i < $formatterCount)
                    {
                       
$output .= $formatters[$i];
                    }
                    break;

               
// fallback to PHP formatter directly - shouldn't be used regularly
               
case 'N':
                case
'z':
                case
't':
                case
'L':
                case
'o':
                case
'B':
                case
'u':
                case
'v':
                case
'e':
                case
'I':
                case
'O':
                case
'P':
                case
'T':
                case
'Z':
                case
'c':
                case
'r':
                case
'U':
                   
$output .= $date->format($identifier);
                break;

               
// anything else is printed
               
default: $output .= $identifier;
            }
        }

        return
$output;
    }

    public function
date($timestamp, $format = null)
    {
        if (
$timestamp instanceof \DateTime)
        {
           
$date = $timestamp;
        }
        else
        {
           
$date = $this->date->setTimestamp($timestamp);
        }

        switch (
$format)
        {
            case
'year':
               
$dateFormat = 'Y';
                break;

            case
'monthDay':
               
$dateFormat = 'F j';
                break;

            case
'picker':
               
$dateFormat = 'Y-m-d';
                break;

            case
'absolute':
            case
'':
               
$dateFormat = $this->options['date_format'];
                break;

            default:
               
$dateFormat = $format;
        }

        return
$this->formatDateTime($date, $dateFormat);
    }

    public function
time($timestamp, $format = null)
    {
        if (
$timestamp instanceof \DateTime)
        {
           
$date = $timestamp;
        }
        else
        {
           
$date = $this->date->setTimestamp($timestamp);
        }

        switch (
$format)
        {
            case
'absolute':
            case
'':
               
$dateFormat = $this->options['time_format'];
                break;

            default:
               
$dateFormat = $format;
        }

        return
$this->formatDateTime($date, $dateFormat);
    }

    public function
dateTime($timestamp)
    {
        list(
$date, $time) = $this->getDateTimeParts($timestamp);
        return
$this->getDateTimeOutput($date, $time);
    }

    public function
getDateTimeParts($timestamp)
    {
        if (
$timestamp instanceof \DateTime)
        {
           
$date = $timestamp;
        }
        else
        {
           
$date = $this->date->setTimestamp($timestamp);
        }

       
$dateTimeFormat = $this->options['date_format'] . '|' . $this->options['time_format'];
        return
explode('|', $this->formatDateTime($date, $dateTimeFormat));
    }

    public function
getDateTimeOutput($date, $time)
    {
        return
strtr($this->getPhraseCacheRaw('date_x_at_time_y'), [
           
'{date}' => $date,
           
'{time}' => $time
       
]);
    }

    protected function
getRelativeDateTimeInternal($timestamp, $date, $time, $getFullDate = false)
    {
       
$timeRef = $this->getDayStartTimestamps();

       
$dateObj = new \DateTime('@' . $timestamp);
       
$dateObj->setTimezone($this->getTimeZone());

       
$interval = $timeRef['now'] - $timestamp;

        if (
$interval < -2)
        {
           
// future date
           
$futureInterval = $timestamp - $timeRef['now'];

            if (
$futureInterval < 60)
            {
                return
$this->getPhraseCacheRaw('in_a_moment');
            }
            else if (
$futureInterval < 120)
            {
                return
$this->getPhraseCacheRaw('in_a_minute');
            }
            else if (
$futureInterval < 3600)
            {
                return
strtr($this->getPhraseCacheRaw('in_x_minutes'), [
                   
'{minutes}' => floor($futureInterval / 60)
                ]);
            }
            else if (
$timestamp < $timeRef['tomorrow'])
            {
               
// today
               
return strtr($this->getPhraseCacheRaw('later_today_at_x'), [
                   
'{time}' => $time
               
]);
            }
            else if (
$timestamp < $dateObj->setTimestamp($timeRef['tomorrow'])->modify('+1 day')->format('U')) // day after tomorrow
           
{
               
// tomorrow
               
return strtr($this->getPhraseCacheRaw('tomorrow_at_x'), [
                   
'{time}' => $time
               
]);
            }
            else if (
$futureInterval < ($dateObj->setTimestamp(\XF::$time)->modify('+1 week')->format('U') - \XF::$time)) // one week in the future
           
{
               
// after tomorrow but within the next week
               
return $this->getDateTimeOutput($date, $time);
            }
            else if (
$getFullDate)
            {
               
// more than a week in the future
               
return $this->getDateTimeOutput($date, $time);
            }
            else
            {
               
// after the next 7 days
               
return $date;
            }
        }
        else if (
$interval <= 60)
        {
            return
$this->getPhraseCacheRaw('a_moment_ago');
        }
        else if (
$interval <= 120)
        {
            return
$this->getPhraseCacheRaw('one_minute_ago');
        }
        else if (
$interval < 3600)
        {
            return
strtr($this->getPhraseCacheRaw('x_minutes_ago'), [
               
'{minutes}' => floor($interval / 60)
            ]);
        }
        else if (
$timestamp >= $timeRef['today'])
        {
            return
strtr($this->getPhraseCacheRaw('today_at_x'), [
               
'{time}' => $time
           
]);
        }
        else if (
$timestamp >= $timeRef['yesterday'])
        {
            return
strtr($this->getPhraseCacheRaw('yesterday_at_x'), [
               
'{time}' => $time
           
]);
        }
        else if (
$timestamp >= $timeRef['week'])
        {
           
$dow = $dateObj->setTimestamp($timestamp)->format('w');
           
$day = $this->getPhraseCacheRaw('day_' . $this->dowTranslation[$dow]);

            return
strtr($this->getPhraseCacheRaw('day_x_at_time_y'), [
               
'{day}' => $day,
               
'{time}' => $time
           
]);
        }
        else if (
$getFullDate)
        {
            return
$this->getDateTimeOutput($date, $time);
        }
        else
        {
            return
$date;
        }
    }

   
/** @var array Relative date output cache  */
   
protected $rdc = [];

    public function
getRelativeDateTimeOutput($timestamp, $date, $time, $getFullDate = false)
    {
        if (!isset(
$this->rdc[$timestamp][$getFullDate]))
        {
           
$this->rdc[$timestamp][$getFullDate] = $this->getRelativeDateTimeInternal($timestamp, $date, $time, $getFullDate);
        }

        return
$this->rdc[$timestamp][$getFullDate];
    }

    public function
getDayStartTimestamps()
    {
        if (!
$this->dayStartTimestamps)
        {
           
$date = new \DateTime('@' . \XF::$time);
           
$date->setTimezone($this->getTimeZone());
           
$date->setTime(0, 0, 0);

            list(
$todayStamp, $todayDow) = explode('|', $date->format('U|w'));

           
$date->modify('+1 day');
           
$tomorrowStamp = $date->format('U');

           
$date->modify('-2 days');
           
$yesterdayStamp = $date->format('U');

           
$date->modify('-5 days');
           
$weekStamp = $date->format('U');

           
$this->dayStartTimestamps = [
               
'tomorrow'  => $tomorrowStamp,
               
'now'       => \XF::$time,
               
'today'     => $todayStamp,
               
'todayDow'  => $todayDow,
               
'yesterday' => $yesterdayStamp,
               
'week'      => $weekStamp
           
];
        }

        return
$this->dayStartTimestamps;
    }

    protected function
_getDatePresets()
    {
        return [
           
'1day' => ['-1 day', '1_day_ago'],
           
'1week' => ['-1 week', '1_week_ago'],
           
'2weeks' => ['-2 weeks', '2_weeks_ago'],
           
'1month' => ['-1 month', '1_month_ago'],
           
'3months' => ['-3 months', '3_months_ago'],
           
'6months' => ['-6 months', '6_months_ago'],
           
'9months' => ['-9 months', '9_months_ago'],
           
'1year' => ['-1 year', '1_year_ago'],
           
'2years' => ['-2 years', '2_years_ago'],
        ];
    }

    public function
getDatePresets($timeStamp = null)
    {
        if (
is_null($timeStamp))
        {
           
$timeStamp = \XF::$time;
        }

       
$presets = [];

        foreach (
$this->_getDatePresets() AS $period => $presetData)
        {
           
$date = new \DateTime('@' . $timeStamp);
           
$date->modify($presetData[0]);
           
$presets[$date->format('Y-m-d')] = \XF::phrase($presetData[1]);
        }

        return
$presets;
    }

   
/**
     * Formats the given number for a language/locale. Also used for file size formatting.
     *
     * @param mixed $number Number to format
     * @param integer|string $precision Number of places to show after decimal point or word "size" for file size
     *
     * @return string Formatted number
     */
   
public function numberFormat($number, $precision = 0)
    {
        return
number_format(floatval($number), $precision,
           
$this->options['decimal_point'], $this->options['thousands_separator']
        );
    }

    public function
shortNumberFormat($number, $precision = 0)
    {
       
$originalNumber = $number;
       
$decimalSep = $this->options['decimal_point'];
       
$thousandsSep = $this->options['thousands_separator'];

        if (
$number >= 1000)
        {
           
// Round number to the nearest 1000 with relevant precision
           
$basePrecision = -3;
           
$number = round($number, $basePrecision + $precision);
        }

       
$phrase = null;

        if (
$number >= 1000000000) // 1B
       
{
           
$number = number_format($number / 1000000000, $precision, $decimalSep, $thousandsSep);
           
$phrase = 'x_b';
        }
        elseif (
$number >= 1000000) // 1M - 999M
       
{
           
$number = number_format($number / 1000000, $precision, $decimalSep, $thousandsSep);
           
$phrase = 'x_m';
        }
        elseif (
$number >= 1000) // 1K - 999K
       
{
           
$number = number_format($number / 1000, $precision, $decimalSep, $thousandsSep);
           
$phrase = 'x_k';
        }

       
// This is the original full-form formatted number
        // we can return this if the number is unphrased anyway and also
        // pass it into the phrase to allow user to opt out of the short format.
       
$default = $this->numberFormat($originalNumber, $precision);

       
// return $number, not $number.0 when the decimal is 0.
       
if (substr($number, -2) === "{$decimalSep}0")
        {
           
$number = substr($number, 0, -2);
        }
        if (
substr($default, -2) === "{$decimalSep}0")
        {
           
$default = substr($default, 0, -2);
        }

        if (
$phrase)
        {
            return
str_replace(['{number}', '{default}'], [$number, $default], $this->getPhraseCacheRaw($phrase));
        }
        else
        {
            return
$default;
        }
    }

    public function
currencyFormat($value, $symbol, $precision = 2, $format = null)
    {
       
$format = $format ?: $this->options['currency_format'];
        return
strtr($format, [
           
'{symbol}' => $symbol,
           
'{value}' => $this->numberFormat($value, $precision)
        ]);
    }

    public function
fileSizeFormat($number)
    {
       
$decimalSep = $this->options['decimal_point'];
       
$thousandsSep = $this->options['thousands_separator'];

        if (
$number >= 1099511627776) // 1 TB
       
{
           
$number = number_format($number / 1099511627776, 1, $decimalSep, $thousandsSep);
           
$phrase = 'x_tb';
        }
        else if (
$number >= 1073741824) // 1 GB
       
{
           
$number = number_format($number / 1073741824, 1, $decimalSep, $thousandsSep);
           
$phrase = 'x_gb';
        }
        else if (
$number >= 1048576) // 1 MB
       
{
           
$number = number_format($number / 1048576, 1, $decimalSep, $thousandsSep);
           
$phrase = 'x_mb';
        }
        else if (
$number >= 1024) // 1 KB
       
{
           
$number = number_format($number / 1024, 1, $decimalSep, $thousandsSep);
           
$phrase = 'x_kb';
        }
        else
        {
           
$number = number_format($number, 0, $decimalSep, $thousandsSep);
           
$phrase = 'x_bytes';
        }

       
// return $number, not $number.0 when the decimal is 0.
       
if (substr($number, -2) === "{$decimalSep}0")
        {
           
$number = substr($number, 0, -2);
        }

        return
str_replace('{size}', $number, $this->getPhraseCacheRaw($phrase));
    }
}