xref: /template/strap/ComboStrap/PipelineUtility.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
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
15*04fd306cSNickeauuse IntlDateFormatter;
16*04fd306cSNickeau
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{
27*04fd306cSNickeau    const QUOTES_CHARACTERS = ['"', '\''];
28*04fd306cSNickeau    const SPACE_CHARACTER = " ";
29*04fd306cSNickeau
3037748cd8SNickeau
3137748cd8SNickeau    /**
32*04fd306cSNickeau     * @param $expression
33*04fd306cSNickeau     * @param array|null $contextData
3437748cd8SNickeau     * @return string
35*04fd306cSNickeau     * @throws ExceptionBadSyntax - if there is any syntax error
3637748cd8SNickeau     */
37*04fd306cSNickeau    static public function execute($expression, array $contextData = null): string
3837748cd8SNickeau    {
3937748cd8SNickeau
4037748cd8SNickeau        /**
41*04fd306cSNickeau         * Get the value (called the message in a pipeline)
4237748cd8SNickeau         */
43*04fd306cSNickeau        $processedExpression = $expression;
44*04fd306cSNickeau        $firstQuoteChar = strpos($processedExpression, '"');
45*04fd306cSNickeau        $firstPipeChar = strpos($processedExpression, '|');
46*04fd306cSNickeau        if ($firstQuoteChar < $firstPipeChar || $firstPipeChar === false) {
4737748cd8SNickeau
4837748cd8SNickeau            /**
49*04fd306cSNickeau             * Example:
50*04fd306cSNickeau             * a literal: "$title"
51*04fd306cSNickeau             * a literal with a pipe: "World | Do" | replace ("world,"you")
5237748cd8SNickeau             */
53*04fd306cSNickeau            $message = null;
54*04fd306cSNickeau            if ($firstQuoteChar !== false) {
55*04fd306cSNickeau                $processedExpression = substr($processedExpression, $firstQuoteChar + 1);
56*04fd306cSNickeau                $secondQuoteChar = strpos($processedExpression, '"');
57*04fd306cSNickeau                if ($secondQuoteChar !== false) {
58*04fd306cSNickeau                    $message = substr($processedExpression, 0, $secondQuoteChar);
59*04fd306cSNickeau                }
60*04fd306cSNickeau            }
61*04fd306cSNickeau
62*04fd306cSNickeau            $pipeCharPosition = strpos($processedExpression, '|');
63*04fd306cSNickeau            if ($pipeCharPosition !== false) {
64*04fd306cSNickeau                $commandChain = substr($processedExpression, $pipeCharPosition + 1);
65*04fd306cSNickeau                if ($message == null) {
66*04fd306cSNickeau                    // not quoted expression
67*04fd306cSNickeau                    // do we support that ?
68*04fd306cSNickeau                    $message = substr($processedExpression, 0, $pipeCharPosition);
69*04fd306cSNickeau                }
70*04fd306cSNickeau            } else {
71*04fd306cSNickeau                if ($message == null) {
72*04fd306cSNickeau                    // not quoted expression
73*04fd306cSNickeau                    // do we support that ?
74*04fd306cSNickeau                    $message = $processedExpression;
75*04fd306cSNickeau                }
76*04fd306cSNickeau                $commandChain = "";
77*04fd306cSNickeau            }
78*04fd306cSNickeau
79*04fd306cSNickeau        } else {
8037748cd8SNickeau
8137748cd8SNickeau            /**
82*04fd306cSNickeau             * Example: a variable with an expression
83*04fd306cSNickeau             * $title | replace ("world,"you")
8437748cd8SNickeau             */
85*04fd306cSNickeau            $message = trim(substr($processedExpression, 0, $firstPipeChar));
86*04fd306cSNickeau            $commandChain = trim(substr($processedExpression, $firstPipeChar + 1));
87*04fd306cSNickeau
88*04fd306cSNickeau        }
89*04fd306cSNickeau
90*04fd306cSNickeau
91*04fd306cSNickeau        /**
92*04fd306cSNickeau         * Command chain splits
93*04fd306cSNickeau         */
94*04fd306cSNickeau        $commands = preg_split("/\|/", $commandChain);
95*04fd306cSNickeau
96*04fd306cSNickeau
97*04fd306cSNickeau        /**
98*04fd306cSNickeau         * We replace after the split to be sure that there is not a | separator in the variable value
99*04fd306cSNickeau         * that would fuck up the process
100*04fd306cSNickeau         */
101*04fd306cSNickeau        $message = \syntax_plugin_combo_variable::replaceVariablesWithValuesFromContext($message, $contextData);
102*04fd306cSNickeau
103*04fd306cSNickeau        $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);
109*04fd306cSNickeau            $commandArgs = preg_split("/\s*,\s*/", $signature);
110*04fd306cSNickeau            /**
111*04fd306cSNickeau             * Delete space characters
112*04fd306cSNickeau             */
11337748cd8SNickeau            $commandArgs = array_map(
11437748cd8SNickeau                'trim',
11537748cd8SNickeau                $commandArgs,
116*04fd306cSNickeau                array_fill(0, sizeof($commandArgs), self::SPACE_CHARACTER)
117*04fd306cSNickeau            );
118*04fd306cSNickeau            /**
119*04fd306cSNickeau             * Delete quote characters
120*04fd306cSNickeau             */
121*04fd306cSNickeau            $commandArgs = array_map(
122*04fd306cSNickeau                'trim',
123*04fd306cSNickeau                $commandArgs,
124*04fd306cSNickeau                array_fill(0, sizeof($commandArgs), $charactersToTrimFromCommand)
12537748cd8SNickeau            );
12637748cd8SNickeau            $commandName = trim($commandName);
12737748cd8SNickeau            if (!empty($commandName)) {
12837748cd8SNickeau                switch ($commandName) {
12937748cd8SNickeau                    case "replace":
130*04fd306cSNickeau                        $message = self::replace($commandArgs, $message);
13137748cd8SNickeau                        break;
13237748cd8SNickeau                    case "head":
133*04fd306cSNickeau                        $message = self::head($commandArgs, $message);
13437748cd8SNickeau                        break;
13537748cd8SNickeau                    case "tail":
136*04fd306cSNickeau                        $message = self::tail($commandArgs, $message);
13737748cd8SNickeau                        break;
13837748cd8SNickeau                    case "rconcat":
139*04fd306cSNickeau                        $message = self::concat($commandArgs, $message, "right");
14037748cd8SNickeau                        break;
14137748cd8SNickeau                    case "lconcat":
142*04fd306cSNickeau                        $message = self::concat($commandArgs, $message, "left");
14337748cd8SNickeau                        break;
14437748cd8SNickeau                    case "cut":
145*04fd306cSNickeau                        $message = self::cut($commandArgs, $message);
14637748cd8SNickeau                        break;
14737748cd8SNickeau                    case "trim":
148*04fd306cSNickeau                        $message = trim($message);
14937748cd8SNickeau                        break;
15037748cd8SNickeau                    case "capitalize":
151*04fd306cSNickeau                        $message = ucwords($message);
152*04fd306cSNickeau                        break;
153*04fd306cSNickeau                    case "format":
154*04fd306cSNickeau                        $message = self::format($commandArgs, $message);
15537748cd8SNickeau                        break;
15637748cd8SNickeau                    default:
15737748cd8SNickeau                        LogUtility::msg("command ($commandName) is unknown", LogUtility::LVL_MSG_ERROR, "pipeline");
15837748cd8SNickeau                }
15937748cd8SNickeau            }
16037748cd8SNickeau        }
161*04fd306cSNickeau        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     */
177*04fd306cSNickeau    public static function head(array $commandArgs, $value)
17837748cd8SNickeau    {
17937748cd8SNickeau        $length = $commandArgs[0];
1804cadd4f8SNickeau        if (strlen($value) < $length) {
1814cadd4f8SNickeau            return $value;
1824cadd4f8SNickeau        }
183*04fd306cSNickeau        $words = explode(" ", $value);
184*04fd306cSNickeau        $headValue = "";
185*04fd306cSNickeau        for ($i = 0; $i < sizeof($words); $i++) {
186*04fd306cSNickeau            if ($i != 0) {
187*04fd306cSNickeau                $headValue .= " ";
188*04fd306cSNickeau            }
189*04fd306cSNickeau            $headValue .= $words[$i];
190*04fd306cSNickeau            if (strlen($headValue) >= $length) {
191*04fd306cSNickeau                break;
192*04fd306cSNickeau            }
193*04fd306cSNickeau        }
194*04fd306cSNickeau
1954cadd4f8SNickeau        $tail = $commandArgs[1];
1964cadd4f8SNickeau        if ($tail !== null) {
1974cadd4f8SNickeau            $headValue .= $tail;
1984cadd4f8SNickeau        }
199*04fd306cSNickeau
2004cadd4f8SNickeau        return $headValue;
20137748cd8SNickeau    }
20237748cd8SNickeau
203*04fd306cSNickeau    private
204*04fd306cSNickeau    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");
214*04fd306cSNickeau                return $value . $string;
21537748cd8SNickeau        }
21637748cd8SNickeau
21737748cd8SNickeau
21837748cd8SNickeau    }
21937748cd8SNickeau
220*04fd306cSNickeau    private
221*04fd306cSNickeau    static function tail(array $commandArgs, $value)
22237748cd8SNickeau    {
22337748cd8SNickeau        $length = $commandArgs[0];
22437748cd8SNickeau        return substr($value, strlen($value) - $length);
22537748cd8SNickeau    }
22637748cd8SNickeau
227*04fd306cSNickeau    private
228*04fd306cSNickeau    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
268*04fd306cSNickeau    /**
269*04fd306cSNickeau     * @throws ExceptionBadSyntax
270*04fd306cSNickeau     */
271*04fd306cSNickeau    public
272*04fd306cSNickeau    static function format(array $commandArgs, $value): string
273*04fd306cSNickeau    {
274*04fd306cSNickeau
275*04fd306cSNickeau        /**
276*04fd306cSNickeau         * For now only date time are
277*04fd306cSNickeau         */
278*04fd306cSNickeau        try {
279*04fd306cSNickeau            $dateTime = Iso8601Date::createFromString($value);
280*04fd306cSNickeau        } catch (ExceptionBadSyntax $e) {
281*04fd306cSNickeau            throw new ExceptionBadSyntax("The format method allows for now only date. The value ($value) is not a date.", PipelineTag::CANONICAL);
282*04fd306cSNickeau        }
283*04fd306cSNickeau
284*04fd306cSNickeau        $size = sizeof($commandArgs);
285*04fd306cSNickeau        $pattern = null;
286*04fd306cSNickeau        $locale = null;
287*04fd306cSNickeau        switch ($size) {
288*04fd306cSNickeau            case 0:
289*04fd306cSNickeau                break;
290*04fd306cSNickeau            case 1:
291*04fd306cSNickeau                $pattern = $commandArgs[0];
292*04fd306cSNickeau                break;
293*04fd306cSNickeau            case 2:
294*04fd306cSNickeau            default:
295*04fd306cSNickeau                $pattern = $commandArgs[0];
296*04fd306cSNickeau                $locale = $commandArgs[1];
297*04fd306cSNickeau                break;
298*04fd306cSNickeau        }
299*04fd306cSNickeau        $localeSeparator = '_';
300*04fd306cSNickeau        if ($locale === null) {
301*04fd306cSNickeau            $path = ExecutionContext::getActualOrCreateFromEnv()->getContextPath();
302*04fd306cSNickeau            $page = MarkupPath::createPageFromPathObject($path);
303*04fd306cSNickeau            $locale = Locale::createForPage($page)->getValueOrDefault();
304*04fd306cSNickeau        }
305*04fd306cSNickeau
306*04fd306cSNickeau        if ($locale === null) {
307*04fd306cSNickeau            // should never happen but yeah
308*04fd306cSNickeau            $locale = 'en_US';
309*04fd306cSNickeau            LogUtility::error("Internal Error: No default locale could be determined. The locale was set to $locale", DateTag::CANONICAL);
310*04fd306cSNickeau        }
311*04fd306cSNickeau
312*04fd306cSNickeau        /**
313*04fd306cSNickeau         * If the user has set a lang
314*04fd306cSNickeau         * Transform it as locale
315*04fd306cSNickeau         */
316*04fd306cSNickeau        if (strlen(trim($locale)) === 2) {
317*04fd306cSNickeau            $derivedLocale = strtolower($locale) . $localeSeparator . strtoupper($locale);
318*04fd306cSNickeau        } else {
319*04fd306cSNickeau            $derivedLocale = $locale;
320*04fd306cSNickeau        }
321*04fd306cSNickeau
322*04fd306cSNickeau        return $dateTime->formatLocale($pattern, $derivedLocale);
323*04fd306cSNickeau
324*04fd306cSNickeau    }
325*04fd306cSNickeau
32637748cd8SNickeau}
327