xref: /template/strap/ComboStrap/PipelineUtility.php (revision d8add9b6d6dddc5a1630f969f72a7f91a2da8f6d)
137748cd8SNickeau<?php
237748cd8SNickeau/**
337748cd8SNickeau * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved.
437748cd8SNickeau *
537748cd8SNickeau * This source code is licensed under the GPL license found in the
637748cd8SNickeau * COPYING  file in the root directory of this source tree.
737748cd8SNickeau *
837748cd8SNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
937748cd8SNickeau * @author   ComboStrap <support@combostrap.com>
1037748cd8SNickeau *
1137748cd8SNickeau */
1237748cd8SNickeau
1337748cd8SNickeaunamespace ComboStrap;
1437748cd8SNickeau
1504fd306cSNickeauuse IntlDateFormatter;
1604fd306cSNickeau
1737748cd8SNickeau/**
1837748cd8SNickeau * Class PipelineUtility
1937748cd8SNickeau * @package ComboStrap
2037748cd8SNickeau * A pipeline to perform filter transformation
2137748cd8SNickeau *
2237748cd8SNickeau * See also
2337748cd8SNickeau * https://getbootstrap.com/docs/5.0/helpers/text-truncation/
2437748cd8SNickeau */
2537748cd8SNickeauclass PipelineUtility
2637748cd8SNickeau{
2704fd306cSNickeau    const QUOTES_CHARACTERS = ['"', '\''];
2804fd306cSNickeau    const SPACE_CHARACTER = " ";
2904fd306cSNickeau
3037748cd8SNickeau
3137748cd8SNickeau    /**
3204fd306cSNickeau     * @param $expression
3304fd306cSNickeau     * @param array|null $contextData
3437748cd8SNickeau     * @return string
3504fd306cSNickeau     * @throws ExceptionBadSyntax - if there is any syntax error
3637748cd8SNickeau     */
3704fd306cSNickeau    static public function execute($expression, array $contextData = null): string
3837748cd8SNickeau    {
3937748cd8SNickeau
4037748cd8SNickeau        /**
4104fd306cSNickeau         * Get the value (called the message in a pipeline)
4237748cd8SNickeau         */
4304fd306cSNickeau        $processedExpression = $expression;
4404fd306cSNickeau        $firstQuoteChar = strpos($processedExpression, '"');
4504fd306cSNickeau        $firstPipeChar = strpos($processedExpression, '|');
4604fd306cSNickeau        if ($firstQuoteChar < $firstPipeChar || $firstPipeChar === false) {
4737748cd8SNickeau
4837748cd8SNickeau            /**
4904fd306cSNickeau             * Example:
5004fd306cSNickeau             * a literal: "$title"
5104fd306cSNickeau             * a literal with a pipe: "World | Do" | replace ("world,"you")
5237748cd8SNickeau             */
5304fd306cSNickeau            $message = null;
5404fd306cSNickeau            if ($firstQuoteChar !== false) {
5504fd306cSNickeau                $processedExpression = substr($processedExpression, $firstQuoteChar + 1);
5604fd306cSNickeau                $secondQuoteChar = strpos($processedExpression, '"');
5704fd306cSNickeau                if ($secondQuoteChar !== false) {
5804fd306cSNickeau                    $message = substr($processedExpression, 0, $secondQuoteChar);
5904fd306cSNickeau                }
6004fd306cSNickeau            }
6104fd306cSNickeau
6204fd306cSNickeau            $pipeCharPosition = strpos($processedExpression, '|');
6304fd306cSNickeau            if ($pipeCharPosition !== false) {
6404fd306cSNickeau                $commandChain = substr($processedExpression, $pipeCharPosition + 1);
6504fd306cSNickeau                if ($message == null) {
6604fd306cSNickeau                    // not quoted expression
6704fd306cSNickeau                    // do we support that ?
6804fd306cSNickeau                    $message = substr($processedExpression, 0, $pipeCharPosition);
6904fd306cSNickeau                }
7004fd306cSNickeau            } else {
7104fd306cSNickeau                if ($message == null) {
7204fd306cSNickeau                    // not quoted expression
7304fd306cSNickeau                    // do we support that ?
7404fd306cSNickeau                    $message = $processedExpression;
7504fd306cSNickeau                }
7604fd306cSNickeau                $commandChain = "";
7704fd306cSNickeau            }
7804fd306cSNickeau
7904fd306cSNickeau        } else {
8037748cd8SNickeau
8137748cd8SNickeau            /**
8204fd306cSNickeau             * Example: a variable with an expression
8304fd306cSNickeau             * $title | replace ("world,"you")
8437748cd8SNickeau             */
8504fd306cSNickeau            $message = trim(substr($processedExpression, 0, $firstPipeChar));
8604fd306cSNickeau            $commandChain = trim(substr($processedExpression, $firstPipeChar + 1));
8704fd306cSNickeau
8804fd306cSNickeau        }
8904fd306cSNickeau
9004fd306cSNickeau
9104fd306cSNickeau        /**
9204fd306cSNickeau         * Command chain splits
9304fd306cSNickeau         */
9404fd306cSNickeau        $commands = preg_split("/\|/", $commandChain);
9504fd306cSNickeau
9604fd306cSNickeau
9704fd306cSNickeau        /**
9804fd306cSNickeau         * We replace after the split to be sure that there is not a | separator in the variable value
9904fd306cSNickeau         * that would fuck up the process
10004fd306cSNickeau         */
10104fd306cSNickeau        $message = \syntax_plugin_combo_variable::replaceVariablesWithValuesFromContext($message, $contextData);
10204fd306cSNickeau
10304fd306cSNickeau        $charactersToTrimFromCommand = implode("", self::QUOTES_CHARACTERS);
10437748cd8SNickeau        foreach ($commands as $command) {
10537748cd8SNickeau            $command = trim($command, " )");
10637748cd8SNickeau            $leftParenthesis = strpos($command, "(");
10737748cd8SNickeau            $commandName = substr($command, 0, $leftParenthesis);
10837748cd8SNickeau            $signature = substr($command, $leftParenthesis + 1);
10904fd306cSNickeau            $commandArgs = preg_split("/\s*,\s*/", $signature);
11004fd306cSNickeau            /**
11104fd306cSNickeau             * Delete space characters
11204fd306cSNickeau             */
11337748cd8SNickeau            $commandArgs = array_map(
11437748cd8SNickeau                'trim',
11537748cd8SNickeau                $commandArgs,
11604fd306cSNickeau                array_fill(0, sizeof($commandArgs), self::SPACE_CHARACTER)
11704fd306cSNickeau            );
11804fd306cSNickeau            /**
11904fd306cSNickeau             * Delete quote characters
12004fd306cSNickeau             */
12104fd306cSNickeau            $commandArgs = array_map(
12204fd306cSNickeau                'trim',
12304fd306cSNickeau                $commandArgs,
12404fd306cSNickeau                array_fill(0, sizeof($commandArgs), $charactersToTrimFromCommand)
12537748cd8SNickeau            );
12637748cd8SNickeau            $commandName = trim($commandName);
12737748cd8SNickeau            if (!empty($commandName)) {
12837748cd8SNickeau                switch ($commandName) {
12937748cd8SNickeau                    case "replace":
13004fd306cSNickeau                        $message = self::replace($commandArgs, $message);
13137748cd8SNickeau                        break;
13237748cd8SNickeau                    case "head":
13304fd306cSNickeau                        $message = self::head($commandArgs, $message);
13437748cd8SNickeau                        break;
13537748cd8SNickeau                    case "tail":
13604fd306cSNickeau                        $message = self::tail($commandArgs, $message);
13737748cd8SNickeau                        break;
13837748cd8SNickeau                    case "rconcat":
13904fd306cSNickeau                        $message = self::concat($commandArgs, $message, "right");
14037748cd8SNickeau                        break;
14137748cd8SNickeau                    case "lconcat":
14204fd306cSNickeau                        $message = self::concat($commandArgs, $message, "left");
14337748cd8SNickeau                        break;
14437748cd8SNickeau                    case "cut":
14504fd306cSNickeau                        $message = self::cut($commandArgs, $message);
14637748cd8SNickeau                        break;
14737748cd8SNickeau                    case "trim":
14804fd306cSNickeau                        $message = trim($message);
14937748cd8SNickeau                        break;
15037748cd8SNickeau                    case "capitalize":
15104fd306cSNickeau                        $message = ucwords($message);
15204fd306cSNickeau                        break;
15304fd306cSNickeau                    case "format":
15404fd306cSNickeau                        $message = self::format($commandArgs, $message);
15537748cd8SNickeau                        break;
15637748cd8SNickeau                    default:
15737748cd8SNickeau                        LogUtility::msg("command ($commandName) is unknown", LogUtility::LVL_MSG_ERROR, "pipeline");
15837748cd8SNickeau                }
15937748cd8SNickeau            }
16037748cd8SNickeau        }
16104fd306cSNickeau        return $message;
16237748cd8SNickeau    }
16337748cd8SNickeau
16437748cd8SNickeau    private static function replace(array $commandArgs, $value)
16537748cd8SNickeau    {
16637748cd8SNickeau        $search = $commandArgs[0];
16737748cd8SNickeau        $replace = $commandArgs[1];
16837748cd8SNickeau        return str_replace($search, $replace, $value);
16937748cd8SNickeau    }
17037748cd8SNickeau
17137748cd8SNickeau    /**
17237748cd8SNickeau     * @param array $commandArgs
17337748cd8SNickeau     * @param $value
17437748cd8SNickeau     * @return false|string
17537748cd8SNickeau     * See also: https://getbootstrap.com/docs/5.0/helpers/text-truncation/
17637748cd8SNickeau     */
17704fd306cSNickeau    public static function head(array $commandArgs, $value)
17837748cd8SNickeau    {
17937748cd8SNickeau        $length = $commandArgs[0];
1804cadd4f8SNickeau        if (strlen($value) < $length) {
1814cadd4f8SNickeau            return $value;
1824cadd4f8SNickeau        }
18304fd306cSNickeau        $words = explode(" ", $value);
18404fd306cSNickeau        $headValue = "";
18504fd306cSNickeau        for ($i = 0; $i < sizeof($words); $i++) {
18604fd306cSNickeau            if ($i != 0) {
18704fd306cSNickeau                $headValue .= " ";
18804fd306cSNickeau            }
18904fd306cSNickeau            $headValue .= $words[$i];
19004fd306cSNickeau            if (strlen($headValue) >= $length) {
19104fd306cSNickeau                break;
19204fd306cSNickeau            }
19304fd306cSNickeau        }
19404fd306cSNickeau
19570bbd7f1Sgerardnico        $tail = $commandArgs[1] ?? null;
1964cadd4f8SNickeau        if ($tail !== null) {
1974cadd4f8SNickeau            $headValue .= $tail;
1984cadd4f8SNickeau        }
19904fd306cSNickeau
2004cadd4f8SNickeau        return $headValue;
20137748cd8SNickeau    }
20237748cd8SNickeau
20304fd306cSNickeau    private
20404fd306cSNickeau    static function concat(array $commandArgs, $value, $side): string
20537748cd8SNickeau    {
20637748cd8SNickeau        $string = $commandArgs[0];
20737748cd8SNickeau        switch ($side) {
20837748cd8SNickeau            case "left":
20937748cd8SNickeau                return $string . $value;
21037748cd8SNickeau            case "right":
21137748cd8SNickeau                return $value . $string;
21237748cd8SNickeau            default:
21337748cd8SNickeau                LogUtility::msg("The side value ($side) is unknown", LogUtility::LVL_MSG_ERROR, "pipeline");
21404fd306cSNickeau                return $value . $string;
21537748cd8SNickeau        }
21637748cd8SNickeau
21737748cd8SNickeau
21837748cd8SNickeau    }
21937748cd8SNickeau
22004fd306cSNickeau    private
22104fd306cSNickeau    static function tail(array $commandArgs, $value)
22237748cd8SNickeau    {
22337748cd8SNickeau        $length = $commandArgs[0];
22437748cd8SNickeau        return substr($value, strlen($value) - $length);
22537748cd8SNickeau    }
22637748cd8SNickeau
22704fd306cSNickeau    private
22804fd306cSNickeau    static function cut(array $commandArgs, $value)
22937748cd8SNickeau    {
23037748cd8SNickeau        $pattern = $commandArgs[0];
23137748cd8SNickeau        $words = preg_split("/$pattern/i", $value);
23237748cd8SNickeau        if ($words !== false) {
23337748cd8SNickeau            $selector = $commandArgs[1];
23437748cd8SNickeau            $startEndSelector = preg_split("/-/i", $selector);
23537748cd8SNickeau            $start = $startEndSelector[0] - 1;
23637748cd8SNickeau            $end = null;
23737748cd8SNickeau            if (isset($startEndSelector[1])) {
23837748cd8SNickeau                $end = $startEndSelector[1];
23937748cd8SNickeau                if (empty($end)) {
24037748cd8SNickeau                    $end = sizeof($words);
24137748cd8SNickeau                }
24237748cd8SNickeau                $end = $end - 1;
24337748cd8SNickeau            }
24437748cd8SNickeau            if ($end == null) {
24537748cd8SNickeau                if (isset($words[$start])) {
24637748cd8SNickeau                    return $words[$start];
24737748cd8SNickeau                } else {
24837748cd8SNickeau                    return $value;
24937748cd8SNickeau                }
25037748cd8SNickeau            } else {
25137748cd8SNickeau                $result = "";
25237748cd8SNickeau                for ($i = $start; $i <= $end; $i++) {
25337748cd8SNickeau                    if (isset($words[$i])) {
25437748cd8SNickeau                        if (!empty($result)) {
25537748cd8SNickeau                            $result .= $pattern;
25637748cd8SNickeau                        }
25737748cd8SNickeau                        $result .= $words[$i];
25837748cd8SNickeau                    }
25937748cd8SNickeau                }
26037748cd8SNickeau                return $result;
26137748cd8SNickeau            }
26237748cd8SNickeau
26337748cd8SNickeau        } else {
26437748cd8SNickeau            return "An error occurred: could not split with the pattern `$pattern`, the value `$value`.";
26537748cd8SNickeau        }
26637748cd8SNickeau    }
26737748cd8SNickeau
26804fd306cSNickeau    /**
26904fd306cSNickeau     * @throws ExceptionBadSyntax
27004fd306cSNickeau     */
27104fd306cSNickeau    public
27204fd306cSNickeau    static function format(array $commandArgs, $value): string
27304fd306cSNickeau    {
27404fd306cSNickeau
27504fd306cSNickeau        /**
27604fd306cSNickeau         * For now only date time are
27704fd306cSNickeau         */
27804fd306cSNickeau        try {
27904fd306cSNickeau            $dateTime = Iso8601Date::createFromString($value);
28004fd306cSNickeau        } catch (ExceptionBadSyntax $e) {
28104fd306cSNickeau            throw new ExceptionBadSyntax("The format method allows for now only date. The value ($value) is not a date.", PipelineTag::CANONICAL);
28204fd306cSNickeau        }
28304fd306cSNickeau
28404fd306cSNickeau        $size = sizeof($commandArgs);
28504fd306cSNickeau        $pattern = null;
28604fd306cSNickeau        $locale = null;
28704fd306cSNickeau        switch ($size) {
28804fd306cSNickeau            case 0:
28904fd306cSNickeau                break;
29004fd306cSNickeau            case 1:
29104fd306cSNickeau                $pattern = $commandArgs[0];
29204fd306cSNickeau                break;
29304fd306cSNickeau            case 2:
29404fd306cSNickeau            default:
29504fd306cSNickeau                $pattern = $commandArgs[0];
29604fd306cSNickeau                $locale = $commandArgs[1];
29704fd306cSNickeau                break;
29804fd306cSNickeau        }
29904fd306cSNickeau        $localeSeparator = '_';
30004fd306cSNickeau        if ($locale === null) {
30104fd306cSNickeau            $path = ExecutionContext::getActualOrCreateFromEnv()->getContextPath();
30204fd306cSNickeau            $page = MarkupPath::createPageFromPathObject($path);
30304fd306cSNickeau            $locale = Locale::createForPage($page)->getValueOrDefault();
30404fd306cSNickeau        }
30504fd306cSNickeau
30604fd306cSNickeau        if ($locale === null) {
30704fd306cSNickeau            // should never happen but yeah
30804fd306cSNickeau            $locale = 'en_US';
30904fd306cSNickeau            LogUtility::error("Internal Error: No default locale could be determined. The locale was set to $locale", DateTag::CANONICAL);
31004fd306cSNickeau        }
31104fd306cSNickeau
31204fd306cSNickeau        /**
31304fd306cSNickeau         * If the user has set a lang
31404fd306cSNickeau         * Transform it as locale
31504fd306cSNickeau         */
31604fd306cSNickeau        if (strlen(trim($locale)) === 2) {
317*d8add9b6SNicolas GERARD            $region = Site::getLanguageRegion();
318*d8add9b6SNicolas GERARD            $derivedLocale = strtolower($region) . $localeSeparator . strtoupper($locale);
31904fd306cSNickeau        } else {
32004fd306cSNickeau            $derivedLocale = $locale;
32104fd306cSNickeau        }
32204fd306cSNickeau
32304fd306cSNickeau        return $dateTime->formatLocale($pattern, $derivedLocale);
32404fd306cSNickeau
32504fd306cSNickeau    }
32604fd306cSNickeau
32737748cd8SNickeau}
328