asm89 / twig-cache-extension

The missing cache extension for Twig. Caching template fragments with Twig.
MIT License
388 stars 27 forks source link

Post-process cache for reducing cache size #13

Closed Koc closed 9 years ago

Koc commented 10 years ago

I'm rendering big list of categories using ul+li. Selected category should use span instead of a. Using standard way (cache key depends on active category id) we store N keys, N - categories count.

This is inefficient:

  1. cache size growth
  2. cache miss rate big
  3. hard to invalidate cache. If we have something like products count near the category then we should invalidate all of the N keys when adding new product to one category. So cache miss rate will increase

I'm proposing add some syntax for second pass for cached entry. Example:

{# original - required N cache records #}
{% cache 'sidebar-categories'~activeCatregory.id ttl %}
    {% set categories = categoriesHelper.loadCategories() %}
    <ul>
        {% for catrgory in categories %}
            <li>
                {% if category.id == activeCatregory.id %}
                    <span>{{ catrgory.title }} ({{ category.productsCount }})</span>
                {% else %}
                    <a href="{{ category.url }}">{{ category.title }} ({{ category.productsCount }})</a>
                {% endif %}
            </li>
        {% endfor %}
    </ul>
{% endcache %}

{# with second pass syntax, only 1 cache record #}
{% cache 'sidebar-categories' ttl {'activeCatergoryId': activeCatergory.id} %} {# pass activeCatregoryId to the cached rendered template #}
    {% set categories = categoriesHelper.loadCategories() %}
    <ul>
        {% for catrgory in categories %}
            <li>
                {% cache_expression('if ('~category.id~' == $activeCatregoryId:') %}
                    <span>{{ catrgory.title }} ({{ category.productsCount }})</span>
                {% cache_expression('else:') %}
                    <a href="{{ category.url }}">{{ category.title }} ({{ category.productsCount }})</a>
                {% cache_expression('endif;') %}
            </li>
        {% endfor %}
    </ul>
{% endcache %}
// will compiled to smth like
<ul>
    <li>
        <?php if (1 == $activeCategoryId): ?>
            <span>category 1 (59)</span>
        <?php else: ?>
            <a href="#ololo">category 1 (59)</a>
        <?php endif; ?>
    </li>
    <li>
        <?php if (2 == $activeCategoryId): ?>
            <span>category 2 (80)</span>
        <?php else: ?>
            <a href="#trololo">category 2 (80)</a>
        <?php endif; ?>
    </li>
</ul>

Syntax sux, but I hope you understand the goal.

asm89 commented 10 years ago

@Koc I understand the problem you're dealing with, but I think the solution will make things very complicated. The extension currently captures all the output of the cache block and stores that. When you have a cache hit, the previously rendered HTML will be outputted immediately. There is no render step.

A "solution" for your problem could be flagging the active category with javascript instead.

<ul data-active="{{ activeCategory.id  }}">
    {% cache 'sidebar-categories'~activeCategory.id ttl %}
        {% set categories = categoriesHelper.loadCategories() %}
        {% for category in categories %}
            <li class="category-{{ category.id }}">
                <a href="{{ category.url }}">{{ category.title }} (...)</a>
            </li>
        {% endfor %}
    {% endcache %}
</ul>
Koc commented 10 years ago

I know about js way to solve this problem but some requirements needed for SEO.

asm89 commented 10 years ago

@Koc did find a nice way of solving this?

Koc commented 10 years ago

currently not. I cann't invent good syntax for this.

Koc commented 10 years ago

@asm89 can you suggest nice syntax for this?

asm89 commented 10 years ago

@Koc I'm unsure:

asm89 commented 9 years ago

Closing this, because I'm not sure this extension would be able to fix this.