Skip to content

Multi-value filters (|| / &&) on content fields bind more parameters than the generated DQL declares #3808

Description

@matesko

A brief description of the issue goes here.

Environment

Package Version
bolt/core 6.1.8
symfony/framework-bundle 6.4.46
doctrine/orm 3.7.1
doctrine/dbal 4.4.4
PHP 8.2.13
Database MariaDB 10.4

Upgraded from Bolt 5.1.24. Same behaviour on a freshly cleared cache.

Description

A setcontent query that filters a content field with multiple values
(|| or &&) fails with:

Too many parameters: the query defines 3 parameters and you bound 4

The same syntax on a system field (e.g. status) works fine, so the
problem seems specific to how field filters are turned into DQL.

The number of declared parameters stays constant no matter how many values
are passed, while the number of bound parameters grows with each value. That
suggests the multi-value filter binds one parameter per value, but the DQL it
produces only ever contains a single placeholder for that field.

Steps to reproduce

ContentType with a plain select field:

blog:
    fields:
        jezik:
            type: select
            required: true
            multiselect: false
            values:
                hr: 'Croatian'
                en: 'English'
                hren: 'Both'

Then run any of these:

{% setcontent records = 'blog' where { jezik: 'hr || hren' } latest limit 1 %}

Results

┌─────────────────────────────────┬───────────────────────────────────────┐
│              Query              │                Result                 │
├─────────────────────────────────┼───────────────────────────────────────┤
│ { jezik: 'hr || hren' }         │ fails — defines 3 parameters, bound 4 │
├─────────────────────────────────┼───────────────────────────────────────┤
│ { jezik: 'hr || hren || en' }   │ fails — defines 3 parameters, bound 5 │
├─────────────────────────────────┼───────────────────────────────────────┤
│ { jezik: 'hr && hren' }         │ fails — defines 3 parameters, bound 4 │
├─────────────────────────────────┼───────────────────────────────────────┤
│ { jezik: 'hr' }                 │ works                                 │
├─────────────────────────────────┼───────────────────────────────────────┤
│ { status: 'published || held' } │ works (system field)                  │
├─────────────────────────────────┼───────────────────────────────────────┤
│ no filter                       │ works                                 │
└─────────────────────────────────┴───────────────────────────────────────┘

Expected: all of the above return records.
Actual: every multi-value filter on a content field throws.

Notes

  • Reproduced through Bolt\Storage\Query::getContent() directly, so it is not
    template-specific.
  • Ruled out a project-level decorator of Bolt\Storage\Directive\OrderDirective
    — the failure is identical with the decorator removed, and with no ordering
    in the query at all.
  • Bolt\Storage\QueryParameterParser::multipleValueHandler() builds one
    placeholder per value and calls $filter->setParameters() with all of them,
    so the mismatch most likely appears further down, where the field filter is
    joined onto the query. I have not traced it past that point.

Workarounds used

  • Two separate setcontent queries merged in Twig.
  • Where the field has a small closed set of values, negation of the complement
    ('!en' instead of 'hr || hren') — single parameter, works.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions