Skip to content

Releases: devtheorem/php-handlebars

1.2.3 Hoisted Closures

11 Apr 00:02

Choose a tag to compare

Changed

  • Improved rendering performance by hoisting the closures for block bodies and {{else}} clauses, avoiding unnecessary re-allocation on repeated invocations.

Fixed

  • Failure to call ambiguous helper (e.g. {{foo}}) in strict mode.
  • blockParams count in HelperOptions for inverse helper calls.

1.2.2 Faithful Dispatch

06 Apr 03:52

Choose a tag to compare

Changed

  • Better aligned compiler and runtime structure with Handlebars.js, fixing numerous edge cases related to helpers and @data variables.

Fixed

  • ../ expressions inside {{else}} blocks of {{#if}}, {{#unless}}, {{#with}}, and sections invoking blockHelperMissing resolved to the wrong context level.
  • A missing helper called via a @data variable or multi-segment path in a subexpression failed to invoke helperMissing.
  • A non-function context property used as a helper (e.g. {{foo "arg"}} where foo is not a closure) incorrectly called helperMissing rather than throwing a distinct error.
  • No error thrown when calling a missing helper via a multi-segment path with arguments (e.g. {{foo.bar "arg"}}).
  • Closures in context data could not be used as block helpers (e.g. {{#fn}}...{{/fn}} where fn is a closure).
  • Closures in context data or @data variables failed to be passed HelperOptions as the last argument in certain cases.
  • Templates with hash arguments on complex paths (e.g. {{foo.bar arg=val}}) were not compiled correctly.
  • Closures in context data were not invoked when accessed via a multi-segment path (e.g. {{foo.bar}}), or via a literal path (e.g. {{"foo"}}) in knownHelpersOnly mode.
  • @data variables incorrectly took priority over helpers with the same name.
  • knownHelpersOnly was not enforced for @data expressions or complex paths used with arguments.

1.2.1 Optimal Simplification

02 Apr 21:01

Choose a tag to compare

Changed

  • Updated to PHP Handlebars Parser 2.0, which removed unnecessary options state from the parser and made it possible to reuse the same parser instance when compiling multiple templates (e.g. for runtime partials). The PHP Handlebars API hasn't changed, but it now performs better and has significantly lower memory usage when compiling two or more templates.
  • Options, HelperOptions, and SafeString are now final, since there's no reason to ever extend them.

Removed

  • Unnecessary internal StringObject class.

1.2.0 Data Frames

30 Mar 05:22

Choose a tag to compare

Added

  • Handlebars::createFrame(): creates a child @data frame inheriting fields from a parent frame, equivalent to Handlebars.createFrame() in Handlebars.js.

Changed

  • To align with Handlebars.js, @data variables passed to fn() or inverse() by block helpers are no longer automatically merged with parent data and @root. For example, if a helper calls fn() with ['data' => ['index' => 0]] as the second parameter, @index will now be the only @data variable inside the block. To set @-prefixed variables while still inheriting parent @data variables, call Handlebars::createFrame($options->data) to create an isolated child frame. Then assign new keys to it before passing it to the data option of fn() or inverse().
  • Handlebars::escapeExpression() now uses strtr() instead of str_replace() for better performance.

Fixed

  • Block param path lookups and literal path lookups (e.g. {{"foo"}}, {{#"foo"}}) in strict mode no longer incorrectly throw when the key exists but its value is null.
  • Inline partials defined inside an {{else}} block no longer leak into the surrounding scope.

1.1.0 Dynamic Partial Resolution

27 Mar 04:09

Choose a tag to compare

Added

  • HelperOptions::hasPartial(): check whether a named partial is registered at runtime.
  • HelperOptions::registerPartial(): register a compiled partial closure from within a helper, enabling the same lazy-loading pattern as Handlebars.registerPartial() in Handlebars.js (#5, zordius/lightncandy#296).

Fixed

  • Nested {{> @partial-block}} calls from runtime partials.
  • Failover rendering for {{> partial}}fallback{{/partial}} blocks where the partial is also called conditionally earlier in the template.
  • isset($options->fn) and isset($options->inverse) now correctly return true for all block helper calls, even when the block is inverted or lacks an {{else}} clause.
  • Closures at complex paths without any arguments (e.g. {{#obj.fn}}) are no longer passed a HelperOptions argument (matching Handlebars.js behavior).
  • Inverted sections with literal block paths (e.g. {{^"foo"}}) now correctly route through blockHelperMissing.
  • With knownHelpersOnly enabled, inverted sections now correctly skip dispatch to unregistered runtime helpers.
  • ../ expressions inside an {{else}} body now correctly resolve to the block helper's scope when there is no enclosing block context.
  • .length lookup on block param variables and in strict mode.

1.0.1 Root SubExpression

24 Mar 18:56

Choose a tag to compare

Fixed

  • Support for sub-expressions that are PathExpression roots (e.g. {{(my-helper foo).bar}}).
  • Compilation of multi-segment if/unless conditions (#15).
  • Helper argument handling in strict mode.
  • assumeObjects errors now align better with Handlebars.js.

1.0.0 AST Compiler

23 Mar 04:20

Choose a tag to compare

Rewrote the parser and compiler to use an abstract syntax tree, based on the same lexical analysis and grammar specification as Handlebars.js. This eliminates a large class of edge cases and parsing bugs that the old regex-based approach failed to handle correctly.

This release is 35-40% faster than v0.9.9 and LightnCandy at compiling and executing complex templates, and uses almost 30% less memory. The code is also significantly simpler and easier to maintain.

Added

  • Support for nested inline partials.
  • Support for closures in data and helper arguments.
  • helperMissing and blockHelperMissing hooks: handle calls to unknown helpers with the same API as in Handlebars.js, replacing the old helperResolver option.
  • knownHelpers compile option: tell the compiler which helpers will be available at runtime for more efficient execution (helper existence checks can be skipped).
  • assumeObjects compile option: a subset of strict mode that generates optimized templates when the data inputs are known to be safe.
  • Support for deprecated {{person/firstname}} path expressions for parity with Handlebars.js (avoid using this syntax in new code, though).

Changed

  • Custom helpers must now be passed at runtime when invoking a template (via the helpers runtime option key), rather than via the Options object passed to compile or precompile. This is a significant optimization, since it eliminates the overhead of reading and tokenizing PHP files to extract helper functions. It also enables sharing helper closures across multiple templates and renders, and removes limitations on what they can access and do (e.g. it resolves zordius/lightncandy#342).
  • Exceptions thrown by custom helpers are no longer caught and re-thrown, so the original exception can now be caught in your own code for easier debugging (#13).
  • The partialResolver closure signature no longer receives an internal Context argument. Now only the partial name is passed.
  • knownHelpersOnly now works as in Handlebars.js, and an exception will be thrown if the template uses a helper which is not in the knownHelpers list.
  • Updated various error messages to align with those output by Handlebars.js.

Removed

  • Options::$helpers: instead pass custom helpers when invoking a template, using the helpers key in the runtime options array (the second argument to the template closure).
  • Options::$helperResolver: use the helperMissing / blockHelperMissing runtime helpers instead.

Fixed

  • Fatal error with deeply nested else if using custom helper (#2).
  • Incorrect rendering of float values (#11).
  • Conditional @partial-block expressions.
  • Support for @partial-block in nested partials (zordius/lightncandy#292).
  • Ability to precompile partials and pass them at runtime (zordius/lightncandy#341).
  • Fatal error when a string parameter to a partial includes curly braces (zordius/lightncandy#316).
  • Behavior when modifying root context in a custom helper (zordius/lightncandy#350).
  • Escaping of block params and partial names.
  • Inline partials defined inside a {{#with}} or other block leaking out of that block's scope after it closes.
  • Numerous other bugs related to scoping, block params, inverted block helpers, section iteration, and depth-relative paths.

0.9.9 Stringable Conditions

15 Oct 19:08

Choose a tag to compare

Added

  • Allow Stringable variables in if statements (#8).

Fixed

  • Raw lookup when key doesn't exist (#3).
  • Spacing and undefined variable for each block in partial (#7).

0.9.8 String Escaping

20 May 14:56

Choose a tag to compare

Added

  • Handlebars::escapeExpression() method (equivalent to the Handlebars.escapeExpression() utility function in Handlebars.js).

Removed

  • Unnecessary $escape parameter on SafeString constructor.

Fixed

0.9.7 Resolvers

04 May 17:55

Choose a tag to compare

Added

  • helperResolver and partialResolver compile options for dynamic handling of partials and helpers (#1).