Skip to content

Commit 10042a6

Browse files
committed
Restore partial and helper resolver options
Closes #1
1 parent 3bcc922 commit 10042a6

8 files changed

Lines changed: 74 additions & 8 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ echo $template(['first' => 'John']); // Error: Runtime: [last] does not exist
6565
* `ignoreStandalone`: Disables standalone tag removal. When set, blocks and partials that are on their own line will not remove the whitespace on that line.
6666
* `explicitPartialContext`: Disables implicit context for partials. When enabled, partials that are not passed a context value will execute against an empty object.
6767
* `helpers`: Provide a key => value array of custom helper functions.
68+
* `helperResolver`: A closure which will be called for any helper not in the `helpers` array to return a function for it.
6869
* `partials`: Provide a key => value array of custom partial templates.
70+
* `partialResolver`: A closure which will be called for any partial not in the `partials` array to return a template for it.
6971

7072
## Custom Helpers
7173

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"require-dev": {
2626
"friendsofphp/php-cs-fixer": "^3.75",
2727
"jbboehr/handlebars-spec": "dev-master",
28-
"phpstan/phpstan": "^2.1.12",
28+
"phpstan/phpstan": "^2.1.14",
2929
"phpunit/phpunit": "^11.5"
3030
},
3131
"autoload": {

composer.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Context.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace DevTheorem\Handlebars;
44

5+
use Closure;
6+
57
/**
68
* @internal
79
*/
@@ -18,9 +20,11 @@ final class Context
1820
* @param array<string, true> $usedHelpers
1921
* @param array<mixed> $parsed
2022
* @param array<string, string> $partials
23+
* @param null|Closure(Context, string):(string|null) $partialResolver
2124
* @param array<mixed> $partialBlock
2225
* @param array<mixed> $inlinePartial
2326
* @param array<string, callable> $helpers
27+
* @param null|Closure(Context, string):(Closure|null) $helperResolver
2428
*/
2529
public function __construct(
2630
public readonly Options $options,
@@ -42,9 +46,11 @@ public function __construct(
4246
public bool $compile = false,
4347
public array $parsed = [],
4448
public array $partials = [],
49+
public ?Closure $partialResolver = null,
4550
public array $partialBlock = [],
4651
public array $inlinePartial = [],
4752
public array $helpers = [],
53+
public ?Closure $helperResolver = null,
4854
public string|false $rawBlock = false,
4955
public readonly string $startChar = '{',
5056
public readonly string $separator = '.',
@@ -56,7 +62,9 @@ public function __construct(
5662
public readonly string $fEnd = ';',
5763
) {
5864
$this->partials = $options->partials;
65+
$this->partialResolver = $options->partialResolver;
5966
$this->helpers = $options->helpers;
67+
$this->helperResolver = $options->helperResolver;
6068
}
6169

6270
/**

src/Options.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
namespace DevTheorem\Handlebars;
44

5+
use Closure;
6+
57
readonly class Options
68
{
79
/**
810
* @param array<string, callable> $helpers
11+
* @param null|Closure(Context, string):(Closure|null) $helperResolver
912
* @param array<string, string> $partials
13+
* @param null|Closure(Context, string):(string|null) $partialResolver
1014
*/
1115
public function __construct(
1216
public bool $knownHelpersOnly = false,
@@ -16,6 +20,8 @@ public function __construct(
1620
public bool $ignoreStandalone = false,
1721
public bool $explicitPartialContext = false,
1822
public array $helpers = [],
23+
public ?Closure $helperResolver = null,
1924
public array $partials = [],
25+
public ?Closure $partialResolver = null,
2026
) {}
2127
}

src/Partial.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public static function resolve(Context $context, string &$name): ?string
5555
if (isset($context->partials[$name])) {
5656
return $context->partials[$name];
5757
}
58+
if ($context->partialResolver) {
59+
return ($context->partialResolver)($context, $name);
60+
}
5861
return null;
5962
}
6063

src/Validator.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,20 @@ public static function resolveHelper(Context $context, array $vars): bool
658658
return false;
659659
}
660660

661-
return isset($context->helpers[$vars[0][0]]);
661+
$name = $vars[0][0];
662+
if (isset($context->helpers[$name])) {
663+
return true;
664+
}
665+
666+
if ($context->helperResolver) {
667+
$helper = ($context->helperResolver)($context, $name);
668+
if ($helper) {
669+
$context->helpers[$name] = $helper;
670+
return true;
671+
}
672+
}
673+
674+
return false;
662675
}
663676

664677
/**

tests/RegressionTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace DevTheorem\Handlebars\Test;
44

5+
use DevTheorem\Handlebars\Context;
56
use DevTheorem\Handlebars\Handlebars;
67
use DevTheorem\Handlebars\HelperOptions;
78
use DevTheorem\Handlebars\Options;
@@ -829,6 +830,29 @@ public static function issueProvider(): array
829830
'expected' => '3',
830831
],
831832

833+
[
834+
'id' => 201,
835+
'template' => '{{foo "world"}}',
836+
'options' => new Options(
837+
helperResolver: function () {
838+
return fn(string $name) => "Hello, $name";
839+
},
840+
),
841+
'expected' => 'Hello, world',
842+
],
843+
[
844+
'id' => 201,
845+
'template' => '{{#foo "test"}}World{{/foo}}',
846+
'options' => new Options(
847+
helperResolver: function (Context $cx, string $name) {
848+
return function ($name, HelperOptions $options) {
849+
return "$name = " . $options->fn();
850+
};
851+
},
852+
),
853+
'expected' => 'test = World',
854+
],
855+
832856
[
833857
'id' => 204,
834858
'template' => '{{#> test name="A"}}B{{/test}}{{#> test name="C"}}D{{/test}}',
@@ -2030,6 +2054,16 @@ public static function issueProvider(): array
20302054
'expected' => 'inline\'partial',
20312055
],
20322056

2057+
[
2058+
'template' => '{{>foo}} and {{>bar}}',
2059+
'options' => new Options(
2060+
partialResolver: function (Context $context, string $name) {
2061+
return "PARTIAL: $name";
2062+
},
2063+
),
2064+
'expected' => 'PARTIAL: foo and PARTIAL: bar',
2065+
],
2066+
20332067
[
20342068
'template' => "{{#> testPartial}}\n ERROR: testPartial is not found!\n {{#> innerPartial}}\n ERROR: innerPartial is not found!\n ERROR: innerPartial is not found!\n {{/innerPartial}}\n ERROR: testPartial is not found!\n {{/testPartial}}",
20352069
'expected' => " ERROR: testPartial is not found!\n ERROR: innerPartial is not found!\n ERROR: innerPartial is not found!\n ERROR: testPartial is not found!\n",

0 commit comments

Comments
 (0)