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 195*70bbd7f1Sgerardnico $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) { 31704fd306cSNickeau $derivedLocale = strtolower($locale) . $localeSeparator . strtoupper($locale); 31804fd306cSNickeau } else { 31904fd306cSNickeau $derivedLocale = $locale; 32004fd306cSNickeau } 32104fd306cSNickeau 32204fd306cSNickeau return $dateTime->formatLocale($pattern, $derivedLocale); 32304fd306cSNickeau 32404fd306cSNickeau } 32504fd306cSNickeau 32637748cd8SNickeau} 327