phptal / PHPTAL

PHP Template Attribute Language — template engine for XSS-proof well-formed XHTML and HTML5 pages
http://phptal.org
GNU Lesser General Public License v2.1
175 stars 43 forks source link

Lacking full support for Closures #57

Open adjenks opened 7 years ago

adjenks commented 7 years ago

On the releases page it states that there was added support for closures: https://github.com/phptal/PHPTAL/releases

However, I found that when I used a closure directly on a template variable a closure would not work. Only when using a "repeat" tag do closures appear to work. I'm not sure where you would fix this, but I found that closure support was provided in RepeatController.php in these lines:

elseif ($source instanceof Closure) {
    $this->iterator = new ArrayIterator( (array) $source() );

So perhaps something similar needs to be done.

For example this will fail to load: $details = function(){return 'some string';}; $template->details = $details;

<b tal:content="details"></b>

But if $details was a closure that returned an array and it was iterrated over like so it works:

 $details = function(){return [0=>['name'=>'Jim']];};

<li tal:repeat="detail details" class="media">
    <div tal:content="detail/name">Name Here</div>
</li>

There might be a typo somewhere in that code but you should get the idea.

I wanted to use a closure to lazy load my template variable but it only worked when I used repeat, so I believe I found a problem. I found that I can temporarily work around this problem by returning a one element array and using the tal:repeat directive.

Potherca commented 7 years ago

Hi! Thank you for taking the time to report this.

In regards to your statement

I found that when I used a closure directly on a template variable a closure would not work.

Could you give some more detail as to what the effect is when this is done? (i.e. is an error visible or is an exception thrown? If so, what is the error message and/or stack-trace?).

I've made two minimal test-cases based on the example you gave but both seem to work (using PHP 5.6 or PHP 7).

Could you provide a minimal test-case that does not work?

Potherca commented 7 years ago

A failing test-case and an example of his workaround have been provided by @adjenks

As he correctly states:

It appears that the issue only shows up if the returned type is an array.

I can accessfoo/nested with tal:content="foo/nested" when it is not a closure, but when it is a closure I cannot access it the same way. I can however access it if I put it in a deeper array and then use repeat.

The failing case produces the following error:

PHPTAL Exception

Array doesn't have key named 'nested'

In <string 3272f4bb7302adf9f5af11e8b36e20f5> line 6

#0 /app/vendor/phptal/phptal/classes/PHPTAL/Context.php(423): PHPTAL_Context::pathError(Array, 'nested', 'nested', NULL)
#1 /app/vendor/phptal/phptal/classes/PHPTAL.php(837) : eval()'d code(19): PHPTAL_Context::path(Array, 'nested')
#2 /app/vendor/phptal/phptal/classes/PHPTAL.php(667): tpl_00000000_string_3272f4bb7302a__ZPddJbn1I4g1iAxcpA1O6w(Object(PHPTAL), Object(PHPTAL_Context))
#3 /app/web/case-04-array-indirect-assignment.php(34): PHPTAL->execute()
#4 {main}
adjenks commented 7 years ago

@Potherca Thanks for working on the bug report. How goes the battle?

Potherca commented 7 years ago

Hi @adjenks,

currently a lot of of my (spare) time is absorbed by other projects. My current time-frame would allow me to look into fixing this issue early April.