spicywebau / craft-neo

A Matrix-like field type for Craft CMS that uses existing fields
Other
402 stars 63 forks source link

`benf\neo\elements::useMemoized` error #588

Closed ryssbowh closed 2 years ago

ryssbowh commented 2 years ago

Description

It's not quite clear what benf\neo\elements::useMemoized first argument should be :

In v2 the doc says we have to pass the Neo field but the method's typing (from comments) is bool|array so I guess that was the same than passing true, which seemed to work.

In v3 passing the neo field doesn't work anymore, the typing has actively changed to bool|array. And passing true results in this error :

An Error occurred while handling another error:
TypeError: benf\neo\elements\db\BlockQuery::useMemoized(): Argument #1 ($use) must be of type array|bool, null given, called in /var/www/craft40/vendor/spicyweb/craft-neo/src/elements/Block.php on line 775 and defined in /var/www/craft40/vendor/spicyweb/craft-neo/src/elements/db/BlockQuery.php:306
Stack trace:
#0 /var/www/craft40/vendor/spicyweb/craft-neo/src/elements/Block.php(775): benf\neo\elements\db\BlockQuery->useMemoized()
#1 /var/www/craft40/vendor/yiisoft/yii2/base/Component.php(139): benf\neo\elements\Block->getChildren()
#2 /var/www/craft40/vendor/craftcms/cms/src/base/Element.php(1916): yii\base\Component->__get()
#3 /var/www/craft40/vendor/craftcms/cms/src/helpers/Template.php(90): craft\base\Element->__get()
#4 /var/www/craft40/storage/runtime/compiled_templates/03/03bd07829880d8940a74eb2c0c2e9c5dfe56c1f63a39bb22dc521463b12d969a.php(123): craft\helpers\Template::attribute()

I use this method in a twig template :

{% macro neoBlock(block, level) %}
    {% if block.level == level %}
        <div class="neo-block {{ block.type.handle }}">
            //Output field here
            {% set children = block.children.all() %}
            {% if children %}
                <div class="neo-block-children">
                    {% for child in children %}
                        {{ _self.neoBlock(child, level + 1)}}
                    {% endfor %}
                </div>
            {% endif %}
        </div>
    {% endif %}
{% endmacro %}

{% for neoBlock in value %}
    {% do neoBlock.useMemoized() %}
{% endfor %}
{% for neoBlock in value %}
    {{ _self.neoBlock(neoBlock, 1)}}
{% endfor %}

My Neo field neo has one block test with one field assets and is eager loaded previously with the following : ["neo","neo.test:assets"]

Steps to reproduce

  1. Use useMemoized without argument on a neo block

Other information

ttempleton commented 2 years ago

In the Neo eager loading docs, the use of block.useMemoized(entry.neoField) assumes that the content of entry.neoField has been eager loaded and is an array of Neo blocks, rather than an actual Neo field instance.

Using useMemoized() without an argument tells the block to use a memoized dataset, without actually giving it a dataset to use, which means it's assumed that a memoized dataset has already been set. If it hasn't already been set, you'd need to call block.setAllElements(blocks) separately to set it. That isn't mentioned in the docs and I'll make a note to clarify it.

In your case, it looks like changing the line

{% do neoBlock.useMemoized() %}

to

{% do neoBlock.useMemoized(value) %}

should resolve the issue.