Skip to content

Shopping list#2969

Open
adriendupuis wants to merge 141 commits into5.0from
shopping-list
Open

Shopping list#2969
adriendupuis wants to merge 141 commits into5.0from
shopping-list

Conversation

@adriendupuis
Copy link
Contributor

@adriendupuis adriendupuis commented Dec 3, 2025

Question Answer
JIRA Ticket IBX-5671
Versions 5.0
Edition Commerce

Document the Commerce's Shopping List LTS Update feature for developers.

Previews

Related pending PRs

Dev installation

composer create-project ibexa/website-skeleton:5.0.x-dev --no-scripts .
composer config repositories.ibexa composer https://updates.ibexa.co
composer require ibexa/commerce:5.0.x-dev --update-with-all-dependencies --no-scripts --no-interaction
composer config repositories.shopping-list vcs https://github.com/ibexa/shopping-list
composer require ibexa/shopping-list:5.0.x-dev --update-with-all-dependencies --no-scripts --no-interaction
composer config repositories.storefront vcs https://github.com/ibexa/storefront
composer require ibexa/storefront:5.0.x-dev --update-with-all-dependencies --no-scripts --no-interaction

Follow Install shopping list

Checklist

  • Text renders correctly
  • Text has been checked with vale
  • Description metadata is up to date
  • Redirects cover removed/moved pages
  • Code samples are working
  • PHP code samples have been fixed with PHP CS fixer
  • Added link to this PR in relevant JIRA ticket or code PR

@github-actions
Copy link

github-actions bot commented Dec 3, 2025

Preview of modified files

Preview of modified Markdown:

Preview of addition to PHP API Reference:

adriendupuis and others added 3 commits March 4, 2026 11:42
Co-authored-by: Marek Nocoń <mnocon@users.noreply.github.com>
Co-authored-by: Marek Nocoń <mnocon@users.noreply.github.com>
@ibexa ibexa deleted a comment from mnocon Mar 4, 2026
@github-actions
Copy link

github-actions bot commented Mar 4, 2026

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/shopping_list/add_to_shopping_list/assets/js/add-to-shopping-list.ts


code_samples/shopping_list/add_to_shopping_list/assets/js/add-to-shopping-list.ts

docs/commerce/shopping_list/shopping_list_design.md@33:``` ts
docs/commerce/shopping_list/shopping_list_design.md@34:[[= include_file('code_samples/shopping_list/add_to_shopping_list/assets/js/add-to-shopping-list.ts') =]]
docs/commerce/shopping_list/shopping_list_design.md@35:```

001⫶// Shopping list service
002⫶import ShoppingList from '@ibexa-shopping-list/src/bundle/Resources/public/js/component/shopping.list';
003⫶// The Add to shopping list interaction
004⫶import { AddToShoppingList } from '@ibexa-shopping-list/src/bundle/Resources/public/js/component/add.to.shopping.list';
005⫶// List of all user's shopping lists
006⫶import { ShoppingListsList } from '@ibexa-shopping-list/src/bundle/Resources/public/js/component/shopping.lists.list';
007⫶
008⫶(function (global: Window, doc: Document) {
009⫶ const shoppingList = new ShoppingList();
010⫶ shoppingList.init(); // Fetch user's shopping lists
011⫶
012⫶ const addToShoppingListsNodes = doc.querySelectorAll<HTMLDivElement>('.ibexa-sl-add-to-shopping-list');
013⫶ addToShoppingListsNodes.forEach((addToShoppingListNode) => {
014⫶ const addToShoppingList = new AddToShoppingList({ node: addToShoppingListNode, ListClass: ShoppingListsList });
015⫶
016⫶ addToShoppingList.init();
017⫶ });
018⫶})(window, window.document);


code_samples/shopping_list/add_to_shopping_list/config/packages/views.yaml


code_samples/shopping_list/add_to_shopping_list/config/packages/views.yaml

docs/commerce/shopping_list/shopping_list_design.md@78:``` yaml hl_lines="7 8"
docs/commerce/shopping_list/shopping_list_design.md@79:[[= include_file('code_samples/shopping_list/add_to_shopping_list/config/packages/views.yaml') =]]
docs/commerce/shopping_list/shopping_list_design.md@80:```

001⫶ibexa:
002⫶ system:
003⫶ default:
004⫶ content_view:
005⫶ full:
006⫶ product:
007❇️ controller: 'App\Controller\ProductViewController::viewAction'
008❇️ template: '@ibexadesign/full/product.html.twig'
009⫶ match:
010⫶ '@Ibexa\Contracts\ProductCatalog\ViewMatcher\ProductBased\IsProduct': true


code_samples/shopping_list/add_to_shopping_list/src/Controller/ProductViewController.php


code_samples/shopping_list/add_to_shopping_list/src/Controller/ProductViewController.php

docs/commerce/shopping_list/shopping_list_design.md@67:``` php hl_lines="24-30"
docs/commerce/shopping_list/shopping_list_design.md@68:[[= include_file('code_samples/shopping_list/add_to_shopping_list/src/Controller/ProductViewController.php') =]]
docs/commerce/shopping_list/shopping_list_design.md@69:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\Controller;
004⫶
005⫶use Ibexa\Contracts\Core\Repository\Iterator\BatchIterator;
006⫶use Ibexa\Contracts\ProductCatalog\Iterator\BatchIteratorAdapter\ProductVariantFetchAdapter;
007⫶use Ibexa\Contracts\ProductCatalog\Local\LocalProductServiceInterface;
008⫶use Ibexa\Contracts\ProductCatalog\Values\Product\ProductVariantQuery;
009⫶use Ibexa\Core\MVC\Symfony\View\ContentView;
010⫶use Ibexa\Core\MVC\Symfony\View\View;
011⫶use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
012⫶use Symfony\Component\HttpFoundation\Request;
013⫶
014⫶class ProductViewController extends AbstractController
015⫶{
016⫶ public function __construct(private readonly LocalProductServiceInterface $productService)
017⫶ {
018⫶ }
019⫶
020⫶ public function viewAction(Request $request, ContentView $view): View
021⫶ {
022⫶ $product = $this->productService->getProductFromContent($view->getContent());
023⫶ if ($product->isBaseProduct()) {
024❇️ $view->addParameters([
025❇️ 'variants' => new BatchIterator(new ProductVariantFetchAdapter(
026❇️ $this->productService,
027❇️ $product,
028❇️ new ProductVariantQuery(),
029❇️ )),
030❇️ ]);
031⫶ }
032⫶
033⫶ return $view;
034⫶ }
035⫶}


code_samples/shopping_list/add_to_shopping_list/templates/themes/standard/full/product.html.twig


code_samples/shopping_list/add_to_shopping_list/templates/themes/standard/full/product.html.twig

docs/commerce/shopping_list/shopping_list_design.md@72:``` twig hl_lines="7 8 16-18 31-33 44"
docs/commerce/shopping_list/shopping_list_design.md@73:[[= include_file('code_samples/shopping_list/add_to_shopping_list/templates/themes/standard/full/product.html.twig') =]]
docs/commerce/shopping_list/shopping_list_design.md@74:```

001⫶{% extends '@ibexadesign/pagelayout.html.twig' %}
002⫶
003⫶{% set product = content|ibexa_get_product %}
004⫶
005⫶{% block meta %}
006⫶ {% set token = csrf_token ?? csrf_token(ibexa_get_rest_csrf_token_intention()) %}
007❇️ <meta name="CSRF-Token" content="{{ token }}"/>
008❇️ <meta name="SiteAccess" content="{{ app.request.get('siteaccess').name }}"/>
009⫶{% endblock %}
010⫶
011⫶{% block content %}
012⫶ <span>{{ ibexa_content_name(content) }}</span>
013⫶ <code>{{ product.code }}</code>
014⫶ {% if not product.isBaseProduct() and can_view_shopping_list and can_edit_shopping_list %}
015⫶ {% set component %}
016❇️ {% include '@ibexadesign/shopping_list/component/add_to_shopping_list/add_to_shopping_list.html.twig' with {
017❇️ product_code: product.code,
018❇️ } %}
019⫶ {% endset %}
020⫶ {{ _self.add_to_shopping_list(product, component) }}
021⫶ {% endif %}
022⫶
023⫶ {% if product.isBaseProduct() %}
024⫶ <ul>
025⫶ {% for variant in variants %}
026⫶ <li>
027⫶ <span>{{ variant.name }}</span>
028⫶ <code>{{ variant.code }}</code>
029⫶ {% if can_view_shopping_list and can_edit_shopping_list %}
030⫶ {% set component %}
031❇️ {% include '@ibexadesign/shopping_list/component/add_to_shopping_list/add_to_shopping_list.html.twig' with {
032❇️ product_code: variant.code,
033❇️ } %}
034⫶ {% endset %}
035⫶ {{ _self.add_to_shopping_list(variant, component) }}
036⫶ {% endif %}
037⫶ </li>
038⫶ {% endfor %}
039⫶ </ul>
040⫶ {% endif %}
041⫶{% endblock %}
042⫶
043⫶{% block javascripts %}
044❇️ {{ encore_entry_script_tags('add-to-shopping-list-js') }}
045⫶{% endblock %}
046⫶
047⫶{% macro add_to_shopping_list(product, component) %}
048⫶ {% set widget_id = 'add-to-shopping-list-' ~ product.code|slug %}
049⫶ <div style="display: inline-block;">
050⫶ <button onclick="(function(){let e=document.getElementById('{{ widget_id }}'); e.style.display=('none'===window.getComputedStyle(e).display)?'block':'none';})()">
051⫶ Add to shopping list
052⫶ </button>
053⫶ <div id="{{ widget_id }}" style="display: none; position: absolute; background: #fff;">
054⫶ {{ component }}
055⫶ </div>
056⫶ </div>
057⫶{% endmacro %}


code_samples/shopping_list/add_to_shopping_list/webpack.config.js


code_samples/shopping_list/add_to_shopping_list/webpack.config.js

docs/commerce/shopping_list/shopping_list_design.md@38:``` js hl_lines="5-14"
docs/commerce/shopping_list/shopping_list_design.md@39:// […]
docs/commerce/shopping_list/shopping_list_design.md@40:
docs/commerce/shopping_list/shopping_list_design.md@41:[[= include_file('code_samples/shopping_list/add_to_shopping_list/webpack.config.js', 43) =]]
docs/commerce/shopping_list/shopping_list_design.md@42:```

001⫶// […]


code_samples/shopping_list/install/schema.mysql.sql


code_samples/shopping_list/install/schema.mysql.sql

docs/commerce/shopping_list/install_shopping_list.md@41:    ```sql
docs/commerce/shopping_list/install_shopping_list.md@42: [[= include_file('code_samples/shopping_list/install/schema.mysql.sql', 0, None, ' ') =]]
docs/commerce/shopping_list/install_shopping_list.md@43: ```

001⫶ CREATE TABLE ibexa_shopping_list (
002⫶ id INT AUTO_INCREMENT NOT NULL,
003⫶ owner_id INT NOT NULL,
004⫶ identifier CHAR(36) NOT NULL COMMENT '(DC2Type:guid)',
005⫶ name VARCHAR(190) DEFAULT NULL,
006⫶ created_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)',
007⫶ updated_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)',
008⫶ is_default TINYINT(1) DEFAULT 0 NOT NULL,
009⫶ UNIQUE INDEX ibexa_shopping_list_identifier_idx (identifier),
010⫶ INDEX ibexa_shopping_list_owner_idx (owner_id),
011⫶ INDEX ibexa_shopping_list_default_idx (is_default),
012⫶ PRIMARY KEY(id)
013⫶ ) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_520_ci` ENGINE = InnoDB;
014⫶ CREATE TABLE ibexa_shopping_list_entry (
015⫶ id INT AUTO_INCREMENT NOT NULL,
016⫶ shopping_list_id INT NOT NULL,
017⫶ product_code VARCHAR(64) NOT NULL,
018⫶ identifier CHAR(36) NOT NULL COMMENT '(DC2Type:guid)',
019⫶ added_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)',
020⫶ UNIQUE INDEX ibexa_shopping_list_entry_identifier_idx (identifier),
021⫶ INDEX ibexa_shopping_list_entry_list_idx (shopping_list_id),
022⫶ INDEX ibexa_shopping_list_entry_product_idx (product_code),
023⫶ INDEX ibexa_shopping_list_entry_added_at_idx (added_at),
024⫶ UNIQUE INDEX ibexa_shopping_list_entry_unique (shopping_list_id, product_code),
025⫶ PRIMARY KEY(id)
026⫶ ) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_520_ci` ENGINE = InnoDB;
027⫶ ALTER TABLE ibexa_shopping_list
028⫶ ADD CONSTRAINT ibexa_shopping_list_owner_fk FOREIGN KEY (owner_id) REFERENCES ibexa_user (contentobject_id) ON UPDATE CASCADE ON DELETE CASCADE;
029⫶ ALTER TABLE ibexa_shopping_list_entry
030⫶ ADD CONSTRAINT ibexa_shopping_list_entry_list_fk FOREIGN KEY (shopping_list_id) REFERENCES ibexa_shopping_list (id) ON UPDATE CASCADE ON DELETE CASCADE;
031⫶ ALTER TABLE ibexa_shopping_list_entry
032⫶ ADD CONSTRAINT ibexa_shopping_list_entry_product_fk FOREIGN KEY (product_code) REFERENCES ibexa_product (code) ON UPDATE CASCADE ON DELETE CASCADE;


code_samples/shopping_list/install/schema.postgresql.sql


code_samples/shopping_list/install/schema.postgresql.sql

docs/commerce/shopping_list/install_shopping_list.md@47:    ```sql
docs/commerce/shopping_list/install_shopping_list.md@48: [[= include_file('code_samples/shopping_list/install/schema.postgresql.sql', 0, None, ' ') =]]
docs/commerce/shopping_list/install_shopping_list.md@49: ```

001⫶ CREATE TABLE ibexa_shopping_list (
002⫶ id SERIAL NOT NULL,
003⫶ owner_id INT NOT NULL,
004⫶ identifier UUID NOT NULL,
005⫶ name VARCHAR(190) DEFAULT NULL,
006⫶ created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
007⫶ updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
008⫶ is_default BOOLEAN DEFAULT false NOT NULL,
009⫶ PRIMARY KEY (id)
010⫶ );
011⫶ CREATE UNIQUE INDEX ibexa_shopping_list_identifier_idx ON ibexa_shopping_list (identifier);
012⫶ CREATE INDEX ibexa_shopping_list_owner_idx ON ibexa_shopping_list (owner_id);
013⫶ CREATE INDEX ibexa_shopping_list_default_idx ON ibexa_shopping_list (is_default);
014⫶ COMMENT ON COLUMN ibexa_shopping_list.created_at IS '(DC2Type:datetime_immutable)';
015⫶ COMMENT ON COLUMN ibexa_shopping_list.updated_at IS '(DC2Type:datetime_immutable)';
016⫶ CREATE TABLE ibexa_shopping_list_entry (
017⫶ id SERIAL NOT NULL,
018⫶ shopping_list_id INT NOT NULL,
019⫶ product_code VARCHAR(64) NOT NULL,
020⫶ identifier UUID NOT NULL,
021⫶ added_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
022⫶ PRIMARY KEY (id)
023⫶ );
024⫶ CREATE UNIQUE INDEX ibexa_shopping_list_entry_identifier_idx ON ibexa_shopping_list_entry (identifier);
025⫶ CREATE INDEX ibexa_shopping_list_entry_list_idx ON ibexa_shopping_list_entry (shopping_list_id);
026⫶ CREATE INDEX ibexa_shopping_list_entry_product_idx ON ibexa_shopping_list_entry (product_code);
027⫶ CREATE INDEX ibexa_shopping_list_entry_added_at_idx ON ibexa_shopping_list_entry (added_at);
028⫶ CREATE UNIQUE INDEX ibexa_shopping_list_entry_unique ON ibexa_shopping_list_entry (shopping_list_id, product_code);
029⫶ COMMENT ON COLUMN ibexa_shopping_list_entry.added_at IS '(DC2Type:datetime_immutable)';
030⫶ ALTER TABLE ibexa_shopping_list
031⫶ ADD CONSTRAINT ibexa_shopping_list_owner_fk FOREIGN KEY (owner_id) REFERENCES ibexa_user (contentobject_id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
032⫶ ALTER TABLE ibexa_shopping_list_entry
033⫶ ADD CONSTRAINT ibexa_shopping_list_entry_list_fk FOREIGN KEY (shopping_list_id) REFERENCES ibexa_shopping_list (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
034⫶ ALTER TABLE ibexa_shopping_list_entry
035⫶ ADD CONSTRAINT ibexa_shopping_list_entry_product_fk FOREIGN KEY (product_code) REFERENCES ibexa_product (code) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;


code_samples/shopping_list/install/src/Migrations/Ibexa/migrations/shopping_list_user.yaml


code_samples/shopping_list/install/src/Migrations/Ibexa/migrations/shopping_list_user.yaml

docs/commerce/shopping_list/install_shopping_list.md@86:``` yaml
docs/commerce/shopping_list/install_shopping_list.md@87:[[= include_file('code_samples/shopping_list/install/src/Migrations/Ibexa/migrations/shopping_list_user.yaml', 4, 29) =]]
docs/commerce/shopping_list/install_shopping_list.md@88:```

001⫶- type: role
002⫶ mode: create
003⫶ metadata:
004⫶ identifier: Shopping List User
005⫶ policies:
006⫶ - module: shopping_list
007⫶ function: create
008⫶ limitations:
009⫶ - identifier: ShoppingListOwner
010⫶ values: [self]
011⫶ - module: shopping_list
012⫶ function: view
013⫶ limitations:
014⫶ - identifier: ShoppingListOwner
015⫶ values: [self]
016⫶ - module: shopping_list
017⫶ function: edit
018⫶ limitations:
019⫶ - identifier: ShoppingListOwner
020⫶ values: [self]
021⫶ - module: shopping_list
022⫶ function: delete
023⫶ limitations:
024⫶ - identifier: ShoppingListOwner
025⫶ values: [self]


code_samples/shopping_list/php_api/src/Command/ShoppingListFilterCommand.php


code_samples/shopping_list/php_api/src/Command/ShoppingListFilterCommand.php

docs/commerce/shopping_list/shopping_list_api.md@73:```php
docs/commerce/shopping_list/shopping_list_api.md@74:[[= include_file('code_samples/shopping_list/php_api/src/Command/ShoppingListFilterCommand.php', 39, 50) =]]
docs/commerce/shopping_list/shopping_list_api.md@75:```

001⫶ $filteredProductCodes = array_filter(
002⫶ $desiredProductCodes,
003⫶ static fn ($productCode): bool => !$list->getEntries()->hasEntryWithProductCode($productCode)
004⫶ );
005⫶ $list = $this->shoppingListService->addEntries(
006⫶ $list,
007⫶ array_map(
008⫶ static fn ($productCode): EntryAddStruct => new EntryAddStruct($productCode),
009⫶ $filteredProductCodes
010⫶ )
011⫶ );


code_samples/shopping_list/php_api/src/Command/ShoppingListMoveCommand.php


code_samples/shopping_list/php_api/src/Command/ShoppingListMoveCommand.php

docs/commerce/shopping_list/shopping_list_api.md@79:```php
docs/commerce/shopping_list/shopping_list_api.md@80:[[= include_file('code_samples/shopping_list/php_api/src/Command/ShoppingListMoveCommand.php', 42, 54) =]]
docs/commerce/shopping_list/shopping_list_api.md@81:```

001⫶ $entriesToRemove = [];
002⫶ $entriesToAdd = [];
003⫶ foreach ($movedProductCodes as $productCode) {
004⫶ if ($sourceList->getEntries()->hasEntryWithProductCode($productCode)) {
005⫶ $entriesToRemove[] = $sourceList->getEntries()->getEntryWithProductCode($productCode);
006⫶ if (!$targetList->getEntries()->hasEntryWithProductCode($productCode)) {
007⫶ $entriesToAdd[] = new EntryAddStruct($productCode);
008⫶ }
009⫶ }
010⫶ }
011⫶ $sourceList = $this->shoppingListService->removeEntries($sourceList, $entriesToRemove);
012⫶ $targetList = $this->shoppingListService->addEntries($targetList, $entriesToAdd);


code_samples/shopping_list/php_api/src/Controller/CartShoppingListTransferController.php


code_samples/shopping_list/php_api/src/Controller/CartShoppingListTransferController.php

docs/commerce/shopping_list/shopping_list_api.md@92:```php
docs/commerce/shopping_list/shopping_list_api.md@93:[[= include_file('code_samples/shopping_list/php_api/src/Controller/CartShoppingListTransferController.php', 69, 92) =]]
docs/commerce/shopping_list/shopping_list_api.md@94:```

001⫶ $this->cartService->emptyCart($cart);
002⫶ $list = $this->shoppingListService->clearShoppingList($list);
003⫶
004⫶ $list = $this->shoppingListService->addEntries($list, [new ShoppingListEntryAddStruct($productCode)]);
005⫶
006⫶ $entry = $list->getEntries()->getEntryWithProductCode($productCode)->getIdentifier();
007⫶ $cart = $this->cartShoppingListTransferService->addSelectedEntriesToCart($list, [$entry], $cart);
008⫶ $cart = $this->cartShoppingListTransferService->addSelectedEntriesToCart($list, [$entry], $cart);
009⫶
010⫶ dump(
011⫶ $list->getEntries()->hasEntryWithProductCode($productCode), // true as the entry is copied and not moved
012⫶ $cart->getEntries()->getEntryForProduct($this->productService->getProduct($productCode))->getQuantity() // 2 as the entry was added twice
013⫶ );
014⫶
015⫶ $list = $this->shoppingListService->clearShoppingList($list); // Empty the list to avoid duplicate and test the move from cart
016⫶
017⫶ $list = $this->cartShoppingListTransferService->moveCartToShoppingList($cart, $list);
018⫶ $cart = $this->cartService->getCart($cart->getIdentifier()); // Refresh local object from persistence
019⫶
020⫶ dump(
021⫶ $list->getEntries()->hasEntryWithProductCode($productCode), // true as, after the clear, the entry is moved from cart
022⫶ $cart->getEntries()->hasEntryForProduct($this->productService->getProduct($productCode)) // false as the entry was moved
023⫶ );


code_samples/shopping_list/search/criteria.php


code_samples/shopping_list/search/criteria.php

docs/search/shopping_list_search_reference/shopping_list_criteria.md@32:```php hl_lines="8-9"
docs/search/shopping_list_search_reference/shopping_list_criteria.md@33:[[= include_file('code_samples/shopping_list/search/criteria.php', 2) =]]
docs/search/shopping_list_search_reference/shopping_list_criteria.md@34:```

001⫶use Ibexa\Contracts\ShoppingList\Value\Query;
002⫶use Ibexa\Contracts\ShoppingList\Value\ShoppingListQuery;
003⫶
004⫶/** @var \Ibexa\Contracts\Core\Repository\PermissionResolver $permissionResolver */
005⫶$query = new ShoppingListQuery(
006⫶ new Query\Criterion\LogicalAnd(
007⫶ new Query\Criterion\OwnerCriterion($permissionResolver->getCurrentUserReference()),
008❇️ new Query\Criterion\IsDefaultCriterion(false)
009❇️ ),
010⫶ [
011⫶ new Query\SortClause\Name(),


code_samples/shopping_list/search/sort_clauses.php


code_samples/shopping_list/search/sort_clauses.php

docs/search/shopping_list_search_reference/shopping_list_sort_clauses.md@21:```php hl_lines="11-12"
docs/search/shopping_list_search_reference/shopping_list_sort_clauses.md@22:[[= include_file('code_samples/shopping_list/search/sort_clauses.php', 2) =]]
docs/search/shopping_list_search_reference/shopping_list_sort_clauses.md@23:```

001⫶use Ibexa\Contracts\ShoppingList\Value\Query\SortClause\IsDefault;
002⫶use Ibexa\Contracts\ShoppingList\Value\Query\SortClause\Name;
003⫶use Ibexa\Contracts\ShoppingList\Value\ShoppingListQuery;
004⫶
005⫶/** @var \Ibexa\Contracts\ShoppingList\ShoppingListServiceInterface $shoppingListService */
006⫶$lists = $shoppingListService->findShoppingLists(
007⫶ new ShoppingListQuery(
008⫶ null,
009⫶ [
010⫶ new IsDefault(IsDefault::SORT_DESC),
011❇️ new Name(),
012❇️ ]


code_samples/shopping_list/shopping_list_rest_api.sh


code_samples/shopping_list/shopping_list_rest_api.sh

docs/commerce/shopping_list/shopping_list_api.md@122:```bash
docs/commerce/shopping_list/shopping_list_api.md@123:[[= include_file('code_samples/shopping_list/shopping_list_rest_api.sh', 5) =]]
docs/commerce/shopping_list/shopping_list_api.md@124:```

001⫶# Log in and store CSRF Token
002⫶csrf_token=`curl -s -c cookie.txt -X 'POST' \
003⫶ "$BASE_URL/api/ibexa/v2/user/sessions" \
004⫶ -H 'accept: application/vnd.ibexa.api.Session+json' \
005⫶ -H 'Content-Type: application/vnd.ibexa.api.SessionInput+json' \
006⫶ -d "{
007⫶ \"SessionInput\": {
008⫶ \"login\": \"$CUSTOMER_USERNAME\",
009⫶ \"password\": \"$CUSTOMER_PASSWORD\"
010⫶ }
011⫶}" | jq -r '.Session.csrfToken'`
012⫶
013⫶# Get default shopping list identifier if it exists
014⫶default_list_identifier=`curl -s -b cookie.txt -X 'GET' \
015⫶ "$BASE_URL/api/ibexa/v2/shopping-list?isDefault=true" \
016⫶ -H 'accept: application/vnd.ibexa.api.ShoppingListCollection+json' \
017⫶ | jq -r '.ShoppingListCollection.ShoppingList[0].identifier'`
018⫶
019⫶# Clear default shopping list
020⫶if [ "" != "$default_list_identifier" ]; then
021⫶ curl -s -b cookie.txt -X 'POST' \
022⫶ "$BASE_URL/api/ibexa/v2/shopping-list/$default_list_identifier/clear" \
023⫶ -H 'accept: application/vnd.ibexa.api.ShoppingList+json' \
024⫶ -H "X-CSRF-Token: $csrf_token" | jq
025⫶fi
026⫶
027⫶# Add entries to the default shopping list,
028⫶# create it if it doesn't exist yet,
029⫶# and get the updated data
030⫶curl -s -b cookie.txt -X 'POST' \
031⫶ "$BASE_URL/api/ibexa/v2/shopping-list/default/entries" \
032⫶ -H 'accept: application/vnd.ibexa.api.ShoppingList+json' \
033⫶ -H "X-CSRF-Token: $csrf_token" \
034⫶ -H 'Content-Type: application/vnd.ibexa.api.ShoppingListEntriesAdd+json' \
035⫶ -d "{
036⫶ \"ShoppingListEntriesAdd\": {
037⫶ \"entries\": [
038⫶ {

Download colorized diff

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 4, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
130 Security Hotspots
53.0% Duplication on New Code (required ≤ 3%)
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants