Code Monkey home page Code Monkey logo

twig-deferred-extension's People

Contributors

rybakit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

twig-deferred-extension's Issues

The compiled methods can lead to invalid PHP code due to duplicate method names

If a template contains a deferred block named foo and another block named foo_deferred, the compiled template will contain 2 methods block_foo_deferred (corresponding to different cases).
The method names for block_*_deferred should probably be changed to deferred_block_* to avoid conflicts with the block_* pattern of block methods.

Redefining a deferred block that is not the first removes other blocks from rendering

Redefining a deferred block that is not the first deferred block of the parent template removes other blocks from rendering.

Here is a test to reproduce the issue :

--TEST--
Failed parents override
--TEMPLATE--
{% extends "level1.twig" %}
{% block overrided deferred %}{{ parent() }}:level2({{data|join(', ')}}){% endblock %}
{% do data.append('lazy2') %}
--TEMPLATE(level1.twig)--
{% block bar '[bar]' %}
{% block foo deferred %}[foo]{% endblock %}
{% block baz '[baz]' %}
{% block overrided deferred %}[overrided]{% endblock %}
{% block zoo '[zoo]' %}
{% do data.append('lazy1') %}
--DATA--
return []
--EXPECT--
[bar][foo][baz][overrided]:level2(lazy2, lazy1)[zoo]

This test currently produces this output : [baz][foo][zoo]

This test deliberately adds intermediate blocks to clearly see the abnormal behavior.

Here is a minimal version to reproduce the issue :

--TEST--
Failed parents override simple
--TEMPLATE--
{% extends "level1.twig" %}
{% block overrided deferred %}{{ parent() }}:level2{% endblock %}
--TEMPLATE(level1.twig)--
{% block foo deferred %}[foo]{% endblock %}
{% block overrided deferred %}[overrided]{% endblock %}
--DATA--
return []
--EXPECT--
[foo][overrided]:level2

This test currently produces : [foo]

In both cases, if we swap the foo and overrided blocks in level1.twig, then the expected rendering is correct.

--TEST--
Passed parents override
--TEMPLATE--
{% extends "level1.twig" %}
{% block overrided deferred %}{{ parent() }}:level2({{data|join(', ')}}){% endblock %}
{% do data.append('lazy2') %}
--TEMPLATE(level1.twig)--
{% block bar '[bar]' %}
{% block overrided deferred %}[overrided]{% endblock %}
{% block baz '[baz]' %}
{% block foo deferred %}[foo]{% endblock %}
{% block zoo '[zoo]' %}
{% do data.append('lazy1') %}
--DATA--
return []
--EXPECT--
[bar][overrided]:level2(lazy2, lazy1)[baz][foo][zoo]
--TEST--
Passed parents override simple
--TEMPLATE--
{% extends "level1.twig" %}
{% block overrided deferred %}{{ parent() }}:level2{% endblock %}
--TEMPLATE(level1.twig)--
{% block overrided deferred %}[overrided]{% endblock %}
{% block foo deferred %}[foo]{% endblock %}
--DATA--
return []
--EXPECT--
[overrided]:level2[foo]

For my part, I have not yet managed to find the cause of the bug.
You will undoubtedly be more efficient.

Bad output when exception is thrown

It looks like deferred acts erratically if an exception is thrown during rendering.

My proposed fix is something like this (against the legacy version, but should apply both):

DeferredExtension

    public function defer(\Twig_Template $template, $blockName)
    {
        ob_start();
        $templateName = $template->getTemplateName();
        $this->blocks[$templateName][] = [ob_get_level(), $blockName];
    }

    public function resolve(\Twig_Template $template, array $context, array $blocks)
    {
        $templateName = $template->getTemplateName();
        if (empty($this->blocks[$templateName])) {
            return;
        }

        while ($block = array_pop($this->blocks[$templateName])) {
            [$level, $blockName] = $block;
            if (ob_get_level() !== $level) {
                continue;
            }

            $buffer = ob_get_clean();

            $blocks[$blockName] = array($template, 'block_'.$blockName.'_deferred');
            $template->displayBlock($blockName, $context, $blocks);

            echo $buffer;
        }

        if ($parent = $template->getParent($context)) {
            $this->resolve($parent, $context, $blocks);
        }
    }

Basically, I store information about the ob level and ignore the buffer if the level doesn't match. I am not sure if this is the right approach, but at least it prevents too many ob_cleans from happening.

Wonderful library

I just wanted to say thank you for this wonderful twig extension.

It saved me a minimum of 1-2 weeks of work.
Came like a gift from heaven - well tested, well maintained, well written.

Thank you.

bug: undefined variable $macros

Actual behaviour

An error is thrown when using filter in a deferred block.

image

Expected behaviour

No error is thrown.

Steps to reproduce

Add the following snippet in your template:

{%- block my_block deferred -%}
    {% for test in test_array|default([])|filter(test => true) %}
    {% endfor %}
{%- endblock -%}

Setting data not working when we include a template from string

Is it possible to set data from a string template and include it after ?

{# page.html.twig #}
{% extends "layout.html.twig" %}

{% block content %}
    {{ data.append('/js/page-header.js') }}

   {{ include(template_from_string(my_template)) }}
 
    {{ data.append('/js/page-footer.js') }}
{% endblock %}
{# my_template #}
{{ data.append('/js/subpage1.js') }}

Does not work with version ^1.18

This is somewhat strange.

When I run the tests in your project, it seems to work fine against 1.18.2. However, in my own project when I try to use 1.18.2, the deferred blocks render nothing. When I use twig 1.17.0, everything works as expected.

I tried to render the demos on README to no avail.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.