Configuration
Clean-Up
After you've installed the Ecommerce Bundle with in a earlier setup, you need to clean up the default configuration.
- Remove
OpenDxp\Ecommerce\Bundle\FrontendBundle\EcommerceFrontendBundle::classfrom yourconfig\bundles.php - Remove
opendxp.security.password_hasher_factoriesfromconfig/packages/opendxp.yaml - Remove
parameters.opendxp_ecommerce.security.frontend_regexfromconfig/packages/security.yaml - Remove
providers.opendxp_ecommerce_userfromconfig/packages/security.yaml - Remove
firewalls.opendxp_ecommerce_frontendfromconfig/packages/security.yaml - Remove
%opendxp_ecommerce.security.frontend_regex%/_partialfromconfig/packages/security.yamlinaccess_control
Installation
Then, proceed with the installation of the Headless Ecommerce Bundle:
Security
# packages/security.yaml
security:
providers:
# [...]
guest_provider:
id: OpenDxp\Bundle\HeadlessEcommerceBundle\Security\GuestProvider
firewalls:
# [...]
# Ecommerce Headless Bundle Firewall
# >> must be added BEFORE headless_api and AFTER opendxp_admin firewall
ecommerce_guest: '%opendxp_headless_ecommerce_bundle.guest_firewall_settings%'
# [...]
User Class
We need to enrich our user entity with Ecommerce user entity.
- Make your user class implementation (e.g.
App\Model\ApiUser) extending from\OpenDxp\Bundle\HeadlessEcommerceBundle\Model\ApiUser - Make your user class interface (e.g.
App\Model\ApiUserInterface) extending from\OpenDxp\Bundle\HeadlessEcommerceBundle\Model\ApiUserInterface - Copy field
customerfromEcommerceUserclass into to your user class definition - Delete fields
firstnameandlastnamein your user class definition - Delete
EcommerceUserclass - Add the email validation rule for the endpoint to change the login identifier. See opendxp-headless docs for details.
Customer Class
Make sure the data object class EcommerceCustomer implements interface \OpenDxp\Bundle\HeadlessEcommerceBundle\Model\CustomerInterface (either in class definition or in your inheritance hierarchy)
Add field token to EcommerceCustomerClass:
- Location: In tab
informationat first position - Type: Input
- Unique: true
- Editable: false
Product Class
Make sure the data object EcommerceProduct implements the interface \OpenDxp\Bundle\HeadlessEcommerceBundle\Model\ProductInterface (either in class definition or in your inheritance hierarchy).
Attribute Group Class
Adjust class EcommerceAttributeGroup:
General Settings:
- Implements interface(s):
\OpenDxp\Bundle\HeadlessEcommerceBundle\Model\AttributeGroupInterface
Add field displayType:
- Type: Select
- Options Source: Configure
- Select Option Values:
list,range
Add field unit:
- Type: Input
Attributes Builder
[!NOTE]
This is an optional feature. If you want to use the product attributes builder, there are some additional steps to be done.
Make sure the data object EcommerceProduct implements the interface \OpenDxp\Bundle\HeadlessEcommerceBundle\Model\ProductAttributeSetAwareInterface (either in class definition or in your inheritance hierarchy).
Create Ecommerce Attribute Set Class
create class EcommerceAttributeSet with fields:
textfield:name (localized)opendxp_ecommerce:relations:attributeGroups (stack: opendxp_ecommerce.attribute_group))
Modify Product Class
- add field with name
attributeSetand typemanyToOneRelation(in tabattribute), allowEcommerceAttributeSet - add field with name
attributesBuilderand typeecommerceProductAttributesBuilder(in tabattribute) - set fields to hidden:
- attributeSet
- allowedAttributeGroups
- attributes
Add Translations
| label | de | en |
|---|---|---|
| opendxp_ecommerce.attribute_set | Set | Set |
| opendxp_ecommerce.attribute_set.attribute_group | Attribut-Gruppe | Attribute Group |
| opendxp_ecommerce.attribute_set.attribute_groups | Attribut-Gruppen | Attribute Grupps |
| opendxp_ecommerce.attribute_set.attributes | Attribute | Attributes |
| opendxp_ecommerce.attribute_set.create_new_attribute | Neues Attribut erstellen | Create new Attribute |
| opendxp_ecommerce.attribute_set.name | Attribut Set Name | Attribute Set Name |
Routes
Remove all Ecommerce static routes which comes by default after ecommerce bundle installation, except:
opendxp_ecommerce_product_detailopendxp_ecommerce_category_list
[!NOTE]
No static routes will be installed if the EcommerceFrontendBundle is not installed. Add the routes manually:
# backend/app/var/config/staticroutes/opendxp_ecommerce_category_list.yaml
opendxp_static_routes:
definitions:
opendxp_ecommerce_category_list:
name: opendxp_ecommerce_category_list
pattern: '/(\b(?!admin\b)[a-zA-Z0-9-_]+)\/category\/(.*?)\~c([0-9]+)$/'
reverse: /%%_locale/category/%%name-c%category
controller: App\Controller\HeadlessController::nullAction
variables: '_locale,name,category'
defaults: null
siteId: { }
methods: { }
priority: 2
creationDate: 1748444333
modificationDate: 1748444333
# backend/app/var/config/staticroutes/opendxp_ecommerce_product_detail.yaml
opendxp_static_routes:
definitions:
opendxp_ecommerce_product_detail:
name: opendxp_ecommerce_product_detail
pattern: '/(\b(?!admin\b)[a-zA-Z0-9-_]+)\/product\/(.*?)\~p([0-9]+)$/'
reverse: /%%_locale/product/%%name-p%product
controller: App\Controller\HeadlessController::nullAction
variables: '_locale,name,product'
defaults: null
siteId: { }
methods: { }
priority: 2
creationDate: 1748444333
modificationDate: 1748444333
Validation
All entity and form validation are bounded to group opendxp_ecommerce_api.
If you need to add more granular validation, add your definition to config/validator/.
Copy all files from headless-ecommerce-bundle/config/validator/*.yaml.example to your app config/validator/ and remove the .example suffix.
Messenger
bin/console messenger:consume opendxp_ecommerce_notification opendxp_ecommerce_index --time-limit=300
Dynamic Search
This bundles ships some default definitions for category / product lists
# packages/dynamic_search.yaml
dynamic_search:
context:
default:
data_provider:
options:
always:
# add ecommerce objects
object_class_names:
- EcommerceCategory
- EcommerceProduct
services:
_defaults:
autowire: true
autoconfigure: true
public: false
# Create Document Definitions
App\DynamicSearch\Definition\Document\EcommerceProductDefinition: ~ # you may want to this class from OpenDxp\Bundle\HeadlessEcommerceBundle\DynamicSearch\Definition\Document\ProductDefinition
App\DynamicSearch\Definition\Document\EcommerceCategoryDefinition: ~ # you may want to this class from OpenDxp\Bundle\HeadlessEcommerceBundle\DynamicSearch\Definition\Document\CategoryDefinition
API Describer
Route Document Describer
nelmio_api_doc:
documentation:
components:
schemas:
# should already be defined in your project!
RouteDocumentAttributes:
items:
oneOf:
- $ref: '#/components/schemas/EcommerceAttribute' # <-- add this one
# [...]
Order Completion Validator
TBD
Extend Order Completion Form
Like any other form, you're able to extend the OpenDxp\Bundle\HeadlessEcommerceBundle\Form\Type\OrderMetaDataType by using a form extension service.
Still, there are two things you need to know:
- You're not able to fetch the order object via
$form->getData(because of security reasons) but will return the submitted metadata as plain array. The order object is available in form optionsorder. - You need to take care about the mapping by yourself! Create a form event listener and populate the order
via
FormEvent::PRE_SUBMITevent for example.
Storage Lists
Storage Lists will help you to generate simple lists like wishlist / compare list easily
Configuration
opendxp_headless_ecommerce:
storage_list:
# Wishlist already exists in ecommerce bundle, so we can use the default storage list config
wishlist:
use_ecommerce_default_storage_list_config: true
# Comparelist does not exist in ecommerce bundle, so we have to define the models
# Everything else will be handled by ecommerce headless bundle
comparelist:
api_path_name: compare-list
storage_list_model: OpenDxp\Model\DataObject\EcommerceCompareList
storage_list_item_model: OpenDxp\Model\DataObject\EcommerceCompareListItem
# disable_caching: false / enable and set to true, if you want to disable opendxp object caching for list and list_item
# paths: define storage path for data objects
paths:
list: ecommerce/comparelist
item: items
Models
storage_list_model
- needs to extend from
OpenDxp\Bundle\HeadlessEcommerceBundle\StorageList\Model\StorageListclass - required fields:
- token [input]
- items [ecommerceRelations]
- customer [ecommerceRelation]
- store [ecommerceStore]
storage_list_item_model
- needs to extend from
OpenDxp\Bundle\HeadlessEcommerceBundle\StorageList\Model\StorageListItemclass - required fields:
- product [ecommerceRelation] (Stack:
opendxp_ecommerce.product) - quantity [numeric]
- storageList [ecommerceRelation] (Stack:
opendxp_ecommerce.[YOUR_STORAGE_LIST_NAME])
- product [ecommerceRelation] (Stack:
Add To Storage List DTO
If you need to use another AddToListDTO:
opendxp_headless_ecommerce:
storage_list:
comparelist:
add_to_storage_list_dto: App\DTO\YourAddToStorageListDtoClass
Expiration
If you want to enable the expiration service, add this to your storage_list_config
opendxp_headless_ecommerce:
storage_list:
comparelist:
expiration:
enabled: true
params:
days: 20
anonymous: true
customer: true
Storage Form Extension
services:
App\Form\Extension\AddToCompareListFormExtension:
tags:
- { name: form.type_extension, extended_type: OpenDxp\Bundle\HeadlessEcommerceBundle\StorageList\Form\AddToStorageListType }
<?php
namespace App\Form\Extension;
class AddToCompareListFormExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
if ($options['storage_list_name'] === 'comparelist') {
$builder->add('myAdditionalFormField', TextType::class);
}
}
public static function getExtendedTypes(): iterable
{
return [AddToStorageListType::class];
}
}