Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this module are documented here.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.2.1] 2026-11-06

### Changed
- `in` and `notIn` on a field with a `values_query` pick the values in a multiselect instead of typing ids in a textarea (`openstudio/query-builder-bundle` 1.2, now required as `^1.2`, built into the editor script). The picked values are stored as an array, which `SqlBuilder` already reads; a list saved before as a comma-separated string reopens in the multiselect.
- A `values_query` falls back to the free input beyond 1000 rows instead of 300: a category tree of a few hundred entries kept every category field (`product_default_category`, `cart_has_category`, `context_category_id`, `context_category_parent_id`, `product_category_title`) on the free input, without any list.

### Added
- `product_category_id` ("Category (ID)") lists the categories, like the other category fields.

## [2.2.0] 2026-11-06

Fixes of the 1.x line (1.4.0 to 1.6.1) carried over to 2.x.
Expand Down Expand Up @@ -90,6 +99,9 @@ Port of the module to Thelia 3. The Thelia 2 line (1.x) is maintained on the `th
- The `/query_builder/products/{hookCode}` Symfony route, replaced by the API Platform resource.
- The `product.top` and `product.bottom` `BaseHook` front hooks, replaced by the theme hook implementation.

[2.2.1]: https://github.com/thelia-modules/QueryBuilder/releases/tag/2.2.1
[2.2.0]: https://github.com/thelia-modules/QueryBuilder/releases/tag/2.2.0
[2.1.1]: https://github.com/thelia-modules/QueryBuilder/releases/tag/2.1.1
[2.1.0]: https://github.com/thelia-modules/QueryBuilder/releases/tag/2.1.0
[2.0.1]: https://github.com/thelia-modules/QueryBuilder/releases/tag/2.0.1
[2.0.0]: https://github.com/thelia-modules/QueryBuilder/releases/tag/2.0.0
2 changes: 1 addition & 1 deletion Config/module.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<language>en_US</language>
<language>fr_FR</language>
</languages>
<version>2.2.0</version>
<version>2.2.1</version>
<authors>
<author>
<name>Samuel Diakité</name>
Expand Down
6 changes: 4 additions & 2 deletions Config/query_builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@
# fields.<code>.operators : restrict allowed operators (react-querybuilder names)
# fields.<code>.values_query : SQL listing the possible values — "value" column required, "label"
# optional, :locale allowed. The BO editor then offers a select ("list of
# values" operator) next to the free operators. Executed on the editor
# screens only; falls back to the free input beyond 300 rows or on SQL
# values" operator, and a multiselect for in/notIn) next to the free
# operators. Executed on the editor screens only; falls back to the free
# input beyond 1000 rows or on SQL
# error. Not allowed on boolean fields.
#
# contexts.<CONTEXT>: hooks usable by rules of this context. Each entry is either a plain
Expand Down Expand Up @@ -149,6 +150,7 @@ fields:
label: "Category (ID)"
field: product_category.category_id
type: number
values_query: "SELECT c.id AS value, ci.title AS label FROM category c JOIN category_i18n ci ON ci.id = c.id AND ci.locale = :locale ORDER BY ci.title"
product_category_title:
label: "Product category title"
field: category_i18n.title
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Only the fields of a data dictionary and a closed list of operators are accepted

- Thelia 3.2 or later (`thelia/core` ^3.2: the catalog price contract the product discounts plug into), Flexy front theme, default-twig back-office
- PHP 8.3+
- `openstudio/query-builder-bundle` ^1.1 (the back-office editor)
- `openstudio/query-builder-bundle` ^1.2 (the back-office editor)

Thelia 2 shops use the 1.x line, maintained on the [`thelia2`](https://github.com/thelia-modules/QueryBuilder/tree/thelia2) branch.

Expand Down Expand Up @@ -75,7 +75,7 @@ Runtime placeholders: `:customer_id`, `:cart_id`, `:cart_product_ids`, `:product

An expression may contain the `:value` token: the value entered in the editor is then expanded inside the expression, one placeholder per item, and the field must restrict its `operators` to `in` and `notIn`, which only set the polarity, or to `=` and `!=`, compiled as a one-item `in` and `notIn`. The "list of values" pick of a field with a `values_query` is stored as `=`, so such a field needs no more than `[in, notIn]` for the pick to compile.

Field types: `text`, `number`, `date`, `datetime` (entered as a date, compared on `DATE()`), `boolean`. A field may declare `values_query` (a `value` column, an optional `label` column, `:locale` allowed): the editor then offers a "list of values" select next to the free operators. Beyond 300 rows or on SQL error the field falls back to the free input. Labels of fields and hooks are translation keys of the `querybuilder` domain.
Field types: `text`, `number`, `date`, `datetime` (entered as a date, compared on `DATE()`), `boolean`. A field may declare `values_query` (a `value` column, an optional `label` column, `:locale` allowed): the editor then offers a "list of values" select next to the free operators, and a multiselect for `in` and `notIn`, stored as an array. Beyond 1000 rows or on SQL error the field falls back to the free input. Labels of fields and hooks are translation keys of the `querybuilder` domain.

A field declares the contexts it is offered in with `contexts`, a list of `QueryBuilder\Enum\Context` values; `GLOBAL`, the default, means every context, and a `GLOBAL` rule itself only sees `GLOBAL` fields. Restrict a field to the contexts where its placeholder is filled: `:product_id` to `PRODUCT`, `:category_id` to `CATEGORY`, `:brand_id` to `BRAND`, `:order_id` to `ORDER`. The cart and the customer come from the session in every context, so their fields stay `GLOBAL` (a `PRODUCT` rule can select the products sharing a brand with the cart). A field also declares the editors it is offered in with `usage`, a list among `rule` (trigger conditions) and `action` (product selection), both by default: a field comparing the selected product to the object of the context is always true in the rule editor and belongs to `[action]`, a field reading the object itself (`:category_id` in a list) selects all or nothing in the action editor and belongs to `[rule]`.

Expand Down
5 changes: 3 additions & 2 deletions Service/FieldsBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
*/
final readonly class FieldsBuilder
{
//Beyond this size a select is unusable: fall back to the free input
private const MAX_VALUES = 300;
//Beyond this size a select is unusable: fall back to the free input. A shop's category tree
//easily passes 300 entries, still usable in a select searched by typing
private const MAX_VALUES = 1000;

//The editor stores the values picked in a select as a plain equality
private const VALUES_LIST_OPERATOR = 'valuesList';
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"require": {
"php": ">=8.3",
"thelia/installer": "~1.1",
"openstudio/query-builder-bundle": "^1.1"
"openstudio/query-builder-bundle": "^1.2"
},
"require-dev": {
"thelia/core": "^3.2",
Expand Down

Large diffs are not rendered by default.

Loading