xref: /template/strap/vendor/salesforce/handlebars-php/src/Handlebars/Helpers.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
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