1*04fd306cSNickeau<?php 2*04fd306cSNickeau/** 3*04fd306cSNickeau * Helpers 4*04fd306cSNickeau * 5*04fd306cSNickeau * a collection of helper function. normally a function like 6*04fd306cSNickeau * function ($sender, $name, $arguments) $arguments is unscaped arguments and 7*04fd306cSNickeau * is a string, not array 8*04fd306cSNickeau * 9*04fd306cSNickeau * @category Xamin 10*04fd306cSNickeau * @package Handlebars 11*04fd306cSNickeau * @author fzerorubigd <fzerorubigd@gmail.com> 12*04fd306cSNickeau * @author Behrooz Shabani <everplays@gmail.com> 13*04fd306cSNickeau * @author Mardix <https://github.com/mardix> 14*04fd306cSNickeau * @copyright 2012 (c) ParsPooyesh Co 15*04fd306cSNickeau * @copyright 2013 (c) Behrooz Shabani 16*04fd306cSNickeau * @copyright 2014 (c) Mardix 17*04fd306cSNickeau * @license MIT 18*04fd306cSNickeau * @link http://voodoophp.org/docs/handlebars 19*04fd306cSNickeau */ 20*04fd306cSNickeau 21*04fd306cSNickeaunamespace Handlebars; 22*04fd306cSNickeau 23*04fd306cSNickeauuse DateTime; 24*04fd306cSNickeauuse InvalidArgumentException; 25*04fd306cSNickeauuse Traversable; 26*04fd306cSNickeauuse LogicException; 27*04fd306cSNickeau 28*04fd306cSNickeauclass Helpers 29*04fd306cSNickeau{ 30*04fd306cSNickeau /** 31*04fd306cSNickeau * @var array array of helpers 32*04fd306cSNickeau */ 33*04fd306cSNickeau protected $helpers = []; 34*04fd306cSNickeau private $tpl = []; 35*04fd306cSNickeau protected $builtinHelpers = [ 36*04fd306cSNickeau "if", 37*04fd306cSNickeau "each", 38*04fd306cSNickeau "with", 39*04fd306cSNickeau "unless", 40*04fd306cSNickeau "bindAttr", 41*04fd306cSNickeau "upper", // Put all chars in uppercase 42*04fd306cSNickeau "lower", // Put all chars in lowercase 43*04fd306cSNickeau "capitalize", // Capitalize just the first word 44*04fd306cSNickeau "capitalize_words", // Capitalize each words 45*04fd306cSNickeau "reverse", // Reverse a string 46*04fd306cSNickeau "format_date", // Format a date 47*04fd306cSNickeau "inflect", // Inflect the wording based on count ie. 1 album, 10 albums 48*04fd306cSNickeau "default", // If a variable is null, it will use the default instead 49*04fd306cSNickeau "truncate", // Truncate section 50*04fd306cSNickeau "raw", // Return the source as is without converting 51*04fd306cSNickeau "repeat", // Repeat a section 52*04fd306cSNickeau "define", // Define a block to be used using "invoke" 53*04fd306cSNickeau "invoke", // Invoke a block that was defined with "define" 54*04fd306cSNickeau ]; 55*04fd306cSNickeau 56*04fd306cSNickeau /** 57*04fd306cSNickeau * Create new helper container class 58*04fd306cSNickeau * 59*04fd306cSNickeau * @param array $helpers array of name=>$value helpers 60*04fd306cSNickeau * @throws \InvalidArgumentException when $helpers is not an array 61*04fd306cSNickeau * (or traversable) or helper is not a callable 62*04fd306cSNickeau */ 63*04fd306cSNickeau public function __construct($helpers = null) 64*04fd306cSNickeau { 65*04fd306cSNickeau foreach($this->builtinHelpers as $helper) { 66*04fd306cSNickeau $helperName = $this->underscoreToCamelCase($helper); 67*04fd306cSNickeau $this->add($helper, [$this, "helper{$helperName}"]); 68*04fd306cSNickeau } 69*04fd306cSNickeau 70*04fd306cSNickeau if ($helpers != null) { 71*04fd306cSNickeau if (!is_array($helpers) && !$helpers instanceof Traversable) { 72*04fd306cSNickeau throw new InvalidArgumentException( 73*04fd306cSNickeau 'HelperCollection constructor expects an array of helpers' 74*04fd306cSNickeau ); 75*04fd306cSNickeau } 76*04fd306cSNickeau foreach ($helpers as $name => $helper) { 77*04fd306cSNickeau $this->add($name, $helper); 78*04fd306cSNickeau } 79*04fd306cSNickeau } 80*04fd306cSNickeau } 81*04fd306cSNickeau 82*04fd306cSNickeau /** 83*04fd306cSNickeau * Add a new helper to helpers 84*04fd306cSNickeau * 85*04fd306cSNickeau * @param string $name helper name 86*04fd306cSNickeau * @param callable $helper a function as a helper 87*04fd306cSNickeau * 88*04fd306cSNickeau * @throws \InvalidArgumentException if $helper is not a callable 89*04fd306cSNickeau * @return void 90*04fd306cSNickeau */ 91*04fd306cSNickeau public function add($name, $helper) 92*04fd306cSNickeau { 93*04fd306cSNickeau if (!is_callable($helper)) { 94*04fd306cSNickeau throw new InvalidArgumentException("$name Helper is not a callable."); 95*04fd306cSNickeau } 96*04fd306cSNickeau $this->helpers[$name] = $helper; 97*04fd306cSNickeau } 98*04fd306cSNickeau 99*04fd306cSNickeau /** 100*04fd306cSNickeau * Check if $name helper is available 101*04fd306cSNickeau * 102*04fd306cSNickeau * @param string $name helper name 103*04fd306cSNickeau * 104*04fd306cSNickeau * @return boolean 105*04fd306cSNickeau */ 106*04fd306cSNickeau public function has($name) 107*04fd306cSNickeau { 108*04fd306cSNickeau return array_key_exists($name, $this->helpers); 109*04fd306cSNickeau } 110*04fd306cSNickeau 111*04fd306cSNickeau /** 112*04fd306cSNickeau * Get a helper. __magic__ method :) 113*04fd306cSNickeau * 114*04fd306cSNickeau * @param string $name helper name 115*04fd306cSNickeau * 116*04fd306cSNickeau * @throws \InvalidArgumentException if $name is not available 117*04fd306cSNickeau * @return callable helper function 118*04fd306cSNickeau */ 119*04fd306cSNickeau public function __get($name) 120*04fd306cSNickeau { 121*04fd306cSNickeau if (!$this->has($name)) { 122*04fd306cSNickeau throw new InvalidArgumentException('Unknown helper :' . $name); 123*04fd306cSNickeau } 124*04fd306cSNickeau return $this->helpers[$name]; 125*04fd306cSNickeau } 126*04fd306cSNickeau 127*04fd306cSNickeau /** 128*04fd306cSNickeau * Check if $name helper is available __magic__ method :) 129*04fd306cSNickeau * 130*04fd306cSNickeau * @param string $name helper name 131*04fd306cSNickeau * 132*04fd306cSNickeau * @return boolean 133*04fd306cSNickeau * @see Handlebras_Helpers::has 134*04fd306cSNickeau */ 135*04fd306cSNickeau public function __isset($name) 136*04fd306cSNickeau { 137*04fd306cSNickeau return $this->has($name); 138*04fd306cSNickeau } 139*04fd306cSNickeau 140*04fd306cSNickeau /** 141*04fd306cSNickeau * Add a new helper to helpers __magic__ method :) 142*04fd306cSNickeau * 143*04fd306cSNickeau * @param string $name helper name 144*04fd306cSNickeau * @param callable $helper a function as a helper 145*04fd306cSNickeau * 146*04fd306cSNickeau * @return void 147*04fd306cSNickeau */ 148*04fd306cSNickeau public function __set($name, $helper) 149*04fd306cSNickeau { 150*04fd306cSNickeau $this->add($name, $helper); 151*04fd306cSNickeau } 152*04fd306cSNickeau 153*04fd306cSNickeau 154*04fd306cSNickeau /** 155*04fd306cSNickeau * Unset a helper 156*04fd306cSNickeau * 157*04fd306cSNickeau * @param string $name helper name to remove 158*04fd306cSNickeau * @return void 159*04fd306cSNickeau */ 160*04fd306cSNickeau public function __unset($name) 161*04fd306cSNickeau { 162*04fd306cSNickeau unset($this->helpers[$name]); 163*04fd306cSNickeau } 164*04fd306cSNickeau 165*04fd306cSNickeau /** 166*04fd306cSNickeau * Check whether a given helper is present in the collection. 167*04fd306cSNickeau * 168*04fd306cSNickeau * @param string $name helper name 169*04fd306cSNickeau * @throws \InvalidArgumentException if the requested helper is not present. 170*04fd306cSNickeau * @return void 171*04fd306cSNickeau */ 172*04fd306cSNickeau public function remove($name) 173*04fd306cSNickeau { 174*04fd306cSNickeau if (!$this->has($name)) { 175*04fd306cSNickeau throw new InvalidArgumentException('Unknown helper: ' . $name); 176*04fd306cSNickeau } 177*04fd306cSNickeau unset($this->helpers[$name]); 178*04fd306cSNickeau } 179*04fd306cSNickeau 180*04fd306cSNickeau /** 181*04fd306cSNickeau * Clear the helper collection. 182*04fd306cSNickeau * 183*04fd306cSNickeau * Removes all helpers from this collection 184*04fd306cSNickeau * 185*04fd306cSNickeau * @return void 186*04fd306cSNickeau */ 187*04fd306cSNickeau public function clear() 188*04fd306cSNickeau { 189*04fd306cSNickeau $this->helpers = []; 190*04fd306cSNickeau } 191*04fd306cSNickeau 192*04fd306cSNickeau /** 193*04fd306cSNickeau * Check whether the helper collection is empty. 194*04fd306cSNickeau * 195*04fd306cSNickeau * @return boolean True if the collection is empty 196*04fd306cSNickeau */ 197*04fd306cSNickeau public function isEmpty() 198*04fd306cSNickeau { 199*04fd306cSNickeau return empty($this->helpers); 200*04fd306cSNickeau } 201*04fd306cSNickeau 202*04fd306cSNickeau /** 203*04fd306cSNickeau * Create handler for the 'if' helper. 204*04fd306cSNickeau * 205*04fd306cSNickeau * {{#if condition}} 206*04fd306cSNickeau * Something here 207*04fd306cSNickeau * {{else if condition}} 208*04fd306cSNickeau * something else if here 209*04fd306cSNickeau * {{else if condition}} 210*04fd306cSNickeau * something else if here 211*04fd306cSNickeau * {{else}} 212*04fd306cSNickeau * something else here 213*04fd306cSNickeau * {{/if}} 214*04fd306cSNickeau * 215*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 216*04fd306cSNickeau * @param \Handlebars\Context $context context object 217*04fd306cSNickeau * @param array $args passed arguments to helper 218*04fd306cSNickeau * @param string $source part of template that is wrapped 219*04fd306cSNickeau * within helper 220*04fd306cSNickeau * 221*04fd306cSNickeau * @return mixed 222*04fd306cSNickeau */ 223*04fd306cSNickeau public function helperIf($template, $context, $args, $source) 224*04fd306cSNickeau { 225*04fd306cSNickeau $tpl = $template->getEngine()->loadString('{{#if ' . $args . '}}' . $source . '{{/if}}'); 226*04fd306cSNickeau $tree = $tpl->getTree(); 227*04fd306cSNickeau $tmp = $context->get($args); 228*04fd306cSNickeau if ($tmp) { 229*04fd306cSNickeau $token = 'else'; 230*04fd306cSNickeau foreach ($tree[0]['nodes'] as $node) { 231*04fd306cSNickeau $name = trim($node['name'] ?? ''); 232*04fd306cSNickeau if ($name && substr($name, 0, 7) == 'else if') { 233*04fd306cSNickeau $token = $node['name']; 234*04fd306cSNickeau break; 235*04fd306cSNickeau } 236*04fd306cSNickeau } 237*04fd306cSNickeau $template->setStopToken($token); 238*04fd306cSNickeau $buffer = $template->render($context); 239*04fd306cSNickeau $template->setStopToken(false); 240*04fd306cSNickeau $template->discard(); 241*04fd306cSNickeau return $buffer; 242*04fd306cSNickeau } else { 243*04fd306cSNickeau foreach ($tree[0]['nodes'] as $key => $node) { 244*04fd306cSNickeau $name = trim(isset($node['name']) ? $node['name'] : ''); 245*04fd306cSNickeau if ($name && substr($name, 0, 7) == 'else if') { 246*04fd306cSNickeau $template->setStopToken($node['name']); 247*04fd306cSNickeau $template->discard(); 248*04fd306cSNickeau $template->setStopToken(false); 249*04fd306cSNickeau $args = $this->parseArgs($context, substr($name, 7)); 250*04fd306cSNickeau $token = 'else'; 251*04fd306cSNickeau $remains = array_slice($tree[0]['nodes'], $key + 1); 252*04fd306cSNickeau foreach ($remains as $remain) { 253*04fd306cSNickeau $name = trim($remain['name'] ?? ''); 254*04fd306cSNickeau if ($name && substr($name, 0, 7) == 'else if') { 255*04fd306cSNickeau $token = $remain['name']; 256*04fd306cSNickeau break; 257*04fd306cSNickeau } 258*04fd306cSNickeau } 259*04fd306cSNickeau if (isset($args[0]) && $args[0]) { 260*04fd306cSNickeau $template->setStopToken($token); 261*04fd306cSNickeau $buffer = $template->render($context); 262*04fd306cSNickeau $template->setStopToken(false); 263*04fd306cSNickeau $template->discard(); 264*04fd306cSNickeau return $buffer; 265*04fd306cSNickeau } else if ($token != 'else') { 266*04fd306cSNickeau continue; 267*04fd306cSNickeau } else { 268*04fd306cSNickeau return $this->renderElse($template, $context); 269*04fd306cSNickeau } 270*04fd306cSNickeau } 271*04fd306cSNickeau } 272*04fd306cSNickeau return $this->renderElse($template, $context); 273*04fd306cSNickeau } 274*04fd306cSNickeau } 275*04fd306cSNickeau 276*04fd306cSNickeau 277*04fd306cSNickeau /** 278*04fd306cSNickeau * Create handler for the 'each' helper. 279*04fd306cSNickeau * example {{#each people}} {{name}} {{/each}} 280*04fd306cSNickeau * example with slice: {{#each people[0:10]}} {{name}} {{/each}} 281*04fd306cSNickeau * example with else 282*04fd306cSNickeau * {{#each Array}} 283*04fd306cSNickeau * {{.}} 284*04fd306cSNickeau * {{else}} 285*04fd306cSNickeau * Nothing found 286*04fd306cSNickeau * {{/each}} 287*04fd306cSNickeau * 288*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 289*04fd306cSNickeau * @param \Handlebars\Context $context context object 290*04fd306cSNickeau * @param array $args passed arguments to helper 291*04fd306cSNickeau * @param string $source part of template that is wrapped 292*04fd306cSNickeau * within helper 293*04fd306cSNickeau * 294*04fd306cSNickeau * @return mixed 295*04fd306cSNickeau */ 296*04fd306cSNickeau public function helperEach($template, $context, $args, $source) 297*04fd306cSNickeau { 298*04fd306cSNickeau list($keyname, $slice_start, $slice_end) = $this->extractSlice($args); 299*04fd306cSNickeau $tmp = $context->get($keyname); 300*04fd306cSNickeau 301*04fd306cSNickeau if (is_array($tmp) || $tmp instanceof Traversable) { 302*04fd306cSNickeau $tmp = array_slice($tmp, $slice_start ?? 0, $slice_end, true); 303*04fd306cSNickeau $buffer = ''; 304*04fd306cSNickeau $islist = array_values($tmp) === $tmp; 305*04fd306cSNickeau 306*04fd306cSNickeau if (is_array($tmp) && ! count($tmp)) { 307*04fd306cSNickeau return $this->renderElse($template, $context); 308*04fd306cSNickeau } else { 309*04fd306cSNickeau 310*04fd306cSNickeau $itemCount = -1; 311*04fd306cSNickeau if ($islist) { 312*04fd306cSNickeau $itemCount = count($tmp); 313*04fd306cSNickeau } 314*04fd306cSNickeau 315*04fd306cSNickeau foreach ($tmp as $key => $var) { 316*04fd306cSNickeau $tpl = clone $template; 317*04fd306cSNickeau if ($islist) { 318*04fd306cSNickeau $context->pushIndex($key); 319*04fd306cSNickeau 320*04fd306cSNickeau // If data variables are enabled, push the data related to this #each context 321*04fd306cSNickeau if ($template->getEngine()->isDataVariablesEnabled()) { 322*04fd306cSNickeau $context->pushData([ 323*04fd306cSNickeau Context::DATA_KEY => $key, 324*04fd306cSNickeau Context::DATA_INDEX => $key, 325*04fd306cSNickeau Context::DATA_LAST => $key == ($itemCount - 1), 326*04fd306cSNickeau Context::DATA_FIRST => $key == 0, 327*04fd306cSNickeau ]); 328*04fd306cSNickeau } 329*04fd306cSNickeau } else { 330*04fd306cSNickeau $context->pushKey($key); 331*04fd306cSNickeau 332*04fd306cSNickeau // If data variables are enabled, push the data related to this #each context 333*04fd306cSNickeau if ($template->getEngine()->isDataVariablesEnabled()) { 334*04fd306cSNickeau $context->pushData([ 335*04fd306cSNickeau Context::DATA_KEY => $key, 336*04fd306cSNickeau ]); 337*04fd306cSNickeau } 338*04fd306cSNickeau } 339*04fd306cSNickeau $context->push($var); 340*04fd306cSNickeau $tpl->setStopToken('else'); 341*04fd306cSNickeau $buffer .= $tpl->render($context); 342*04fd306cSNickeau $context->pop(); 343*04fd306cSNickeau if ($islist) { 344*04fd306cSNickeau $context->popIndex(); 345*04fd306cSNickeau } else { 346*04fd306cSNickeau $context->popKey(); 347*04fd306cSNickeau } 348*04fd306cSNickeau 349*04fd306cSNickeau if ($template->getEngine()->isDataVariablesEnabled()) { 350*04fd306cSNickeau $context->popData(); 351*04fd306cSNickeau } 352*04fd306cSNickeau } 353*04fd306cSNickeau return $buffer; 354*04fd306cSNickeau } 355*04fd306cSNickeau } else { 356*04fd306cSNickeau return $this->renderElse($template, $context); 357*04fd306cSNickeau } 358*04fd306cSNickeau } 359*04fd306cSNickeau 360*04fd306cSNickeau /** 361*04fd306cSNickeau * Applying the DRY principle here. 362*04fd306cSNickeau * This method help us render {{else}} portion of a block 363*04fd306cSNickeau * @param \Handlebars\Template $template 364*04fd306cSNickeau * @param \Handlebars\Context $context 365*04fd306cSNickeau * @return string 366*04fd306cSNickeau */ 367*04fd306cSNickeau private function renderElse($template, $context) 368*04fd306cSNickeau { 369*04fd306cSNickeau $template->setStopToken('else'); 370*04fd306cSNickeau $template->discard(); 371*04fd306cSNickeau $template->setStopToken(false); 372*04fd306cSNickeau return $template->render($context); 373*04fd306cSNickeau } 374*04fd306cSNickeau 375*04fd306cSNickeau 376*04fd306cSNickeau /** 377*04fd306cSNickeau * Create handler for the 'unless' helper. 378*04fd306cSNickeau * {{#unless condition}} 379*04fd306cSNickeau * Something here 380*04fd306cSNickeau * {{else}} 381*04fd306cSNickeau * something else here 382*04fd306cSNickeau * {{/unless}} 383*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 384*04fd306cSNickeau * @param \Handlebars\Context $context context object 385*04fd306cSNickeau * @param array $args passed arguments to helper 386*04fd306cSNickeau * @param string $source part of template that is wrapped 387*04fd306cSNickeau * within helper 388*04fd306cSNickeau * 389*04fd306cSNickeau * @return mixed 390*04fd306cSNickeau */ 391*04fd306cSNickeau public function helperUnless($template, $context, $args, $source) 392*04fd306cSNickeau { 393*04fd306cSNickeau $tmp = $context->get($args); 394*04fd306cSNickeau if (!$tmp) { 395*04fd306cSNickeau $template->setStopToken('else'); 396*04fd306cSNickeau $buffer = $template->render($context); 397*04fd306cSNickeau $template->setStopToken(false); 398*04fd306cSNickeau $template->discard(); 399*04fd306cSNickeau return $buffer; 400*04fd306cSNickeau } else { 401*04fd306cSNickeau return $this->renderElse($template, $context); 402*04fd306cSNickeau } 403*04fd306cSNickeau } 404*04fd306cSNickeau 405*04fd306cSNickeau /** 406*04fd306cSNickeau * Create handler for the 'with' helper. 407*04fd306cSNickeau * Needed for compatibility with PHP 5.2 since it doesn't support anonymous 408*04fd306cSNickeau * functions. 409*04fd306cSNickeau * 410*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 411*04fd306cSNickeau * @param \Handlebars\Context $context context object 412*04fd306cSNickeau * @param array $args passed arguments to helper 413*04fd306cSNickeau * @param string $source part of template that is wrapped 414*04fd306cSNickeau * within helper 415*04fd306cSNickeau * 416*04fd306cSNickeau * @return mixed 417*04fd306cSNickeau */ 418*04fd306cSNickeau public function helperWith($template, $context, $args, $source) 419*04fd306cSNickeau { 420*04fd306cSNickeau $tmp = $context->get($args); 421*04fd306cSNickeau $context->push($tmp); 422*04fd306cSNickeau $buffer = $template->render($context); 423*04fd306cSNickeau $context->pop(); 424*04fd306cSNickeau 425*04fd306cSNickeau return $buffer; 426*04fd306cSNickeau } 427*04fd306cSNickeau 428*04fd306cSNickeau /** 429*04fd306cSNickeau * Create handler for the 'bindAttr' helper. 430*04fd306cSNickeau * Needed for compatibility with PHP 5.2 since it doesn't support anonymous 431*04fd306cSNickeau * functions. 432*04fd306cSNickeau * 433*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 434*04fd306cSNickeau * @param \Handlebars\Context $context context object 435*04fd306cSNickeau * @param array $args passed arguments to helper 436*04fd306cSNickeau * @param string $source part of template that is wrapped 437*04fd306cSNickeau * within helper 438*04fd306cSNickeau * 439*04fd306cSNickeau * @return mixed 440*04fd306cSNickeau */ 441*04fd306cSNickeau public function helperBindAttr($template, $context, $args, $source) 442*04fd306cSNickeau { 443*04fd306cSNickeau return $args; 444*04fd306cSNickeau } 445*04fd306cSNickeau 446*04fd306cSNickeau /** 447*04fd306cSNickeau * To uppercase string 448*04fd306cSNickeau * 449*04fd306cSNickeau * {{#upper data}} 450*04fd306cSNickeau * 451*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 452*04fd306cSNickeau * @param \Handlebars\Context $context context object 453*04fd306cSNickeau * @param array $args passed arguments to helper 454*04fd306cSNickeau * @param string $source part of template that is wrapped 455*04fd306cSNickeau * within helper 456*04fd306cSNickeau * 457*04fd306cSNickeau * @return string 458*04fd306cSNickeau */ 459*04fd306cSNickeau public function helperUpper($template, $context, $args, $source) 460*04fd306cSNickeau { 461*04fd306cSNickeau return strtoupper($context->get($args)); 462*04fd306cSNickeau } 463*04fd306cSNickeau 464*04fd306cSNickeau /** 465*04fd306cSNickeau * To lowercase string 466*04fd306cSNickeau * 467*04fd306cSNickeau * {{#lower data}} 468*04fd306cSNickeau * 469*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 470*04fd306cSNickeau * @param \Handlebars\Context $context context object 471*04fd306cSNickeau * @param array $args passed arguments to helper 472*04fd306cSNickeau * @param string $source part of template that is wrapped 473*04fd306cSNickeau * within helper 474*04fd306cSNickeau * 475*04fd306cSNickeau * @return string 476*04fd306cSNickeau */ 477*04fd306cSNickeau public function helperLower($template, $context, $args, $source) 478*04fd306cSNickeau { 479*04fd306cSNickeau return strtolower($context->get($args)); 480*04fd306cSNickeau } 481*04fd306cSNickeau 482*04fd306cSNickeau /** 483*04fd306cSNickeau * to capitalize first letter 484*04fd306cSNickeau * 485*04fd306cSNickeau * {{#capitalize}} 486*04fd306cSNickeau * 487*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 488*04fd306cSNickeau * @param \Handlebars\Context $context context object 489*04fd306cSNickeau * @param array $args passed arguments to helper 490*04fd306cSNickeau * @param string $source part of template that is wrapped 491*04fd306cSNickeau * within helper 492*04fd306cSNickeau * 493*04fd306cSNickeau * @return string 494*04fd306cSNickeau */ 495*04fd306cSNickeau public function helperCapitalize($template, $context, $args, $source) 496*04fd306cSNickeau { 497*04fd306cSNickeau return ucfirst($context->get($args)); 498*04fd306cSNickeau } 499*04fd306cSNickeau 500*04fd306cSNickeau /** 501*04fd306cSNickeau * To capitalize first letter in each word 502*04fd306cSNickeau * 503*04fd306cSNickeau * {{#capitalize_words data}} 504*04fd306cSNickeau * 505*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 506*04fd306cSNickeau * @param \Handlebars\Context $context context object 507*04fd306cSNickeau * @param array $args passed arguments to helper 508*04fd306cSNickeau * @param string $source part of template that is wrapped 509*04fd306cSNickeau * within helper 510*04fd306cSNickeau * 511*04fd306cSNickeau * @return string 512*04fd306cSNickeau */ 513*04fd306cSNickeau public function helperCapitalizeWords($template, $context, $args, $source) 514*04fd306cSNickeau { 515*04fd306cSNickeau return ucwords($context->get($args)); 516*04fd306cSNickeau } 517*04fd306cSNickeau 518*04fd306cSNickeau /** 519*04fd306cSNickeau * To reverse a string 520*04fd306cSNickeau * 521*04fd306cSNickeau * {{#reverse data}} 522*04fd306cSNickeau * 523*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 524*04fd306cSNickeau * @param \Handlebars\Context $context context object 525*04fd306cSNickeau * @param array $args passed arguments to helper 526*04fd306cSNickeau * @param string $source part of template that is wrapped 527*04fd306cSNickeau * within helper 528*04fd306cSNickeau * 529*04fd306cSNickeau * @return string 530*04fd306cSNickeau */ 531*04fd306cSNickeau public function helperReverse($template, $context, $args, $source) 532*04fd306cSNickeau { 533*04fd306cSNickeau return strrev($context->get($args)); 534*04fd306cSNickeau } 535*04fd306cSNickeau 536*04fd306cSNickeau /** 537*04fd306cSNickeau * Format a date 538*04fd306cSNickeau * 539*04fd306cSNickeau * {{#format_date date 'Y-m-d @h:i:s'}} 540*04fd306cSNickeau * 541*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 542*04fd306cSNickeau * @param \Handlebars\Context $context context object 543*04fd306cSNickeau * @param array $args passed arguments to helper 544*04fd306cSNickeau * @param string $source part of template that is wrapped 545*04fd306cSNickeau * within helper 546*04fd306cSNickeau * 547*04fd306cSNickeau * @return mixed 548*04fd306cSNickeau */ 549*04fd306cSNickeau public function helperFormatDate($template, $context, $args, $source) 550*04fd306cSNickeau { 551*04fd306cSNickeau preg_match("/(.*?)\s+(?:(?:\"|\')(.*?)(?:\"|\'))/", $args, $m); 552*04fd306cSNickeau $keyname = $m[1]; 553*04fd306cSNickeau $format = $m[2]; 554*04fd306cSNickeau 555*04fd306cSNickeau $date = $context->get($keyname); 556*04fd306cSNickeau if ($format) { 557*04fd306cSNickeau $dt = new DateTime; 558*04fd306cSNickeau if (is_numeric($date)) { 559*04fd306cSNickeau $dt = (new DateTime)->setTimestamp($date); 560*04fd306cSNickeau } else { 561*04fd306cSNickeau $dt = new DateTime($date); 562*04fd306cSNickeau } 563*04fd306cSNickeau return $dt->format($format); 564*04fd306cSNickeau } else { 565*04fd306cSNickeau return $date; 566*04fd306cSNickeau } 567*04fd306cSNickeau } 568*04fd306cSNickeau 569*04fd306cSNickeau /** 570*04fd306cSNickeau * {{inflect count 'album' 'albums'}} 571*04fd306cSNickeau * {{inflect count '%d album' '%d albums'}} 572*04fd306cSNickeau * 573*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 574*04fd306cSNickeau * @param \Handlebars\Context $context context object 575*04fd306cSNickeau * @param array $args passed arguments to helper 576*04fd306cSNickeau * @param string $source part of template that is wrapped 577*04fd306cSNickeau * within helper 578*04fd306cSNickeau * 579*04fd306cSNickeau * @return mixed 580*04fd306cSNickeau */ 581*04fd306cSNickeau public function helperInflect($template, $context, $args, $source) 582*04fd306cSNickeau { 583*04fd306cSNickeau preg_match("/(.*?)\s+(?:(?:\"|\')(.*?)(?:\"|\'))\s+(?:(?:\"|\')(.*?)(?:\"|\'))/", $args, $m); 584*04fd306cSNickeau $keyname = $m[1]; 585*04fd306cSNickeau $singular = $m[2]; 586*04fd306cSNickeau $plurial = $m[3]; 587*04fd306cSNickeau $value = $context->get($keyname); 588*04fd306cSNickeau $inflect = ($value <= 1) ? $singular : $plurial; 589*04fd306cSNickeau return sprintf($inflect, $value); 590*04fd306cSNickeau } 591*04fd306cSNickeau 592*04fd306cSNickeau /** 593*04fd306cSNickeau * Provide a default fallback 594*04fd306cSNickeau * 595*04fd306cSNickeau * {{default title "No title available"}} 596*04fd306cSNickeau * 597*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 598*04fd306cSNickeau * @param \Handlebars\Context $context context object 599*04fd306cSNickeau * @param array $args passed arguments to helper 600*04fd306cSNickeau * @param string $source part of template that is wrapped 601*04fd306cSNickeau * within helper 602*04fd306cSNickeau * 603*04fd306cSNickeau * @return string 604*04fd306cSNickeau */ 605*04fd306cSNickeau public function helperDefault($template, $context, $args, $source) 606*04fd306cSNickeau { 607*04fd306cSNickeau preg_match("/(.*?)\s+(?:(?:\"|\')(.*?)(?:\"|\'))/", trim($args), $m); 608*04fd306cSNickeau $keyname = $m[1]; 609*04fd306cSNickeau $default = $m[2]; 610*04fd306cSNickeau $value = $context->get($keyname); 611*04fd306cSNickeau return ($value) ?: $default; 612*04fd306cSNickeau } 613*04fd306cSNickeau 614*04fd306cSNickeau /** 615*04fd306cSNickeau * Truncate a string to a length, and append and ellipsis if provided 616*04fd306cSNickeau * {{#truncate content 5 "..."}} 617*04fd306cSNickeau * 618*04fd306cSNickeau * 619*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 620*04fd306cSNickeau * @param \Handlebars\Context $context context object 621*04fd306cSNickeau * @param array $args passed arguments to helper 622*04fd306cSNickeau * @param string $source part of template that is wrapped 623*04fd306cSNickeau * within helper 624*04fd306cSNickeau * 625*04fd306cSNickeau * @return string 626*04fd306cSNickeau */ 627*04fd306cSNickeau public function helperTruncate($template, $context, $args, $source) 628*04fd306cSNickeau { 629*04fd306cSNickeau preg_match("/(.*?)\s+(.*?)\s+(?:(?:\"|\')(.*?)(?:\"|\'))/", trim($args), $m); 630*04fd306cSNickeau $keyname = $m[1]; 631*04fd306cSNickeau $limit = $m[2]; 632*04fd306cSNickeau $ellipsis = $m[3]; 633*04fd306cSNickeau $value = substr($context->get($keyname), 0, $limit); 634*04fd306cSNickeau if ($ellipsis && strlen($context->get($keyname)) > $limit) { 635*04fd306cSNickeau $value .= $ellipsis; 636*04fd306cSNickeau } 637*04fd306cSNickeau return $value; 638*04fd306cSNickeau } 639*04fd306cSNickeau 640*04fd306cSNickeau /** 641*04fd306cSNickeau * Return the data source as is 642*04fd306cSNickeau * 643*04fd306cSNickeau * {{#raw}} {{/raw}} 644*04fd306cSNickeau * 645*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 646*04fd306cSNickeau * @param \Handlebars\Context $context context object 647*04fd306cSNickeau * @param array $args passed arguments to helper 648*04fd306cSNickeau * @param string $source part of template that is wrapped 649*04fd306cSNickeau * within helper 650*04fd306cSNickeau * 651*04fd306cSNickeau * @return mixed 652*04fd306cSNickeau */ 653*04fd306cSNickeau public function helperRaw($template, $context, $args, $source) 654*04fd306cSNickeau { 655*04fd306cSNickeau return $source; 656*04fd306cSNickeau } 657*04fd306cSNickeau 658*04fd306cSNickeau /** 659*04fd306cSNickeau * Repeat section $x times. 660*04fd306cSNickeau * 661*04fd306cSNickeau * {{#repeat 10}} 662*04fd306cSNickeau * This section will be repeated 10 times 663*04fd306cSNickeau * {{/repeat}} 664*04fd306cSNickeau * 665*04fd306cSNickeau * 666*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 667*04fd306cSNickeau * @param \Handlebars\Context $context context object 668*04fd306cSNickeau * @param array $args passed arguments to helper 669*04fd306cSNickeau * @param string $source part of template that is wrapped 670*04fd306cSNickeau * within helper 671*04fd306cSNickeau * 672*04fd306cSNickeau * @return string 673*04fd306cSNickeau */ 674*04fd306cSNickeau public function helperRepeat($template, $context, $args, $source) 675*04fd306cSNickeau { 676*04fd306cSNickeau $buffer = $template->render($context); 677*04fd306cSNickeau return str_repeat($buffer, intval($args)); 678*04fd306cSNickeau } 679*04fd306cSNickeau 680*04fd306cSNickeau 681*04fd306cSNickeau /** 682*04fd306cSNickeau * Define a section to be used later by using 'invoke' 683*04fd306cSNickeau * 684*04fd306cSNickeau * --> Define a section: hello 685*04fd306cSNickeau * {{#define hello}} 686*04fd306cSNickeau * Hello World! 687*04fd306cSNickeau * 688*04fd306cSNickeau * How is everything? 689*04fd306cSNickeau * {{/define}} 690*04fd306cSNickeau * 691*04fd306cSNickeau * --> This is how it is called 692*04fd306cSNickeau * {{#invoke hello}} 693*04fd306cSNickeau * 694*04fd306cSNickeau * 695*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 696*04fd306cSNickeau * @param \Handlebars\Context $context context object 697*04fd306cSNickeau * @param array $args passed arguments to helper 698*04fd306cSNickeau * @param string $source part of template that is wrapped 699*04fd306cSNickeau * within helper 700*04fd306cSNickeau * 701*04fd306cSNickeau * @return null 702*04fd306cSNickeau */ 703*04fd306cSNickeau public function helperDefine($template, $context, $args, $source) 704*04fd306cSNickeau { 705*04fd306cSNickeau $this->tpl["DEFINE"][$args] = clone($template); 706*04fd306cSNickeau } 707*04fd306cSNickeau 708*04fd306cSNickeau /** 709*04fd306cSNickeau * Invoke a section that was created using 'define' 710*04fd306cSNickeau * 711*04fd306cSNickeau * --> Define a section: hello 712*04fd306cSNickeau * {{#define hello}} 713*04fd306cSNickeau * Hello World! 714*04fd306cSNickeau * 715*04fd306cSNickeau * How is everything? 716*04fd306cSNickeau * {{/define}} 717*04fd306cSNickeau * 718*04fd306cSNickeau * --> This is how it is called 719*04fd306cSNickeau * {{#invoke hello}} 720*04fd306cSNickeau * 721*04fd306cSNickeau * 722*04fd306cSNickeau * @param \Handlebars\Template $template template that is being rendered 723*04fd306cSNickeau * @param \Handlebars\Context $context context object 724*04fd306cSNickeau * @param array $args passed arguments to helper 725*04fd306cSNickeau * @param string $source part of template that is wrapped 726*04fd306cSNickeau * within helper 727*04fd306cSNickeau * 728*04fd306cSNickeau * @return null 729*04fd306cSNickeau */ 730*04fd306cSNickeau public function helperInvoke($template, $context, $args, $source) 731*04fd306cSNickeau { 732*04fd306cSNickeau if (! isset($this->tpl["DEFINE"][$args])) { 733*04fd306cSNickeau throw new LogicException("Can't INVOKE '{$args}'. '{$args}' was not DEFINE "); 734*04fd306cSNickeau } 735*04fd306cSNickeau return $this->tpl["DEFINE"][$args]->render($context); 736*04fd306cSNickeau } 737*04fd306cSNickeau 738*04fd306cSNickeau 739*04fd306cSNickeau /** 740*04fd306cSNickeau * Change underscore helper name to CamelCase 741*04fd306cSNickeau * 742*04fd306cSNickeau * @param string $string 743*04fd306cSNickeau * @return string 744*04fd306cSNickeau */ 745*04fd306cSNickeau private function underscoreToCamelCase($string) 746*04fd306cSNickeau { 747*04fd306cSNickeau return str_replace(' ', '', ucwords(str_replace('_', ' ', $string))); 748*04fd306cSNickeau } 749*04fd306cSNickeau 750*04fd306cSNickeau /** 751*04fd306cSNickeau * slice 752*04fd306cSNickeau * Allow to split the data that will be returned 753*04fd306cSNickeau * #loop[start:end] => starts at start trhough end -1 754*04fd306cSNickeau * #loop[start:] = Starts at start though the rest of the array 755*04fd306cSNickeau * #loop[:end] = Starts at the beginning through end -1 756*04fd306cSNickeau * #loop[:] = A copy of the whole array 757*04fd306cSNickeau * 758*04fd306cSNickeau * #loop[-1] 759*04fd306cSNickeau * #loop[-2:] = Last two items 760*04fd306cSNickeau * #loop[:-2] = Everything except last two items 761*04fd306cSNickeau * 762*04fd306cSNickeau * @param string $string 763*04fd306cSNickeau * @return Array [tag_name, slice_start, slice_end] 764*04fd306cSNickeau */ 765*04fd306cSNickeau private function extractSlice($string) 766*04fd306cSNickeau { 767*04fd306cSNickeau preg_match("/^([\w\._\-]+)(?:\[([\-0-9]*?:[\-0-9]*?)\])?/i", $string, $m); 768*04fd306cSNickeau $slice_start = $slice_end = null; 769*04fd306cSNickeau if (isset($m[2])) { 770*04fd306cSNickeau list($slice_start, $slice_end) = explode(":", $m[2]); 771*04fd306cSNickeau $slice_start = (int) $slice_start; 772*04fd306cSNickeau $slice_end = $slice_end ? (int) $slice_end : null; 773*04fd306cSNickeau } 774*04fd306cSNickeau return [$m[1], $slice_start, $slice_end]; 775*04fd306cSNickeau } 776*04fd306cSNickeau 777*04fd306cSNickeau /** 778*04fd306cSNickeau * Parse avariable from current args 779*04fd306cSNickeau * 780*04fd306cSNickeau * @param \Handlebars\Context $context context object 781*04fd306cSNickeau * @param array $args passed arguments to helper 782*04fd306cSNickeau * @return array 783*04fd306cSNickeau */ 784*04fd306cSNickeau private function parseArgs($context, $args) 785*04fd306cSNickeau { 786*04fd306cSNickeau $args = preg_replace('/\s+/', ' ', trim($args)); 787*04fd306cSNickeau $eles = explode(' ', $args); 788*04fd306cSNickeau foreach ($eles as $key => $ele) { 789*04fd306cSNickeau if (in_array(substr($ele, 0, 1), ['\'', '"'])) { 790*04fd306cSNickeau $val = trim($ele, '\'"'); 791*04fd306cSNickeau } else if (is_numeric($ele)) { 792*04fd306cSNickeau $val = $ele; 793*04fd306cSNickeau } else { 794*04fd306cSNickeau $val = $context->get($ele); 795*04fd306cSNickeau } 796*04fd306cSNickeau $eles[$key] = $val; 797*04fd306cSNickeau } 798*04fd306cSNickeau return $eles; 799*04fd306cSNickeau } 800*04fd306cSNickeau} 801