Pimcore E-Commerce Framework Overview
User
E-Commerce Framework
Why Pimcore E-Commerce Framework
The e-commerce environment has fundamentally changed and e-commerce
projects often face new challenges like:
complex product structures: lots of data attributes, complex product
relations, configurable product systems, different sources for products
complex pricing structures: product dependent price sources, tier pricing,
pricing matrices, individual pricing rules, integration of remote pricing
services
complex availability calculations
thousands customer groups with: customer group specific prices, customer
group specific assortments
individual checkouts: individual integration of backend systems,
integration of multi-channel processes into checkout workflow
individual design
highly agile projects with changing requirements: 'fail fast', fast
changing environments and requirements
etc.
We think for these challenges a default shop system that pops out of a box,
that has a fixed product data model, fixed workflows, a template based
frontend and needs to be connected and integrated with other systems via
interfaces is not the tool to go for.
We think for these challenges you need...
a framework for developers to build outstanding e-commerce solutions for
customers,
with a native integration into Pimcore,
with a component based architecture
and a strict separation between backend functionality and frontend
presentation.
That is the idea behind the E-Commerce Framework of Pimcore. Like Pimcore
itself, it is not a ready made system, it is a set of tools and
functionality to help building e-commerce applications really fast and
flexible.
Provided Functionality in a Nutshell
Tools for indexing, listing, searching and filtering products
Implementations of carts, wish lists, comparison lists, etc.
Concepts for flexible and complex pricing, taxes and availability
functionality
Functionality and tools for implementing checkout processes
Pricing Rules and Vouchers
Tools for working with and managing Orders
Concepts for setting up multi tenant and multi shop solutions
For a first impression have a look at our Demo. For more complex solutions
have a look at our case studies.
Working With E-Commerce Framework
Following aspects are short-cuts into the documentation for start working
with the E-Commerce Framework:
Architecture Overview
Installation and Configuration
Indexing and Listing Products
Filtering Products
Working with Prices
Working with Carts
Setting up Checkouts
Integrating Payment Functionality
Working with Orders
Tracking Manager
Events
ChatGPT
## Why Choose the Pimcore E-Commerce Framework?
The e-commerce landscape has evolved significantly, posing new challenges
for e-commerce projects such as:
### Complex Product Structures
- **Extensive Data Attributes:** Handling products with numerous
attributes.
- **Product Relations:** Managing complex inter-product relationships.
- **Configurable Products:** Creating systems for customizable products.
- **Diverse Sources:** Integrating products from various sources.
### Complex Pricing Structures
- **Multiple Price Sources:** Handling product-specific price data.
- **Tier Pricing:** Implementing pricing that varies with quantity.
- **Pricing Matrices:** Managing complex pricing scenarios.
- **Individual Pricing Rules:** Creating custom pricing rules.
- **Remote Services Integration:** Connecting to external pricing services.
### Availability Calculations
- **Sophisticated Availability Rules:** Implementing complex logic to
determine product availability.
### Customer Group Management
- **Customer-Specific Pricing:** Assigning prices based on customer groups.
- **Assortments:** Creating specific product assortments for different
customer groups.
### Custom Checkout Processes
- **Backend System Integration:** Customizing backend integrations for
checkouts.
- **Multi-Channel Workflows:** Integrating multi-channel processes into
checkout.
### Individual Design and Agility
- **Custom Designs:** Creating unique, custom front-end designs.
- **Agility:** Adapting to fast-changing requirements and failing fast for
rapid iteration.
### Flexible and Developer-Friendly
For these challenges, a traditional out-of-the-box shop system with fixed
product data models, workflows, and template-based frontends that require
extensive integration isn't ideal. Instead, you need:
- **A Developer Framework:** A toolkit for developers to build custom e-
commerce solutions.
- **Native Pimcore Integration:** Seamless integration with Pimcore.
- **Component-Based Architecture:** Flexible, modular components.
- **Backend-Frontend Separation:** Clear distinction between backend logic
and frontend presentation.
## Provided Functionality in a Nutshell
### Product Management
- **Indexing, Listing, Searching, Filtering:** Efficient tools for managing
and displaying products.
### Cart and Wishlist Management
- **Carts, Wishlists, Comparison Lists:** Ready-to-use implementations for
common e-commerce features.
### Pricing and Availability
- **Flexible Pricing and Taxes:** Tools for handling complex pricing and
tax scenarios.
- **Availability:** Functions for managing product availability.
### Checkout Processes
- **Custom Checkouts:** Tools for implementing tailored checkout processes.
- **Payment Integration:** Easily integrate various payment
functionalities.
### Order Management
- **Order Tools:** Comprehensive tools for managing orders.
- **Pricing Rules and Vouchers:** Implementing pricing rules and voucher
systems.
### Multi-Tenant and Multi-Shop Solutions
- **Multi-Shop Setup:** Concepts for creating and managing multiple shops
within a single Pimcore instance.
## Getting Started with the E-Commerce Framework
### Key Documentation Sections:
- **[Architecture
Overview](https://pimcore.com/docs/pimcore/current/Development_Documentatio
n/E-Commerce_Framework/Architecture_Overview.html)**
- **[Installation and
Configuration](https://pimcore.com/docs/pimcore/current/Development_Documen
tation/E-Commerce_Framework/Installation_and_Configuration.html)**
- **[Indexing and Listing
Products](https://pimcore.com/docs/pimcore/current/Development_Documentatio
n/E-Commerce_Framework/Indexing_and_Listing_Products.html)**
- **[Filtering
Products](https://pimcore.com/docs/pimcore/current/Development_Documentatio
n/E-Commerce_Framework/Filtering_Products.html)**
- **[Working with
Prices](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Working_with_Prices.html)**
- **[Working with
Carts](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Working_with_Carts.html)**
- **[Setting up
Checkouts](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/Setting_up_Checkouts.html)**
- **[Integrating Payment
Functionality](https://pimcore.com/docs/pimcore/current/Development_Documen
tation/E-Commerce_Framework/Integrating_Payment_Functionality.html)**
- **[Working with
Orders](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Working_with_Orders.html)**
- **[Tracking
Manager](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Tracking_Manager.html)**
-
**[Events](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/Events.html)**
For a practical demonstration, you can explore the [Pimcore
Demo](https://demo.pimcore.com/) and review complex case studies to
understand the framework's capabilities.
User
Architecture Overview
The following architecture overview shows available framework components.
The component configuration takes place in the pimcore_ecommerce_framework
configuration node and a factory is responsible for resolving of the
implementations. For each component a custom implementation can be
configured and used.
bigpicture
Separation of Concerns
We try to separate different functionality and encapsulate them as good as
possible in the different components. Following list should state the basic
ideas and represent a guideline for future extensions:
Index Service
The Index Service is responsible for all aspects concerning indexing
products and providing an API to access product data from the index.
These aspects contain among other things:
Defining which attributes should be indexed.
Implementations for different search backends (e.g. mysql, elasticsearch,
fact finder, findologic).
Product Lists as the API to access the product data stored in the search
index. Product Lists can be used by controllers to display product
listings.
Filter Service
The Filter Service is responsible for all aspects concerning filtering
products and setting up a filtered navigation. It is tightly coupled with
the Product Lists of the Index Service, provides the developer a simple API
for building a layered navigation and takes care of query generation,
counting results and stuff.
Availability System
The Availability System is responsible for all aspects concerning product
availability. Here the logic for calculating availabilities, calling
external availability services, etc. is encapsulated. Each product has an
Availability System assigned and when it comes to getting the availability
of a product, this should be delegated to the Availability System of the
product.
Price System and Taxes
Like Availability Systems, there are Price Systems which are responsible
for all aspects of getting product prices. Here the logic of calculating
the product prices should be encapsulated. Each product has a Price System
and when it comes to getting the price of a product, this should be
delegated to the Price System of the product.
Also Tax Management is located in this component.
Pricing Manager
In addition to the Price System, there is the Pricing Manager which is
responsible for all aspects concerning modification of prices for marketing
purposes. Therefore pricing rules (e.g. certain products, certain time
frames, ...) build conditions which need to be valid that certain pricing
actions (e.g. product price discount, free shipping, ...) are executed.
Voucher System
The Voucher System is responsible for all aspects concerning vouchers for
customers. These aspects contain among other things:
Voucher Services
Voucher Tokens
Voucher Statistics
Modification of product prices based on vouchers which is done with the
help of the Pricing Manager.
Cart Manager
The Cart Manager is responsible for all aspects concerning carts. These
aspects contain among other things:
Different cart implementations
CRUD-Operations on carts
Price calculations for carts
Price modifications for carts (like shipping costs, etc.)
Checkout Manager
The Checkout Manager is responsible for all aspects concerning checkout
process and an one-stop API for getting through the checkout process. The
Checkout Manager always works with a cart and at certain points in the
checkout process it delegates to other components to convert the cart to an
order object (Order Manager), start payment operations (Commit Order
Processor and Payment Manager) and commits the order (Commit Order
Processor).
Commit Order Processor
The Commit Order Processor is part of the Checkout Manager namespace and is
responsible for all aspects concerning committing and order.
These aspects contain among other things:
Handle payment response
commit order payment
commit order and send order to other backend systems (e.g. erp system)
In contrast to the Checkout Manager, the Commit Order Processor does not
work with carts anymore and can be initialized without a cart. Therefore it
also can be used to commit orders in combination with server side payment
notifications when no cart is available anymore.
Payment Manager
The Payment Manager is responsible for all aspects concerning payment. The
main aspect is the implementation of different Payment Providers to
integrate them into the framework.
Order Manager
The Order Manager is responsible for all aspects of working with orders
except committing them (which is the responsibility of the Commit Order
Processor). These aspects contain among other things:
Creating orders based on carts
Order Storage
Loading orders
Loading order lists and filter them (Order List)
Working with orders after order commit (Order Agent)
ChatGPT
## Pimcore E-Commerce Framework Architecture Overview
The Pimcore E-Commerce Framework is designed to provide a flexible and
robust set of tools for building custom e-commerce solutions. It leverages
a component-based architecture with a strict separation of concerns,
ensuring that different functionalities are well encapsulated within
distinct components. Here's a detailed look at the key components:
### Index Service
The **Index Service** handles all aspects of product indexing and provides
an API for accessing product data from the index.
- **Attribute Definition:** Determine which attributes are indexed.
- **Search Backend Implementations:** Supports various search backends like
MySQL, Elasticsearch, Fact Finder, Findologic.
- **Product Lists:** API for accessing indexed product data, used by
controllers to display product listings.
### Filter Service
The **Filter Service** manages product filtering and filtered navigation.
- **Layered Navigation:** Provides a simple API for building layered
navigation.
- **Query Generation and Result Counting:** Handles the generation of
queries and counting of filtered results.
- **Integration with Index Service:** Works closely with Product Lists for
displaying filtered products.
### Availability System
The **Availability System** deals with product availability calculations
and integration with external availability services.
- **Availability Logic:** Encapsulates the logic for determining product
availability.
- **External Services:** Integrates with external availability services.
- **Product Assignment:** Each product has an assigned Availability System
for availability checks.
### Price System and Taxes
The **Price System** manages product pricing and tax calculations.
- **Price Calculation:** Encapsulates logic for calculating product prices.
- **Product Assignment:** Each product has an assigned Price System.
- **Tax Management:** Manages tax calculations and assignments.
### Pricing Manager
The **Pricing Manager** handles modifications to product prices for
marketing purposes.
- **Pricing Rules:** Conditions under which certain pricing actions (e.g.,
discounts, free shipping) are executed.
- **Pricing Actions:** Actions that modify product prices based on the
rules.
### Voucher System
The **Voucher System** manages customer vouchers.
- **Voucher Services:** Core functionalities related to vouchers.
- **Voucher Tokens:** Handles the creation and validation of voucher
tokens.
- **Voucher Statistics:** Tracks voucher usage and effectiveness.
- **Price Modifications:** Works with the Pricing Manager to apply voucher-
based price changes.
### Cart Manager
The **Cart Manager** oversees all cart-related operations.
- **Cart Implementations:** Different types of cart implementations.
- **CRUD Operations:** Create, Read, Update, Delete operations on carts.
- **Price Calculations:** Computes prices for cart items.
- **Price Modifications:** Applies additional charges or discounts (e.g.,
shipping costs).
### Checkout Manager
The **Checkout Manager** handles the entire checkout process.
- **Cart to Order Conversion:** Converts cart to order object via the Order
Manager.
- **Payment Operations:** Initiates payment processes through the Payment
Manager.
- **Order Commitment:** Commits the order using the Commit Order Processor.
### Commit Order Processor
The **Commit Order Processor** finalizes the order process.
- **Payment Handling:** Manages payment responses and commits payments.
- **Order Commitment:** Sends the committed order to backend systems (e.g.,
ERP).
- **Independent Operation:** Can commit orders without a cart, useful for
server-side payment notifications.
### Payment Manager
The **Payment Manager** integrates various payment providers into the
framework.
- **Payment Providers:** Implements different payment methods.
- **Payment Processing:** Manages the entire payment transaction lifecycle.
### Order Manager
The **Order Manager** manages all post-commit order operations.
- **Order Creation:** Creates orders from carts.
- **Order Storage:** Handles storage and retrieval of orders.
- **Order Lists:** Loads and filters order lists.
- **Order Post-Processing:** Manages orders after they are committed (Order
Agent).
## Component Configuration
All components are configured within the `pimcore_ecommerce_framework`
configuration node. The framework uses a factory pattern to resolve the
implementations, allowing for custom implementations for each component.
## Conclusion
The Pimcore E-Commerce Framework's architecture provides a flexible,
modular approach to building e-commerce solutions. By separating concerns
and encapsulating functionalities within distinct components, it ensures
scalability, maintainability, and ease of customization.
User
Installation and First Configuration
This section describes the installation of the E-Commerce Framework and the
first steps of configuration.
Installation
Minimum Requirements
Pimcore >= 11.0
Install
Install bundle via composer:
composer require pimcore/ecommerce-framework-bundle
Enable bundle via console or extensions manager:
php bin/console pimcore:bundle:install PimcoreEcommerceFrameworkBundle
Check if the bundle has been installed:
php bin/console pimcore:bundle:list
+---------------------------------+---------+-----------+----+-----+-----+
| Bundle | Enabled | Installed | I? | UI? | UP? |
+---------------------------------+---------+-----------+----+-----+-----+
| PimcoreEcommerceFrameworkBundle | ✔ | ✔ | ❌ | ✔ | ❌ |
+---------------------------------+---------+-----------+----+-----+-----+
The installer does following tasks:
Install several field collections.
Install several object classes.
Install several object bricks.
Create additional tables for carts, pricing rules, vouchers, etc.
Import translations for Pimcore Admin UI and Order Backend.
Add additional permissions.
If either classes, field collections, object bricks or tables already
exist, the installation cannot be started.
After this installation routine, additional configurations have to be made
- most important Product and ProductCategory. Please see Configuration for
further information on available options.
Configure Product and Product Category Class
The E-Commerce Framework installation does not create classes for products
and product categories. That is because the framework does not limit you on
specific classes or class structures. Literally every class can act as a
product or product category class and it is also possible to have several
product classes (if necessary).
The only requirement is, that the classes have to be 'prepared' for being
products or product categories.
Product
There are two ways of preparing a Pimcore class for product-usage in the E-
Commerce Framework
The Pimcore class needs to extend the abstract class \Pimcore\Bundle\
EcommerceFrameworkBundle\Model\AbstractProduct
This is useful, when both product index and checkout functionality are
based on the E-Commerce Framework.
Make sure that the Pimcore class implements either \Pimcore\Bundle\
EcommerceFrameworkBundle\Model\IndexableInterface or \Pimcore\Bundle\
EcommerceFrameworkBundle\Model\CheckoutableInterface - or both, depending
on the use case it is used for.
This is useful, when e.g. only checkout functionality is based on the E-
Commerce Framework, but not the product presentation.
The interfaces define methods that are needed for the two use cases and
need to be implemented.
For the abstract class use the parent class functionality of Pimcore. For
implementing the interfaces use either the parent class functionality or
the overriding models functionality of Pimcore (see also Overriding
Models).
If using the abstract class, also have a look at its implementation. You
might need to override a few methods that cannot be implemented by the
abstract class and throw an exception depending on the use case you are
using it.
Product Category
When a product category class is used, this class needs to extend the
abstract class \Pimcore\Bundle\EcommerceFrameworkBundle\Model\
AbstractCategory.
For product categories only one Pimcore class should be used. For products,
several Pimcore classes can be used. Possibly the index update scripts need
to be adapted.
Configuring Pimcore Ecommerce Framework
The E-Commerce Framework is split up into multiple components which can be
configured individually. For further reading please see:
Configuration describes configuration features valid for the whole
framework configuration
PimcoreEcommerceFrameworkBundle Configuration Reference contains a
reference of the whole configuration tree
Please see the following sections for a description of each component and
and a configuration reference describing the configuration entries relevant
to the component:
Cart Manager
Price Systems
Availability Systems
Checkout Manager and Checkout Steps
Payment Providers
Index Service and which attributes should be in the Product Index
Pricing Manager
...
For detailed information see comments within the configuration file.
Depending on your use case, you might not need all components configured in
the configuration file.
During development you will return to the configuration and adjust the
settings multiple times.
ChatGPT
## Installation and First Configuration of Pimcore E-Commerce Framework
### Minimum Requirements
- **Pimcore Version:** Pimcore >= 11.0
### Installation Steps
1. **Install the Bundle via Composer:**
```bash
composer require pimcore/ecommerce-framework-bundle
```
2. **Enable the Bundle:**
You can enable the bundle using the console or the extensions manager.
```bash
php bin/console pimcore:bundle:install PimcoreEcommerceFrameworkBundle
```
3. **Verify Installation:**
Check if the bundle has been successfully installed.
```bash
php bin/console pimcore:bundle:list
```
You should see:
```plaintext
+---------------------------------+---------+-----------+----+-----
+-----+
| Bundle | Enabled | Installed | I? | UI? | UP?
|
+---------------------------------+---------+-----------+----+-----
+-----+
| PimcoreEcommerceFrameworkBundle | ✔ | ✔ | ❌ | ✔ | ❌
|
+---------------------------------+---------+-----------+----+-----
+-----+
```
### Installation Tasks
The installer performs the following tasks:
- Installs several field collections.
- Installs several object classes.
- Installs several object bricks.
- Creates additional tables for carts, pricing rules, vouchers, etc.
- Imports translations for Pimcore Admin UI and Order Backend.
- Adds additional permissions.
> **Note:** If classes, field collections, object bricks, or tables already
exist, the installation cannot be started.
### Post-Installation Configuration
#### Configuring Product and Product Category Classes
The E-Commerce Framework does not create product and product category
classes. You must configure these manually.
1. **Product Configuration:**
There are two ways to prepare a Pimcore class for product usage in the
E-Commerce Framework:
- **Extend Abstract Class:**
The class should extend `\Pimcore\Bundle\EcommerceFrameworkBundle\
Model\AbstractProduct`. This is useful when both product index and checkout
functionality rely on the E-Commerce Framework.
```php
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractProduct;
class MyProduct extends AbstractProduct {
// Implement necessary methods
```
- **Implement Interfaces:**
The class should implement `\Pimcore\Bundle\EcommerceFrameworkBundle\
Model\IndexableInterface` or `\Pimcore\Bundle\EcommerceFrameworkBundle\
Model\CheckoutableInterface` (or both) based on the required functionality.
```php
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\IndexableInterface;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\
CheckoutableInterface;
class MyProduct implements IndexableInterface, CheckoutableInterface {
// Implement necessary methods
```
2. **Product Category Configuration:**
Product category classes should extend `\Pimcore\Bundle\
EcommerceFrameworkBundle\Model\AbstractCategory`.
```php
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractCategory;
class MyProductCategory extends AbstractCategory {
// Implement necessary methods
```
> **Note:** For product categories, only one Pimcore class should be used.
For products, multiple classes can be utilized, which might require
adapting index update scripts.
### Configuring the Pimcore E-Commerce Framework
The E-Commerce Framework is divided into multiple components that can be
configured individually. Key configuration areas include:
- **Cart Manager**
- **Price Systems**
- **Availability Systems**
- **Checkout Manager and Checkout Steps**
- **Payment Providers**
- **Index Service (Product Attributes)**
- **Pricing Manager**
### Configuration Reference
#### General Configuration
For a comprehensive guide to configuring the framework, refer to the
configuration file comments and the following resources:
-
**[Configuration](https://pimcore.com/docs/pimcore/current/Development_Docu
mentation/E-Commerce_Framework/Configuration.html)**: General framework
configuration features.
- **[PimcoreEcommerceFrameworkBundle Configuration
Reference](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/
PimcoreEcommerceFrameworkBundle_Configuration_Reference.html)**: Detailed
configuration tree reference.
#### Component Configuration
Each component has specific configuration entries. Refer to the relevant
sections for detailed configuration instructions:
- **[Cart
Manager](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Cart_Manager.html)**
- **[Price
Systems](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Price_Systems.html)**
- **[Availability
Systems](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Availability_Systems.html)**
- **[Checkout Manager and Checkout
Steps](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Checkout_Manager_and_Checkout_Steps.html)**
- **[Payment
Providers](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/Payment_Providers.html)**
- **[Index
Service](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Index_Service.html)**
- **[Pricing
Manager](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Pricing_Manager.html)**
> **Tip:** During development, you will frequently revisit and adjust the
configuration settings to fine-tune your e-commerce solution.
By following these steps and guidelines, you can successfully install and
configure the Pimcore E-Commerce Framework to create a robust, flexible,
and scalable e-commerce solution.
User
Configuration
The E-Commerce Framework is implemented as semantic bundle configuration
which means that you can configure the framework in any of the loaded
config files (e.g. /config/config.yaml or
*Bundle/Resources/config/pimcore/config.yaml) by adding configuration to
the pimcore_ecommerce_framework node.
The configuration is built upon the Symfony Config Component and defines a
well-known configuration tree which is validated against a defined
configuration structure. While configuring the framework you'll get instant
feedback on configuration errors. As Pimcore defines a standard
configuration for the E-Commerce Framework, your custom configuration will
be merged into the standard configuration. You can dump the final (merged,
validated and normalized) configuration at any time with the following
command:
$ bin/console debug:config pimcore_ecommerce_framework
A reference of available configuration entries can be found on
PimcoreEcommerceFrameworkBundle Configuration Reference.
As the E-Commerce Framework makes heavy use of Symfony service definitions
and you'll need to reference IDs of custom services in the configuration
it's advised that you are comfortable to work with Symfony's Service
Container.
Tenant support and _defaults sections
As certain components of the E-Commerce Framework support different
tenants, Pimcore adds a way to specify settings which are common to all
tenants in a special tenant named _defaults. If such a tenant exists, its
values will be merged into all other tenants and the _defaults tenant will
be removed afterwards. The logic described below applies to all components
supporting tenants.
As example, a simple cart_manager configuration section which defines a
default and a noShipping tenant:
pimcore_ecommerce_framework:
cart_manager:
tenants:
# _defaults will be automatically merged into every tenant and
removed afterwards
# the result will be a default and a noShipping
_defaults:
cart:
factory_id: CartFactoryId
price_calculator:
factory_id: PriceCalculatorFactoryId
factory_options:
foo: bar
default:
price_calculator:
factory_options:
baz: 1234
noShipping:
price_calculator:
factory_options:
baz: 4321
In addition to the _defaults tenant, you can define additional tenants
starting with _defaults to make use of YAML inheritance.
pimcore_ecommerce_framework:
cart_manager:
tenants:
_defaults_foo:
price_calculator:
factory_options: &defaults_foo_options # define an
anchor
class: MyCommonCalculatorClass
default:
price_calculator:
factory_options:
<<: *defaults_foo_options # import anchor
anotherOne:
price_calculator:
factory_options:
<<: *defaults_foo_options # import anchor
Of course you can still use the PHP config file format by importing a PHP
config file from your config.yaml to be completely free how to merge common
configuration entries.
Service IDs and tenant specifics
When configuring tenant specific services, there are multiple configuration
entries demanding a service ID as configuration value. This means, the
system expects the configured value to be available as service definition
on the container. You can read through the service definitions defined in
PimcoreEcommerceFrameworkBundle to get an insight of default e-commerce
services.
As an example let's take a look at a price system configuration:
# when loading the "default" price system, use a service named "App\
Ecommerce\PriceSystem\CustomPriceSystem"
pimcore_ecommerce_framework:
price_systems:
default:
# price system defined and configured as container service
id: App\Ecommerce\PriceSystem\CustomPriceSystem
The configuration above expects something like this configured as service:
services:
App\Ecommerce\PriceSystem\CustomPriceSystem:
arguments:
- 'foo'
The "default" price system is just an alias to your existing service and
when loading that price system, your service will be directly loaded.
Getting the "default" price system from the ecommerce framework factory
will result in the same instance as getting App\Ecommerce\PriceSystem\
CustomPriceSystem directly from the container.
Service IDs in tenant context
Now let's take a look at another example handling tenants:
pimcore_ecommerce_framework:
order_manager:
tenants:
default:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager
options:
# parent_order_folder: /orders/default/%%Y/%%m/%%d #
deprecated and discouraged
order_parent_path: /orders/default/*Y*/*M*/*D*
b2b:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager
options:
# parent_order_folder: /orders/b2b/%%Y/%%m/%%d #
deprecated and discouraged
order_parent_path: /orders/b2b/*Y*/*M*/*D*
As you can see we define 2 tenants default and b2b with the same order
manager ID but with different options for each tenant. In this case it's
not possible to just alias the default or the b2b order manager to the
given service ID as we need multiple order manager instances based on this
service definition. In this case the framework takes the configured service
ID as template to configure 2 independent child services by utilizing the
configured service id as parent service.
This means, that when you request the Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\OrderManager service from the
container, it would be neither the default nor the b2b tenant. In fact,
getting that service directly wouldn't work anyways as it is missing
dependencies. If you take a look at the service definition you can see that
the definition is missing the OrderAgentFactoryInterface argument which
will be resolved and set for each tenant specific order manager.
In short, when configuring multiple tenant specific service to the same
service id the framework will:
create a new child definition from the configured service
set tenant specific arguments (as the options above) to the tenant specific
child service
register the child service under a another ID which can be resolved by the
factory
To keep your services clean and give the service container more
optimization (and performance) possibilities you should define your parent
services as private (see order manager definition in the linked config
above) as this will result in the parent definition being removed from the
compiled container.
This child definition pattern applies to nearly all service IDs configured
inside tenants with the exception of reusable services (e.g. getters and
interpreters in the product index configuration) which do not have an
internal state and therefore can be reused throughout multiple tenants.
ChatGPT
## Configuration of the Pimcore E-Commerce Framework
The E-Commerce Framework is configured as a semantic bundle, allowing you
to customize it within any loaded config files (e.g., `/config/config.yaml`
or `*Bundle/Resources/config/pimcore/config.yaml`) by adding settings to
the `pimcore_ecommerce_framework` node. It utilizes the Symfony Config
Component, which provides a structured configuration tree validated against
a predefined schema. This ensures that configuration errors are identified
instantly.
### Key Configuration Steps
1. **Dump the Final Configuration:**
You can view the merged, validated, and normalized configuration at any
time using the following command:
```bash
bin/console debug:config pimcore_ecommerce_framework
```
2. **Reference Documentation:**
Refer to the [PimcoreEcommerceFrameworkBundle Configuration Reference]
(https://pimcore.com/docs/pimcore/current/Development_Documentation/E-
Commerce_Framework/
PimcoreEcommerceFrameworkBundle_Configuration_Reference.html) for a
comprehensive list of available configuration entries.
### Tenant Support and _defaults Sections
Certain components support different tenants. Pimcore allows you to specify
settings common to all tenants using a special tenant named `_defaults`.
These settings are automatically merged into all other tenants.
#### Example Configuration:
```yaml
pimcore_ecommerce_framework:
cart_manager:
tenants:
_defaults:
cart:
factory_id: CartFactoryId
price_calculator:
factory_id: PriceCalculatorFactoryId
factory_options:
foo: bar
default:
price_calculator:
factory_options:
baz: 1234
noShipping:
price_calculator:
factory_options:
baz: 4321
```
You can also define additional tenants starting with `_defaults` to utilize
YAML inheritance.
#### Inheritance Example:
```yaml
pimcore_ecommerce_framework:
cart_manager:
tenants:
_defaults_foo:
price_calculator:
factory_options: &defaults_foo_options
class: MyCommonCalculatorClass
default:
price_calculator:
factory_options:
<<: *defaults_foo_options
anotherOne:
price_calculator:
factory_options:
<<: *defaults_foo_options
```
### Service IDs and Tenant-Specific Services
When configuring tenant-specific services, multiple entries might require a
service ID as the configuration value. This means the system expects the
configured value to be available as a service definition in the container.
#### Example: Price System Configuration
```yaml
pimcore_ecommerce_framework:
price_systems:
default:
id: App\Ecommerce\PriceSystem\CustomPriceSystem
```
Service definition:
```yaml
services:
App\Ecommerce\PriceSystem\CustomPriceSystem:
arguments:
- 'foo'
```
### Tenant-Specific Service Configuration
In cases where multiple tenant-specific services are needed, you can define
these in a way that each tenant has its own instance derived from a common
service template.
#### Example: Order Manager Configuration
```yaml
pimcore_ecommerce_framework:
order_manager:
tenants:
default:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager
options:
order_parent_path: /orders/default/*Y*/*M*/*D*
b2b:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager
options:
order_parent_path: /orders/b2b/*Y*/*M*/*D*
```
In this configuration:
- The `order_manager_id` is used as a template to create two independent
child services with tenant-specific options.
- The framework handles the creation of child definitions and assigns
tenant-specific arguments to these child services, which are then
registered under different IDs for factory resolution.
> **Note:** When configuring multiple tenant-specific services to the same
service ID, the framework will:
1. Create a new child definition from the configured service.
2. Set tenant-specific arguments to the child service.
3. Register the child service under another ID for resolution by the
factory.
### Best Practices
- **Parent Services:** Define parent services as private to optimize the
service container and improve performance. The parent definition is removed
from the compiled container, leaving only the tenant-specific child
services.
By adhering to these configuration guidelines and leveraging the flexible
architecture of the Pimcore E-Commerce Framework, you can build a robust
and scalable e-commerce solution tailored to your specific needs.
User
PimcoreEcommerceFrameworkBundle Configuration Reference
The following is the generated reference for the
pimcore_ecommerce_framework configuration tree. This reference can be
generated by issuing the following command:
$ bin/console config:dump-reference pimcore_ecommerce_framework
IMPORTANT This is just a reference for the configuration tree, you need to
adjust it to replace the required configurations by setting up the
respective module.
# Default configuration for extension with alias:
"pimcore_ecommerce_framework"
pimcore_ecommerce_framework:
# Default scale used for Decimal objects
decimal_scale: 4
# Configuration of Pimcore backend menu entries
pimcore:
menu:
# Enabling/Disabling Pricing Rules menu entry. User specific
settings can be done via permissions.
pricing_rules:
enabled: true
# Configuring order list menu - enabling/disabling and defining
route of order list to inject custom implementations of order backend.
order_list:
enabled: true
route: pimcore_ecommerce_backend_admin-
order_list
path: null
# Configuration of e-commerce framework factory
factory:
# Service Id of factory implementation
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Factory
# If true the factory will not fall back to the default tenant if a
tenant is passed but not existing
strict_tenants: false
# Configuration of environment
environment:
environment_id: Pimcore\Bundle\EcommerceFrameworkBundle\
SessionEnvironment
options: []
# Settings for cart manager
cart_manager:
# Configuration per tenant. If a _defaults key is set, it will be
merged into every tenant. It needs to be set in every file. A tenant named
"default" is mandatory.
tenants:
# Examples:
_defaults:
cart:
factory_id: CartFactory
default:
cart:
factory_options:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart
price_calculator:
modificators:
shipping:
class: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\CartPriceModificator\Shipping
options:
charge: 5.90
noShipping:
price_calculator:
factory_id: PriceCalculatorFactory
modificators: []
# Prototype
name:
# Service id of cart service
cart_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\MultiCartManager
# Configuration for carts
cart:
# Service id of cart factory and configuration array
factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\CartFactory
factory_options:
# Defaults:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart
guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart
price_calculator:
factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\CartPriceCalculatorFactory
factory_options:
# 'class' defines the class name of the price
calculator, which the factory instantiates.
# If you wish to replace or extend the price
calculation routine shipped with the e-commerce
# framework provide your custom class name here.
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceCalculator
# List price modificators for cart, e.g. for shipping-
cost, special discounts, etc. Key is name of modificator.
modificators:
# Prototype
name:
class: ~ # Required
options: []
# Configuration of Order Manager
order_manager:
# Configuration per tenant. If a _defaults key is set, it will be
merged into every tenant. A tenant named "default" is mandatory.
tenants:
# Prototype
name:
# Service id for order manager implementation
order_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\V7\OrderManager
# Options for order manager
options:
# Pimcore object class for orders
order_class: \Pimcore\Model\DataObject\
OnlineShopOrder
# Pimcore object class for order items
order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem
# Class for order listing
list_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing
# Class for order item listing
list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item
# Default parent folder for new orders
# parent_order_folder: /order/%%Y/%%m/%%d # deprecated
and discouraged
order_parent_path: /order/*Y*/*M*/*D*
order_agent:
# Service id for order agent factory
factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\AgentFactory
factory_options: []
# Configuration of Pricing Manager
pricing_manager:
# Condition mapping from name to used class
conditions:
# Prototype
name: ~
# Action mapping from name to used class
actions:
# Prototype
name: ~
# Configuration per tenant. If a _defaults key is set, it will be
merged into every tenant. A tenant named "default" is mandatory.
tenants:
default: ~
# Prototype
name:
enabled: true
# Service id of pricing manager
pricing_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PricingManager
# Options for pricing manager
pricing_manager_options:
rule_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Rule
price_info_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PriceInfo
environment_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Environment
# Configuration of price systems - key is name of price system.
price_systems:
# Prototype
name:
id: ~ # Required
# Configuration of availability systems - key is name of price system.
availability_systems:
# Prototype
name:
id: ~ # Required
# Configuration of checkout manager
checkout_manager:
# Configuration per tenant. If a _defaults key is set, it will be
merged into every tenant. A tenant named "default" is mandatory.
tenants:
# Prototype
name:
factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\CheckoutManagerFactory
factory_options: []
# Define payment provider which should be used for payment.
Payment providers are defined in payment_manager section.
payment:
provider: null
# Define used commit order processor
commit_order_processor:
id: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\CommitOrderProcessor
options: []
# Define different checkout steps which need to be
committed before commit of order is possible
steps:
# Prototype
name:
class: ~ # Required
options: []
# Configuration of payment manager and payment providers
payment_manager:
payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager
# Configuration of payment providers, key is name of provider.
providers:
# Prototype
name:
name: ~
# Service id of payment provider implementation
provider_id: ~ # Required
# Currently active profile
profile: ~ # Required
# Available profiles with options
profiles:
# Prototype
name:
# Prototype
name: ~
# Configuration of index service
index_service:
index_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\IndexService
default_tenant: default
# Configure assortment tenants - at least one tenant has to be
configured. If a _defaults key is set, it will be merged into every tenant.
tenants:
# Prototype
name:
enabled: true
# Service id of config implementation
config_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\DefaultMysql
config_options: []
# Worker id of worker implementation. Can be omitted, then
default worker id of configured config is used.
worker_id: ~
# Placeholder values in this tenant attributes definition
(locale: "%%locale%%") will be replaced by the given placeholder value (eg.
"de_AT")
placeholders:
'%%locale%%': 'de_AT'
# Add columns for general fulltext search index of product
list - they must be part of the column configuration below
search_attributes: []
# Attributes definition for product index - key is name of
attribute
attributes:
# Prototype
name:
name: ~ # Required
# Defines object attribute field name, can be
omitted if the same like name of index attribute
field_name: null
# Type of index attribute (database column or
elasticsearch data type)
type: null
# Locale for localized fields, can be omitted if
not necessary
locale: null
# Defines filter group for filter definition in
filter service
filter_group: null
options: []
# Service id of getter for this field
getter_id: null
getter_options: []
# Service id of interpreter for this field
interpreter_id: null
interpreter_options: []
# Hides field in field list selection data type of
filter service - default to false
hide_in_fieldlist_datatype: false
# Configuration of filter service
filter_service:
# Configuration per tenant. If a _defaults key is set, it will be
merged into every tenant.
tenants:
# Prototype
name:
enabled: true
service_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterService
# Assign backend implementations and views to filter type
field collections
filter_types:
# Prototype
name:
# Service id for filter type implementation
filter_type_id: ~ # Required
# Default template for filter, can be overwritten
in filter definition
template: ~ # Required
options: []
# Configuration of voucher service
voucher_service:
# Service id of voucher service implementation
voucher_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\DefaultService
voucher_service_options:
# Reservations older than x MINUTES get removed by maintenance
task
reservation_minutes_threshold: 5
# Statistics older than x DAYS get removed by maintenance task
statistics_days_threshold: 30
# Configuration of token managers
token_managers:
# Service id of token manager factory
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\TokenManager\TokenManagerFactory
# Mapping for token manager implementations
mapping:
# Prototype
name: ~
# Configuration of offer tool
offer_tool:
# Service id for offer tool service
service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OfferTool\DefaultService
order_storage:
# Pimcore object class for offers
offer_class: Pimcore\Model\DataObject\OfferToolOffer
# Pimcore object class for offer items
offer_item_class: Pimcore\Model\DataObject\
OfferToolOfferItem
# default path for new offers
offer_parent_path: /offertool/offers/*Y*/*M*
#parent_folder_path: /offertool/offers/%%Y/%%m # deprecated
and discouraged, use offer_parent_path instead
# Configuration of Tracking Manager
tracking_manager:
# Service id of tracking manager
tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager
# Enable/Disable trackers and configure them
trackers:
# Prototype
enhanced_ecommerce:
# Service id for tracker
id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce
enabled: false
# Service id for item builder for tracker
item_builder_id: Pimcore\Bundle\
EcommerceFrameworkBundle\Tracking\TrackingItemBuilder
# List of assortment and checkout tenants where this
tracker should be activated for.
tenants:
# Add list of assortment tenants where the tracker
should be activated for. Empty array means activated for all tenants.
assortment: []
# Add list of checkout tenants where the tracker should
be activated for. Empty array means activated for all tenants.
checkout: []
ChatGPT
The Pimcore E-Commerce Framework's configuration tree is extensive and
allows for a high degree of customization to meet various business needs.
Below is a detailed reference for configuring the different components of
the `pimcore_ecommerce_framework`.
### Configuration Tree
```yaml
pimcore_ecommerce_framework:
# Default scale used for Decimal objects
decimal_scale: 4
# Configuration of Pimcore backend menu entries
pimcore:
menu:
pricing_rules:
enabled: true
order_list:
enabled: true
route: pimcore_ecommerce_backend_admin-order_list
path: null
# Configuration of e-commerce framework factory
factory:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\Factory
strict_tenants: false
# Configuration of environment
environment:
environment_id: Pimcore\Bundle\EcommerceFrameworkBundle\
SessionEnvironment
options: []
# Settings for cart manager
cart_manager:
tenants:
_defaults:
cart:
factory_id: CartFactory
default:
cart:
factory_options:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart
price_calculator:
modificators:
shipping:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping
options:
charge: 5.90
noShipping:
price_calculator:
factory_id: PriceCalculatorFactory
modificators: []
# Prototype
name:
cart_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\MultiCartManager
cart:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartFactory
factory_options:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart
guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart
price_calculator:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceCalculatorFactory
factory_options:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceCalculator
modificators:
# Prototype
name:
class: ~ # Required
options: []
# Configuration of Order Manager
order_manager:
tenants:
# Prototype
name:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager
options:
order_class: \Pimcore\Model\DataObject\OnlineShopOrder
order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem
list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing
list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item
order_parent_path: /order/*Y*/*M*/*D*
order_agent:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory
factory_options: []
# Configuration of Pricing Manager
pricing_manager:
conditions:
# Prototype
name: ~
actions:
# Prototype
name: ~
tenants:
default: ~
# Prototype
name:
enabled: true
pricing_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PricingManager
pricing_manager_options:
rule_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\Rule
price_info_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PriceInfo
environment_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Environment
# Configuration of price systems
price_systems:
# Prototype
name:
id: ~ # Required
# Configuration of availability systems
availability_systems:
# Prototype
name:
id: ~ # Required
# Configuration of checkout manager
checkout_manager:
tenants:
# Prototype
name:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory
factory_options: []
payment:
provider: null
commit_order_processor:
id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor
options: []
steps:
# Prototype
name:
class: ~ # Required
options: []
# Configuration of payment manager and payment providers
payment_manager:
payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager
providers:
# Prototype
name:
name: ~
provider_id: ~ # Required
profile: ~ # Required
profiles:
# Prototype
name:
# Prototype
name: ~
# Configuration of index service
index_service:
index_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\IndexService
default_tenant: default
tenants:
# Prototype
name:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
config_options: []
worker_id: ~
placeholders:
'%%locale%%': 'de_AT'
search_attributes: []
attributes:
# Prototype
name:
name: ~ # Required
field_name: null
type: null
locale: null
filter_group: null
options: []
getter_id: null
getter_options: []
interpreter_id: null
interpreter_options: []
hide_in_fieldlist_datatype: false
# Configuration of filter service
filter_service:
tenants:
# Prototype
name:
enabled: true
service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
FilterService\FilterService
filter_types:
# Prototype
name:
filter_type_id: ~ # Required
template: ~ # Required
options: []
# Configuration of voucher service
voucher_service:
voucher_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\DefaultService
voucher_service_options:
reservation_minutes_threshold: 5
statistics_days_threshold: 30
token_managers:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\TokenManager\TokenManagerFactory
mapping:
# Prototype
name: ~
# Configuration of offer tool
offer_tool:
service_id: Pimcore\Bundle\EcommerceFrameworkBundle\OfferTool\
DefaultService
order_storage:
offer_class: Pimcore\Model\DataObject\OfferToolOffer
offer_item_class: Pimcore\Model\DataObject\OfferToolOfferItem
offer_parent_path: /offertool/offers/*Y*/*M*
# Configuration of Tracking Manager
tracking_manager:
tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager
trackers:
# Prototype
enhanced_ecommerce:
id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce
enabled: false
item_builder_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingItemBuilder
tenants:
assortment: []
checkout: []
```
### Detailed Explanation of Configuration Sections
#### General Settings
- **`decimal_scale`:** Specifies the default scale for decimal objects.
#### Pimcore Backend Menu Configuration
- **`pimcore.menu`:** Manages the visibility and settings of backend menu
entries.
- **`pricing_rules`:** Enables or disables the Pricing Rules menu entry.
- **`order_list`:** Configures the order list menu entry, including
enabling/disabling and defining the route.
#### Factory Configuration
- **`factory`:** Defines the factory service and tenant behavior.
- **`factory_id`:** Service ID of the factory implementation.
- **`strict_tenants`:** If true, the factory will not fall back to the
default tenant if a specified tenant does not exist.
#### Environment Configuration
- **`environment`:** Specifies the environment configuration.
- **`environment_id`:** Service ID for the session environment.
- **`options`:** Additional options for the environment.
#### Cart Manager Configuration
- **`cart_manager`:** Defines settings for the cart manager, supporting
multiple tenants.
- **`tenants`:** Contains tenant-specific configurations.
- **`_defaults`:** Settings common to all tenants.
- **`default`:** Mandatory tenant configuration.
- **`name`:** Prototype for tenant configurations.
#### Order Manager Configuration
- **`order_manager`:** Manages order-related settings.
- **`tenants`:** Tenant-specific configurations.
- **`name`:** Prototype for tenant configurations.
#### Pricing Manager Configuration
- **`pricing_manager`:** Handles pricing rules and actions.
- **`conditions`:** Maps condition names to classes.
- **`actions`:** Maps action names to classes.
- **`tenants`:** Tenant-specific configurations.
#### Price Systems Configuration
- **`price_systems`:** Configures different price systems.
- **`name`:** Prototype for price system configurations.
#### Availability Systems Configuration
- **`availability_systems`:** Configures different availability systems.
- **`name`:** Prototype for availability system configurations.
#### Checkout Manager Configuration
- **`checkout_manager`:** Manages the checkout process.
- **`tenants`:** Tenant-specific configurations.
#### Payment Manager Configuration
- **`payment_manager`:** Configures payment providers and the payment
manager.
- **`providers`:** Configures individual payment providers.
#### Index Service Configuration
- **`index_service`:** Manages the index service and tenant-specific
settings.
- **`tenants`:** Tenant-specific configurations.
#### Filter Service Configuration
ChatGPT
- **`filter_service`:** Configures the filter service.
- **`tenants`:** Tenant-specific configurations.
#### Voucher Service Configuration
- **`voucher_service`:** Manages voucher-related settings.
- **`voucher_service_options`:** Options for the voucher service.
- **`token_managers`:** Configures token managers.
#### Offer Tool Configuration
- **`offer_tool`:** Manages offer tool settings.
- **`order_storage`:** Configures offer storage settings.
#### Tracking Manager Configuration
- **`tracking_manager`:** Manages tracking settings.
- **`trackers`:** Configures individual trackers.
### Example Configurations
#### Example Cart Manager Configuration
```yaml
pimcore_ecommerce_framework:
cart_manager:
tenants:
_defaults:
cart:
factory_id: CartFactory
default:
cart:
factory_options:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart
price_calculator:
modificators:
shipping:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping
options:
charge: 5.90
noShipping:
price_calculator:
factory_id: PriceCalculatorFactory
modificators: []
```
#### Example Order Manager Configuration
```yaml
pimcore_ecommerce_framework:
order_manager:
tenants:
default:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager
options:
order_class: \Pimcore\Model\DataObject\OnlineShopOrder
order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem
list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing
list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item
order_parent_path: /order/*Y*/*M*/*D*
order_agent:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory
factory_options: []
```
These configurations can be customized further to fit specific business
requirements. For detailed component configurations, refer to the
respective sections in the documentation.
User
Index Service
The Index Service (in combination with the Filter Service) provides
functionality for indexing, listing, filtering and searching products.
In the heart of this component is the Product Index - an optimized storage
of product data for all kinds of queries. Depending on the implementation,
the Product Index is stored in a special mysql table, in elasticsearch or
any other search provider (currently implemented are fact finder and
findologic). These implementations can be configured in Assortment Tenants.
The default tenant always uses DefaultMysql as implementation.
The separate Product Index has several advantages:
It is completely independent from the Pimcore object structure, only
contains needed information and can pre-calculate complex data.
It can be optimized without any side effects on Pimcore for requirements
considering filtering, listing and searching products.
It supports assortment tenants and therefore allows optimized indices for
multiple assortments within one system.
Based on the Product Index the Product List provides a one stop API for
accessing data and listing products.
See the following topics for details:
Configuration of the product index
Assortment Tenant configuration
Data architecture and indexing process
Working with Product Lists
Mockup Objects in Product List Results
ChatGPT
## Index Service Overview
The Index Service, in combination with the Filter Service, offers powerful
functionality for indexing, listing, filtering, and searching products
within Pimcore's E-Commerce Framework.
### Key Components
#### Product Index
The **Product Index** is an optimized storage solution for product data,
designed for various types of queries. Depending on the implementation, the
Product Index can be stored in different backends such as:
- **MySQL (Default):** DefaultMysql implementation.
- **Elasticsearch**
- **Fact Finder**
- **Findologic**
### Advantages of the Product Index
1. **Independence:** The Product Index is separate from the Pimcore object
structure, containing only necessary information and pre-calculated complex
data.
2. **Optimization:** It can be optimized for filtering, listing, and
searching products without affecting Pimcore's core functionalities.
3. **Assortment Tenants:** Supports multiple optimized indices for
different assortments within a single system.
4. **Product List API:** Provides a comprehensive API for accessing and
listing products based on the Product Index.
### Configuration and Usage
#### Configuration of the Product Index
Configuring the product index involves defining how and where the product
data will be stored and accessed. This is usually done in the configuration
files, specifying the details for each tenant and their respective indexing
methods.
#### Assortment Tenant Configuration
Assortment tenants allow you to create optimized indices for different
product assortments within your e-commerce system. Each tenant can have its
own unique configuration, tailored to the specific needs of that
assortment.
#### Data Architecture and Indexing Process
The data architecture involves structuring the product data for efficient
indexing and retrieval. The indexing process ensures that the product data
is processed and stored in the Product Index, ready for fast queries.
#### Working with Product Lists
The Product List API provides a unified interface for accessing product
data from the Product Index. It supports various operations such as listing
products, applying filters, and executing searches.
#### Mockup Objects in Product List Results
Mockup objects are placeholder objects used in product list results to
ensure consistent data structures during testing and development.
### Example Configuration
#### Index Service Configuration
```yaml
pimcore_ecommerce_framework:
index_service:
index_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\IndexService
default_tenant: default
tenants:
default:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
config_options: []
worker_id: ~
placeholders:
'%%locale%%': 'de_AT'
search_attributes: []
attributes:
product_name:
name: product_name
field_name: name
type: string
locale: null
filter_group: general
options: []
getter_id: null
getter_options: []
interpreter_id: null
interpreter_options: []
hide_in_fieldlist_datatype: false
```
This configuration specifies the use of the DefaultMysql implementation for
the default tenant, along with several attributes and options for the
product index.
### Conclusion
The Index Service and its integration with the Filter Service provide a
robust framework for managing product data in Pimcore's E-Commerce
Framework. By configuring the Product Index and utilizing the Product List
API, you can efficiently handle complex queries, filtering, and listing of
products, tailored to the needs of different assortments and tenants within
your system.
User
Product Index Configuration
The configuration of the Product Index defines the content of the Product
Index (which attributes are extracted how and stored where) and takes place
in the pimcore_ecommerce_framework configuration within the section
index_service. The product index can define multiple tenants (see
Assortment Tenant Configuration) which can be configured individually. Each
tenant defines a set of attributes to index/search and a configuration and
worker class responsible for storing and managing the index.
pimcore_ecommerce_framework:
index_service:
# product index defines multiple tenants which can be disabled
individually
# a tenant can define placeholders which will be replaced
tenants:
_defaults:
attributes:
name:
type: varchar(255)
filter_group: string
locale: '%%locale%%'
default:
enabled: false
# service ID of the desired configuration
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
# optional set of options passed to the config service -
available options vary by config
# implementation
config_options:
foo: bar
# optional - id of the worker handling the index. worker
and config must be matching as a worker
# is only able to accept a certain config implementation
(e.g. an elasticsearch worker can only operate
# on an elasticsearch config). as long as you don't
implement a custom worker you can omit the wotker_id
# as the system is able to automatically resolve the worker
for a given config
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql
# placeholders will be replaced with the value defined here
# you can use placeholders to define multiple tenant
configuration
# via _defaults which set the locale based on a placeholder
# in this example, the "default" tenant will have the
attributes name
# and seoname and use "de_AT" as locale for the "name"
attribute
# please make sure to use double %% or another char as {}
to denote placeholders
# as "%locale%" would be replaced by the "%locale%"
container parameter instead
# of the placeholder
placeholders:
'%%locale%%': de_AT
# add columns for general fulltext search index of
productlist
# they must be part of the attributes configuration below
search_attributes:
- name
- seoname
# defines search index attributes and how they're gathered
# as the _defaults entry already defines a name attribute,
we'll end
# up with name and seoname here
attributes:
seoname:
type: varchar(255)
filter_group: string
INT:
attributes:
name_en: &name_en
locale: '%%locale%%'
filter_group: string
placeholders:
'%%locale%%': en
BE:
attributes:
name_fr:
<<: *name_en
# placeholders will be replaced with the value
defined here
# attribute level placeholders will be processed
before tenant level placeholders
# in this example, the "BE" (belgium) tenant will
have the attributes "name_fr", "name_de"
# and "name_nl" referencing the same attribute
config as tenant "INT" (international)
# with attribute "name_en", but using use "fr",
"de" and "nl" as locale
placeholders:
'%%locale%%': fr
name_de:
<<: *name_en
placeholders:
'%%locale%%': de
name_nl:
<<: *name_en
placeholders:
'%%locale%%': nl
example_tenant:
attributes:
rucksacksLoad:
type: 'double'
filter_group: double
# a getter is a specific service responsible for
getting the value from an object
# this must be defined as service - as we use the
class name as service id you can
# just use the fully qualified class name. you can
use your own getters if you define
# them as service first
getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultBrickGetter
# options passed to the getter. available options
vary by getter implementation - see
# getter for available options
getter_options:
brickfield: specificAttributes
bricktype: rucksackSpecs
fieldname: load
# an interpreter can further transform the value
retrieved by the getter. same logic applies as
# for getters - interpreter must be defined as
service
interpreter_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\Numeric
# interpreter can define options which are passed
to the interpreter when interpreting the value
interpreter_options: {}
search_attributes
Defines attributes which should be considered in fulltext-search. All
attributes must be defined within the attributes-section.
attributes
Defines for all attributes if and how they should be indexed. Each
attribute is referenced with an unique name (e.g. seoname or rucksacksLoad
in the example above) which is the name of the attribute in the product
index. The following configuration options are available:
type (mandatory for mysql): Datatype for column in Product Index.
field_name (optional): Field name in product object, needed if it is
different than name in index. Defaults to name
locale (optional): Used locale for data retrieving if field is in a
localized field.
getter_id (optional): Service ID of a special getter implementation for
getting attribute value. Per default, the method get<NAME>() of the product
object is called. If this is not suitable, an alternative getter class can
be defined which is responsible for getting the value. This can be used for
calculations, getting complex values (field collections, object bricks),
etc. Getter implementations need to implement \Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Getter\GetterInterface interface and
be defined as service. Best practice is to use the fully qualified class
name as service ID and to reference the class name in the configuration.
getter_options (optional): options passed to the getter when resolving a
value. Available options vary by getter implementation.
interpreter_id (optional): By default all data is stored without any
transformation in the Product Index. With an interpreter, this data can be
transformed and manipulated before storing. This can be used for only
saving IDs of assets, normalization of data, special treatment of
relations, etc. Interpreter implementations need to implement Pimcore\
Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
InterpreterInterface interface. The same service ID best practices as for
getters apply to interpreters.
interpreter_options (optional): options passed to the interpreter.
Available options vary by interpreter implementation.
hide_in_fieldlist_datatype (optional): Hides column in FieldList drop down
(see FilterService for more information).
filter_group (optional): Defines filter group for the FieldList drop down
(see FilterService for more information).
Relations in Product Index
Relations are stored in a special way in Product Index and also need to be
filtered in a different way in the Product List.
In order to store relations correctly in the Product Index, relation
attributes must have an interpreter defined which implements the interface
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
RelationInterpreterInterface.
Selection of available Getters:
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultBrickGetter: Gets data from an Object Brick. Needed configuration:
brickfield: Field name of Object Brick, e.g. bricks.
bricktype: Type of Object Brick, e.g. TentBrick.
fieldname: Field name of attribute in Object Brick, e.g. height.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultBrickGetterSequence: Same as DefaultBrickGetter, but can use more
than one source definition and stores first found value in Product Index.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultBrickGetterSequenceToMultiselect: Like DefaultBrickGetterSequence,
but stores all found values as a multi select in the Product Index.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\TagsGetter:
Gets Tags of product object and returns them as array.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultClassificationAttributeGetter: Gets attribute value from
classification store. Possible options:
key_id - id of the classification store attribute
group_id - id of the group related to the id | key can occur multiple times
in classification store field through multiple groups
fieldname - name of the field upon which the classification store is saved
on the specific object (defaults to attributes)
Selection of available Interpreters:
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\AssetId:
Stores only asset id into Product Index.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultObjects: Default interpreter to store object relations as relations
into the Product Index.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultRelations: Same as DefaultObjects but also for other relations to
Assets and Documents. Also can deal with ObjectMetadata.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultStructuredTable: Interpreter for structured table data type. Expects
following configuration options:
row
column
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\IdList:
Returns id list of given values as CSV list. If configuration option
multiSelectEncoded is set, it returns id list encoded as multi select
(relevant for filtering in Product List).
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\Numeric:
Returns floatval of given value.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
QuantityValue: Interprets quantity value data types, by default by
serializing it to string, when config option onlyValue set to true, it
returns only value
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\ObjectId:
Returns id of given object.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
ObjectIdSum: Calculates sum if ids of given objects. Could be used for
similarity calculation.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
ObjectValue: Get value from an related object. Expects following
configuration options:
['target']['fieldname']: Field name of value to get. Is used for getter
generation which is called on given object.
['target']['locale']: Locale is optionally passed as first parameter to
getter.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\Round:
Rounds given value to integer.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\Soundex:
Returns soundex of given value. Could be used for similarity calculation.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultClassificationStore: Stores all classification store attributes of a
data object to the index. Only usable in combination with elasticsearch.
See Filter Classification Store for details.
Depending on the Product Index implementation, the Product Index
configuration can be slightly different. See sample configurations for
specific Product Iindex implementations.
ChatGPT
## Product Index Configuration
The Product Index configuration in Pimcore defines how product attributes
are extracted, transformed, and stored. This configuration is crucial for
optimizing queries, indexing, and filtering product data. Here's a
comprehensive guide to configuring the Product Index within the
`pimcore_ecommerce_framework` configuration.
### Configuration Structure
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
_defaults:
attributes:
name:
type: varchar(255)
filter_group: string
locale: '%%locale%%'
default:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
config_options:
foo: bar
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql
placeholders:
'%%locale%%': de_AT
search_attributes:
- name
- seoname
attributes:
name:
type: varchar(255)
filter_group: string
seoname:
type: varchar(255)
filter_group: string
INT:
attributes:
name_en: &name_en
locale: '%%locale%%'
filter_group: string
placeholders:
'%%locale%%': en
BE:
attributes:
name_fr:
<<: *name_en
placeholders:
'%%locale%%': fr
name_de:
<<: *name_en
placeholders:
'%%locale%%': de
name_nl:
<<: *name_en
placeholders:
'%%locale%%': nl
example_tenant:
attributes:
rucksacksLoad:
type: 'double'
filter_group: double
getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultBrickGetter
getter_options:
brickfield: specificAttributes
bricktype: rucksackSpecs
fieldname: load
interpreter_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\Numeric
interpreter_options: {}
```
### Configuration Details
#### Tenants
The configuration supports multiple tenants, each with its own set of
indexed attributes and options. Tenants allow you to create optimized
indices for different product assortments.
- **_defaults:** Common settings for all tenants. These settings are merged
into every tenant configuration.
- **default:** Mandatory tenant configuration.
- **other tenants (e.g., INT, BE):** Additional tenants with unique
configurations.
#### Attributes
Defines the attributes to be indexed for each tenant. Each attribute can
have the following options:
- **type (mandatory for MySQL):** The data type of the attribute (e.g.,
varchar(255), double).
- **field_name:** The name of the field in the product object if different
from the index name.
- **locale:** The locale used for data retrieval if the field is localized.
- **getter_id:** The service ID of a custom getter for retrieving attribute
values.
- **getter_options:** Options passed to the getter.
- **interpreter_id:** The service ID of a custom interpreter for
transforming attribute values before storing them.
- **interpreter_options:** Options passed to the interpreter.
- **filter_group:** Defines the filter group for the FieldList dropdown in
the FilterService.
- **hide_in_fieldlist_datatype:** Hides the column in the FieldList
dropdown.
#### Example Attribute Configuration
```yaml
attributes:
name:
type: varchar(255)
filter_group: string
seoname:
type: varchar(255)
filter_group: string
rucksacksLoad:
type: 'double'
filter_group: double
getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
Getter\DefaultBrickGetter
getter_options:
brickfield: specificAttributes
bricktype: rucksackSpecs
fieldname: load
interpreter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Interpreter\Numeric
interpreter_options: {}
```
### Getters
Getters are services responsible for retrieving the value of an attribute
from a product object. They can be customized and need to implement the
`GetterInterface`.
- **DefaultBrickGetter:** Retrieves data from an Object Brick.
- **Options:**
- `brickfield`: Field name of the Object Brick.
- `bricktype`: Type of Object Brick.
- `fieldname`: Attribute field name in the Object Brick.
### Interpreters
Interpreters transform and manipulate attribute values before storing them
in the Product Index. They need to implement the `InterpreterInterface`.
- **Numeric:** Returns the float value of the given value.
### Example Configuration with Getters and Interpreters
```yaml
attributes:
rucksacksLoad:
type: 'double'
filter_group: double
getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
Getter\DefaultBrickGetter
getter_options:
brickfield: specificAttributes
bricktype: rucksackSpecs
fieldname: load
interpreter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Interpreter\Numeric
interpreter_options: {}
```
### Search Attributes
Defines attributes that should be included in fulltext searches. These
attributes must be part of the attributes configuration.
```yaml
search_attributes:
- name
- seoname
```
### Placeholder Values
Placeholders allow you to define multiple tenant configurations by setting
values that can be dynamically replaced.
```yaml
placeholders:
'%%locale%%': de_AT
```
### Complete Example
Here's a complete example configuration for the Product Index with multiple
tenants, getters, interpreters, and placeholders.
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
_defaults:
attributes:
name:
type: varchar(255)
filter_group: string
locale: '%%locale%%'
default:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
config_options:
foo: bar
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql
placeholders:
'%%locale%%': de_AT
search_attributes:
- name
- seoname
attributes:
name:
type: varchar(255)
filter_group: string
seoname:
type: varchar(255)
filter_group: string
INT:
attributes:
name_en: &name_en
locale: '%%locale%%'
filter_group: string
placeholders:
'%%locale%%': en
BE:
attributes:
name_fr:
<<: *name_en
placeholders:
'%%locale%%': fr
name_de:
<<: *name_en
placeholders:
'%%locale%%': de
name_nl:
<<: *name_en
placeholders:
'%%locale%%': nl
example_tenant:
attributes:
rucksacksLoad:
type: 'double'
filter_group: double
getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultBrickGetter
getter_options:
brickfield: specificAttributes
bricktype: rucksackSpecs
fieldname: load
interpreter_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\Numeric
interpreter_options: {}
```
This configuration sets up the Product Index for various tenants, each with
its own attributes and options, utilizing getters and interpreters to
retrieve and transform data as needed.
User
Assortment Tenant Configuration
The E-Commerce Framework provides a two level Assortment Tenant system for
the Product Index:
Assortment Tenant: The first level of tenants are heavy-weight tenants.
They allow multiple shop instances within one system. The shop instances
are completely independent from each other and can contain complete
different products, index attributes and even use different product index
implementations.
Assortment Subtenant: The second level of tenants are light-weight tenants,
which exist within a shop instance. Light-weight tenants use the same
Product Index with the same attributes as their parent shop, but can
contain a subset of the products. So they are meant to be used for
implementing different product assortments within one shop.
One system can have multiple tenants (heavy- and light-weight). But too
many tenants can have bad effects on the performance of saving products,
since all Product Indices need to be updated on every save.
By default the system always uses one heavy-weight tenant (which is
DefaultMysql), but the default tenant can be disabled.
Assortment Tenants
For setting up an Assortment Tenant, following steps are necessary:
Implementation of a Tenant Config: The Tenant Config class is the central
configuration of an assortment tenant, defines which products are available
for the tenant and provides the connection to the used Product Index
implementation. It needs to implement Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\ConfigInterface. For detailed
information see in-source documentation of the interface. Following
implementations are provided by the framework and may be extended:
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\DefaultMysql:
Provides a simple mysql implementation of the product index.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ConfigOptimizedMysql:
Provides an optimized mysql implementation of the product index.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\ElasticSearch:
Provides a default elasticsearch implementation of the product index.
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
DefaultFindologic: Provides a default findologic implementation of the
product index.
Configuring Assortment Tenants within configuration: Each tenant has to be
configured within the index_service configuration by defining the tenant
config class and index attributes. Depending on the Product Index
implementation, additional configuration may be necessary.
Declare the service: You need to declare the service as well so the class
can be used. On your service configuration or for instance at the top of
the ecommerce configuration file:
services:
MyBundle\Service\MySubtenantConfig:
calls:
- [setAttributeFactory, ['@Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\AttributeFactory']]
Setting current Assortment Tenant for Frontend
The E-Commerce Framework Environment provides following methods to set the
current Assortment Tenant when working with Product Lists in Code:
<?php
/**
* sets current assortment tenant which is used for indexing and
product lists
* @param string $tenant
* @return mixed
*/
public function setCurrentAssortmentTenant($tenant);
/**
* gets current assortment tenant which is used for indexing and
product lists
* @return string
*/
public function getCurrentAssortmentTenant();
/**
* sets current assortment sub tenant which is used for indexing and
product lists
* @param string $subTenant
* @return mixed
*/
public function setCurrentAssortmentSubTenant($subTenant);
/**
* gets current assortment sub tenant which is used for indexing and
product lists
* @return string
*/
public function getCurrentAssortmentSubTenant();
The current Assortment Tenant has to be set in the application controllers,
e.g. after the login of a specific customer. The Index Service provides the
corresponding Product List implementation based on the current tenant.
Example:
<?php
$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\
Factory::getInstance();
//setting assortment tenant
$environment = $factory->getEnvironment();
$environment->setCurrentAssortmentTenant("elasticsearch");
//getting suitable product list
$productlist = $factory->getIndexService()-
>getProductListForCurrentTenant();
//doing stuff with product list
Assortment Subtenants
Subtenants are light-weight tenants, which share the same Product Index
with the same attributes as their parent assortment tenant.
Implementing an Assortment Subtenant for MySQL
The mapping which product is assigned to with subtenant is done with an
additional mapping table. The necessary joins and conditions are
implemented within additional methods within Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\MysqlConfigInterface:
/**
* return table name of product index tenant relations for subtenants
* @return string
*/
public function getTenantRelationTablename();
/**
* return join statement in case of subtenants
* @return string
*/
public function getJoins();
/**
* returns additional condition in case of subtenants
* @return string
*/
public function getCondition();
In order to populate the additional mapping data, also following methods
have to be implemented:
/**
* in case of subtenants returns a data structure containing all sub
tenants
* @param IndexableInterface $object
* @param int|null $subObjectId
* @return mixed $subTenantData
*/
public function prepareSubTenantEntries(IndexableInterface $object,
$subObjectId = null);
/**
* populates index for tenant relations based on given data
* @param mixed $objectId
* @param mixed $subTenantData
* @param mixed $subObjectId
* @return void
*/
public function updateSubTenantEntries($objectId, $subTenantData,
$subObjectId = null);
For an complete example have a look at the sample implementation.
Implementing an Assortment Subtenant for Elasticsearch
In order to populate the additional mapping data, the following method has
to be implemented:
/**
* in case of subtenants returns a data structure containing all sub
tenants
* @param IndexableInterface $object
* @param int|null $subObjectId
* @return array $subTenantData
*/
public function prepareSubTenantEntries(IndexableInterface $object,
$subObjectId = null);
For an complete example have a look at the sample implementation.
Note: This is currently only implemented for MySQL and elasticsearch based
product index implementations.
ChatGPT
## Assortment Tenant Configuration
The E-Commerce Framework supports a two-level Assortment Tenant system for
the Product Index:
1. **Assortment Tenant:** These are heavy-weight tenants, allowing multiple
independent shop instances within one system. Each tenant can have
different products, index attributes, and Product Index implementations.
2. **Assortment Subtenant:** These are light-weight tenants within a shop
instance, sharing the same Product Index and attributes as the parent
tenant but containing a subset of products.
### Assortment Tenant Configuration
### Steps to Configure an Assortment Tenant
1. **Implementing a Tenant Config:**
- The Tenant Config class defines the product availability and Product
Index connection. It must implement `Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\ConfigInterface`.
- Available implementations provided by the framework include:
- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
DefaultMysql`
- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
ConfigOptimizedMysql`
- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
ElasticSearch`
- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
DefaultFindologic`
2. **Configuring Assortment Tenants:**
- Configure each tenant within the `index_service` configuration by
defining the tenant config class and index attributes.
- Declare the service for the tenant config class.
### Example Configuration
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
default:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
config_options: []
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql
placeholders:
'%%locale%%': de_AT
search_attributes:
- name
- seoname
attributes:
name:
type: varchar(255)
filter_group: string
seoname:
type: varchar(255)
filter_group: string
elasticsearch_tenant:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options: []
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch
search_attributes:
- name
- description
attributes:
name:
type: text
filter_group: string
description:
type: text
filter_group: string
```
### Declaring the Service
Ensure that the service for the tenant config class is declared, so it can
be used by the framework.
```yaml
services:
MyBundle\Service\MyTenantConfig:
calls:
- [setAttributeFactory, ['@Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\AttributeFactory']]
```
### Setting the Current Assortment Tenant in Frontend
The E-Commerce Framework Environment provides methods to set and get the
current Assortment Tenant and Subtenant.
```php
<?php
$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance();
// Setting assortment tenant
$environment = $factory->getEnvironment();
$environment->setCurrentAssortmentTenant("elasticsearch_tenant");
// Getting suitable product list
$productlist = $factory->getIndexService()-
>getProductListForCurrentTenant();
// Doing stuff with product list
```
### Assortment Subtenant Configuration
Subtenants share the same Product Index with the same attributes as their
parent tenant but can have a subset of the products.
### Implementing an Assortment Subtenant for MySQL
For MySQL, the subtenant configuration involves mapping product assignments
with an additional mapping table and implementing necessary methods for
joins and conditions.
#### Example Configuration for MySQL Subtenant
```php
<?php
class MySubtenantConfig implements Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\MysqlConfigInterface
// Implementation of required methods
public function getTenantRelationTablename() {
return 'my_subtenant_relation_table';
public function getJoins() {
return 'JOIN my_subtenant_relation_table ON ...';
public function getCondition() {
return 'my_subtenant_relation_table.subtenant_id = ...';
public function prepareSubTenantEntries(IndexableInterface $object,
$subObjectId = null) {
// Prepare subtenant entries
}
public function updateSubTenantEntries($objectId, $subTenantData,
$subObjectId = null) {
// Update subtenant entries
```
### Implementing an Assortment Subtenant for Elasticsearch
For Elasticsearch, the subtenant configuration involves implementing
methods to prepare subtenant entries.
#### Example Configuration for Elasticsearch Subtenant
```php
<?php
class MyElasticsearchSubtenantConfig implements Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\ElasticsearchConfigInterface
// Implementation of required methods
public function prepareSubTenantEntries(IndexableInterface $object,
$subObjectId = null) {
// Prepare subtenant entries
```
### Complete Example of Tenant and Subtenant Configuration
Here's a complete example demonstrating the configuration of tenants and
subtenants:
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
default:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
config_options: []
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql
placeholders:
'%%locale%%': de_AT
search_attributes:
- name
- seoname
attributes:
name:
type: varchar(255)
filter_group: string
seoname:
type: varchar(255)
filter_group: string
elasticsearch_tenant:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options: []
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch
search_attributes:
- name
- description
attributes:
name:
type: text
filter_group: string
description:
type: text
filter_group: string
subtenant_mysql:
enabled: true
config_id: MyBundle\Service\MySubtenantConfig
config_options: []
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql
attributes:
subtenant_attribute:
type: varchar(255)
filter_group: string
subtenant_elasticsearch:
enabled: true
config_id: MyBundle\Service\MyElasticsearchSubtenantConfig
config_options: []
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch
attributes:
subtenant_attribute:
type: text
filter_group: string
```
### Summary
By leveraging the Assortment Tenant and Subtenant configurations, you can
create highly customized and optimized product indices tailored to the
needs of different shop instances and product assortments within your
Pimcore E-Commerce Framework.
User
Data Architecture and Indexing Process
Depending on the Product Index implementation, there are two different
Product Index data architectures and ways for indexing: Simple Mysql
Architecture and Optimized Architecture.
For indexing itself the provided Pimcore console commands can be used.
Simple Mysql Architecture
Pimcore object data is transferred directly to the Product Index.
After every update of a Pimcore object, the changes are directly written
into the Product Index.
Only used for \Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
DefaultMysql
Updates of dependent objects (like child objects, variants that inherit
data, related objects) are not transferred into the index automatically.
productindex-simple
Console Commands for Simple Mysql Architecture
For manually updating the whole index use following command:
php bin/console ecommerce:indexservice:bootstrap --update-index
If you need to create or update the index structures you can use:
php bin/console ecommerce:indexservice:bootstrap --create-or-update-index-
structure
By default, Pimcore assumes that the product class is Pimcore\Model\
DataObject\Product. If you have a different product class name, please use
the --object-list-class param and provide the listing class name that
should be used.
For further details (e.g. only updating certain product types, apply list
conditions) see --help section of the ecommerce:indexservice:bootstrap
command.
Optimized Architecture
In the optimized architecture, object data is transferred not directly to
the Product Index.
In this case a so called store table is between the Pimcore objects and the
Product Index. This store table enables to ...
... update the Product Index only if index relevant data has changed.
Therefore the load on the index itself is reduced and unnecessary write
operations are prevented.
... update the Product Index asynchronously and therefore update also
dependent elements (children, variants, ...) of an updated Pimcore object
without impact on save performance.
... rebuilding the whole Product Index out of the store table much faster
since no direct interaction with Pimcore objects is needed.
After every update of a Pimcore object, the changes are written into the
store table and all child objects of the updated object are added to the so
called preparation queue (see later). As a consequence a periodic full
update should not be necessary any more.
Used for optimized mysql, elasticsearch, ...
productindex-optimized
Console Commands for Optimized Architecture
For updating data in index following commands are available.
For process the preparation queue and update Pimcore objects to the index
store table, use following command. This command should be executed
periodically (e.g. all 10 minutes).
php bin/console ecommerce:indexservice:process-preparation-queue
To update the Product Index based on changes stored in the store table use
the following command. This command should be executed periodically (e.g.
all 10 minutes).
php bin/console ecommerce:indexservice:process-update-queue
For manually update all Pimcore objects in the index store use following
command. As stated before, this should only be necessary for an initial
fill-up of the index. After that, at least Product Index Store and Pimcore
objects should always be in sync. It is important to execute
ecommerce:indexservice:process-preparation-queue and
ecommerce:indexservice:process-update-queue periodically though.
php bin/console ecommerce:indexservice:bootstrap --update-index
By default, Pimcore assumes that the product class is Pimcore\Model\
DataObject\Product. If you have a different product class name, please use
the --object-list-class param and provide the listing class name that
should be used.
Invalidate either the preparation queue or the index-update queue. This is
usually only needed during development when the store table is out of sync.
Reset the preparation queue for instance when your product model returns
updated data for a field.
php bin/console ecommerce:indexservice:reset-queue preparation --
tenant=MyTenant
php bin/console ecommerce:indexservice:reset-queue update-index --
tenant=MyTenant
If you need to create or update the index structures you can still use:
php bin/console ecommerce:indexservice:bootstrap --create-or-update-index-
structure
For further details see --help section of the commands.
Paralelization of Indexing
All indexing commands include the parallelization trait of webmozart. Thus
indexing can be parallelized very easily by adding the --processes=X option
to the command.
Be aware that depending on the command too many parallel processes might
cause deadlocks on database.
ChatGPT
## Data Architecture and Indexing Process in Pimcore E-Commerce Framework
### Product Index Architectures
There are two main data architectures and indexing processes depending on
the Product Index implementation:
1. **Simple MySQL Architecture**
2. **Optimized Architecture**
### 1. Simple MySQL Architecture
In the Simple MySQL Architecture, Pimcore object data is transferred
directly to the Product Index. This architecture is straightforward but has
some limitations, especially with handling dependent objects.
#### Key Features
- **Direct Transfer:** Object data is directly written into the Product
Index after every update.
- **Immediate Updates:** Changes are immediately reflected in the Product
Index.
- **Limited Scope:** Does not automatically update dependent objects (e.g.,
child objects, variants, related objects).
- **Implementation:** Used for `\Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql`.
#### Console Commands for Simple MySQL Architecture
- **Manually Update the Whole Index:**
```bash
php bin/console ecommerce:indexservice:bootstrap --update-index
```
- **Create or Update Index Structures:**
```bash
php bin/console ecommerce:indexservice:bootstrap --create-or-update-
index-structure
```
- **Specify a Different Product Class:**
```bash
php bin/console ecommerce:indexservice:bootstrap --object-list-
class="Your\Custom\ProductClass"
```
### 2. Optimized Architecture
In the Optimized Architecture, a store table is used between Pimcore
objects and the Product Index. This allows for more efficient indexing and
updating processes.
#### Key Features
- **Intermediary Store Table:** Changes are written to a store table before
being transferred to the Product Index.
- **Efficient Updates:** Updates the Product Index only if relevant data
has changed, reducing unnecessary write operations.
- **Asynchronous Processing:** Updates can be processed asynchronously,
allowing for updates to dependent elements without impacting save
performance.
- **Faster Rebuilds:** The Product Index can be rebuilt quickly from the
store table without direct interaction with Pimcore objects.
- **Implementation:** Used for optimized MySQL, Elasticsearch, and other
advanced configurations.
#### Console Commands for Optimized Architecture
- **Process the Preparation Queue:**
```bash
php bin/console ecommerce:indexservice:process-preparation-queue
```
This command should be executed periodically (e.g., every 10 minutes).
- **Process the Update Queue:**
```bash
php bin/console ecommerce:indexservice:process-update-queue
```
This command should also be executed periodically (e.g., every 10
minutes).
- **Manually Update All Pimcore Objects in the Index Store:**
```bash
php bin/console ecommerce:indexservice:bootstrap --update-index
```
- **Invalidate Queues (Preparation or Update):**
```bash
php bin/console ecommerce:indexservice:reset-queue preparation --
tenant=MyTenant
php bin/console ecommerce:indexservice:reset-queue update-index --
tenant=MyTenant
```
- **Create or Update Index Structures:**
```bash
php bin/console ecommerce:indexservice:bootstrap --create-or-update-
index-structure
```
- **Specify a Different Product Class:**
```bash
php bin/console ecommerce:indexservice:bootstrap --object-list-
class="Your\Custom\ProductClass"
```
### Parallelization of Indexing
All indexing commands support parallelization using the `webmozart`
parallelization trait. You can parallelize the indexing process by adding
the `--processes=X` option to the command.
#### Example:
```bash
php bin/console ecommerce:indexservice:process-update-queue --processes=4
```
**Note:** Using too many parallel processes may cause database deadlocks.
### Summary
The choice between Simple MySQL Architecture and Optimized Architecture
depends on the specific needs and complexity of your e-commerce setup. The
Simple MySQL Architecture is straightforward and easy to implement but may
not handle complex relationships and dependent objects efficiently. The
Optimized Architecture, on the other hand, offers more flexibility and
efficiency by using an intermediary store table and supporting asynchronous
updates, making it suitable for more complex and large-scale
implementations.
User
Special Aspects for Elasticsearch
Basically Elasticsearch worker works as described in the optimized
architecture. Currently, Elasticsearch 8 is supported.
Installation
Elasticsearch 8
To work properly Pimcore requires the Elasticsearch client, install them
with: composer require pimcore/elasticsearch-client.
Index Configuration
Elasticsearch provides a couple of additional configuration options for the
index to utilize elasticsearch features. See Configuration Details for more
information.
Reindexing Mode
It is possible that elasticsearch cannot update the mapping, e.g. if data
types of attributes change on the fly. For this case, a reindex is
necessary. If it is necessary, a native ES reindex is executed
automatically during bin/console ecommerce:indexservice:bootstrap --create-
or-update-index-structure.
While reindex is executed, no updates are written to the ES index. The
changes remain in store table and are transferred to index during next
execution of bin/console ecommerce:indexservice:process-update-queue after
reindex is finished.
All queries that take place during reindex go to the old index. As soon the
reindex is finished, the current index is switched to the newly created
index and the old index is deleted.
As a result, during reindex the results delivered by Product Lists can
contain old data.
To manually start a reindex, following command can be used: bin/console
ecommerce:indexservice:elasticsearch-sync reindex.
Indexing of Classification Store Attributes
With elasticsearch it is possible to index all attributes of Classification
Store data without defining an attribute for each single classification
store key.
For details see Filter Classification Store in Filter Service
documentation.
Synonyms
Pimcore provides an out-of-the box integration for synonyms in
elasticsearch. See Synonyms for details.
ChatGPT
## Special Aspects for Elasticsearch in Pimcore E-Commerce Framework
Elasticsearch offers powerful capabilities for indexing and searching,
which can be leveraged within the Pimcore E-Commerce Framework. Here are
the special aspects and configurations required for using Elasticsearch as
your Product Index.
### Installation
To use Elasticsearch with Pimcore, you need to install the Elasticsearch
client.
#### Step-by-Step Installation
1. **Install Elasticsearch Client:**
```bash
composer require pimcore/elasticsearch-client
```
2. **Configure Elasticsearch in your `pimcore_ecommerce_framework`:**
Ensure your configuration file reflects the necessary settings for
Elasticsearch.
### Index Configuration
Elasticsearch allows additional configurations to utilize its advanced
features. Here are the key points for configuring Elasticsearch within
Pimcore.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
default:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
index_name: my_custom_index
number_of_shards: 3
number_of_replicas: 2
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch
search_attributes:
- name
- description
attributes:
name:
type: text
filter_group: string
description:
type: text
filter_group: string
```
### Reindexing Mode
Elasticsearch may require reindexing if the data types of attributes
change. Pimcore handles reindexing automatically during index structure
creation or updates.
#### Automatic Reindexing
1. **Reindex Execution:**
When necessary, a native Elasticsearch reindex is automatically executed
during:
```bash
php bin/console ecommerce:indexservice:bootstrap --create-or-update-
index-structure
```
2. **Behavior During Reindex:**
- **Index Updates:** Updates are paused during reindexing.
- **Data Storage:** Changes are stored in the store table.
- **Query Execution:** Queries are directed to the old index until the
reindexing is complete.
- **Index Switch:** Once reindexing is done, the new index is activated,
and the old index is deleted.
3. **Manual Reindexing:**
To manually start a reindex:
```bash
php bin/console ecommerce:indexservice:elasticsearch-sync reindex
```
### Indexing of Classification Store Attributes
Elasticsearch can index all attributes of the Classification Store data
without needing to define an attribute for each key. This simplifies the
process and improves efficiency.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
default:
enabled: true
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options: []
search_attributes:
- classification_store
attributes:
classification_store:
type: object
getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultClassificationAttributeGetter
getter_options:
key_id: your_key_id
group_id: your_group_id
fieldname: attributes
```
### Synonyms
Pimcore integrates with Elasticsearch to support synonyms out of the box.
This feature enhances search functionality by allowing different terms with
similar meanings to be treated equivalently.
#### Configuring Synonyms
1. **Define Synonyms:**
Create a synonyms file or list that Elasticsearch can use.
2. **Integrate Synonyms in Configuration:**
Update your Elasticsearch index configuration to include the synonyms.
### Example Commands
#### Update the Whole Index
```bash
php bin/console ecommerce:indexservice:bootstrap --update-index
```
#### Create or Update Index Structures
```bash
php bin/console ecommerce:indexservice:bootstrap --create-or-update-index-
structure
```
#### Process Preparation Queue
```bash
php bin/console ecommerce:indexservice:process-preparation-queue
```
Execute periodically, e.g., every 10 minutes.
#### Process Update Queue
```bash
php bin/console ecommerce:indexservice:process-update-queue
```
Execute periodically, e.g., every 10 minutes.
#### Manually Start Reindex
```bash
php bin/console ecommerce:indexservice:elasticsearch-sync reindex
```
### Parallelization of Indexing
You can parallelize indexing commands using the `--processes=X` option.
#### Example:
```bash
php bin/console ecommerce:indexservice:process-update-queue --processes=4
```
### Summary
By integrating Elasticsearch into the Pimcore E-Commerce Framework, you can
leverage advanced indexing and search capabilities, including efficient
data handling, support for synonyms, and enhanced performance through
optimized architecture and asynchronous updates. Ensure to configure your
Elasticsearch settings appropriately and use the provided console commands
to manage indexing and reindexing processes effectively.
User
Configuration Configuration
Following aspects need to be considered in index configuration:
General Configuration Options
In the config_options area general elasticsearch settings can be made -
like hosts, index settings, etc.
client_config
logging: (deprecated, for Elasticsearch 7 only) true/false to activate
logging of elasticsearch client
indexName: index name to be used, if not provided tenant name is used as
index name
index_settings
Index settings that are used when creating a new index. They are passed 1:1
as settings param to the body of the create index command. Details see also
elasticsearch Docs.
es_client_name (for Elasticsearch 8 only)
Elasticsearch 8 client configuration takes place via Pimcore Elasticsearch
Client Bundle and has two parts.
Configuring an elasticsearch client in separate configuration
# Configure an elasticsearch client
pimcore_elasticsearch_client:
es_clients:
default:
hosts: ['elastic:9200']
username: 'elastic'
password: 'somethingsecret'
logger_channel: 'pimcore.elasticsearch'
Define the client name to be used by an elasticsearch tenant. This will be
done via the es_client_name configuration in the config_options.
synonym_providers
Specify synonym providers for synonym filters defined in filter section of
index settings. For details see Synonyms.
Sample Config
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
client_config:
logging: false
indexName: 'ecommerce-demo-elasticsearch'
# elasticsearch client name, for Elasticsearch 8 only
es_client_name: default
index_settings:
number_of_shards: 5
number_of_replicas: 0
max_ngram_diff: 30
analysis:
analyzer:
my_ngram_analyzer:
tokenizer: my_ngram_tokenizer
allow_list_analyzer:
tokenizer: standard
filter:
- allow_list_filter
tokenizer:
my_ngram_tokenizer:
type: ngram
min_gram: 2
max_gram: 15
token_chars: [letter, digit]
filter:
allow_list_filter:
type: keep
keep_words:
- was
- WAS
Data Types for attributes
The type of the data attributes needs to be set to elasticsearch data
types..
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
attributes:
name:
locale: '%%locale%%'
type: keyword
In addition to the type configuration, you also can provide custom mappings
for a field. If provided, these mapping configurations are used for
creating the mapping of the elasticsearch index.
You can also skip the type and mapping, then ES will try to create dynamic
mapping.
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
attributes:
name:
locale: '%%locale%%'
type: text
options:
mapping:
type: text
store: true
index: not_analyzed
fields:
analyzed:
type: text
analyzer: german
analyzed_ngram:
type: text
analyzer: my_ngram_analyzer
ChatGPT
## Elasticsearch Configuration for Pimcore E-Commerce Framework
When integrating Elasticsearch with Pimcore, it's essential to configure
various settings to leverage Elasticsearch's full capabilities. Here's a
detailed guide on setting up Elasticsearch in the Pimcore E-Commerce
Framework.
### General Configuration Options
#### `config_options` Section
This section allows you to set general Elasticsearch settings such as
hosts, index settings, and client configurations.
1. **Client Configuration (`client_config`):**
- **`logging`:** Enable or disable logging of Elasticsearch client
(deprecated in Elasticsearch 8).
- **`indexName`:** Specify the index name to be used. If not provided,
the tenant name is used as the index name.
2. **Index Settings (`index_settings`):**
- These settings are passed 1:1 as the `settings` parameter to the body
of the `create index` command. For more details, refer to the
[Elasticsearch
documentation](https://www.elastic.co/guide/en/elasticsearch/reference/
current/indices-create-index.html).
3. **Elasticsearch Client Name (`es_client_name`):**
- For Elasticsearch 8, configure the Elasticsearch client via the
Pimcore Elasticsearch Client Bundle and specify the client name.
### Elasticsearch 8 Client Configuration
#### Configure Elasticsearch Client
This configuration is done separately in the Pimcore Elasticsearch Client
Bundle:
```yaml
pimcore_elasticsearch_client:
es_clients:
default:
hosts: ['http://elastic:9200']
username: 'elastic'
password: 'somethingsecret'
logger_channel: 'pimcore.elasticsearch'
```
#### Reference Client in Tenant Configuration
In the `config_options` of the tenant configuration, specify the client
name to be used:
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
client_config:
logging: false
indexName: 'ecommerce-demo-elasticsearch'
es_client_name: default
index_settings:
number_of_shards: 5
number_of_replicas: 0
max_ngram_diff: 30
analysis:
analyzer:
my_ngram_analyzer:
tokenizer: my_ngram_tokenizer
allow_list_analyzer:
tokenizer: standard
filter:
- allow_list_filter
tokenizer:
my_ngram_tokenizer:
type: ngram
min_gram: 2
max_gram: 15
token_chars: [letter, digit]
filter:
allow_list_filter:
type: keep
keep_words:
- was
- WAS
```
### Data Types for Attributes
Specify Elasticsearch data types for your attributes in the `attributes`
section of the tenant configuration. You can also provide custom mappings
for each field.
#### Basic Attribute Configuration
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
attributes:
name:
locale: '%%locale%%'
type: keyword
```
#### Custom Mappings
If you want to provide custom mappings for a field, you can add the
`mapping` configuration:
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
attributes:
name:
locale: '%%locale%%'
type: text
options:
mapping:
type: text
store: true
index: not_analyzed
fields:
analyzed:
type: text
analyzer: german
analyzed_ngram:
type: text
analyzer: my_ngram_analyzer
```
### Sample Full Configuration
Here's a sample full configuration combining all aspects mentioned:
```yaml
pimcore_elasticsearch_client:
es_clients:
default:
hosts: ['http://elastic:9200']
username: 'elastic'
password: 'somethingsecret'
logger_channel: 'pimcore.elasticsearch'
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
client_config:
logging: false
indexName: 'ecommerce-demo-elasticsearch'
es_client_name: default
index_settings:
number_of_shards: 5
number_of_replicas: 0
max_ngram_diff: 30
analysis:
analyzer:
my_ngram_analyzer:
tokenizer: my_ngram_tokenizer
allow_list_analyzer:
tokenizer: standard
filter:
- allow_list_filter
tokenizer:
my_ngram_tokenizer:
type: ngram
min_gram: 2
max_gram: 15
token_chars: [letter, digit]
filter:
allow_list_filter:
type: keep
keep_words:
- was
- WAS
attributes:
name:
locale: '%%locale%%'
type: text
options:
mapping:
type: text
store: true
index: not_analyzed
fields:
analyzed:
type: text
analyzer: german
analyzed_ngram:
type: text
analyzer: my_ngram_analyzer
```
### Additional Notes
- **Synonym Providers:** To specify synonym providers for synonym filters,
see the Synonyms documentation for more details.
- **Dynamic Mapping:** If you skip the type and mapping, Elasticsearch will
attempt to create dynamic mappings for your fields.
This comprehensive configuration guide should help you set up and optimize
Elasticsearch for use with the Pimcore E-Commerce Framework, ensuring you
leverage the full capabilities of Elasticsearch for efficient and scalable
product indexing and searching.
User
Synonyms
Synonyms
With elasticsearch so called synonym filters can be configured to further
optimize search behavior. For details see Synonym Token Filter and
following pages at elasticsearch documentation.
Pimcore provides an out-of-the box integration to provide synonyms for the
synonym filters of elasticsearch.
Synonym Providers
Synonym providers are symfony services that implement the
SynonymProviderInterface, load synonyms from a specific source and provide
it for using them in elasticsearch synonym filters.
Sources can be simple files, Pimcore assets, Pimcore data objects, database
tables or what ever source is needed. Pimcore ships with a simple
FileSynonymProvider that can be used right away. The synonym source is a
file (e.g. a Pimcore asset) that follows the Solr file format.
Besides the service configuration itself, the synonym providers need to be
configured in index service configuration as follows.
pimcore_ecommerce_framework:
index_service:
tenants:
<YOUR_ELASTIC_SEARCH_TENANT>:
enabled: true
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
synonym_providers:
app_synonym_filter:
# service ID of synonym provider to use
provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider
# additional options for synonym provider (are
applied to a child-service instance of given synonym provider
options:
synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'
Matching Synonym Providers to Synonym Filters
Matching between synonym providers and synonym filters in index settings
takes place via name. In the sample below there the synonym provider
app_synonym_filter provides the synonyms for the filter app_synonym_filter.
The filter definition in the index settings can hold just an empty array
(as some definition is required). During index building, index resetting or
reloading of synonyms, the synonyms are loaded from synonyms provider and
injected to the synonyms array of the corresponding synonyms filter.
pimcore_ecommerce_framework:
index_service:
tenants:
<YOUR_ELASTIC_SEARCH_TENANT>:
enabled: true
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
synonym_providers:
app_synonym_filter:
# service ID of synonym provider to use
provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider
# additional options for synonym provider (are
applied to a child-service instance of given synonym provider
options:
synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'
index_settings:
analysis:
filter:
app_synonym_filter: # mapping between
synonym_provider and filter based on name
type: synonym # or synonym_graph or any
other ES type
synonyms: [] # provide an empy array
here, for ES6 [], for ES5[""]
Don't forget to also add the synonyms filter to an analysers filter array
where needed - as described in elasticsearch docs.
Updating Synonyms
There are three ways of updating the synonyms in the elasticsearch index.
For all applies that the synonyms are loaded from synonyms provider and
injected to the synonyms array of the corresponding synonyms filter by
Pimcore.
Index Creation
During index creation the synonyms are loaded from synonym providers and
applied to index.
Reindex
During reindex the synonyms are loaded from synonym providers and applied
to index when new index is created.
This is the recommended way to update synonyms during runtime at a
production system as there is no service downtime.
Elasticsearch sync command
With the command bin/console ecommerce:indexservice:elasticsearch-sync
update-synonyms synonyms can be updated in the current index. For that, the
index has to be closed and reopened which means a short downtime of the
index.
ChatGPT
## Synonyms in Elasticsearch for Pimcore E-Commerce Framework
Synonyms in Elasticsearch help optimize search behavior by matching
different terms with similar meanings. Pimcore integrates this
functionality through synonym filters and synonym providers.
### Synonym Providers
Synonym providers in Pimcore are Symfony services that implement the
`SynonymProviderInterface`. They load synonyms from various sources, such
as files, assets, data objects, or databases, and provide them to
Elasticsearch synonym filters. Pimcore includes a `FileSynonymProvider` for
quick integration.
#### FileSynonymProvider Example
1. **Service Configuration**
Define the service for the synonym provider in your `services.yaml` or
configuration file:
```yaml
services:
app.synonym_provider.file:
class: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
SynonymProvider\FileSynonymProvider
arguments:
['%kernel.project_dir%/public/var/assets/system/synonyms.txt']
```
2. **Index Service Configuration**
Configure the synonym provider in the `index_service` configuration:
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
enabled: true
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
synonym_providers:
app_synonym_filter:
provider_id: app.synonym_provider.file
options:
synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'
```
### Matching Synonym Providers to Synonym Filters
Synonym providers and synonym filters are matched by name. The following
example shows how to match a synonym provider to a synonym filter in
Elasticsearch index settings.
#### Example Configuration
1. **Index Service Configuration with Synonym Provider**
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
enabled: true
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
synonym_providers:
app_synonym_filter:
provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider
options:
synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'
index_settings:
analysis:
filter:
app_synonym_filter:
type: synonym
synonyms: [] # Provide an empty
array here
```
2. **Add Synonyms Filter to Analyzer's Filter Array**
Update the `analysis` section to include the synonyms filter in the
appropriate analyzers:
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
config_options:
index_settings:
analysis:
analyzer:
my_custom_analyzer:
type: custom
tokenizer: standard
filter:
- lowercase
- app_synonym_filter
```
### Updating Synonyms
#### Index Creation
During index creation, synonyms are loaded from synonym providers and
applied to the index.
#### Reindex
During a reindex, synonyms are updated from the synonym providers and
applied to the new index. This approach is recommended for updating
synonyms in a production environment without downtime.
#### Elasticsearch Sync Command
To update synonyms in the current index, use the following command. This
requires closing and reopening the index, resulting in a short downtime.
```bash
php bin/console ecommerce:indexservice:elasticsearch-sync update-synonyms
```
### Summary
Integrating synonyms in Elasticsearch within the Pimcore E-Commerce
Framework involves configuring synonym providers, matching them with
synonym filters, and updating the index as necessary. By following these
steps, you can enhance search capabilities and provide a more robust search
experience for users.
### Complete Example
```yaml
pimcore_elasticsearch_client:
es_clients:
default:
hosts: ['http://elastic:9200']
username: 'elastic'
password: 'somethingsecret'
logger_channel: 'pimcore.elasticsearch'
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
enabled: true
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
synonym_providers:
app_synonym_filter:
provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider
options:
synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'
es_client_name: default
index_settings:
number_of_shards: 5
number_of_replicas: 0
max_ngram_diff: 30
analysis:
analyzer:
my_custom_analyzer:
type: custom
tokenizer: standard
filter:
- lowercase
- app_synonym_filter
filter:
app_synonym_filter:
type: synonym
synonyms: []
attributes:
name:
locale: '%%locale%%'
type: text
options:
mapping:
type: text
store: true
index: not_analyzed
fields:
analyzed:
type: text
analyzer: standard
analyzed_ngram:
type: text
analyzer: my_custom_analyzer
```
This configuration ensures that synonyms are properly integrated and
utilized within Elasticsearch, enhancing the search functionality of your
Pimcore E-Commerce Framework.
User
Special Aspects for Findologic Exporter
Basically findologic worker works as described in the optimized
architecture. But there is an additional speciality with the export:
Executing php bin/console ecommerce:indexservice:process-update-queue does
not write the data directly to Findologic, but into an extra table \
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\
DefaultFindologic::EXPORT_TABLE_NAME (default is
ecommerceframework_productindex_export_findologic).
Findologic then can use the endpoint /ecommerceframework/findologic-export,
which delivers all data directly based on the export table. Valid
parameters for this endpoint are:
start: Pagination start.
count: Count of delivered entries.
shopKey: Shop key to identify the shop.
id: Filter for Product-ID
type: Filter for type
ChatGPT
## Special Aspects for Findologic Exporter
When using the Findologic exporter with Pimcore's E-Commerce Framework,
there are additional specifics to consider, especially regarding data
export and endpoint integration.
### Overview
The Findologic worker operates under the optimized architecture but
includes a unique export process. Instead of writing data directly to
Findologic, the data is written to an extra table. Findologic can then
fetch the data from this table using a dedicated endpoint.
### Key Points
1. **Data Export to Findologic Table:**
- When you execute the command to process the update queue, data is not
sent directly to Findologic.
- Instead, data is written to an export table defined by
`DefaultFindologic::EXPORT_TABLE_NAME` (default is
`ecommerceframework_productindex_export_findologic`).
2. **Findologic Data Fetching Endpoint:**
- Findologic uses the endpoint `/ecommerceframework/findologic-export`
to fetch data directly from the export table.
- The endpoint supports several parameters for data filtering and
pagination.
### Endpoint Parameters
- **`start`:** The starting point for pagination.
- **`count`:** The number of entries to deliver.
- **`shopKey`:** The shop key to identify the shop.
- **`id`:** Filter based on Product ID.
- **`type`:** Filter based on the type.
### Example Configuration
#### Configuring the Findologic Exporter
1. **Tenant Configuration:**
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyFindologicTenant:
enabled: true
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultFindologic
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\Findologic
config_options:
export_table_name:
ecommerceframework_productindex_export_findologic
# Additional configuration options can be added here
attributes:
name:
type: text
price:
type: float
description:
type: text
```
2. **Running Commands:**
- **Process the Update Queue:**
```bash
php bin/console ecommerce:indexservice:process-update-queue
```
- **Create or Update Index Structures:**
```bash
php bin/console ecommerce:indexservice:bootstrap --create-or-update-
index-structure
```
- **Manually Update All Pimcore Objects in the Index Store:**
```bash
php bin/console ecommerce:indexservice:bootstrap --update-index
```
### Fetching Data from the Export Table
Findologic can fetch data using the following endpoint:
**Endpoint URL:**
```
/ecommerceframework/findologic-export
```
**Example Request:**
```
GET /ecommerceframework/findologic-export?
start=0&count=100&shopKey=myShopKey
```
**Parameters:**
- **`start`:** (integer) The starting point for pagination (e.g., 0).
- **`count`:** (integer) The number of entries to return (e.g., 100).
- **`shopKey`:** (string) The key identifying the shop (e.g., myShopKey).
- **`id`:** (integer, optional) Filter results by Product ID.
- **`type`:** (string, optional) Filter results by type.
### Example Workflow
1. **Update the Export Table:**
Run the update queue command to ensure the export table is populated
with the latest product data.
```bash
php bin/console ecommerce:indexservice:process-update-queue
```
2. **Findologic Fetches Data:**
Findologic sends a request to the export endpoint to fetch the updated
product data.
```http
GET /ecommerceframework/findologic-export?
start=0&count=100&shopKey=myShopKey
```
### Summary
By configuring the Findologic exporter in Pimcore's E-Commerce Framework,
you can efficiently manage product data export to Findologic. The process
involves writing data to an intermediate export table and providing an
endpoint for Findologic to fetch this data. This setup ensures a seamless
integration and efficient data handling for your e-commerce needs.
User
Product List
Working with Product Lists
The API for getting (and filtering, ...) products out of the Product Index
are so called Product Lists. They all implement the interface \Pimcore\
Bundle\EcommerceFrameworkBundle\IndexService\ProductList\
ProductListInterface and need to be Product Index implementation specific.
Detailed method documentation is available in in-source documentation.
For how to get a Product List instance suitable for the current Product
Index implementation and filter for products see following code sample:
<?php
$list = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance()-
>getIndexService()->getProductListForCurrentTenant();
$list->addCondition("name = 'testproduct'", 'name');
$list->addRelationCondition('category', "dest IN (1024,1025,1026)");
$list->setOrder("ASC");
$list->setOrderKey('name');
$list->load();
All filtered attributes need to be in the Product Index. The Product List
implements all iterator and paginator interfaces and can be used in foreach
loops and in combination with Knp\Paginator.
For logging standard Symfony logging is used. E-Commerce Framework Product
Indices log into special channels like pimcore_ecommerce_indexupdater,
pimcore_ecommerce_sql, pimcore_ecommerce_es and
pimcore_ecommerce_findologic.
ChatGPT
## Working with Product Lists in Pimcore E-Commerce Framework
The API for retrieving and filtering products from the Product Index in
Pimcore is handled through Product Lists. These lists are specific to the
Product Index implementation and adhere to the `ProductListInterface`.
### Getting and Filtering Products
To obtain a Product List instance that is suitable for the current Product
Index implementation and to filter products, follow the example below:
### Code Sample
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
// Get a Product List instance for the current tenant
$list = Factory::getInstance()->getIndexService()-
>getProductListForCurrentTenant();
// Add conditions to filter products
$list->addCondition("name = 'testproduct'", 'name');
$list->addRelationCondition('category', "dest IN (1024,1025,1026)");
// Set ordering
$list->setOrder("ASC");
$list->setOrderKey('name');
// Load the filtered product list
$products = $list->load();
```
### Explanation of Code
- **Get Product List Instance:**
```php
$list = Factory::getInstance()->getIndexService()-
>getProductListForCurrentTenant();
```
This method retrieves a Product List instance suitable for the current
tenant's Product Index implementation.
- **Add Conditions:**
```php
$list->addCondition("name = 'testproduct'", 'name');
$list->addRelationCondition('category', "dest IN (1024,1025,1026)");
```
Conditions are added to filter the products based on specific attributes.
The attributes need to be part of the Product Index.
- **Set Order:**
```php
$list->setOrder("ASC");
$list->setOrderKey('name');
```
Define the order and the key to order by.
- **Load Products:**
```php
$products = $list->load();
```
Load the products that match the specified conditions and ordering.
### Attributes in Product Index
All attributes used for filtering must be included in the Product Index.
Ensure that these attributes are configured appropriately in your Product
Index configuration.
### Using Product Lists with Iterators and Paginators
Product Lists in Pimcore implement iterator and paginator interfaces,
making them compatible with foreach loops and pagination libraries like
`Knp\Paginator`.
### Example with Foreach Loop
```php
<?php
foreach ($list as $product) {
echo $product->getName();
```
### Example with Knp\Paginator
```php
<?php
use Knp\Component\Pager\PaginatorInterface;
// Assuming $paginator is an instance of KnpPaginator
$pagination = $paginator->paginate(
$list, /* query NOT result */
$request->query->getInt('page', 1), /* page number */
10 /* limit per page */
);
```
### Logging
Pimcore's E-Commerce Framework uses standard Symfony logging. Product
Indices log into specific channels, such as:
- `pimcore_ecommerce_indexupdater`
- `pimcore_ecommerce_sql`
- `pimcore_ecommerce_es`
- `pimcore_ecommerce_findologic`
These logs can help you monitor and debug the indexing and retrieval
processes.
### Summary
By using Product Lists, you can effectively retrieve and filter products
from the Product Index in Pimcore. The example code provided demonstrates
how to obtain a Product List instance, apply filters, set ordering, and
load the products. Additionally, Product Lists support iterators and
pagination, facilitating smooth integration with UI components. Logging
through specific channels ensures that you can track the indexing and
retrieval processes for effective debugging and monitoring.
User
Mockup Objects in Product List Results
Normally the result of Product Lists contain Pimcore product objects. When
retrieving lists with many entries this can result in performance issues
during rendering product listings - especially on high traffic applications
when Pimcore product objects are very complex, heavily use content
inheritance and have lots of relations.
To address this issue, Product Lists can return so called Mockup objects
instead of the original Pimcore product objects. The idea is that these
Mockup objects are a lightweight a selection of the product data, therefore
are much smaller and load faster.
By default the optimized product index implementations of the E-Commerce
Framework support Mockup objects in a transparent way and you can take
advantage from the faster loading times.
This means that the corresponding product lists return Mockup objects which
contain all data that is stored into the product index. If a getter is
called on the Mockup object (e.g. $product->getName()), it first tries to
get the requested data from the index data. If the data is not available,
the call is delegated to the original Pimcore object. Then the call is
delegated, following log message is written to Pimcore log files - if
system is in debug mode as WARN, otherwise as INFO.
"Method $method not in Mockup implemented, delegating to object with id
{$this->id}."
So, the only thing you need to take care about: make sure that all the data
that is printed in product listing is available in the product index.
Using Custom Mockup Object Implementation
Of course, it might be necessary to use custom Mockup implementations. To
do you, overwrite the createMockupObject($objectId, $data, $relations)
method in your Config implementation. For an example see MyOptimizedMysql
in the Demo.
ChatGPT
## Mockup Objects in Product List Results
When dealing with high traffic applications and complex Pimcore product
objects, performance issues can arise, especially during product listing
rendering. To address this, Pimcore's E-Commerce Framework supports the use
of Mockup objects in product lists. These lightweight objects improve
performance by loading faster and containing only a selection of product
data.
### How Mockup Objects Work
- **Transparent Integration:** The optimized product index implementations
in Pimcore E-Commerce Framework support Mockup objects by default.
- **Data Retrieval:** Mockup objects attempt to retrieve requested data
from the index. If the data is not available, the call is delegated to the
original Pimcore product object.
- **Logging:** If a method is not implemented in the Mockup object and the
call is delegated to the original object, a log message is written. In
debug mode, this is logged as WARN; otherwise, it is logged as INFO:
```
"Method $method not in Mockup implemented, delegating to object with id
{$this->id}."
```
### Example Code for Using Mockup Objects
Here's an example of how to work with Product Lists that return Mockup
objects:
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
// Get a Product List instance for the current tenant
$list = Factory::getInstance()->getIndexService()-
>getProductListForCurrentTenant();
// Add conditions to filter products
$list->addCondition("name = 'testproduct'", 'name');
$list->addRelationCondition('category', "dest IN (1024,1025,1026)");
// Set ordering
$list->setOrder("ASC");
$list->setOrderKey('name');
// Load the filtered product list
$products = $list->load();
// Iterate through the products
foreach ($products as $product) {
// Using a getter on a Mockup object
echo $product->getName();
```
### Custom Mockup Object Implementation
In some cases, you might need to use custom Mockup implementations. To do
this, you need to overwrite the `createMockupObject($objectId, $data,
$relations)` method in your Config implementation.
#### Example Custom Mockup Implementation
1. **Create Custom Mockup Class:**
```php
namespace App\Ecommerce\Mockup;
use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\MockupObject;
class CustomMockupObject extends MockupObject
public function getCustomData()
return $this->data['customData'] ?? null;
}
```
2. **Overwrite `createMockupObject` Method:**
```php
namespace App\Ecommerce\Config;
use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
OptimizedMysql;
class MyOptimizedMysql extends OptimizedMysql
protected function createMockupObject($objectId, $data, $relations)
return new \App\Ecommerce\Mockup\CustomMockupObject($objectId,
$data, $relations);
```
3. **Configure the Custom Implementation:**
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyOptimizedTenant:
enabled: true
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\OptimizedMysql
config_id: App\Ecommerce\Config\MyOptimizedMysql
config_options: []
attributes:
name:
type: text
customData:
type: keyword
```
### Ensuring Data Availability in Product Index
To ensure that Mockup objects function correctly, make sure that all the
data needed for product listings is available in the product index. Define
the necessary attributes in the product index configuration.
### Summary
Mockup objects provide a lightweight and efficient way to handle product
listings in high traffic and complex applications. By implementing Mockup
objects, you can improve performance and ensure faster data retrieval. For
custom needs, you can create and configure custom Mockup objects to handle
specific data requirements.
User
Filter Service
Basic Idea of the Filter Service
The Filter Service supports the developers in setting up E-Commerce product
listings with filters and layered navigation known from classic shop
systems. Therefore it provides functionality to ...
... configure available filters and to set up the product listings in the
frontend.
... generating the necessary filter conditions for the Product Index based
on the filter type and user input.
... printing out the configured filter with possible filter values etc. to
the frontend.
To provide this functionality, a few components are necessary. The Filter
Service links all these components together and provides the developer a
clean API for creating product listings in the frontend.
1 - Setting up Filter Types
Each product listing has different filters like drop downs, multi selects,
input fields, number ranges, etc. Each of these Filter Types require
special configuration
special presentation in the view
special filter conditions for the Product Index
The Filter Types are responsible for these three tasks and can be used for
composing filter definition objects (see next chapter).
The backend implementation of Filter Types takes place in php classes which
extend the abstract class \Pimcore\Bundle\EcommerceFrameworkBundle\
FilterService\FilterType\AbstractFilterType and are responsible for
creating the correct filter conditions based on the Product Index
implementation and rendering the filter output to the frontend.
Therefore \Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterType\AbstractFilterType expects the two methods getFilterValues() and
addCondition() to be implemented.
Each Filter Type needs to be defined as service and registered on the
pimcore_ecommerce_framework.filter_service configuration. The framework
already defines a number of core filter types in
filter_service_filter_types.yaml.
FilterTypes are dependent of the used index backend. You need to use
different FilterTypes when using MySQL or ElasticSearch etc. Pimcore ships
with FilterTypes implementations for all supported index backends. For
details see for example Elasticsearch Config.
pimcore_ecommerce_framework:
filter_service:
tenants:
default:
# assign backend implementations and views to filter type
field collections
filter_types:
# filter type for the FilterNumberRange field
collection
FilterNumberRange:
# service id for filter type implementation
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRange
# default template for filter, can be overwritten
in filter definition
template: ':Shop/filters:range.html.php'
FilterNumberRangeSelection:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRangeSelection
template: ':Shop/filters:numberrange.html.php'
FilterSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\Select
template: ':Shop/filters:select.html.php'
FilterSelectFromMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\SelectFromMultiSelect
template: ':Shop/filters:select.html.php'
FilterMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\MultiSelect
template: ':Shop/filters:multiselect.html.php'
FilterMultiSelectFromMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\
MultiSelectFromMultiSelect
template: ':Shop/filters:multiselect.html.php'
FilterMultiRelation:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\MultiSelectRelation
template: ':Shop/filters:multiselect-
relation.html.php'
FilterCategory:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\SelectCategory
template: ':Shop/filters:select_category.html.php'
FilterRelation:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\SelectRelation
template: ':Shop/filters:object_relation.html.php'
Optionally, you can configure a custom filter service which relies on a
custom helper implementation. The helper is a tool for the Pimcore backend
controller to get possible group by values for a certain field (used by
object data type IndexFieldSelection, e.g. in filter definitions). First,
create your filter service definition:
services:
app.custom_filter_service:
class: Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterService
arguments:
- '@Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterGroupHelper'
You can now use the service definition in the filter_service config:
pimcore_ecommerce_framework:
filter_service:
tenants:
default:
service_id: app.custom_filter_service
filter_types:
# ...
Configuration elements are:
FilterCategory: The key of the array represents the field collection type
(= name of field collection) for configuration in filter definition objects
(see next chapter).
class: Backend implementation of the filter type.
script: Default view script of the filter type, can be overwritten in the
filter definition objects. You can find some script filter examples in the
Demo here.
Helper: Is a helper implementation that gets available values for pre
select settings in the filter definition objects based on the filter group
setting in the index attributes definition.
2 - Setting up FilterDefinition Objects
The configuration of available filters and the set up of product listings
in the frontend takes place in FilterDefinition Pimcore objects.
Configuration options are beside others:
General settings like page size etc.
PreConditions for pre filtering of products, e.g. only products of a
certain category. These preconditions cannot be changed by the user in the
frontend.
Filters that are visible in the frontend.
FilterDefinition
The configuration of preconditions and filters is done by field collection
entries, whereby the field collection types are mapped to Filter Types and
their backend implementations in the
pimcore_ecommerce_framework.filter_service config section (see previous
chapter). The Filter Definition class can be extended and modified to
custom needs of the system.
Filter Definition objects can be assigned to category objects to build up
automatic category pages or to area bricks in Pimcore documents to set up
manual landing pages etc. Both is demonstrated at our Demo and also
available as source code.
In case that a filter contains relational objects (FilterMultiRelation,
FilterRelation, etc.), the getName() method of the object is used to render
the text in pre-select lists and filters. Implement the
getNameForFilterDefinition() method in your data objects to show customized
(HTML) texts, including icons.
3 - Putting it all together
Once Filter Types and Filter Definitions are set up, it is quite easy to
put it all together and use the Filter Service in controller actions.
Controller
For setting up the Filter Service (including Product List with Knp\
Paginator) within the controller use following sample:
<?php
$ecommerceFactory = \Pimcore\Bundle\EcommerceFrameworkBundle\
Factory::getInstance();
$templateParams = [];
$params = array_merge($request->query->all(), $request->attributes->all());
$indexService = $ecommerceFactory->getIndexService();
$productListing = $indexService->getProductListForCurrentTenant();
$templateParams['productListing'] = $productListing;
//get filter definition from document, category or global settings
$filterDefinition = //TODO ...get from somewhere;
// create and init filter service
$filterService = $ecommerceFactory->getFilterService();
(new \Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper)-
>setupProductList($filterDefinition, $productListing, $params,
$filterService, true, true);
$templateParams['filterService'] = $filterService;
$templateParams['filterDefinition'] = $filterDefinition;
// inject and use Knp Paginator service: PaginatorInterface $paginator
$paginator = $paginator->paginate(
$productListing,
$request->get('page', 1),
18
);
$templateParams['results'] = $paginator;
$templateParams['paginationVariables'] = $paginator->getPaginationData();
return $this->render('Path/template.html.twig', $templateParams);
For a sample of a controller see our demo here.
View
For putting all filters to the frontend use following sample. It is
important that this sample is inside a form in order to get the parameter
of changed filters delivered back to the controller.
{% if(filterDefinition.filters|length > 0) %}
{% for filter in filterDefinition.filters %}
{% set filterMarkup = filterService.filterFrontend(filter,
productListing, currentFilter) %}
{{ filterMarkup | raw }}
{% endfor %}
{% endif %}
ChatGPT
## Filter Service in Pimcore E-Commerce Framework
The Filter Service in Pimcore's E-Commerce Framework helps developers
create E-Commerce product listings with filters and layered navigation.
This guide explains how to set up and use the Filter Service effectively.
### 1. Setting up Filter Types
Filter types define the types of filters used in product listings, such as
dropdowns, multi-selects, input fields, and number ranges. Each filter type
requires special configuration, presentation, and filter conditions.
#### Configuration Example
Define filter types in the `pimcore_ecommerce_framework.filter_service`
configuration:
```yaml
pimcore_ecommerce_framework:
filter_service:
tenants:
default:
filter_types:
FilterNumberRange:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRange
template: ':Shop/filters:range.html.php'
FilterSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\Select
template: ':Shop/filters:select.html.php'
```
#### Custom Filter Service
To configure a custom filter service, create a service definition and use
it in the filter service configuration:
```yaml
services:
app.custom_filter_service:
class: Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterService
arguments:
- '@Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterGroupHelper'
pimcore_ecommerce_framework:
filter_service:
tenants:
default:
service_id: app.custom_filter_service
filter_types:
# Define your filter types here
```
### 2. Setting up FilterDefinition Objects
FilterDefinition objects configure available filters and set up product
listings in the frontend. These objects can include general settings,
preconditions, and visible filters.
#### Example FilterDefinition Configuration
Create FilterDefinition objects in Pimcore and map them to filter types in
your configuration:
```yaml
pimcore_ecommerce_framework:
filter_service:
tenants:
default:
filter_types:
FilterNumberRange:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRange
template: ':Shop/filters:range.html.php'
```
Assign FilterDefinition objects to category objects for automatic category
pages or to area bricks in Pimcore documents for manual landing pages.
### 3. Putting it All Together
Integrate the Filter Service with your controllers and views to create
dynamic product listings.
#### Controller Setup
Here's an example of setting up the Filter Service within a controller:
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
// Controller action
public function productListAction(Request $request, PaginatorInterface
$paginator)
$ecommerceFactory = Factory::getInstance();
$templateParams = [];
$params = array_merge($request->query->all(), $request->attributes-
>all());
$indexService = $ecommerceFactory->getIndexService();
$productListing = $indexService->getProductListForCurrentTenant();
$templateParams['productListing'] = $productListing;
// Get filter definition from document, category or global settings
$filterDefinition = // TODO: Retrieve the filter definition
// Create and init filter service
$filterService = $ecommerceFactory->getFilterService();
(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);
$templateParams['filterService'] = $filterService;
$templateParams['filterDefinition'] = $filterDefinition;
// Inject and use Knp Paginator service
$pagination = $paginator->paginate(
$productListing,
$request->get('page', 1),
18
);
$templateParams['results'] = $pagination;
$templateParams['paginationVariables'] = $pagination-
>getPaginationData();
return $this->render('Path/template.html.twig', $templateParams);
```
#### View Setup
Render filters in the frontend:
```twig
<form method="get" action="{{ path('your_route') }}">
{% if filterDefinition.filters|length > 0 %}
{% for filter in filterDefinition.filters %}
{% set filterMarkup = filterService.filterFrontend(filter,
productListing, currentFilter) %}
{{ filterMarkup | raw }}
{% endfor %}
{% endif %}
<button type="submit">Apply Filters</button>
</form>
```
### Conclusion
By setting up filter types, configuring FilterDefinition objects, and
integrating the Filter Service in controllers and views, you can create
powerful, dynamic product listings with layered navigation in Pimcore's E-
Commerce Framework. This approach ensures efficient filtering and better
user experience for your e-commerce application.
User
Filter Service with Elasticsearch
Definition of Filter Types
When using elasticsearch as Product Index, different FilterTypes must be
configured for the corresponding tenant. These filter types create the
elasticsearch specific conditions for each filter.
Here is an example for the configuration:
pimcore_ecommerce_framework:
filter_service:
tenants:
ElasticSearch:
filter_types:
FilterNumberRange:
# Service id for filter type implementation
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\NumberRange
# Default template for filter, can be overwritten
in filter definition
template: ':Shop/filters:range.html.php'
FilterNumberRangeSelection:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
NumberRangeSelection
template: ':Shop/filters:numberrange.html.php'
FilterSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\Select
template: ':Shop/filters:select.html.php'
FilterSelectFromMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectFromMultiSelect
template: ':Shop/filters:select.html.php'
FilterMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\MultiSelect
template: ':Shop/filters:multiselect.html.php'
FilterMultiSelectFromMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectFromMultiSelect
template: ':Shop/filters:multiselect.html.php'
FilterMultiRelation:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectRelation
template: ':Shop/filters:multiselect-
relation.html.php'
FilterCategory:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectCategory
template: ':Shop/filters:select_category.html.php'
FilterRelation:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectRelation
template: ':Shop/filters:object_relation.html.php'
Filtering for Classification Store Attributes
With the document structure of elasticsearch it is easily possible to index
and filter for classification store attributes without defining them all
als separate attributes in the index definition. See Filter Classification
Store for details.
Filtering for Nested Documents in General
For information how to take leverage of the nested documents feature for
elasticsearch and make even more sophisticated search queries, have a look
at Filter Nested Documents.
ChatGPT
## Filter Service with Elasticsearch in Pimcore E-Commerce Framework
When using Elasticsearch as the Product Index in Pimcore's E-Commerce
Framework, you need to configure specific filter types for the
Elasticsearch tenant. These filter types create Elasticsearch-specific
conditions for each filter, allowing for powerful and optimized product
filtering.
### Configuring Filter Types for Elasticsearch
To configure filter types for Elasticsearch, define them in the
`pimcore_ecommerce_framework.filter_service` configuration section for the
Elasticsearch tenant.
### Example Configuration
Here's an example configuration for defining various filter types for an
Elasticsearch tenant:
```yaml
pimcore_ecommerce_framework:
filter_service:
tenants:
ElasticSearch:
filter_types:
FilterNumberRange:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\NumberRange
template: ':Shop/filters:range.html.php'
FilterNumberRangeSelection:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
NumberRangeSelection
template: ':Shop/filters:numberrange.html.php'
FilterSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\Select
template: ':Shop/filters:select.html.php'
FilterSelectFromMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectFromMultiSelect
template: ':Shop/filters:select.html.php'
FilterMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\MultiSelect
template: ':Shop/filters:multiselect.html.php'
FilterMultiSelectFromMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectFromMultiSelect
template: ':Shop/filters:multiselect.html.php'
FilterMultiRelation:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectRelation
template: ':Shop/filters:multiselect-
relation.html.php'
FilterCategory:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectCategory
template: ':Shop/filters:select_category.html.php'
FilterRelation:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectRelation
template: ':Shop/filters:object_relation.html.php'
```
### Filtering for Classification Store Attributes
Elasticsearch allows for efficient indexing and filtering of classification
store attributes without needing to define each attribute separately in the
index definition. This flexibility enables you to work with complex product
data more effectively.
### Filtering for Nested Documents
Elasticsearch's nested documents feature allows for sophisticated search
queries, enabling you to perform complex filtering operations on nested
objects within your product data. This can be particularly useful for
filtering on attributes within nested documents.
### Implementing Filter Service in Controller and View
To use the Filter Service in your controller and view, follow the steps
below:
#### Controller Setup
1. **Initialize the Filter Service:**
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
// Controller action
public function productListAction(Request $request, PaginatorInterface
$paginator)
$ecommerceFactory = Factory::getInstance();
$templateParams = [];
$params = array_merge($request->query->all(), $request->attributes-
>all());
$indexService = $ecommerceFactory->getIndexService();
$productListing = $indexService->getProductListForCurrentTenant();
$templateParams['productListing'] = $productListing;
// Get filter definition from document, category, or global
settings
$filterDefinition = // TODO: Retrieve the filter definition
// Create and init filter service
$filterService = $ecommerceFactory->getFilterService();
(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);
$templateParams['filterService'] = $filterService;
$templateParams['filterDefinition'] = $filterDefinition;
// Inject and use Knp Paginator service
$pagination = $paginator->paginate(
$productListing,
$request->get('page', 1),
18
);
$templateParams['results'] = $pagination;
$templateParams['paginationVariables'] = $pagination-
>getPaginationData();
return $this->render('Path/template.html.twig', $templateParams);
```
#### View Setup
2. **Render Filters in the Frontend:**
```twig
<form method="get" action="{{ path('your_route') }}">
{% if filterDefinition.filters|length > 0 %}
{% for filter in filterDefinition.filters %}
{% set filterMarkup = filterService.filterFrontend(filter,
productListing, currentFilter) %}
{{ filterMarkup | raw }}
{% endfor %}
{% endif %}
<button type="submit">Apply Filters</button>
</form>
```
### Summary
By configuring specific filter types for Elasticsearch in the Pimcore E-
Commerce Framework, you can leverage the powerful indexing and search
capabilities of Elasticsearch. This setup allows for efficient and dynamic
product filtering, enhancing the user experience in your e-commerce
application. Be sure to define your filter types and integrate the Filter
Service properly in both the controller and the view to achieve optimal
results.
User
Filter Classification Store
With elasticsearch it is possible to index all attributes of Classification
Store data without defining an attribute for each single classification
store key.
To do so, follow these steps
1) Index Definition
Pimcore ships with a special interpreter to load all classification store
attributes to the index. To use this interpreter add following attribute
configuration into your index definition:
some_field_name:
fieldname: 'my_classification_store_field_name'
interpreter: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
Interpreter\DefaultClassificationStore
filtergroup: classificationstore
options:
mapping:
type: 'object'
properties:
keys:
type: 'long'
values:
type: 'object'
This results in a data structure in your index similar to this:
"some_field_name" : {
"values" : {
"1" : [
"one value"
],
"2" : [
"another value"
],
"3" : [
"123",
"99"
],
"5" : [
"AT",
"DZ"
],
"4" : [
""
},
"keys" : [
1,
2,
3,
5,
This contains all the classification store IDs as well as all the data.
2) Filter Type
To interpret the indexed data correctly, a special filter type is needed.
As this filter type works only in combination with elasticsearch, it is not
activated by default. Following steps are necessary to activate it:
make sure the field collection FilteSelectClsStoreAttributes is installed
and is allowed in the filter list of the filter definition class.
add following filter type mapping (see here for details):
FilteSelectClsStoreAttributes:
filter_type_id: Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterType\ElasticSearch\SelectClassificationStoreAttributes
template: 'product/filters/nested_attributes.html.twig'
3) Template
The template for the filter has to render not only one filter, but the
whole list of possible filters for the classification store attributes. For
a sample template see our demo.
ChatGPT
## Filtering Classification Store Attributes with Elasticsearch
Pimcore allows indexing all attributes of a Classification Store using
Elasticsearch without needing to define each attribute individually. This
setup improves efficiency and flexibility when dealing with complex product
data.
### Steps to Implement Classification Store Filtering
### 1. Index Definition
To load all Classification Store attributes into the index, you need to
configure a special interpreter. Add the following attribute configuration
to your index definition:
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
ElasticSearch:
attributes:
classification_store:
fieldname: 'my_classification_store_field_name'
interpreter: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultClassificationStore
filtergroup: classificationstore
options:
mapping:
type: 'object'
properties:
keys:
type: 'long'
values:
type: 'object'
```
#### Resulting Data Structure
This configuration results in an index data structure like this:
```json
"classification_store": {
"values": {
"1": ["one value"],
"2": ["another value"],
"3": ["123", "99"],
"5": ["AT", "DZ"],
"4": [""]
},
"keys": [1, 2, 3, 5, 4]
```
This structure includes all Classification Store IDs and their associated
data.
### 2. Filter Type
To correctly interpret the indexed data, a special filter type is needed.
This filter type is specific to Elasticsearch.
#### Steps to Activate the Filter Type
1. **Ensure the Field Collection is Installed:**
Ensure the `FilteSelectClsStoreAttributes` field collection is installed
and allowed in the filter list of the Filter Definition class.
2. **Add Filter Type Mapping:**
```yaml
pimcore_ecommerce_framework:
filter_service:
tenants:
ElasticSearch:
filter_types:
FilteSelectClsStoreAttributes:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectClassificationStoreAttributes
template:
'product/filters/nested_attributes.html.twig'
```
### 3. Template
The template for the filter must render the entire list of possible filters
for the Classification Store attributes. Here’s an example template for
rendering nested attributes filters:
#### Example Twig Template
```twig
{% for attribute in filter.attributes %}
<div class="filter-group">
<label>{{ attribute.label }}</label>
<select name="{{ attribute.name }}">
<option value="">All</option>
{% for option in attribute.options %}
<option value="{{ option.value }}">{{ option.label
}}</option>
{% endfor %}
</select>
</div>
{% endfor %}
```
### Putting It All Together
#### Controller
Here's an example of setting up the Filter Service within a controller:
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
public function productListAction(Request $request, PaginatorInterface
$paginator)
$ecommerceFactory = Factory::getInstance();
$templateParams = [];
$params = array_merge($request->query->all(), $request->attributes-
>all());
$indexService = $ecommerceFactory->getIndexService();
$productListing = $indexService->getProductListForCurrentTenant();
$templateParams['productListing'] = $productListing;
// Retrieve the filter definition
$filterDefinition = // TODO: Retrieve the filter definition
// Initialize filter service
$filterService = $ecommerceFactory->getFilterService();
(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);
$templateParams['filterService'] = $filterService;
$templateParams['filterDefinition'] = $filterDefinition;
// Use Knp Paginator service
$pagination = $paginator->paginate(
$productListing,
$request->get('page', 1),
18
);
$templateParams['results'] = $pagination;
$templateParams['paginationVariables'] = $pagination-
>getPaginationData();
return $this->render('Path/template.html.twig', $templateParams);
```
#### View
Render the filters in the frontend using a form:
```twig
<form method="get" action="{{ path('your_route') }}">
{% if filterDefinition.filters|length > 0 %}
{% for filter in filterDefinition.filters %}
{% set filterMarkup = filterService.filterFrontend(filter,
productListing, currentFilter) %}
{{ filterMarkup | raw }}
{% endfor %}
{% endif %}
<button type="submit">Apply Filters</button>
</form>
```
### Summary
By configuring your Elasticsearch index and setting up the appropriate
filter types, you can efficiently manage and filter Classification Store
attributes. Ensure your templates and controllers are correctly set up to
leverage these filters, providing a seamless user experience in your
Pimcore E-Commerce application.
User
Filter for nested documents
In some cases it is necessary to store an array of objects, but in a way so
that they can be queried independently of each other, i.e. if you want to
store an array of additional data from field collections. The data in your
index may look as follows:
"_source": {
"attributes": {
"my_attributes": [
"id": "12345",
"name": "Höhe",
"value": "15 mm"
},
"id": "12346",
"name": "Länge",
"value": "7 mm"
},
"id": "12347",
"name": "Breite",
"value": "30 mm"
To utilize the nested document functionality the mapping type of the field
my_attributes must be defined as nested, to let elasticsearch know about
the sub-documents:
attributes:
filtergroup: string
type: 'nested'
options:
mapping:
type: 'nested'
interpreter_id: App\Ecommerce\IndexService\Interpreter\MyAttributes
interpreter_options:
locale: '%%locale%%'
Now you can create a filter for the nested document field, which has to be
defined in a nested manner as well:
class SelectMyAttribute extends \Pimcore\Bundle\EcommerceFrameworkBundle\
FilterService\FilterType\AbstractFilterType
public function prepareGroupByValues(AbstractFilterDefinitionType
$filterDefinition, ProductListInterface $productList): void
/** @var AbstractElasticSearch $productList */
$nestedPath = "attributes.my_attributes";
// first group by id
$subAggregationField = $nestedPath . ".id";
// then group by value
$subSubAggregationField = $nestedPath . ".value.keyword";
$productList->prepareGroupByValuesWithConfig($this-
>getField($filterDefinition), true, false, [
"nested" => [
"path" => $nestedPath
],
"aggs" => [
$subAggregationField => [
"terms" => [
"size" => 200,
"field" => $subAggregationField
],
"aggs" => [
$subSubAggregationField => [
"terms" => [
"size" => 200,
"field" => $subSubAggregationField
]);
public function addCondition(AbstractFilterDefinitionType
$filterDefinition, ProductListInterface $productList, array $currentFilter,
array $params, bool $isPrecondition = false): void
$nestedPath = "attributes.my_attributes";
// @todo: get $myAttributeValue and $myAttributeId from request
params
$condition = [
"nested" => [
"path" => $nestedPath,
"query" => [
"bool" => [
$mode => [
"term" => [
$nestedPath . ".value.keyword" =>
$myAttributeValue
],
"term" => [
$nestedPath."id" => $myAttributeId
];
$productList->addCondition($condition, $this-
>getField($filterDefinition));
public function getFilterValues(AbstractFilterDefinitionType
$filterDefinition, ProductListInterface $productList, array
$currentFilter): array
{
$field = $this->getField($filterDefinition);
$this->prepareGroupByValues($filterDefinition, $productList);
$values = $productList->getGroupByValues($field, true, !
$filterDefinition->getUseAndCondition());
return [
'label' => $filterDefinition->getLabel(),
'values' => $values,
'metaData' => $filterDefinition->getMetaData(),
'hasValue' => $this->hasValue,
];
Further information
Read more about
nested documents
nested queries
nested aggregations
in the official elasticsearch documentation.
ChatGPT
## Filtering for Nested Documents in Elasticsearch with Pimcore
Elasticsearch supports the concept of nested documents, which allows you to
store arrays of objects that can be queried independently. This is useful
for complex data structures like arrays of field collections. Here's how to
set up and use nested documents in Pimcore's E-Commerce Framework.
### Step-by-Step Guide
### 1. Index Definition
Define the field as nested in your Elasticsearch index configuration. This
lets Elasticsearch know to treat the sub-documents as independent entities.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
ElasticSearch:
attributes:
my_attributes:
filtergroup: string
type: 'nested'
options:
mapping:
type: 'nested'
interpreter_id: App\Ecommerce\IndexService\
Interpreter\MyAttributes
interpreter_options:
locale: '%%locale%%'
```
### 2. Implementing Custom Filter Type
Create a custom filter type to handle nested documents. This filter type
will prepare the group-by values, add conditions to the query, and fetch
filter values.
#### Custom Filter Type Class
```php
<?php
namespace App\Ecommerce\FilterService\FilterType;
use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\FilterType\
AbstractFilterType;
use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\FilterType\
AbstractFilterDefinitionType;
use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\
ProductListInterface;
use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ElasticSearch\
AbstractElasticSearch;
class SelectMyAttribute extends AbstractFilterType
public function prepareGroupByValues(AbstractFilterDefinitionType
$filterDefinition, ProductListInterface $productList): void
/** @var AbstractElasticSearch $productList */
$nestedPath = "attributes.my_attributes";
// first group by id
$subAggregationField = $nestedPath . ".id";
// then group by value
$subSubAggregationField = $nestedPath . ".value.keyword";
$productList->prepareGroupByValuesWithConfig($this-
>getField($filterDefinition), true, false, [
"nested" => [
"path" => $nestedPath
],
"aggs" => [
$subAggregationField => [
"terms" => [
"size" => 200,
"field" => $subAggregationField
],
"aggs" => [
$subSubAggregationField => [
"terms" => [
"size" => 200,
"field" => $subSubAggregationField
]
]
]);
public function addCondition(AbstractFilterDefinitionType
$filterDefinition, ProductListInterface $productList, array $currentFilter,
array $params, bool $isPrecondition = false): void
$nestedPath = "attributes.my_attributes";
// @todo: get $myAttributeValue and $myAttributeId from request
params
$myAttributeValue = $params['my_attribute_value'] ?? null;
$myAttributeId = $params['my_attribute_id'] ?? null;
$condition = [
"nested" => [
"path" => $nestedPath,
"query" => [
"bool" => [
"must" => [
"term" => [
$nestedPath . ".value.keyword" =>
$myAttributeValue
],
[
"term" => [
$nestedPath . ".id" => $myAttributeId
];
$productList->addCondition($condition, $this-
>getField($filterDefinition));
public function getFilterValues(AbstractFilterDefinitionType
$filterDefinition, ProductListInterface $productList, array
$currentFilter): array
$field = $this->getField($filterDefinition);
$this->prepareGroupByValues($filterDefinition, $productList);
$values = $productList->getGroupByValues($field, true, !
$filterDefinition->getUseAndCondition());
return [
'label' => $filterDefinition->getLabel(),
'values' => $values,
'metaData' => $filterDefinition->getMetaData(),
'hasValue' => $this->hasValue,
];
```
### 3. Configuration
Add the custom filter type to your
`pimcore_ecommerce_framework.filter_service` configuration.
```yaml
pimcore_ecommerce_framework:
filter_service:
tenants:
ElasticSearch:
filter_types:
SelectMyAttribute:
filter_type_id: App\Ecommerce\FilterService\
FilterType\SelectMyAttribute
template:
'product/filters/nested_attributes.html.twig'
```
### 4. Using the Filter in Controller and View
#### Controller
Initialize and use the custom filter type in your controller:
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
public function productListAction(Request $request, PaginatorInterface
$paginator)
$ecommerceFactory = Factory::getInstance();
$templateParams = [];
$params = array_merge($request->query->all(), $request->attributes-
>all());
$indexService = $ecommerceFactory->getIndexService();
$productListing = $indexService->getProductListForCurrentTenant();
$templateParams['productListing'] = $productListing;
// Retrieve the filter definition
$filterDefinition = // TODO: Retrieve the filter definition
// Initialize filter service
$filterService = $ecommerceFactory->getFilterService();
(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);
$templateParams['filterService'] = $filterService;
$templateParams['filterDefinition'] = $filterDefinition;
// Use Knp Paginator service
$pagination = $paginator->paginate(
$productListing,
$request->get('page', 1),
18
);
$templateParams['results'] = $pagination;
$templateParams['paginationVariables'] = $pagination-
>getPaginationData();
return $this->render('Path/template.html.twig', $templateParams);
```
#### View
Render the filters in the frontend:
```twig
<form method="get" action="{{ path('your_route') }}">
{% if filterDefinition.filters|length > 0 %}
{% for filter in filterDefinition.filters %}
{% set filterMarkup = filterService.filterFrontend(filter,
productListing, currentFilter) %}
{{ filterMarkup | raw }}
{% endfor %}
{% endif %}
<button type="submit">Apply Filters</button>
</form>
```
### Conclusion
By configuring Elasticsearch with nested document support and implementing
custom filter types, you can efficiently manage complex data structures and
provide powerful filtering capabilities in your Pimcore E-Commerce
Framework. Ensure your controller and view are set up to handle the custom
filters and display the filtered results effectively.
User
Working with Prices
Prices are an essential part of every E-Commerce solution. In order to be
able to implement complex and very custom pricing schemes, the E-Commerce
Framework has the concept of Pricing Systems. These Pricing Systems
encapsulate all the logic of retrieving and calculating prices.
The Tax Management Component adds functionality for dealing with taxes and
should be flexible enough to implement all kinds of tax structures.
With Pricing Rules and Vouchers marketing actions can be implemented.
For details on how to calculate with prices, see Calculate with Prices.
ChatGPT
## Working with Prices in Pimcore E-Commerce Framework
Prices are a crucial part of any e-commerce solution. The Pimcore E-
Commerce Framework provides a robust system for managing prices, including
support for complex pricing schemes, tax management, pricing rules, and
vouchers.
### Overview of Pricing Systems
Pricing Systems in Pimcore encapsulate all the logic needed to retrieve and
calculate prices. They are flexible and extensible, allowing you to
implement custom pricing schemes to meet your specific business needs.
### Key Components
1. **Pricing Systems**: Encapsulate logic for retrieving and calculating
prices.
2. **Tax Management**: Adds functionality for dealing with various tax
structures.
3. **Pricing Rules**: Implement marketing actions based on specific
conditions.
4. **Vouchers**: Implement discount mechanisms and special offers.
### Configuring Pricing Systems
To use a Pricing System, you need to define it in your configuration.
Here's an example:
#### Configuration Example
```yaml
pimcore_ecommerce_framework:
price_systems:
default:
id: App\Ecommerce\PriceSystem\CustomPriceSystem
```
#### Custom Price System Class
Create a custom Price System class that implements the logic for
calculating prices:
```php
<?php
namespace App\Ecommerce\PriceSystem;
use Pimcore\Bundle\EcommerceFrameworkBundle\PricingManager\PriceSystem\
PriceSystemInterface;
use Pimcore\Model\DataObject\AbstractObject;
class CustomPriceSystem implements PriceSystemInterface
public function getPrice(AbstractObject $product, $context = [])
// Implement your price calculation logic here
$basePrice = $product->getBasePrice();
// Apply custom logic, e.g., discounts, taxes, etc.
$finalPrice = $basePrice * 1.2; // Example logic
return $finalPrice;
}
```
### Tax Management
The Tax Management component handles tax calculations and can be configured
to support various tax structures.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
tax_manager:
default:
id: App\Ecommerce\TaxManager\CustomTaxManager
```
#### Custom Tax Manager Class
Create a custom Tax Manager class to implement tax calculation logic:
```php
<?php
namespace App\Ecommerce\TaxManager;
use Pimcore\Bundle\EcommerceFrameworkBundle\PricingManager\TaxManager\
TaxManagerInterface;
use Pimcore\Model\DataObject\AbstractObject;
class CustomTaxManager implements TaxManagerInterface
public function calculateTax(AbstractObject $product, $context = [])
// Implement your tax calculation logic here
$taxRate = 0.2; // Example tax rate
return $product->getBasePrice() * $taxRate;
```
### Pricing Rules
Pricing Rules allow you to implement marketing actions based on specific
conditions. They can be used to apply discounts, special offers, and other
promotional activities.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
pricing_manager:
default:
pricing_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\PricingManager
pricing_manager_options:
rule_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\Rule
price_info_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\PriceInfo
environment_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\Environment
```
### Vouchers
Vouchers can be used to implement discount mechanisms and special offers.
They provide a way to offer promotional codes and discounts to customers.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
voucher_service:
voucher_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\DefaultService
voucher_service_options:
reservation_minutes_threshold: 5
statistics_days_threshold: 30
token_managers:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\TokenManager\TokenManagerFactory
mapping:
default:
id: App\Ecommerce\VoucherService\CustomTokenManager
```
### Example Workflow for Calculating Prices
Here's an example of how to use the Pricing System, Tax Management, and
Vouchers to calculate a final price for a product.
#### Controller Example
```php
<?php
namespace App\Controller;
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Model\DataObject\Product;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ProductController extends AbstractController
public function calculatePriceAction(Request $request, $productId)
$product = Product::getById($productId);
$ecommerceFactory = Factory::getInstance();
$priceSystem = $ecommerceFactory->getPriceSystem();
$taxManager = $ecommerceFactory->getTaxManager();
$voucherService = $ecommerceFactory->getVoucherService();
// Calculate base price
$price = $priceSystem->getPrice($product);
// Calculate tax
$tax = $taxManager->calculateTax($product);
// Apply vouchers (example)
$voucherCode = $request->get('voucherCode');
if ($voucherCode) {
$voucher = $voucherService->validateVoucher($voucherCode);
if ($voucher) {
$price -= $voucher->getDiscount();
// Calculate final price
$finalPrice = $price + $tax;
return new Response(sprintf('Final price for product %d: %.2f',
$productId, $finalPrice));
```
### Summary
By configuring and utilizing the Pricing System, Tax Management, Pricing
Rules, and Vouchers in Pimcore's E-Commerce Framework, you can implement
complex and customized pricing schemes. These components provide a flexible
way to handle price calculations, tax management, and promotional
activities, ensuring your e-commerce solution meets all your business
needs.
User
Price Systems
In terms of pricing, the E-Commerce Framework has the concept of Price
Systems. These Price Systems are responsible for retrieving or calculating
prices and returning so called PriceInfo objects which contain the
calculated prices. Each product can have its own Price System.
So very complex pricing structures and different price sources can be
integrated into the system quite easily.
In terms of product availabilities and stocks, the very similar concept of
Availability Systems is used.
Configuration of Price Systems
A price system is a class implementing Pimcore\Bundle\
EcommerceFrameworkBundle\PriceSystem\PriceSystemInterface which is defined
as service and registered with a name in the
pimcore_ecommerce_framework.price_systems configuration tree. The framework
already ships with a number of concrete implementations which you can use
as starting point.
There are 3 places where the configuration of Price Systems takes place:
Product class: Each product has to implement the method
getPriceSystemName() which returns the name of its Price System.
Service definition: Each price system must be registered as service
Configuration: The price_systems section maps price system names to service
IDs
The product class returns the name of a price system:
<?php
class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\
CheckoutableInterface
public function getPriceSystemName(): string
return 'foo';
Each price system must be defined as service (either a service defined by
core configuration or your custom services):
# services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
# defines a completely custom price system as service
# arguments depend on your implementation
App\Ecommerce\PriceSystem\CustomPriceSystem:
arguments:
- 'bar'
# this reuses a core price system, but defines a new service which sets
custom options
# on the price system (a custom price attribute). available options
vary by implementation
app.custom_attribute_price_system:
class: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem
arguments:
$options:
attribute_name: customPriceField
The price_systems configuration maps names to service IDs:
pimcore_ecommerce_framework:
# defines 3 price systems
price_systems:
# the attribute price system is already defined in core
price_systems.yaml service definition
default:
id: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem
foo:
id: App\Ecommerce\PriceSystem\CustomPriceSystem
bar:
id: app.custom_attribute_price_system
The simplest price system is Pimcore\Bundle\EcommerceFrameworkBundle\
PriceSystem\AttributePriceSystem which reads the price from an attribute of
the product object. For implementing custom price systems have a look at
method comments of \Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface and the implementations of the existing price systems.
Getting and Printing Prices
Once the Price Systems are set up correctly, working with prices should be
quite easy. Each product has the method getOSPrice() which returns a \
Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInterface object
with the price of the product.
Internally the product gets its Price System and starts the price
calculation to get the price.
When the price system returns a custom PriceInfo object (e.g. with
additional stock prices, customer specific prices etc.), this PriceInfo can
be retrieved by calling getOSPriceInfo() method of the product object.
A sample for printing the price on a product detail page is:
<p class="price">
<span>{{ product.OSPrice }}</span>
</p>
ChatGPT
## Price Systems in Pimcore E-Commerce Framework
Pimcore's E-Commerce Framework utilizes the concept of Price Systems to
handle complex pricing structures and different price sources. Each product
can have its own Price System, allowing for flexible and customized pricing
calculations.
### Key Concepts
1. **Price Systems**: Responsible for retrieving or calculating prices and
returning `PriceInfo` objects.
2. **PriceInfo Objects**: Contain the calculated prices.
3. **Availability Systems**: Similar concept for managing product
availabilities and stocks.
### Configuration of Price Systems
Price Systems are classes that implement the `Pimcore\Bundle\
EcommerceFrameworkBundle\PriceSystem\PriceSystemInterface`. They are
defined as services and registered in the
`pimcore_ecommerce_framework.price_systems` configuration tree.
### Steps to Configure Price Systems
1. **Product Class Configuration**:
Each product must implement the `getPriceSystemName` method to return
the name of its Price System.
```php
<?php
class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\
Model\CheckoutableInterface
public function getPriceSystemName(): string
{
return 'foo';
```
2. **Service Definition**:
Define each Price System as a service in your `services.yaml`.
```yaml
services:
_defaults:
autowire: true
autoconfigure: true
# Custom price system service
App\Ecommerce\PriceSystem\CustomPriceSystem:
arguments:
- 'bar'
# Core price system with custom options
app.custom_attribute_price_system:
class: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem
arguments:
$options:
attribute_name: customPriceField
```
3. **Configuration Mapping**:
Map the Price System names to service IDs in the
`pimcore_ecommerce_framework.price_systems` configuration.
```yaml
pimcore_ecommerce_framework:
price_systems:
default:
id: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem
foo:
id: App\Ecommerce\PriceSystem\CustomPriceSystem
bar:
id: app.custom_attribute_price_system
```
### Implementing a Custom Price System
To implement a custom Price System, create a class that implements the
`PriceSystemInterface`.
#### Custom Price System Class
```php
<?php
namespace App\Ecommerce\PriceSystem;
use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfo;
class CustomPriceSystem implements PriceSystemInterface
public function getPrice(AbstractObject $product, array $context = []):
PriceInfo
// Implement your price calculation logic here
$basePrice = $product->getBasePrice();
// Apply custom logic, e.g., discounts, taxes, etc.
$finalPrice = $basePrice * 1.2; // Example logic
return new PriceInfo($finalPrice);
```
### Working with Prices
Once the Price Systems are set up correctly, retrieving and displaying
prices is straightforward.
1. **Getting Prices**:
Each product has a `getOSPrice` method that returns a `PriceInterface`
object with the product's price.
```php
$price = $product->getOSPrice();
```
2. **Getting PriceInfo**:
If the Price System returns a custom `PriceInfo` object, it can be
retrieved using the `getOSPriceInfo` method.
```php
$priceInfo = $product->getOSPriceInfo();
```
3. **Displaying Prices in Templates**:
To display the price on a product detail page, you can use the following
Twig template code:
```twig
<p class="price">
<span>{{ product.OSPrice }}</span>
</p>
```
### Example Workflow
Here’s an example workflow for setting up and using a custom Price System:
1. **Define the Custom Price System Class**:
```php
<?php
namespace App\Ecommerce\PriceSystem;
use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfo;
class CustomPriceSystem implements PriceSystemInterface
public function getPrice(AbstractObject $product, array $context =
[]): PriceInfo
// Custom price calculation logic
$basePrice = $product->getBasePrice();
$finalPrice = $basePrice * 1.2;
return new PriceInfo($finalPrice);
```
2. **Register the Service**:
```yaml
services:
App\Ecommerce\PriceSystem\CustomPriceSystem:
arguments:
- 'bar'
```
3. **Map the Price System**:
```yaml
pimcore_ecommerce_framework:
price_systems:
foo:
id: App\Ecommerce\PriceSystem\CustomPriceSystem
```
4. **Implement the Product Class**:
```php
<?php
class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\
Model\CheckoutableInterface
public function getPriceSystemName(): string
{
return 'foo';
```
5. **Display the Price in a Twig Template**:
```twig
<p class="price">
<span>{{ product.OSPrice }}</span>
</p>
```
### Conclusion
By configuring and utilizing Price Systems in Pimcore's E-Commerce
Framework, you can implement complex and flexible pricing schemes tailored
to your business needs. This approach ensures accurate price calculations
and enhances the overall shopping experience for your customers.
User
Tax Management
Within the Price Systems there is a Tax Management component to deal with
all sorts of taxes. So it is possible to calculate and print out taxes as
needed.
The Tax Management is quite transparent and should not affect the system
very deeply. As a result - if not necessary (e.g. because you have a B2B
system, etc.) - you don't need to deal with taxes in E-Commerce Framework
at all. Also, if you have your very own tax implementation, this should be
perfectly possible and you should need to not deal with the Tax Management
in the E-Commerce Framework at all. Just use all the default values and
every thing should be fine.
Components of Tax Management
If you need to deal with taxes following components are important to know
of:
Tax Configuration with OnlineShopTaxClass
The configuration of taxes is done with OnlineShopTaxClass Pimcore objects
within in the Pimcore Backend UI. The actual tax calculation is always
based on the configuration of such a tax class. So, tax configurations for
different countries and product groups can be established. The tax
calculation is always based on one tax class, a combination of tax classes
is not possible. The configuration concludes a TaxEntryCombinationMode
(combine and one after another) and one or more tax entries with a name and
a tax rate in percent.
tax classes
The selection of the correct tax class (for a certain country and a certain
product group) is done by the Price System (see next section).
Tax Class Selection with Price Systems
The Price System decides for each product and environment which tax class
to take for tax calculation. Therefore following two methods need to be
implemented:
getTaxClassForProduct: Should return tax class for given product. The
default implementation returns a generic tax class based on the Website
Settings or - if not set - an empty tax class.
getTaxClassForPriceModification: See later for more information.
The logic behind the tax class selection can be of any complexity. It can
be based on a simple Website Setting (for one tax class fits all), or based
on a complex matrix with product group, sending country, delivering country
and several other aspects.
Tax Calculation with TaxCalculationService
The actual tax calculation is done in the
TaxCalculationService::updateTaxes(PriceInterface $price, $calculationMode
= self::CALCULATION_FROM_NET) method. It updates taxes in given price
object by using its tax entries, tax combination mode and net or gross
amount based on the given $calculationMode.
The calculation is done by the framework in two places:
By Price Systems when creating the PriceInfo objects
By PriceInterface objects when setAmount, setGrossAmount or setNetAmount is
called and $recalc is set to true.
The PriceInterface object
Every price in the E-Commerce Framework comes down to an PriceInterface
object. Therefore also all calculated taxes and all necessary information
for calculating taxes is stored in PriceInterface objects. Following
methods are important:
getTaxEntries(), setTaxEntries($taxEntries): Sets and gets tax entries for
price. Each price can have one or more tax entries based on the tax laws.
Each of these tax entries contain percent rate and calculated amount. The
order of the tax entries is important.
getTaxEntryCombinationMode(),
setTaxEntryCombinationMode($taxEntryCombinationMode): Sets and gets the tax
entry combination mode which defines how tax calculation is done based on
the tax entries:
TaxEntry::CALCULATION_MODE_COMBINE: Sum up all tax rates and calculate tax
amount afterwards.
TaxEntry::CALCULATION_MODE_ONE_AFTER_ANOTHER: For each tax rate calculate
tax amount, add it to total price and then calculate tax amount for next
tax rate based on new total sum.
TaxEntry::CALCULATION_MODE_FIXED: Amounts and percent rates are fixed and
cannot be (re)calculated based on information within the PriceInterface
object. This mode is needed for subTotal and grandTotal in
CartPriceCalculator.
getGrossAmount(), setGrossAmount($grossAmount, $recalc = false): Sets and
gets gross amount of price. If $recalc is set to true, corresponding net
price is calculated based on tax entries and tax entry combination mode.
getNetAmount(), setNetAmount($netAmount, $recalc = false): Sets and gets
net amount of price. If $recalc is set to true, corresponding gross price
is calculated based on tax entries and tax entry combination mode.
getAmount(), setAmount($amount, $priceMode = self::PRICE_MODE_GROSS,
$recalc = false): Gets the gross amount by default and sets the gross or
net amount based on the params.
Special Aspects
Tax Calculation in Pricing Rules
E-Commerce Framework Pricing Rules always modify the gross price of the
product and recalculate the net price based on the tax entries of the
product price. So specified discount amounts on product level need to be
configured as gross discounts.
Since cart discounts are implemented as CartPriceModificators the next
point is important for them. It might be necessary to extend the default
implementation of the cart discounts for the correct selection of the tax
class for discounts. The default implementation uses the
getTaxClassForPriceModification method of the Price System called default
for tax class selection.
Tax Calculation in CartPriceModificators
The CartPriceModificators themselves can decide if the modification should
be done as net or gross amount since the interface
ModificatedPriceInterface extends PriceInterface and therefore all tax
related information as explained above. The method
getTaxClassForPriceModification in Price Systems can be used to delegate
the tax class selection to Price Systems.
Putting the Pieces Together
For setting up the tax management, following steps are necessary.
1) Defining Tax Classes
Create and configure all the OnlineShopTaxClass objects within Pimcore.
2) Configuring Price System
Setup the correct price systems and implement their methods
getTaxClassForProduct and getTaxClassForPriceModification. It might also be
necessary to have a look at the CartPriceModificator for cart discounts and
make sure that it selects the correct tax class.
3) Printing Taxes
To print taxes into the frontend use following samples:
Product Detail Page
{% set price = product.OSPrise %}
<strong>{{ price }}</strong>
<div class="tax">
<p><strong>{{ 'shop.detail.included_tax'|trans }}'</strong></p>
<ul>
{% for entry in price.taxEntries %}
<li>{{ entry.entry.name }}: {{ entry.percent }}%
({{ price.currency.toCurrency(entry.amount) }})</li>
{% endfor %}
</ul>
</div>
Cart
{% set grandTotal = cart.priceCalculator.grandTotal %}
{% if grandTotal.taxEntries %}
<tr>
<td>{{ 'cart.taxes'|trans }}</td>
<td>
{% for taxEntry in grandTotal.taxEntries %}
{{ taxEntry.entry.name }}: {{ taxEntry.percent }}%
({{ grandTotal.currency.toCurrency(taxEntry.amount) }})<br/>
{% endfor %}
</td>
</tr>
{% endif %}
Order Confirmation Mail
{% if order.taxInfo %}
<tr>
<td>{{ 'cart.taxes'|trans }}</td>
<td>
{% for taxEntry in order.taxInfo %}
{{ taxEntry[0] }}: {{ taxEntry[1] }}
({{ currency.toCurrency(taxEntry[2])) }})<br/>
{% endfor %}
</td>
</tr>
{% endif %}
4) Taxes in OnlineShopOrders
Make sure that all tax related attributes are available in OnlineShopOrder
and OnlineShopOrderItem. Then the E-Commerce Framework populates all needed
values automatically and therefore stores the tax information in the order
objects.
ChatGPT
## Tax Management in Pimcore E-Commerce Framework
Pimcore's E-Commerce Framework includes a robust Tax Management component
to handle various tax calculations and configurations. This allows for
flexible tax management suitable for different business needs, including
B2C and B2B environments.
### Key Components of Tax Management
1. **OnlineShopTaxClass**: Configures taxes for different countries and
product groups.
2. **Price Systems**: Selects the correct tax class for each product and
price modification.
3. **TaxCalculationService**: Calculates and updates taxes based on the
given mode (net or gross).
4. **PriceInterface**: Stores all calculated taxes and necessary
information for tax calculation.
### Steps to Implement Tax Management
### 1. Defining Tax Classes
Tax classes are configured using `OnlineShopTaxClass` objects in the
Pimcore Backend UI. Each tax class can have one or more tax entries with a
name and tax rate.
#### Example Tax Class Configuration

### 2. Configuring Price Systems
Price Systems decide which tax class to use for tax calculations. Implement
the following methods in your Price System:
- `getTaxClassForProduct`: Returns the tax class for the given product.
- `getTaxClassForPriceModification`: Returns the tax class for price
modifications.
#### Example Price System Implementation
```php
<?php
namespace App\Ecommerce\PriceSystem;
use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfo;
use Pimcore\Model\DataObject\OnlineShopTaxClass;
class CustomPriceSystem implements PriceSystemInterface
public function getTaxClassForProduct(AbstractObject $product):
OnlineShopTaxClass
// Implement logic to select the appropriate tax class for the
product
return $this->getTaxClassByName('default_tax_class');
public function getTaxClassForPriceModification(AbstractObject
$product): OnlineShopTaxClass
{
// Implement logic to select the appropriate tax class for price
modifications
return $this->getTaxClassByName('discount_tax_class');
private function getTaxClassByName($name)
return OnlineShopTaxClass::getByName($name);
```
### 3. Tax Calculation with TaxCalculationService
The `TaxCalculationService` performs the actual tax calculations. It
updates taxes in the given `PriceInterface` object using the tax entries,
combination mode, and calculation mode (net or gross).
### 4. Working with PriceInterface
Every price in the E-Commerce Framework is represented by a
`PriceInterface` object. This object contains all tax-related information
and methods to manage tax calculations:
- `getTaxEntries()`, `setTaxEntries($taxEntries)`: Get and set tax entries.
- `getTaxEntryCombinationMode()`, `setTaxEntryCombinationMode($mode)`: Get
and set the tax entry combination mode.
- `getGrossAmount()`, `setGrossAmount($amount, $recalc = false)`: Get and
set the gross amount.
- `getNetAmount()`, `setNetAmount($amount, $recalc = false)`: Get and set
the net amount.
- `getAmount()`, `setAmount($amount, $priceMode = self::PRICE_MODE_GROSS,
$recalc = false)`: Get and set the amount based on the price mode (gross or
net).
### Special Aspects
#### Tax Calculation in Pricing Rules
Pricing rules always modify the gross price and recalculate the net price
based on the tax entries.
#### Tax Calculation in CartPriceModificators
Cart price modifiers can decide whether the modification should be done on
the net or gross amount. They use the `getTaxClassForPriceModification`
method of the Price System for tax class selection.
### Example: Putting It All Together
#### Defining Tax Classes
Create and configure `OnlineShopTaxClass` objects in Pimcore.
#### Configuring Price System
Setup the Price System and implement the methods for tax class selection.
#### Printing Taxes in the Frontend
##### Product Detail Page
```twig
{% set price = product.OSPrice %}
<strong>{{ price }}</strong>
<div class="tax">
<p><strong>{{ 'shop.detail.included_tax'|trans }}</strong></p>
<ul>
{% for entry in price.taxEntries %}
<li>{{ entry.entry.name }}: {{ entry.percent }}%
({{ price.currency.toCurrency(entry.amount) }})</li>
{% endfor %}
</ul>
</div>
```
##### Cart
```twig
{% set grandTotal = cart.priceCalculator.grandTotal %}
{% if grandTotal.taxEntries %}
<tr>
<td>{{ 'cart.taxes'|trans }}</td>
<td>
{% for taxEntry in grandTotal.taxEntries %}
{{ taxEntry.entry.name }}: {{ taxEntry.percent }}%
({{ grandTotal.currency.toCurrency(taxEntry.amount) }})<br/>
{% endfor %}
</td>
</tr>
{% endif %}
```
##### Order Confirmation Mail
```twig
{% if order.taxInfo %}
<tr>
<td>{{ 'cart.taxes'|trans }}</td>
<td>
{% for taxEntry in order.taxInfo %}
{{ taxEntry[0] }}: {{ taxEntry[1] }}
({{ currency.toCurrency(taxEntry[2]) }})<br/>
{% endfor %}
</td>
</tr>
{% endif %}
```
### Summary
By configuring tax classes, setting up Price Systems, and implementing tax
calculation logic, you can effectively manage taxes in Pimcore's E-Commerce
Framework. This setup allows for flexible and accurate tax calculations,
ensuring compliance with various tax regulations and enhancing the overall
user experience.
User
Pricing Rules
Pricing Rules are supported by the E-Commerce Framework out of the box. The
pricing rules themselves can be configured in the Pimcore Backend UI by
putting conditions and actions together.
Pricing Rules
Once active, all rules are checked and applied automatically by the system
- including reducing product prices, adding price modificators to reduce
cart totals, removing shipping costs and adding gift items to the cart.
To print the applied rules in the frontend, the developer needs to add some
lines of code. Depending on the location, following scripts can be used.
Product Detail Page
{% set priceInfo = product.OSPriceInfo %}
{% if priceInfo.rules %}
<div class="discounts">
<p><strong>{{ 'shop.detail.your_benefit'|trans
}}</strong></p>
<ul>
<?php foreach($priceInfo->getRules() as $rule ) { ?>
{% for rule in priceInfo.rules %}
<?php foreach($rule->getActions() as
$action) { ?>
{% for action in rule.actions %}
{% if action is instanceof('Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Action\ProductDiscount') %}
{% if action.amount > 0 %}
<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.amount'|trans([action.amount])
}}</li>
{% elseif action.percent > 0 %}
<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.percent'|
trans([action.percent]) }}</li>
{% endif %}
{% elseif action is
instanceof('Pimcore\Bundle\EcommerceFrameworkBundle\PricingManager\Action\
GiftInterface') %}
<li>
{{ 'shop.detail.your_benefit.discount.gift'|
trans }}, <a
href="{{ action.product.getShopDetailLink() }}">{{ action.product.name }}</
a>
</li>
{% elseif action is instanceof('Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Action\FreeShipping') %}
<li>
{{ 'shop.detail.your_benefit.discount.freeshipping'|trans }}
</li>
<?php } ?>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
Cart Product List - Printing Gift Items
{% for item in car.giftItems %}
{% set linkDetail = item.product.shopDetailLink %}
<tr>
<td class="cart-list-items-image">
<a href="{{ linkDetail }}" >
<img src="{{ item.product.firstImage({width:
120, height: 120, aspectratio: true}) }}" alt="" border="0" />
</a>
</td>
<td class="cart-list-items-name" valign="top">
<a href="{{ linkDetail }}"
>{{ item.product.OSName }}</a>
</td>
<td class="cart-list-items-quantity">
{{ item.count }}
</td>
</tr>
{% endfor %}
All other price modifications on cart level are included as cart price
modificators. See Cart manager for more details and how to print them.
ChatGPT
## Pricing Rules in Pimcore E-Commerce Framework
Pimcore's E-Commerce Framework supports pricing rules out of the box. These
rules can be configured in the Pimcore Backend UI and are automatically
applied by the system. They can be used to reduce product prices, apply
discounts, remove shipping costs, and add gift items to the cart.
### Configuring Pricing Rules
Pricing rules are set up by combining conditions and actions. This allows
you to create complex marketing strategies directly within the Pimcore
backend.
### Displaying Applied Pricing Rules in the Frontend
To display the pricing rules applied to a product or cart, you need to add
some custom code to your templates. Here are examples for different
scenarios.
### 1. Product Detail Page
To display the applied pricing rules on the product detail page, use the
following Twig template code:
```twig
{% set priceInfo = product.OSPriceInfo %}
{% if priceInfo.rules %}
<div class="discounts">
<p><strong>{{ 'shop.detail.your_benefit'|trans }}</strong></p>
<ul>
{% for rule in priceInfo.rules %}
{% for action in rule.actions %}
{% if action is instanceof('Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Action\ProductDiscount') %}
{% if action.amount > 0 %}
<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.amount'|trans({'%amount%':
action.amount}) }}</li>
{% elseif action.percent > 0 %}
<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.percent'|trans({'%percent%':
action.percent}) }}</li>
{% endif %}
{% elseif action is instanceof('Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Action\GiftInterface') %}
<li>
{{ 'shop.detail.your_benefit.discount.gift'|
trans }}, <a
href="{{ action.product.getShopDetailLink() }}">{{ action.product.name }}</
a>
</li>
{% elseif action is instanceof('Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Action\FreeShipping') %}
<li>{{ 'shop.detail.your_benefit.discount.freeshipping'|trans }}</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
```
### 2. Cart Product List - Printing Gift Items
To display gift items added to the cart by pricing rules, use the following
Twig template code:
```twig
{% for item in cart.giftItems %}
{% set linkDetail = item.product.shopDetailLink %}
<tr>
<td class="cart-list-items-image">
<a href="{{ linkDetail }}">
<img src="{{ item.product.firstImage({width: 120, height:
120, aspectratio: true}) }}" alt="" border="0" />
</a>
</td>
<td class="cart-list-items-name" valign="top">
<a href="{{ linkDetail }}">{{ item.product.OSName }}</a>
</td>
<td class="cart-list-items-quantity">
{{ item.count }}
</td>
</tr>
{% endfor %}
```
### 3. Cart Price Modifications
All other price modifications at the cart level are included as cart price
modifiers. You can print them similarly by accessing the price modifiers
from the cart object.
### Example: Displaying Cart Price Modifications
Here's an example of how to display cart price modifications in the cart
template:
```twig
{% set grandTotal = cart.priceCalculator.grandTotal %}
{% if grandTotal.taxEntries %}
<tr>
<td>{{ 'cart.taxes'|trans }}</td>
<td>
{% for taxEntry in grandTotal.taxEntries %}
{{ taxEntry.entry.name }}: {{ taxEntry.percent }}%
({{ grandTotal.currency.toCurrency(taxEntry.amount) }})<br/>
{% endfor %}
</td>
</tr>
{% endif %}
```
### Summary
By setting up pricing rules in the Pimcore backend and adding the
appropriate code to your templates, you can provide dynamic pricing and
discounts to your customers. This enhances the shopping experience and
allows you to implement complex marketing strategies effortlessly.
User
Vouchers
Like Pricing Rules, also vouchers are supported out of the box by the
framework. To use vouchers, following steps are necessary:
Create an OnlineShopVoucherSeries object.
Create tokens based on the OnlineShopVoucherSeries.
Create a Pricing Rule for the OnlineShopVoucherSeries and define the
benefit of the voucher.
Allow the user to add a token to his cart.
Display voucher information to user.
Create an OnlineShopVoucherSeries object
A voucher series contains basic information of the voucher and settings for
creating the voucher tokens. It is represented by OnlineShopVoucherSeries
objects. The corresponding class is added to the system during installation
of the E-Commerce Framework. Creating Voucher Series
Currently there are two types of vouchers supported - Single and Pattern.
Single: One single token is defined that can be used multiple times.
Voucher Series Settings Single
Pattern: Tokens are generated based on a certain pattern definition.
Voucher Series Settings Pattern
Create tokens based on the OnlineShopVoucherSeries
In the Pimcore Backend UI, each OnlineShopVoucherSeries object has an
additional tab for managing the voucher tokens. Depending on the token type
there are different functions for managing the tokens and some statistics
concerning the voucher.
Simple: 'Activate' the token and specify how often it may be used. Create
Tokens Simple
Pattern: Create tokens based on the defined pattern, export created tokens
as csv and get an overview of created tokens and their usages. Create
Tokens Pattern
Create a Pricing Rule for the OnlineShopVoucherSeries
Once a voucher series is defined and tokens are created, a pricing rule has
to define the benefits of the voucher. To do so, a special condition allows
to specify the voucher series the pricing rule should be valid for. As
action all available actions for pricing rules can be used.
The voucher token condition also can contain an error message, that can be
shown if voucher token is added to cart, but not all other conditions of
the pricing rule are met.
Pricing Rule
Allow the User to Add a Token to his Cart
A voucher token is always applied to a cart. To do so, use following
snippet.
<?php
if ($token = strip_tags($request->get('voucher-code', ''))) {
try {
$success = $cart->addVoucherToken($token);
if ($success) {
$this->addFlash('success', $translator->trans('cart.voucher-
code-added'));
} else {
$this->addFlash('danger', $translator->trans('cart.voucher-
code-cound-not-be-added'));
} catch (VoucherServiceException $e) {
$this->addFlash('danger', $translator->trans('cart.error-voucher-
code-' . $e->getCode()));
Error Codes of Exceptions thrown
Code Description
1 Token already in use.
2 Token already reserved.
3 Token reservation not possible.
4 No token for this code exists.
5 Criteria oncePerCart: Token of same series already in cart.
6 Criteria onlyTokenPerCart: Tokens in cart and tried to add token of
type "only".
7 Criteria onlyTokenPerCart: Token of type "only" already in cart.
8 No more usages for a single token.
8 Token code not found in cart.
Display Voucher Information
Since benefits for vouchers are defined via pricing rules, no special
actions are needed to display them. They are just displayed the same way as
all other Pricing Rules.
Another consequence of defining the benefits of vouchers via pricing rules
is, that additional criteria (like date range etc.) can be defined to be
required to get the benefits. To get all necessary detail information about
vouchers, use getPricingManagerTokenInformationDetails of the cart or the
voucher service. This method returns an array of
PricingManagerTokenInformation for each added token with following
information:
Voucher Token
Token Object
List of applied pricing rules that require the given voucher token.
List of not applied pricing rules that would take the given voucher token
into account but are not applied because some other conditions are not met.
List of error messages that are defined in voucher token conditions of all
pricing rules that would take the given voucher token into account but are
not applied because some other conditions are not met.
Flag that indicates if no pricing rules are defined for the given voucher
token at all.
See an sample snippet to display the voucher information to the customer:
<form method="post" action="{{ path('shop-cart-apply-voucher') }}"
class="card p-2 mb-4">
{% if (cart.pricingManagerTokenInformationDetails | length > 0) %}
<ul class="list-group pb-3">
{% for codeInfo in cart.pricingManagerTokenInformationDetails %}
<li class="list-group-item">
<div class="row">
<div class="col-10" style="padding-top: 4px">
<div>{{ codeInfo.tokenCode }}</div>
{% if (codeInfo.errorMessages | length) > 0 %}
<small class="text-
muted">{{ codeInfo.errorMessages | join(', ') }}</small>
{% endif %}
{% if (codeInfo.noValidRule) %}
<small class="text-muted">{{ 'cart.voucher-no-
rule' | trans }}</small>
{% endif %}
</div>
<div class="col-2">
<a href="{{ path('shop-cart-remove-voucher',
{'voucher-code': codeInfo.tokenCode}) }}" class="btn btn-outline-danger
btn-sm">
<i class="fa fa-trash" aria-hidden="true"></i>
</a>
</div>
</div>
</li>
{% endfor %}
</ul>
{% endif %}
<div class="input-group">
<input name="voucher-code" type="text" class="form-control"
placeholder="{{ 'cart.voucher-code' | trans }}">
<div class="input-group-append">
<button type="submit" class="btn btn-secondary">{{ 'cart.apply-
voucher-code' | trans }}</button>
</div>
</div>
</form>
ChatGPT
## Using Vouchers in Pimcore E-Commerce Framework
Pimcore's E-Commerce Framework supports vouchers out of the box, allowing
for flexible and powerful promotional campaigns. Here's how to set up and
use vouchers in your Pimcore e-commerce application.
### Steps to Implement Vouchers
1. **Create an OnlineShopVoucherSeries Object**
2. **Create Tokens Based on the OnlineShopVoucherSeries**
3. **Create a Pricing Rule for the OnlineShopVoucherSeries**
4. **Allow the User to Add a Token to Their Cart**
5. **Display Voucher Information to the User**
### 1. Create an OnlineShopVoucherSeries Object
An `OnlineShopVoucherSeries` object contains the basic information and
settings for creating voucher tokens. Two types of vouchers are supported:
- **Single**: One single token that can be used multiple times.
- **Pattern**: Tokens generated based on a pattern.
#### Example
**Voucher Series Settings - Single:**

**Voucher Series Settings - Pattern:**

### 2. Create Tokens Based on the OnlineShopVoucherSeries
Each `OnlineShopVoucherSeries` object has a tab for managing voucher tokens
in the Pimcore Backend UI.
- **Simple**: Activate the token and specify how often it may be used.
- **Pattern**: Create tokens based on the pattern, export tokens as CSV,
and view token statistics.
### 3. Create a Pricing Rule for the OnlineShopVoucherSeries
Define the benefits of the voucher using a pricing rule. This involves
specifying the voucher series the rule applies to and setting the actions.
#### Example Pricing Rule

### 4. Allow the User to Add a Token to Their Cart
A voucher token is applied to a cart. Use the following PHP snippet to add
a voucher token to the cart:
```php
<?php
if ($token = strip_tags($request->get('voucher-code', ''))) {
try {
$success = $cart->addVoucherToken($token);
if ($success) {
$this->addFlash('success', $translator->trans('cart.voucher-
code-added'));
} else {
$this->addFlash('danger', $translator->trans('cart.voucher-
code-could-not-be-added'));
} catch (VoucherServiceException $e) {
$this->addFlash('danger', $translator->trans('cart.error-voucher-
code-' . $e->getCode()));
```
#### Error Codes
| Code | Description |
|------|-------------|
| 1 | Token already in use. |
| 2 | Token already reserved. |
| 3 | Token reservation not possible. |
| 4 | No token for this code exists. |
| 5 | Token of the same series already in the cart. |
| 6 | Tried to add token of type "only" while other tokens exist. |
| 7 | Token of type "only" already in the cart. |
| 8 | No more usages for a single token. |
| 9 | Token code not found in the cart. |
### 5. Display Voucher Information to the User
Voucher benefits are defined via pricing rules, so they are displayed in
the same way as other pricing rules. Use
`getPricingManagerTokenInformationDetails` to retrieve detailed voucher
information.
#### Example Snippet to Display Voucher Information
```twig
<form method="post" action="{{ path('shop-cart-apply-voucher') }}"
class="card p-2 mb-4">
{% if cart.pricingManagerTokenInformationDetails | length > 0 %}
<ul class="list-group pb-3">
{% for codeInfo in cart.pricingManagerTokenInformationDetails
%}
<li class="list-group-item">
<div class="row">
<div class="col-10" style="padding-top: 4px">
<div>{{ codeInfo.tokenCode }}</div>
{% if codeInfo.errorMessages | length > 0 %}
<small class="text-
muted">{{ codeInfo.errorMessages | join(', ') }}</small>
{% endif %}
{% if codeInfo.noValidRule %}
<small class="text-muted">{{ 'cart.voucher-
no-rule' | trans }}</small>
{% endif %}
</div>
<div class="col-2">
<a href="{{ path('shop-cart-remove-voucher',
{'voucher-code': codeInfo.tokenCode}) }}" class="btn btn-outline-danger
btn-sm">
<i class="fa fa-trash" aria-
hidden="true"></i>
</a>
</div>
</div>
</li>
{% endfor %}
</ul>
{% endif %}
<div class="input-group">
<input name="voucher-code" type="text" class="form-control"
placeholder="{{ 'cart.voucher-code' | trans }}">
<div class="input-group-append">
<button type="submit" class="btn btn-secondary">{{ 'cart.apply-
voucher-code' | trans }}</button>
</div>
</div>
</form>
```
### Summary
By following these steps, you can effectively manage and apply vouchers in
your Pimcore E-Commerce application. This setup allows for flexible
promotional campaigns, enhancing the user experience and encouraging
customer loyalty.
User
Calculate with Prices
As floating point numbers (float, double) are not able to represent numbers
exactly (see here if you want to know details), and exact numbers are a
strict demand to e-commerce applications the E-Commerce Framrwork uses
Decimal value objects instead of floats to represent prices. These value
objects internally store the represented value as integer by defining a
fixed amount of supported digits (so-called scale) after the comma and by
multiplying the actual value with the given scale on construction. The
scale is set to 4 by default, but can be changed globally in the
pimcore_ecommerce_framework.decimal_scale config entry.
An example: Given a scale of 4, a Decimal will internally represent a
number of 123.45 as 1234500 by calculating 123.45 * 10^4 = 1234500.
To calculate with these values, the Decimal class exposes methods like
add(), sub(), mul(), div() and others to run calculations without having to
deal with the internal scale representation. For details see the Decimal
class definition and the corresponding test which contains a lot of usage
examples and describes the Decimal behaviour quite well.
Important: The Decimal is designed as immutable value object. Every
operation yields a new instance of a Decimal representing the new value.
Please be aware that this needs to be considered when calculating with
Decimals and/or when extending the Decimal class with custom functionality.
On the DB side, all E-Commerce Framework class definitions supporting price
values were updated to store prices as DECIMAL data type. This means, when
fetching a price value from an ecommerce-object (e.g. an order), it will be
a string instead of a float. This string can directly be passed to the
Decimal value object's create() method.
A usage example:
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
$a = Decimal::create(10);
$b = Decimal::create(20);
$c = $a->add($b);
var_dump($c->asString()); // 30.0000 as the default string representation
contains all digits depending on the scale
// regarding immutability:
$a->add($b);
// $a is still 10 and will never be changed - the add() method returns a
new object ($c in the example above)
$a->equals(Decimal::create(30)); // false
$a->equals(Decimal::create(10)); // true
In most cases, you should be able to build a Decimal object by using the
static create() method which is able to build a Decimal from strings,
integers and floating point numbers. If needed, you can also make use of a
number of from* methods directly exposing costruction logic for a specific
type (e.g. fromDecimal(Decimal $decimal)).
Rounding logic
The Decimal object will try to avoid rounding and calculating with floats
if possible. If you pass a string to the create() method, it will try to
convert the numeric string to an integer with string operations before
falling back to converting it into a float which is rounded.
Examples (given a scale of 4):
Decimal::create('123') will just add 4 chars of 0 to the string and cast it
to an integer (no floats involved) - results in 1230000
Decimal::create('123.45') will move the dot to the right by 2 places and
add 2 chars of 0 - results in 1234500
However, if the given value exceeds the maximum scale or is a float value,
the create() method needs to fall back to float calculations and rounding
to generate the integer representation:
Decimal::create('123.1234567') with a string value will fall back to float
calculations as the amount of digits after the comma exceed the scale of 4.
The value is first multiplied with 10^4, resulting in PHP casting the
string to float. The float 1231234.567 is then passed to PHP's round()
function with a precision parameter of 0 and a default rounding mode of
PHP_ROUND_HALF_UP, resulting in an integer representation of 1231235 (note
the rounding on the last digit).
Decimal::create(123.1234567) with a float value will have the same
behaviour as above (skipping the string conversion).
You can influence how rounding is applied by specifying the $roundingMode
parameter on the create() method:
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
var_dump(Decimal::create('123.55555', 4, PHP_ROUND_HALF_DOWN)->asString());
// 123.5555
var_dump(Decimal::create('123.55555', 4, PHP_ROUND_HALF_UP)->asString());
// 123.5556
Please be aware that as rounding is applied only when exceeding the scale,
the following can happen:
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
// supported by scale -> 1.9999
var_dump(Decimal::create('1.9999')->asString());
// rounding is applied -> 2.0000
var_dump(Decimal::create('1.99999')->asString());
This is important to know as it could lead to unexpected calculation
results. The DECIMAL mysql data type has the same behaviour - if you
calculate with Decimals at a higher scale you still need to update your
class definitions to match that scale as otherwise the same rounding logic
will be applied by the database. However, while doing calculations (e.g.
tax or discount calculations, reports), you're free to calculate at a
higher scale by passing the scale parameter to the create() method and just
setting the resulting value to the scale represented on the DB. Example:
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
// operate at a high scale supporting 8 digits after the comma
$a = Decimal::create(10, 8);
// do calculations
$b = $a->toPercentage(15);
// create a representation with a lower scale - at this point rounding
logic will be applied
$result = $b->withScale(4);
// an order object
$order->setTotalPrice($result->asString());
$order->save();
Extending the Decimal class
You're free to add custom calculation logic to the Decimal class, but
please make sure every operation returns a new instance holding the
calculated value. An object can never change its internal state (value and
scale) after construction!
Caveats/aspects good to know
In order to have sufficient number of digits in integer datatype, your
system should run on 64 bit infrastructure. On 32 bit systems, you would be
able to handle prices up to 214,748.3647 only (since max int value with 32
bit is 2,147,483,647). The Decimal implementation contains logic to throw
an exception on an integer overflow in case the used numbers are too
large/small.
ChatGPT
## Working with Prices in Pimcore E-Commerce Framework
### Decimal Value Objects
To handle prices accurately, the Pimcore E-Commerce Framework uses
`Decimal` value objects instead of floating point numbers. This ensures
precise price representation and calculations. The `Decimal` class
internally stores the value as an integer, scaled to a fixed number of
digits after the decimal point.
### Scale Configuration
The default scale (number of digits after the decimal point) is set to 4
but can be adjusted globally via the
`pimcore_ecommerce_framework.decimal_scale` configuration entry.
**Example**: With a scale of 4, the number 123.45 is internally represented
as 1234500 (i.e., 123.45 * 10^4 = 1234500).
### Creating and Using Decimal Objects
The `Decimal` class provides methods like `add()`, `sub()`, `mul()`, and
`div()` for calculations, ensuring the internal scale representation is
managed correctly.
**Example Usage**:
```php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
$a = Decimal::create(10);
$b = Decimal::create(20);
$c = $a->add($b);
echo $c->asString(); // Outputs: 30.0000
// Immutability example:
$a->add($b);
echo $a->asString(); // Outputs: 10.0000
echo $a->equals(Decimal::create(30)); // Outputs: false
echo $a->equals(Decimal::create(10)); // Outputs: true
```
### Construction Methods
You can create a `Decimal` object using various methods:
- `create()`: Builds a `Decimal` from strings, integers, and floats.
- `fromDecimal()`: Builds a `Decimal` from another `Decimal` object.
### Rounding Logic
The `Decimal` object avoids floating-point calculations when possible. When
necessary, it uses PHP's rounding functions.
**Examples**:
```php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
echo Decimal::create('123')->asString(); // Outputs: 123.0000
echo Decimal::create('123.45')->asString(); // Outputs: 123.4500
echo Decimal::create('123.1234567', 4, PHP_ROUND_HALF_UP)->asString(); //
Outputs: 123.1235
echo Decimal::create('123.1234567', 4, PHP_ROUND_HALF_DOWN)->asString(); //
Outputs: 123.1234
```
### Rounding and Scale Examples
When the value exceeds the scale, rounding is applied:
```php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
echo Decimal::create('1.9999')->asString(); // Outputs: 1.9999
echo Decimal::create('1.99999')->asString(); // Outputs: 2.0000
```
### Calculating with Higher Scale
You can perform calculations at a higher scale and then adjust the result
to a lower scale for storage.
**Example**:
```php
use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;
// Higher scale calculation
$a = Decimal::create(10, 8);
$b = $a->toPercentage(15);
// Adjusting to a lower scale
$result = $b->withScale(4);
$order->setTotalPrice($result->asString());
$order->save();
```
### Extending the Decimal Class
When extending the `Decimal` class, ensure that every operation returns a
new instance, as `Decimal` objects are immutable.
### Caveats
- Ensure your system runs on a 64-bit infrastructure to handle large price
values accurately. On 32-bit systems, the maximum price is limited to
214,748.3647 due to the 32-bit integer limit.
- The `Decimal` class includes logic to throw an exception on integer
overflow, preventing inaccuracies due to excessively large or small values.
### Summary
The Pimcore E-Commerce Framework's use of `Decimal` value objects ensures
precise price calculations, essential for e-commerce applications. By
leveraging the provided methods and adhering to the immutability principle,
you can perform accurate and reliable pricing operations.
User
Working with Availabilities
For availabilities there is a similar concepts like the PriceSystems for
prices - which is called Availability Systems.
The Availability Systems are responsible for retrieving or calculating
availabilities of a product and returning a so called AvailabilityInfo
object which contains all the availability information. Each product can
have its own Availability System.
Configuration of Availability Systems
An availability system is a class implementing Pimcore\Bundle\
EcommerceFrameworkBundle\AvailabilitySystem\AvailabilitySystemInterface
which is defined as service and registered with a name in the
pimcore_ecommerce_framework.availability_systems configuration tree.
Currently, the framework ships only with a sample implementation which you
can use as starting point.
There are 3 places where the configuration of Availability Systems takes
place:
Product class: Each product has to implement the method
getAvailabilitySystemName() which returns the name of its Availability
System.
Service definition: Each Availability System must be registered as service
Configuration: The availability_systems section maps Availability System
names to service IDs
The product class returns the name of an Availability System:
<?php
class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\
CheckoutableInterface
public function getAvailabilitySystemName(): string
return 'myAvailabilitySystem';
Each Availability System must be defined as service (either a service
defined by core configuration or your custom services):
# services.yaml
_defaults:
public: false
autowire: true
autoconfigure: true
# AVAILABILITY SYSTEMS
Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem: ~
The availability_systems configuration maps names to service IDs:
pimcore_ecommerce_framework:
# defines 3 availability systems
availability_systems:
# the availability system is already defined in core
availability_systems.yaml service definition
default:
id: Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem
foo:
id: App\Ecommerce\AvailabilitySystem\CustomAvailabilitySystem
bar:
id: app.custom_attribute_availability_system
Getting Availabilities
Each product (if it implements CheckoutableInterface) needs to implement
the method getOSAvailabilityInfo which in the default implementation gets
the corresponding Availability System and calculates the availability.
The return value is an AvailabilityInterface object, which at least has one
getAvailable method and can contain additional availability information
(e.g. availability for different storage locations etc.).
This can be used to visualize availability on product detail pages or to
check, if a product can actually be checked out.
ChatGPT
## Working with Availabilities in Pimcore E-Commerce Framework
### Overview
Pimcore E-Commerce Framework provides a system for managing product
availabilities called **Availability Systems**. These systems are
responsible for retrieving or calculating the availability of a product and
returning an `AvailabilityInfo` object containing all the relevant
availability information. Each product can have its own Availability
System.
### Configuration of Availability Systems
Availability Systems are configured through a combination of product class
methods, service definitions, and framework configuration entries.
### Steps to Configure Availability Systems
1. **Implement the Availability System Interface**
2. **Define the Service**
3. **Map the Configuration**
### 1. Implement the Availability System Interface
An Availability System is a class that implements the `Pimcore\Bundle\
EcommerceFrameworkBundle\AvailabilitySystem\AvailabilitySystemInterface`.
Each product must implement the `getAvailabilitySystemName()` method to
return the name of its Availability System.
#### Example: Product Class Implementation
```php
<?php
class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\
CheckoutableInterface
public function getAvailabilitySystemName(): string
return 'myAvailabilitySystem';
```
### 2. Define the Service
Each Availability System must be defined as a service. This can be a core
service or a custom service.
#### Example: services.yaml
```yaml
services:
_defaults:
public: false
autowire: true
autoconfigure: true
# Define the default availability system
Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem: ~
# Define a custom availability system
App\Ecommerce\AvailabilitySystem\CustomAvailabilitySystem:
arguments: ['@some_dependency']
```
### 3. Map the Configuration
The `availability_systems` section in the configuration tree maps names to
service IDs.
#### Example: Configuration (config.yaml)
```yaml
pimcore_ecommerce_framework:
availability_systems:
default:
id: Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem
foo:
id: App\Ecommerce\AvailabilitySystem\CustomAvailabilitySystem
bar:
id: app.custom_attribute_availability_system
```
### Example Custom Availability System
#### Custom Availability System Class
```php
<?php
namespace App\Ecommerce\AvailabilitySystem;
use Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystemInterface;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilityInfo;
class CustomAvailabilitySystem implements AvailabilitySystemInterface
public function getAvailability(AbstractObject $product):
AvailabilityInfo
// Custom logic to determine availability
$isAvailable = $product->getStock() > 0;
return new AvailabilityInfo($isAvailable);
```
### Retrieving Availabilities
Each product that implements `CheckoutableInterface` must implement the
`getOSAvailabilityInfo()` method. This method retrieves the corresponding
Availability System and calculates the availability.
#### Example: Product Class Method
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilityInfo;
class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\
CheckoutableInterface
public function getOSAvailabilityInfo(): AvailabilityInfo
$availabilitySystemName = $this->getAvailabilitySystemName();
$availabilitySystem = \Pimcore::getContainer()-
>get('pimcore_ecommerce.factory')
->getAvailabilitySystem($availabilitySystemName);
return $availabilitySystem->getAvailability($this);
```
### Using Availability Information
The returned `AvailabilityInfo` object can be used to visualize
availability on product detail pages or to check if a product can be
checked out.
#### Example: Displaying Availability on Product Detail Page
```twig
{% set availabilityInfo = product.OSAvailabilityInfo %}
{% if availabilityInfo.isAvailable %}
<p class="available">In Stock</p>
{% else %}
<p class="not-available">Out of Stock</p>
{% endif %}
```
### Summary
By following these steps, you can configure and use Availability Systems in
Pimcore's E-Commerce Framework. This setup allows for flexible and
customized availability calculations, enhancing the overall shopping
experience for your customers.
User
Cart Manager
The Cart Manager is responsible for all aspects concerning carts and can
manage multiple carts. Important to know is, that in the E-Commerce
Framework every user specific product collection is a cart. No matter how
it is called (cart, wish list, compare list, ...), all these product
collections need the same base functionality. Therefore, all different
product collections are carts with a specific name.
Working with Carts
Creating carts
<?php
$manager = Factory::getInstance()->getCartManager();
$cartId = $manager->createCart(array('name' => $cartName));
$cart = $manager->getCart( $cartId );
Adding and removing products
<?php
$manager = Factory::getInstance()->getCartManager();
$cart = $manager->getCartByName($cartName);
$id = $cart->addItem( $product, $amount );
$cart->save();
$cart->removeItem( $id );
$cart->save();
//alternative way
$cartItemId = $manager->addToCart( $product, $amount, $cart->getId() );
//save is done automatically
$manager->removeFromCart($cartItemId, $cartId);
//save is done automatically
List products of cart
<?php
$manager = Factory::getInstance()->getCartManager();
$cart = $manager->getCartByName($cartName);
if (count($cart->getItems()) > 0) {
foreach ($cart->getItems() as $item) {
$product = $item->getProduct();
//item key
$cartItemId = $item->getItemKey();
//item amount
$amount = $item->getCount();
//price info and price
$priceInfo = $item->getPriceInfo();
$price = $item->getPrice();
Price Calculation in Carts
Each cart has a CartPriceCalculator (configuration see below) which is
responsible for calculating total sums of the cart. The CartPriceCalculator
sums up all product prices to a sub total, adds (or subtracts) so called
price modificators like shipping costs, cart discounts, etc. and then
calculates a grand total.
See sample below for how to get the different sums:
<?php
// delivers sum without any price modifications
$subTotal = $cart->getPriceCalculator()->getSubTotal();
// iterates through all price modifications
foreach ($cart->getPriceCalculator()->getPriceModifications() as $name =>
$modification) {
// $name is the label of a modification
// $modification is an implementation of \Pimcore\Bundle\
EcommerceFrameworkBundle\PriceSystem\ModificatedPriceInterface
// delivers sum including all price modifications
$grandTotal = $cart->getPriceCalculator()->getGrandTotal();
Configuration of Cart Manager
The configuration takes place in the
pimcore_ecommerce_framework.cart_manager configuration section which is
tenant aware.
pimcore_ecommerce_framework:
cart_manager:
tenants:
# defaults for all cart managers
_defaults:
# define service manager id of cart service - following
value is default and can be omitted
cart_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\MultiCartManager
# configuration for carts - the following values are set by
default and can be omitted
cart:
# service ID of a cart factory which creates individual
carts at runtime
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartFactory
# options passed to cart factory, e.g. the cart class
(available options vary by factory implementation)
factory_options:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart
guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart
default:
price_calculator:
# list price modificators for cart, e.g. for shipping-
cost, special discounts, ...
# key is name of modificator
modificators:
shipping:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping
# configuration options for price modificator
options:
charge: "5.90"
# additional checkout tenant for cart manager
# - active tenant is set at \Pimcore\Bundle\
EcommerceFrameworkBundle\EnvironmentInterface::setCurrentCheckoutTenant()
noShipping: ~ # inherits from _defaults
Following elements are configured:
Cart manager service ID: The cart manager is the basic entry point for
working with carts. It is responsible for all interactions with different
carts and provides functionality as creating carts, adding/removing
products and also creates the corresponding price calculator.
Cart factory service ID: builds carts when needed and can be configured
with cart class name and further options varying by factory implementation
Price calculator factory service ID + options and modificators: The price
calculator is a framework for calculation and modification (shipping costs,
discounts, ...) of prices on cart level. Each modification is implemented
in a CartPriceModificatorInterface class. See Shipping or Discount for
examples.
Available Cart Implementations
Following cart implementations are shipped with Pimcore core and can be
configured in the factory_options section of the cart manager
configuration:
Session-Cart (class name Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\SessionCart): This cart implementation stores all cart
information in the session of the user. If the session is cleared, also the
carts are deleted. Use this implementation when no user login is available
and storing carts in the database has no benefit.
Database-Cart (class name Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\Cart): This cart implementation stores all cart information in
the database. In this case, it is important that the currently logged in
user is set to the E-Commerce Framework Environment with the code snippet
in the box below. Use this implementation when user logins are available
and the carts should be persisted beyond session lifetime.
Note: if you are using the database cart, don't forget to set the currently
logged in user to the environment like follows: Factory::getInstance()-
>getEnvironment()->setCurrentUserId(YOUR_USER_ID)
Checkout Tenants for Carts
The E-Commerce Framework has the concept of so called Checkout Tenants
which allow different cart manager and checkout manager configurations
based on a currently active checkout tenant.
The current checkout tenant is set in the framework environment as follows:
<?php
$environment = Factory::getInstance()->getEnvironment();
$environment->setCurrentCheckoutTenant('default');
$environment->save();
$environment->setCurrentCheckoutTenant('noShipping');
$environment->save();
Once set, the cart manager uses all specific settings of the currently
active checkout tenant which are configured in the configuration
(identified by tenant name).
See also Demo for some examples.
Adding Custom Properties to Cart Items
Following steps are necessary to add additional custom properties to cart
items:
Extend Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartItem
implementation and add your custom properties including getters/setters.
Extend Cart::getCartItemClassName implementation and make sure your custom
CartItem implementation gets returned.
Provide the custom properties as key-value pairs in $params parameter in
the following methods:
Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\AbstractCart::addItem
Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
AbstractCart::updateItem
Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
CartManagerInterface::addToCart
ChatGPT
## Cart Manager in Pimcore E-Commerce Framework
The Cart Manager in Pimcore E-Commerce Framework manages all aspects
related to carts, including creating, adding/removing products, and
calculating prices. Each user-specific product collection (cart, wishlist,
compare list, etc.) is managed as a cart within this framework.
### Working with Carts
#### Creating Carts
```php
$manager = Factory::getInstance()->getCartManager();
$cartId = $manager->createCart(['name' => $cartName]);
$cart = $manager->getCart($cartId);
```
#### Adding and Removing Products
```php
$manager = Factory::getInstance()->getCartManager();
$cart = $manager->getCartByName($cartName);
$id = $cart->addItem($product, $amount);
$cart->save();
$cart->removeItem($id);
$cart->save();
// Alternative way
$cartItemId = $manager->addToCart($product, $amount, $cart->getId());
// Save is done automatically
$manager->removeFromCart($cartItemId, $cartId);
// Save is done automatically
```
#### Listing Products in a Cart
```php
$manager = Factory::getInstance()->getCartManager();
$cart = $manager->getCartByName($cartName);
if (count($cart->getItems()) > 0) {
foreach ($cart->getItems() as $item) {
$product = $item->getProduct();
// Item key
$cartItemId = $item->getItemKey();
// Item amount
$amount = $item->getCount();
// Price info and price
$priceInfo = $item->getPriceInfo();
$price = $item->getPrice();
```
### Price Calculation in Carts
Each cart has a `CartPriceCalculator` that is responsible for calculating
the total sums of the cart. The calculator sums up all product prices to a
subtotal, applies price modifications (e.g., shipping costs, discounts),
and calculates the grand total.
#### Example: Retrieving Sums
```php
// Delivers sum without any price modifications
$subTotal = $cart->getPriceCalculator()->getSubTotal();
// Iterates through all price modifications
foreach ($cart->getPriceCalculator()->getPriceModifications() as $name =>
$modification) {
// $name is the label of a modification
// $modification is an implementation of \Pimcore\Bundle\
EcommerceFrameworkBundle\PriceSystem\ModificatedPriceInterface
// Delivers sum including all price modifications
$grandTotal = $cart->getPriceCalculator()->getGrandTotal();
```
### Configuration of Cart Manager
Configuration is defined in the `pimcore_ecommerce_framework.cart_manager`
section of the configuration file and is tenant-aware.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
cart_manager:
tenants:
# defaults for all cart managers
_defaults:
# define service manager id of cart service - following
value is default and can be omitted
cart_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\MultiCartManager
# configuration for carts - the following values are set by
default and can be omitted
cart:
# service ID of a cart factory which creates individual
carts at runtime
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartFactory
# options passed to cart factory, e.g. the cart class
(available options vary by factory implementation)
factory_options:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart
guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart
default:
price_calculator:
# list price modificators for cart, e.g. for shipping-
cost, special discounts, ...
# key is name of modificator
modificators:
shipping:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping
# configuration options for price modificator
options:
charge: "5.90"
# additional checkout tenant for cart manager
# - active tenant is set at \Pimcore\Bundle\
EcommerceFrameworkBundle\EnvironmentInterface::setCurrentCheckoutTenant()
noShipping: ~ # inherits from _defaults
```
### Elements of Configuration
- **Cart manager service ID**: Entry point for working with carts,
responsible for creating carts and interacting with them.
- **Cart factory service ID**: Builds carts when needed, configurable with
cart class name and other options.
- **Price calculator factory service ID**: Calculates and modifies prices
on the cart level (e.g., shipping costs, discounts).
### Available Cart Implementations
- **Session-Cart** (`Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
SessionCart`): Stores cart information in the user's session. Ideal for
guest users without login.
- **Database-Cart** (`Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
Cart`): Stores cart information in the database. Ideal for logged-in users,
ensuring persistence beyond session lifetime.
### Setting Current User for Database Cart
```php
Factory::getInstance()->getEnvironment()->setCurrentUserId(YOUR_USER_ID);
```
### Checkout Tenants for Carts
Checkout Tenants allow different cart manager and checkout manager
configurations based on the active tenant.
#### Setting the Checkout Tenant
```php
$environment = Factory::getInstance()->getEnvironment();
$environment->setCurrentCheckoutTenant('default');
$environment->save();
$environment->setCurrentCheckoutTenant('noShipping');
$environment->save();
```
### Adding Custom Properties to Cart Items
1. **Extend CartItem Implementation**
```php
namespace App\Ecommerce\CartManager;
use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartItem;
class CustomCartItem extends CartItem
private $customProperty;
public function getCustomProperty()
return $this->customProperty;
}
public function setCustomProperty($customProperty)
$this->customProperty = $customProperty;
```
2. **Extend Cart Implementation**
```php
namespace App\Ecommerce\CartManager;
use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\Cart;
class CustomCart extends Cart
protected function getCartItemClassName()
return CustomCartItem::class;
```
3. **Provide Custom Properties**
```php
$cart->addItem($product, $amount, ['customProperty' => 'value']);
```
By following these steps, you can effectively manage and customize the cart
functionalities in Pimcore's E-Commerce Framework. This flexibility allows
you to adapt the cart system to meet various business requirements.
User
Checkout Manager
The Checkout Manager is responsible for all aspects concerning checkout
process and an one-stop API for getting through the checkout process.
But: The checkout manager is not an out-of-the-box checkout process! It is
a tool and a set of components the developer can use to create a use case
specific checkout process.
Starting with Pimcore 6.1 an optimized checkout manager architecture was
introduced. This is parallel to the old architecture, which is deprecated
now and will be removed in Pimcore 10. For details see Checkout Manager
Details.
Involved Modules and their function
Controller: Website Controller that controls the flow.
Cart: Cart is the cart and user should be able to modify the cart all the
time.
CheckoutManager: One-Stop API for controller to manage checkout, start and
handle payments and commit orders.
OrderManager: API for working with orders - creating them, listing them,
etc.
OrderAgent: API for manipulating single order, also responsible for status
management of payments within order.
PaymentProvider: Interface to payment provider.
CommitOrderProcessor: Worker that handles all steps to commit order after
payment was successfully finished by user.
See following sub pages for detailed information
Basic configuration of Checkout Manager
Setting up Checkout Steps
Committing Orders
Integrating Payment
Using Checkout Tenants
ChatGPT
## Checkout Manager in Pimcore E-Commerce Framework
The Checkout Manager is a comprehensive tool and set of components designed
to facilitate the creation of a customized checkout process. It integrates
various modules such as controllers, carts, payment providers, and order
management to ensure a seamless and flexible checkout experience.
### Involved Modules and Their Functions
1. **Controller**: Manages the flow of the checkout process through website
controllers.
2. **Cart**: Allows users to modify the cart at any time during the
checkout process.
3. **CheckoutManager**: Provides a one-stop API for managing the checkout
process, starting and handling payments, and committing orders.
4. **OrderManager**: API for creating, listing, and managing orders.
5. **OrderAgent**: API for manipulating single orders and managing payment
statuses within orders.
6. **PaymentProvider**: Interface to various payment providers.
7. **CommitOrderProcessor**: Handles all steps to commit the order after
payment is successfully completed.
### Basic Configuration of Checkout Manager
The configuration is defined in the
`pimcore_ecommerce_framework.checkout_manager` section of the configuration
file and is tenant-aware.
#### Example Configuration
```yaml
pimcore_ecommerce_framework:
checkout_manager:
tenants:
# defaults for all checkout managers
_defaults:
# define service manager id of checkout manager - following
value is default and can be omitted
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory
# configuration for checkout steps - the following values
are set by default and can be omitted
steps:
review:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\ReviewStep
options:
template: ':Checkout:review.html.twig'
default:
# Define payment provider to use
payment:
provider: my_payment_provider
# Define commit order processor
commit_order_processor:
id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CommitOrderProcessor
options: []
```
### Setting Up Checkout Steps
Checkout steps define the flow of the checkout process. Each step is a
class that implements specific logic for a stage in the checkout process.
#### Example: Defining Checkout Steps
```yaml
pimcore_ecommerce_framework:
checkout_manager:
tenants:
default:
steps:
review:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\ReviewStep
options:
template: ':Checkout:review.html.twig'
payment:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\PaymentStep
options:
template: ':Checkout:payment.html.twig'
confirmation:
class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\ConfirmationStep
options:
template: ':Checkout:confirmation.html.twig'
```
### Committing Orders
The `CommitOrderProcessor` is responsible for finalizing the order after
payment is completed. It handles order creation, payment status updates,
and order confirmation.
#### Example: Order Committing
```php
$checkoutManager = $factory->getCheckoutManager();
$checkoutManager->startCheckout($cart, $user, $checkoutTenant);
$commitOrderProcessor = $checkoutManager->getCommitOrderProcessor();
$commitOrderProcessor->commitOrder($order, $paymentStatus);
```
### Integrating Payment
Payment integration is done through `PaymentProvider` interfaces. Each
payment provider handles the interaction with different payment gateways.
#### Example: Payment Provider Configuration
```yaml
pimcore_ecommerce_framework:
payment_manager:
providers:
my_payment_provider:
provider_id: App\Ecommerce\PaymentProvider\
MyPaymentProvider
profile: default
profiles:
default:
username: 'my_username'
password: 'my_password'
```
#### Example: Payment Provider Implementation
```php
namespace App\Ecommerce\PaymentProvider;
use Pimcore\Bundle\EcommerceFrameworkBundle\PaymentManager\
PaymentProviderInterface;
class MyPaymentProvider implements PaymentProviderInterface
public function processPayment($order, $paymentDetails)
{
// Implement payment processing logic
public function getPaymentStatus($order)
// Implement logic to retrieve payment status
```
### Using Checkout Tenants
Checkout Tenants allow different configurations for the checkout process
based on the active tenant. This enables multiple checkout flows within the
same system.
#### Example: Setting Checkout Tenant
```php
$environment = Factory::getInstance()->getEnvironment();
$environment->setCurrentCheckoutTenant('default');
$environment->save();
$environment->setCurrentCheckoutTenant('customTenant');
$environment->save();
```
### Summary
The Checkout Manager in Pimcore E-Commerce Framework provides a robust and
flexible set of tools to create a custom checkout process. By leveraging
the various modules and configuration options, developers can tailor the
checkout experience to meet specific business needs. This comprehensive
approach ensures that all aspects of the checkout, from cart management to
payment processing, are seamlessly integrated and easily manageable.
User
Basic Configuration
The configuration takes place in the
pimcore_ecommerce_framework.checkout_manager configuration section and is
tenant aware.
pimcore_ecommerce_config:
checkout_manager:
tenants:
_defaults:
# the following two values are default values an can be
omitted
# service ID of a checkout manager factory which builds
cart specific checkout managers
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory
# options passed to the factory - available options vary by
implementation
factory_options:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy
# commit order processor
commit_order_processor:
# order processor service ID
id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor
# options passed to the commit order processor -
available options vary by implementation
options:
confirmation_mail: /en/emails/order-confirmation
# define different checkout steps which need to be
committed before commit of order is possible
steps:
deliveryaddress:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress
# example step from the Ecommerce demo, which extends
AbstractStep
confirm:
class: \App\Ecommerce\Checkout\Confirm
default:
# define payment provider which should be used for payment.
# payment providers are defined in payment_manager section.
payment:
provider: qpay
paypal:
payment:
provider: paypal
Following elements are configured:
Service ID and options of the checkout manager factory: The Checkout
Manager is a central player of the checkout process. It checks the state of
single checkout steps, is responsible for the payment integration and also
calls the commit order processor in the end. As the a checkout manager is
specific to a cart instance, checkout manager factory takes care of
creating checkout managers on demand.
Optional configuration option handle_pending_payments_strategy defines
strategy how to handle pending payments. See Integrating Payment for
details.
Checkout steps and their implementation: Each checkout step (e.g. Delivery
address, delivery date, ...) needs a concrete checkout step implementation.
The implementation is responsible for storing and validating the necessary
data, is project dependent and has to be implemented for each project.
Service ID and options of the commit order processor: When finalization of
the order is done by the commit order processor. This is the places, where
custom ERP integrations and other project dependent order finishing stuff
should be placed.
Additional stuff like:
Mail configuration
Payment Implementation
Checkout Tenants
ChatGPT
## Basic Configuration of Checkout Manager
The configuration of the Checkout Manager in the Pimcore E-Commerce
Framework is managed within the
`pimcore_ecommerce_framework.checkout_manager` section of the configuration
file. This setup is tenant-aware, allowing for multiple checkout flows
within the same system.
### Example Configuration
```yaml
pimcore_ecommerce_framework:
checkout_manager:
tenants:
_defaults:
# Service ID of a checkout manager factory which builds
cart specific checkout managers
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory
# Options passed to the factory - available options vary by
implementation
factory_options:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy
# Commit order processor
commit_order_processor:
# Order processor service ID
id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor
# Options passed to the commit order processor -
available options vary by implementation
options:
confirmation_mail: /en/emails/order-confirmation
# Define different checkout steps which need to be
committed before commit of order is possible
steps:
deliveryaddress:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress
# Example step from the Ecommerce demo, which extends
AbstractStep
confirm:
class: \App\Ecommerce\Checkout\Confirm
default:
# Define payment provider which should be used for payment.
# Payment providers are defined in payment_manager section.
payment:
provider: qpay
paypal:
payment:
provider: paypal
```
### Configured Elements
1. **Service ID and Options of the Checkout Manager Factory**
- **Factory ID**: Identifies the factory that creates checkout managers
for specific cart instances.
- **Factory Options**: Includes settings like the class of the checkout
manager and strategies for handling pending payments.
2. **Handle Pending Payments Strategy**
- **Strategy**: Defines how to handle pending payments. For example,
`CancelPaymentOrRecreateOrderStrategy`.
3. **Checkout Steps and Their Implementation**
- Each step in the checkout process (e.g., delivery address, delivery
date) needs a concrete implementation. These steps are responsible for
storing and validating necessary data. Example:
```yaml
steps:
deliveryaddress:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress
confirm:
class: \App\Ecommerce\Checkout\Confirm
```
4. **Commit Order Processor**
- **Order Processor Service ID**: Identifies the service responsible
for finalizing the order.
- **Options**: Includes settings such as the path to the confirmation
email template.
5. **Additional Configurations**
- **Mail Configuration**: Specifies the email templates to be used
during the checkout process.
- **Payment Implementation**: Configures payment providers used in the
checkout process.
- **Checkout Tenants**: Allows for tenant-specific configurations,
enabling different checkout flows within the same system.
### Explanation of Key Elements
#### 1. Checkout Manager Factory
The Checkout Manager Factory is central to the checkout process. It ensures
that each cart instance has a specific checkout manager that handles the
state of individual checkout steps, integrates payment, and invokes the
commit order processor.
#### 2. Handle Pending Payments Strategy
The strategy for handling pending payments defines how the system should
manage payments that are not completed immediately. This can include
cancelling pending payments or recreating orders.
#### 3. Checkout Steps
Checkout steps are custom implementations that handle specific parts of the
checkout process. They are responsible for data validation and storage.
Each step is configured with a class that implements the required
functionality.
#### 4. Commit Order Processor
The commit order processor finalizes the order by performing tasks such as
integrating with ERP systems and sending confirmation emails. It is
customizable to meet specific project requirements.
#### 5. Additional Configurations
Additional settings include mail configurations for sending order
confirmations, payment provider settings, and tenant-specific checkout
flows.
### Summary
By configuring the Checkout Manager and its associated components,
developers can create a flexible and customizable checkout process tailored
to specific business needs. The tenant-aware configuration allows for
multiple checkout flows within the same system, ensuring that different
user groups can have unique checkout experiences.
User
Checkout Steps
For each checkout step (e.g. delivery address, delivery date, ...) there
has to be a concrete checkout step implementation. This implementation is
responsible for storage and loading of necessary checkout data for each
step. It needs to extend \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\AbstractStep and implement \Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\CheckoutStepInterface.
Following methods have to be implemented:
commit($data): Is called when step is finished and data needs to be saved.
getData(): Returns saved data for this step.
getName(): Returns name of the step.
Configuration of Checkout Steps:
See configuration for checkout step configuration.
Sample Implementation of a Checkout Step:
<?php
namespace Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager;
/**
* Class \Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
DeliveryAddress
* sample implementation for delivery address
*/
class DeliveryAddress extends AbstractStep implements CheckoutStepInterface
/**
* namespace key
*/
const PRIVATE_NAMESPACE = 'delivery_address';
public function getName(): string
return 'deliveryaddress';
/**
* sets delivered data and commits step
*/
public function commit(mixed $data): bool
$this->cart->setCheckoutData(self::PRIVATE_NAMESPACE,
json_encode($data));
return true;
/**
* returns saved data of step
*/
public function getData(): mixed
$data = json_decode($this->cart-
>getCheckoutData(self::PRIVATE_NAMESPACE));
return $data;
Working with Steps:
<?php
$manager = Factory::getInstance()->getCheckoutManager($cart);
$step = $manager->getCheckoutStep("deliveryaddress");
$address = new stdClass();
//fill address
$manager->commitStep($step, $address);
$step = $manager->getCheckoutStep("deliverydate");
$manager->commitStep($step, $data);
$cart->save();
ChatGPT
## Checkout Steps in Pimcore E-Commerce Framework
Each checkout step in the Pimcore E-Commerce Framework must have a concrete
implementation responsible for the storage and retrieval of the necessary
checkout data. These implementations must extend `\Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\AbstractStep` and implement `\
Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CheckoutStepInterface`.
### Required Methods for Checkout Steps
1. **commit($data)**: Called when the step is finished, and data needs to
be saved.
2. **getData()**: Returns the saved data for this step.
3. **getName()**: Returns the name of the step.
### Example Implementation of a Checkout Step
Here is a sample implementation for a delivery address step:
```php
namespace Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager;
/**
* Class DeliveryAddress
* Sample implementation for delivery address
*/
class DeliveryAddress extends AbstractStep implements CheckoutStepInterface
/**
* Namespace key
*/
const PRIVATE_NAMESPACE = 'delivery_address';
public function getName(): string
return 'deliveryaddress';
/**
* Sets delivered data and commits step
*/
public function commit(mixed $data): bool
$this->cart->setCheckoutData(self::PRIVATE_NAMESPACE,
json_encode($data));
return true;
/**
* Returns saved data of step
*/
public function getData(): mixed
$data = json_decode($this->cart-
>getCheckoutData(self::PRIVATE_NAMESPACE));
return $data;
```
### Configuration of Checkout Steps
Checkout steps are configured in the `pimcore_ecommerce_framework`
configuration section. Below is an example of how to configure checkout
steps:
```yaml
pimcore_ecommerce_framework:
checkout_manager:
tenants:
default:
steps:
deliveryaddress:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress
confirm:
class: \App\Ecommerce\Checkout\Confirm
```
### Working with Steps
Here is an example of how to work with checkout steps in a controller:
```php
$manager = Factory::getInstance()->getCheckoutManager($cart);
// Working with the delivery address step
$step = $manager->getCheckoutStep("deliveryaddress");
$address = new stdClass();
// Fill address with necessary data
$address->street = '123 Main St';
$address->city = 'Anytown';
$address->postalCode = '12345';
$address->country = 'USA';
$manager->commitStep($step, $address);
// Working with another step (e.g., delivery date)
$step = $manager->getCheckoutStep("deliverydate");
$deliveryDate = new stdClass();
// Fill delivery date with necessary data
$deliveryDate->date = '2024-07-25';
$manager->commitStep($step, $deliveryDate);
$cart->save();
```
### Summary
Implementing and configuring checkout steps in the Pimcore E-Commerce
Framework involves creating concrete implementations of each step,
configuring them in the system, and then managing these steps within your
application. This modular approach allows for a highly customizable and
flexible checkout process that can be tailored to specific business needs.
User
Committing Orders
After all checkout steps are completed, the order can be committed. If no
payment is involved, this is done as follows. If payment is involved, have
a look at the Payment Integration docs.
<?php
$manager = Factory::getInstance()->getCheckoutManager($cart);
$order = $manager->commitOrder();
While committing the order, the checkout manager delegates it to the
specified commit order processor implementation, which needs to implement \
Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CommitOrderProcessorInterface.
This is the place where all functionality for committing the order (e.g.
sending orders to erp systems, sending order confirmation mails, ...) is
located.
The default implementation \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor provides basic functionality like
creating a Pimcore order object and sending an order confirmation mail.
Order creation itself is delegated to the \Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\OrderManagerInterface.
Typically needed Custom Extensions
In simple use cases a project specific implementation needs
...to extend \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\V7\
OrderManager and overwrite the method applyCustomCheckoutDataToOrder to add
additional custom fields to the order object and
...to extend \Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CommitOrderProcessor and overwrite the method processOrder where website
specific functionality is integrated (sending orders to erp systems, ...).
See following examples for details.
Order Manager
If additional information needs to be stored into the order, the
OrderManager has to be extended. For more Information concerning the
OrderManager see the documentation.
A simple implementation of App\Ecommerce\Order\OrderManager could look
like:
<?php
class OrderManager extends \Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager
/**
* @throws InvalidConfigException
*/
protected function applyCustomCheckoutDataToOrder(CartInterface $cart,
AbstractOrder $order): AbstractOrder
/** @var AbstractOrder $order */
$order = parent::applyCustomCheckoutDataToOrder($cart, $order);
$checkout = Factory::getInstance()->getCheckoutManager($cart);
$deliveryAddress = $checkout->getCheckoutStep('deliveryaddress') ?
$checkout->getCheckoutStep('deliveryaddress')->getData() : null;
$confirm = $checkout->getCheckoutStep('confirm') ? $checkout-
>getCheckoutStep('confirm')->getData() : null;
if($deliveryAddress) {
//inserting delivery and billing address from checkout step
delivery
$order->setCustomerFirstname( $deliveryAddress->firstname );
$order->setCustomerLastname( $deliveryAddress->lastname );
$order->setCustomerCompany( $deliveryAddress->company );
$order->setCustomerStreet( $deliveryAddress->address );
$order->setCustomerZip( $deliveryAddress->zip );
$order->setCustomerCity( $deliveryAddress->city );
$order->setCustomerCountry( $deliveryAddress->country );
$order->setCustomerEmail( $deliveryAddress->email );
$order->setDeliveryFirstname( $deliveryAddress->firstname );
$order->setDeliveryLastname( $deliveryAddress->lastname );
$order->setDeliveryCompany( $deliveryAddress->company );
$order->setDeliveryStreet( $deliveryAddress->address );
$order->setDeliveryZip( $deliveryAddress->zip );
$order->setDeliveryCity( $deliveryAddress->city );
$order->setDeliveryCountry( $deliveryAddress->country );
} else if($confirm) {
//in quick checkout - only get email-adress from confirm step
$order->setCustomerEmail( $confirm );
return $order;
Commit Order Processor
A simple implementation of \App\Checkout\Processor could look like:
<?php
class Processor extends CommitOrderProcessor
protected function processOrder(AbstractOrder $order): void
//send order to ERP-System
try {
$connector = ERPConnector::getInstance();
$erpOrderNumber = $connector->sendOrder($order);
$order->setOrderNumber($erpOrderNumber);
} catch(Exception $e) {
Logger::error($e->getMessage());
throw $e;
If needed, further methods can be overwritten. E.g. sendConfirmationMail if
special e-mails should be sent to specific persons.
After commit order was successful, the user can be directed to a success-
page.
ChatGPT
## Committing Orders in Pimcore E-Commerce Framework
After all checkout steps are completed, the final step is to commit the
order. This involves saving the order details, sending order confirmation
emails, and potentially integrating with external systems such as ERP.
### Basic Order Commit without Payment
For scenarios where no payment is involved, committing the order is
straightforward:
```php
$manager = Factory::getInstance()->getCheckoutManager($cart);
$order = $manager->commitOrder();
```
### Commit Order Processor
The `CheckoutManager` delegates the order committing process to a specified
`CommitOrderProcessor` implementation. This processor must implement `\
Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CommitOrderProcessorInterface`.
### Default Implementation
The default `CommitOrderProcessor` implementation provides basic
functionality like creating a Pimcore order object and sending an order
confirmation email. Order creation is handled by `\Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\OrderManagerInterface`.
### Custom Extensions
In more complex scenarios, you will typically need to extend the default
implementations to handle additional custom fields or integrate with
external systems.
### Extending Order Manager
To store additional information in the order, you need to extend the
`OrderManager`.
Here’s a simple implementation of `App\Ecommerce\Order\OrderManager`:
```php
<?php
namespace App\Ecommerce\Order;
use Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\V7\OrderManager as
BaseOrderManager;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractOrder;
use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartInterface;
class OrderManager extends BaseOrderManager
protected function applyCustomCheckoutDataToOrder(CartInterface $cart,
AbstractOrder $order): AbstractOrder
$order = parent::applyCustomCheckoutDataToOrder($cart, $order);
$checkout = \Pimcore\Bundle\EcommerceFrameworkBundle\
Factory::getInstance()->getCheckoutManager($cart);
$deliveryAddress = $checkout->getCheckoutStep('deliveryaddress') ?
$checkout->getCheckoutStep('deliveryaddress')->getData() : null;
$confirm = $checkout->getCheckoutStep('confirm') ? $checkout-
>getCheckoutStep('confirm')->getData() : null;
if ($deliveryAddress) {
// Insert delivery and billing address from checkout step
delivery
$order->setCustomerFirstname($deliveryAddress->firstname);
$order->setCustomerLastname($deliveryAddress->lastname);
$order->setCustomerCompany($deliveryAddress->company);
$order->setCustomerStreet($deliveryAddress->address);
$order->setCustomerZip($deliveryAddress->zip);
$order->setCustomerCity($deliveryAddress->city);
$order->setCustomerCountry($deliveryAddress->country);
$order->setCustomerEmail($deliveryAddress->email);
$order->setDeliveryFirstname($deliveryAddress->firstname);
$order->setDeliveryLastname($deliveryAddress->lastname);
$order->setDeliveryCompany($deliveryAddress->company);
$order->setDeliveryStreet($deliveryAddress->address);
$order->setDeliveryZip($deliveryAddress->zip);
$order->setDeliveryCity($deliveryAddress->city);
$order->setDeliveryCountry($deliveryAddress->country);
} elseif ($confirm) {
// In quick checkout - only get email address from confirm step
$order->setCustomerEmail($confirm);
return $order;
```
### Extending Commit Order Processor
To handle custom logic during the order commit, such as sending the order
to an ERP system, extend the `CommitOrderProcessor`.
Here’s a simple implementation of `\App\Checkout\Processor`:
```php
<?php
namespace App\Checkout;
use Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CommitOrderProcessor;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractOrder;
use Pimcore\Log\Logger;
class Processor extends CommitOrderProcessor
protected function processOrder(AbstractOrder $order): void
// Send order to ERP-System
try {
$connector = ERPConnector::getInstance();
$erpOrderNumber = $connector->sendOrder($order);
$order->setOrderNumber($erpOrderNumber);
} catch (Exception $e) {
Logger::error($e->getMessage());
throw $e;
```
Further methods can be overridden as needed, such as `sendConfirmationMail`
for sending custom emails.
### Final Steps
After successfully committing the order, the user can be directed to a
success page.
### Summary
The checkout process in Pimcore E-Commerce Framework involves configuring
and extending various components such as the `CheckoutManager`,
`OrderManager`, and `CommitOrderProcessor` to handle custom business logic,
additional fields, and integration with external systems. By following the
steps outlined above, you can customize the checkout process to fit the
specific needs of your e-commerce application.
User
Payment Integration
To integrate payment into the checkout process, instead of calling
$manager->commitOrder(); like described in Committing Orders, a few more
steps are necessary.
Initialize Payment in Controller
After all checkout steps are completed, the payment can be started. This is
done as follows:
/**
* @Route("/checkout-init-payment", name="shop-checkout-init-payment")
*/
public function initPaymentAction(Request $request, Factory $factory) {
// ... do some stuff, and get $cart
/** @var CheckoutManagerInterface $checkoutManager */
$checkoutManager = $factory->getCheckoutManager($cart);
//optional - init payment and get Pimcore internal payment ID (e.g. if
needed for config of payment provider)
$paymentInformation = $checkoutManager->initOrderPayment();
$config = new DatatransRequest([
//all options needed for payment provider - you also can use
setters of the corresponding object
]);
// start payment
$startPaymentResponse = $checkoutManager-
>startOrderPaymentWithPaymentProvider($config);
// depending on response type handle start payment response - e.g.
render form, render snippet, etc.
$paymentForm = $startPaymentResponse->getForm();
return $this->render('payment/init_payment.html.twig', [
'form' => $paymentForm->getForm()->createView()
]);
Build payment view
Once the payment is started, the created payment form needs to be
integrated into the view script. Depending on the payment provider, also
other data structures can be created:
<p>{{ 'Starting Payment' }}</p>
{{ form(form) }}
For more samples see our demo
Handle Payment Response
When the user finishes the payment, the given response (either via redirect
or via server side call) has to be handled as follows. If payment handling
was successful, the order needs to be committed.
A client side handling could look like as follows:
/**
* @Route("/checkout-payment-response", name="shop-checkout-payment-
response")
*/
public function paymentResponseAction(Request $request, Factory $factory,
RequestStack $requestStack) {
// ... do some stuff, and get $cart
$checkoutManager = $factory->getCheckoutManager($cart);
$params = []; // ... get all necessary parameters for payment provider,
e.g. by array_merge($request->query->all(), $request->request->all());
try {
$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);
// optional to clear payment
// if this call is necessary depends on payment provider and
configuration.
// its possible to execute this later (e.g. when shipment is done)
// $payment = $checkoutManager->getPayment();
// $paymentStatus = $payment->executeDebit();
// $orderAgent = Factory::getInstance()->getOrderManager()-
>createOrderAgent($order);
// $orderAgent->updatePayment($paymentStatus);
$session = $requestStack->getSession();
$session->set("last_order_id", $order->getId());
$goto = $this->generateUrl('shop-checkout-completed');
} catch (\Exception $e) {
$this->addFlash('danger', $e->getMessage());
$goto = $this->generateUrl('shop-checkout-address');
return $this->render('payment/payment_response.html.twig', ['goto' =>
$goto]);
A server side handling could look as follows:
<?php
public function serverSideQPayAction(Request $request, Factory
$factory) {
Logger::info("Starting server side call");
$params = array_merge($request->query->all(), $request->request-
>all());
$environment = $factory->getEnvironment();
//if checkout tenant is set via param, use that one for this
request
if($params['checkouttenant']) {
$environment-
>setCurrentCheckoutTenant($params['checkouttenant'], false);
$commitOrderProcessor = $factory->getCommitOrderProcessor();
$paymentProvider = $factory->getPaymentManager()-
>getProvider("unzer");
if($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {
Logger::info("Order with same payment is already committed,
doing nothing. OrderId is " . $committedOrder->getId());
} else {
$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment( $params, $paymentProvider );
Logger::info("Finished server side call. OrderId is " . $order-
>getId());
}
exit("success");
Dealing with Pending Payments
Depending on the shops user journey, it might be possible, that a user
starts multiple payments. Typical use cases for that can be:
User starts payment → user goes back to shop and changes cart → user starts
checkout and payment with modified cart again
User has multiple tabs open → user starts payment in first tab → user
starts another payment in second tab → user finishes first payment → user
finishes second payment
The ecommerce application needs a strategy how to deal with that. Tthe
checkout manager can be configured with one of the following strategies how
to handle pending payments when a new payment is started (with
handle_pending_payments_strategy factory option):
RecreateOrder: Create new order every time a payment is started and leave
old orders untouched.
factory_options:
class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
AlwaysRecreateOrderStrategy
CancelPaymentOrRecreateOrder (default value): Cancel payments if possible
and cart has not changed, create new order when cart has changed.
factory_options:
class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy
ThrowException: Throw exceptions to make handling of these cases in
controller possible.
factory_options:
class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
ThrowExceptionStrategy
Above mentioned use cases will now result in following behavior:
User starts payment → user goes back to shop and changes cart → user starts
checkout and payment with modified cart again:
Cart can be changed despite pending payments.
When user restarts payment, new order is created for new payment (with new
cart content):
If user finishes the first payment, first order is finished → all post
order processes are done based on first order.
If user finishes second payment, second order is finished.
If user finishes both payments, user has two orders.
User has multiple tabs open → user starts payment in first tab → user
starts another payment in second tab → user finishes first payment → user
finishes second payment:
Depending on configured CancelPaymentOrRecreateOrderStrategy when user
starts second payment following things can happen:
RecreateOrder: Another order is created and user has two orders when he
finishes both payments.
CancelPaymentOrRecreateOrder: First payment would be cancelled, user only
has one order. When user finishes both payments, both payment information
entries will be in one order.
ThrowException: When starting second payment an exception will be thrown
and controller needs to decide what to do.
It is possible to implement custom strategies as they are just services
implementing HandlePendingPaymentsStrategyInterface.
For more details see Payment Docs section.
ChatGPT
## Payment Integration in Pimcore E-Commerce Framework
Integrating payment into the checkout process involves several steps to
ensure a smooth transaction experience. This guide will walk you through
initializing payments, handling payment responses, and managing pending
payments.
### Initialize Payment in Controller
After completing all checkout steps, the payment process can be initiated.
Here's how to start a payment:
```php
/**
* @Route("/checkout-init-payment", name="shop-checkout-init-payment")
*/
public function initPaymentAction(Request $request, Factory $factory) {
// ... do some stuff, and get $cart
/** @var CheckoutManagerInterface $checkoutManager */
$checkoutManager = $factory->getCheckoutManager($cart);
//optional - init payment and get Pimcore internal payment ID (e.g. if
needed for config of payment provider)
$paymentInformation = $checkoutManager->initOrderPayment();
$config = new DatatransRequest([
//all options needed for payment provider - you also can use
setters of the corresponding object
]);
// start payment
$startPaymentResponse = $checkoutManager-
>startOrderPaymentWithPaymentProvider($config);
// depending on response type handle start payment response - e.g.
render form, render snippet, etc.
$paymentForm = $startPaymentResponse->getForm();
return $this->render('payment/init_payment.html.twig', [
'form' => $paymentForm->getForm()->createView()
]);
```
### Build Payment View
Once the payment is initiated, the created payment form needs to be
integrated into the view script. Depending on the payment provider, other
data structures may also be created:
```twig
<p>{{ 'Starting Payment' }}</p>
{{ form(form) }}
```
### Handle Payment Response
When the user finishes the payment, the response needs to be handled. If
the payment handling is successful, the order is committed.
#### Client-Side Handling
```php
/**
* @Route("/checkout-payment-response", name="shop-checkout-payment-
response")
*/
public function paymentResponseAction(Request $request, Factory $factory,
RequestStack $requestStack) {
// ... do some stuff, and get $cart
$checkoutManager = $factory->getCheckoutManager($cart);
$params = array_merge($request->query->all(), $request->request-
>all());
try {
$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);
// optional to clear payment
// if this call is necessary depends on payment provider and
configuration.
// its possible to execute this later (e.g. when shipment is done)
// $payment = $checkoutManager->getPayment();
// $paymentStatus = $payment->executeDebit();
// $orderAgent = Factory::getInstance()->getOrderManager()-
>createOrderAgent($order);
// $orderAgent->updatePayment($paymentStatus);
$session = $requestStack->getSession();
$session->set("last_order_id", $order->getId());
$goto = $this->generateUrl('shop-checkout-completed');
} catch (\Exception $e) {
$this->addFlash('danger', $e->getMessage());
$goto = $this->generateUrl('shop-checkout-address');
return $this->render('payment/payment_response.html.twig', ['goto' =>
$goto]);
```
#### Server-Side Handling
```php
public function serverSideQPayAction(Request $request, Factory $factory) {
Logger::info("Starting server side call");
$params = array_merge($request->query->all(), $request->request-
>all());
$environment = $factory->getEnvironment();
//if checkout tenant is set via param, use that one for this request
if($params['checkouttenant']) {
$environment->setCurrentCheckoutTenant($params['checkouttenant'],
false);
$commitOrderProcessor = $factory->getCommitOrderProcessor();
$paymentProvider = $factory->getPaymentManager()->getProvider("unzer");
if($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {
Logger::info("Order with same payment is already committed, doing
nothing. OrderId is " . $committedOrder->getId());
} else {
$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment($params, $paymentProvider);
Logger::info("Finished server side call. OrderId is " . $order-
>getId());
exit("success");
}
```
### Dealing with Pending Payments
To handle scenarios where users might start multiple payments, you need a
strategy for managing pending payments. The checkout manager can be
configured with one of the following strategies:
1. **RecreateOrder:** Create a new order every time a payment is started
and leave old orders untouched.
```yaml
factory_options:
class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
AlwaysRecreateOrderStrategy
```
2. **CancelPaymentOrRecreateOrder (default):** Cancel payments if possible
and the cart has not changed, create a new order when the cart has changed.
```yaml
factory_options:
class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy
```
3. **ThrowException:** Throw exceptions to make handling these cases
possible in the controller.
```yaml
factory_options:
class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
ThrowExceptionStrategy
```
### Summary
Integrating payment into the checkout process involves initializing the
payment, handling payment responses, and managing pending payments. By
following the steps outlined above, you can ensure a smooth payment process
for your e-commerce application using the Pimcore E-Commerce Framework.
User
Checkout Manager Details
Following documentation page provide a few more insights on Checkout
Manager Architecture.
Architecture Details
Architecture V7
Stars mark places, where events are thrown. For details see EventManager
docs.
ChatGPT
### Checkout Manager Details from the Uploaded Document
#### Overview
The Checkout Manager in Pimcore provides a comprehensive API to handle the
checkout process. It is a key component in building customizable checkout
workflows for e-commerce applications. The architecture ensures
flexibility, allowing developers to integrate various custom features,
payment gateways, and order processing mechanisms.
#### Architecture Details
1. **Checkout Steps**:
- Each checkout step needs to implement `CheckoutStepInterface` and
extend `AbstractStep`.
- Common methods include `commit()` for saving data, `getData()` for
retrieving stored data, and `getName()` for identifying the step.
2. **Order Management**:
- Orders are managed through `OrderManagerInterface`.
- Custom order processing can be achieved by extending the default
`OrderManager` and overriding methods like
`applyCustomCheckoutDataToOrder`.
3. **Payment Integration**:
- Payments are handled via the `PaymentProviderInterface`.
- The payment process can be initiated and managed through methods like
`initOrderPayment()` and `startOrderPaymentWithPaymentProvider()`.
- Handling responses from payment gateways involves validating and
committing the order based on the payment status.
4. **Event Handling**:
- Various events are thrown at different stages of the checkout
process, allowing for custom event-driven actions.
- Event management can be customized based on specific business
requirements.
5. **Custom Implementations**:
- Developers can create custom implementations of key components such
as `CommitOrderProcessor` and `OrderManager` to add specific business
logic, integrate with ERP systems, or handle custom notifications.
- Example: Extending `CommitOrderProcessor` to include sending order
details to an ERP system.
6. **Pending Payments**:
- The framework provides strategies to handle pending payments, such as
recreating orders, canceling previous payments, or throwing exceptions for
manual handling.
- Developers can implement custom strategies by implementing
`HandlePendingPaymentsStrategyInterface`.
#### Key Components and Usage
- **Factory Initialization**:
```php
$manager = Factory::getInstance()->getCheckoutManager($cart);
```
- **Setting Up Steps**:
```php
$step = $manager->getCheckoutStep("deliveryaddress");
$address = new stdClass();
// fill address
$manager->commitStep($step, $address);
$cart->save();
```
- **Committing Orders**:
```php
$order = $manager->commitOrder();
```
- **Payment Initialization**:
```php
$checkoutManager = $factory->getCheckoutManager($cart);
$paymentInformation = $checkoutManager->initOrderPayment();
```
- **Handling Payment Response**:
```php
$params = array_merge($request->query->all(), $request->request->all());
$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);
```
These snippets highlight the modularity and extensibility of the Checkout
Manager, allowing for tailored implementations to fit specific e-commerce
workflows.
For more detailed information, please refer to the full documentation
provided in the PDF【75:0†Checkout Manager.pdf】.
User
Checkout Tenants for Checkout
The E-Commerce Framework has the concept of Checkout Tenants which allow
different cart manager and checkout manager configurations based on a
currently active checkout tenant.
The current checkout tenant is set in the framework environment as follows.
Once set, the checkout manager uses all specific settings of the currently
active checkout tenant.
So different checkout steps, different payment providers etc. can be
implemented within one shop.
<?php
$environment = Factory::getInstance()->getEnvironment();
$environment->setCurrentCheckoutTenant('default');
$environment->save();
$environment->setCurrentCheckoutTenant('noShipping');
$environment->save();
When using server-by-server payment confirmation communication, make sure
that the correct tenant is set during the response handling!
ChatGPT
### Checkout Tenants for Checkout
The concept of Checkout Tenants in the Pimcore E-Commerce Framework allows
for different configurations of the cart manager and checkout manager
depending on the currently active tenant. This enables the implementation
of different checkout steps, payment providers, and other configurations
within a single shop instance.
#### Setting the Current Checkout Tenant
The current checkout tenant is set in the framework environment. Once set,
the checkout manager will use the specific settings configured for the
active tenant.
```php
$environment = Factory::getInstance()->getEnvironment();
$environment->setCurrentCheckoutTenant('default');
$environment->save();
$environment->setCurrentCheckoutTenant('noShipping');
$environment->save();
```
#### Configuration of Checkout Tenants
To configure different checkout tenants, you define them in the
`pimcore_ecommerce_framework` configuration section.
```yaml
pimcore_ecommerce_framework:
checkout_manager:
tenants:
_defaults:
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory
factory_options:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy
commit_order_processor:
id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor
options:
confirmation_mail: /en/emails/order-confirmation
steps:
deliveryaddress:
class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress
confirm:
class: \App\Ecommerce\Checkout\Confirm
default:
payment:
provider: qpay
paypal:
payment:
provider: paypal
```
### Server-Side Payment Confirmation
When handling server-side payment confirmations, it is crucial to ensure
that the correct tenant is set during the response handling. This ensures
that the appropriate configuration and steps are used for processing the
payment and committing the order.
#### Example Server-Side Payment Confirmation Handling
```php
/**
* @Route("/server-side-payment-confirmation",
name="server_side_payment_confirmation")
*/
public function serverSidePaymentConfirmationAction(Request $request,
Factory $factory) {
Logger::info("Starting server side call");
$params = array_merge($request->query->all(), $request->request-
>all());
$environment = $factory->getEnvironment();
// Ensure the correct checkout tenant is set based on request
parameters
if (isset($params['checkouttenant'])) {
$environment->setCurrentCheckoutTenant($params['checkouttenant'],
false);
$commitOrderProcessor = $factory->getCommitOrderProcessor();
$paymentProvider = $factory->getPaymentManager()->getProvider("unzer");
if ($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {
Logger::info("Order with same payment is already committed, doing
nothing. OrderId is " . $committedOrder->getId());
} else {
$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment($params, $paymentProvider);
Logger::info("Finished server side call. OrderId is " . $order-
>getId());
exit("success");
```
### Benefits of Checkout Tenants
1. **Flexibility**: Different checkout processes and payment configurations
can be implemented for various customer groups or scenarios within the same
shop.
2. **Customization**: Tailor the checkout experience based on specific
needs, such as offering different payment providers for different
countries.
3. **Scalability**: Manage complex checkout processes efficiently without
duplicating configuration for each variant.
By leveraging checkout tenants, e-commerce applications built with Pimcore
can provide a more flexible and tailored shopping experience, accommodating
various business needs and customer preferences.
User
Payment Manager
The Payment Manager is responsible for all aspects concerning payment. The
main aspect is the implementation of different Payment Provider to
integrate them into the framework.
Basic workflow
[SHOP] Init payment provider ($payment->initPayment()).
[SHOP] User click pay button and is redirected to the payment provider
page.
[PAYMENT PROVIDER] User fill up payment information and is redirected back
to the shop.
[SHOP] Check if the payment is authorised ($payment->handleResponse()). At
this step the order can be committed.
[SHOP] Clearing payment if its required ($payment->executeDebit())
For more information about integrating Payment into checkout processes see
Integrating Payment Docs.
Configuration
Configuration of Payment Manager takes place in the
pimcore_ecommerce_config.payment_manager config section:
pimcore_ecommerce_config:
payment_manager:
# service ID of payment manager implementation - following value is
default value an can be omitted
payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager
# configuration of payment providers, key is name of provider
providers:
datatrans:
# service ID of payment provider implementation
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Datatrans
# active profile - you can define multiple profiles in the
section below
profile: sandbox
# available profiles with options - options vary on the
provider implementation as the
profiles:
sandbox:
merchant_id: 1000011011
sign: 30916165706580013
use_digital_signature: false
live:
merchant_id: merchant_id_id
sign: sign_id
use_digital_signature: false
mode: live
ogone:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\OGone
profile: sandbox
profiles:
sandbox:
secret: D343DDFD3434
pspid: MyTestAccount
mode: sandbox
# encryptionType: SHA256 or SHA512 (optional)
live:
secret: D343DDFD3434
pspid: MyLiveAccount
mode: live
# encryptionType: SHA256 or SHA512 (optional)
mpay24:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Mpay24Seamless
profile: testsystem
profiles:
_defaults:
#paypal_activate_item_level: true
partial:
Shared/Includes/Shop/Payment/paymentMethods.html.php
payment_methods:
cc:
paypal:
sofort:
invoice:
testsystem:
merchant_id: 95387
password: 7&jcQ%v6RB
testSystem: true
debugMode: true
live:
merchant_id: todo
password: todo
testSystem: false
debugMode: false
hobex:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Hobex
profile: sandbox
profiles:
sandbox:
entityId: '8a829418530df1d201531299e097175c'
authorizationBearer:
'OGE4Mjk0MTg1MzBkZjFkMjAxNTMxMjk5ZTJjMTE3YWF8ZzJnU3BnS2hLUw=='
testSystem: true
payment_methods:
- VISA
- MASTER
- SOFORTUEBERWEISUNG
- SEPA
The payment provider name will be referenced from the checkout manager
configuration and can be used to fetch a specific provider from the payment
manager.
Payment Providers
Following Payment Providers are available as a dedicated bundle to be
integrated into the E-commerce framework:
Datatrans
PayPalSmartButton
Klarna
OGone
MPay24
PayU
Unzer (former Heidelpay)
Hobex
Third-party Payment Provider Integrations
BS PAYONE
Further Payment Aspects
Recurring Payments
ChatGPT
## Payment Manager
The Payment Manager in Pimcore E-Commerce Framework is responsible for
managing payment providers and handling the payment processes. Below are
the main components and workflow of the Payment Manager.
### Basic Workflow
1. **Initialize Payment Provider:** The shop initializes the payment
provider using `$payment->initPayment()`.
2. **User Redirected to Payment Provider:** The user clicks the pay button
and is redirected to the payment provider's page.
3. **User Completes Payment Information:** The user fills in the payment
information and is redirected back to the shop.
4. **Authorize Payment:** The shop checks if the payment is authorized
using `$payment->handleResponse()`. At this step, the order can be
committed.
5. **Execute Payment:** The shop clears the payment if required using
`$payment->executeDebit()`.
### Configuration
The configuration for the Payment Manager is done in the
`pimcore_ecommerce_config.payment_manager` configuration section.
```yaml
pimcore_ecommerce_config:
payment_manager:
# Default service ID for payment manager implementation
payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager
# Configuration of payment providers
providers:
datatrans:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Datatrans
profile: sandbox
profiles:
sandbox:
merchant_id: 1000011011
sign: 30916165706580013
use_digital_signature: false
live:
merchant_id: merchant_id_id
sign: sign_id
use_digital_signature: false
mode: live
ogone:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\OGone
profile: sandbox
profiles:
sandbox:
secret: D343DDFD3434
pspid: MyTestAccount
mode: sandbox
# encryptionType: SHA256 or SHA512 (optional)
live:
secret: D343DDFD3434
pspid: MyLiveAccount
mode: live
# encryptionType: SHA256 or SHA512 (optional)
mpay24:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Mpay24Seamless
profile: testsystem
profiles:
_defaults:
#paypal_activate_item_level: true
partial:
Shared/Includes/Shop/Payment/paymentMethods.html.php
payment_methods:
cc:
paypal:
sofort:
invoice:
testsystem:
merchant_id: 95387
password: 7&jcQ%v6RB
testSystem: true
debugMode: true
live:
merchant_id: todo
password: todo
testSystem: false
debugMode: false
hobex:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Hobex
profile: sandbox
profiles:
sandbox:
entityId: '8a829418530df1d201531299e097175c'
authorizationBearer:
'OGE4Mjk0MTg1MzBkZjFkMjAxNTMxMjk5ZTJjMTE3YWF8ZzJnU3BnS2hLUw=='
testSystem: true
payment_methods:
- VISA
- MASTER
- SOFORTUEBERWEISUNG
- SEPA
```
### Payment Providers
Below is a list of available payment providers that can be integrated into
the Pimcore E-Commerce framework:
- Datatrans
- PayPalSmartButton
- Klarna
- OGone
- MPay24
- PayU
- Unzer (former Heidelpay)
- Hobex
### Third-party Payment Provider Integrations
In addition to the built-in payment providers, third-party integrations
such as BS PAYONE can be implemented.
### Recurring Payments
The framework also supports recurring payments, though specific
configuration and implementation details would depend on the payment
provider and the use case.
### Example Integration with Payment Provider
#### Initializing Payment in Controller
```php
/**
* @Route("/checkout-init-payment", name="shop-checkout-init-payment")
*/
public function initPaymentAction(Request $request, Factory $factory) {
// ... do some stuff, and get $cart
/** @var CheckoutManagerInterface $checkoutManager */
$checkoutManager = $factory->getCheckoutManager($cart);
// Optional - init payment and get Pimcore internal payment ID (e.g. if
needed for config of payment provider)
$paymentInformation = $checkoutManager->initOrderPayment();
$config = new DatatransRequest([
// All options needed for payment provider - you also can use
setters of the corresponding object
]);
// Start payment
$startPaymentResponse = $checkoutManager-
>startOrderPaymentWithPaymentProvider($config);
// Depending on response type handle start payment response - e.g.
render form, render snippet, etc.
$paymentForm = $startPaymentResponse->getForm();
return $this->render('payment/init_payment.html.twig', [
'form' => $paymentForm->getForm()->createView()
]);
```
#### Handling Payment Response
```php
/**
* @Route("/checkout-payment-response", name="shop-checkout-payment-
response")
*/
public function paymentResponseAction(Request $request, Factory $factory,
RequestStack $requestStack) {
// ... do some stuff, and get $cart
$checkoutManager = $factory->getCheckoutManager($cart);
$params = array_merge($request->query->all(), $request->request-
>all());
try {
$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);
// Optional to clear payment
// if this call is necessary depends on payment provider and
configuration.
// its possible to execute this later (e.g. when shipment is done)
// $payment = $checkoutManager->getPayment();
// $paymentStatus = $payment->executeDebit();
// $orderAgent = Factory::getInstance()->getOrderManager()-
>createOrderAgent($order);
// $orderAgent->updatePayment($paymentStatus);
$session = $requestStack->getSession();
$session->set("last_order_id", $order->getId());
$goto = $this->generateUrl('shop-checkout-completed');
} catch (\Exception $e) {
$this->addFlash('danger', $e->getMessage());
$goto = $this->generateUrl('shop-checkout-address');
return $this->render('payment/payment_response.html.twig', ['goto' =>
$goto]);
```
#### Server-Side Payment Confirmation
```php
/**
* @Route("/server-side-payment-confirmation",
name="server_side_payment_confirmation")
*/
public function serverSidePaymentConfirmationAction(Request $request,
Factory $factory) {
Logger::info("Starting server side call");
$params = array_merge($request->query->all(), $request->request-
>all());
$environment = $factory->getEnvironment();
// Ensure the correct checkout tenant is set based on request
parameters
if (isset($params['checkouttenant'])) {
$environment->setCurrentCheckoutTenant($params['checkouttenant'],
false);
$commitOrderProcessor = $factory->getCommitOrderProcessor();
$paymentProvider = $factory->getPaymentManager()->getProvider("unzer");
if ($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {
Logger::info("Order with same payment is already committed, doing
nothing. OrderId is " . $committedOrder->getId());
} else {
$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment($params, $paymentProvider);
Logger::info("Finished server side call. OrderId is " . $order-
>getId());
exit("success");
```
This configuration and workflow ensure a seamless integration of various
payment providers into the Pimcore E-Commerce Framework, enabling flexible
and reliable payment processing for different e-commerce scenarios.
ChatGPT
### Implementing Recurring Payments
To implement recurring payments in Pimcore's E-Commerce Framework, follow
these guidelines:
### 1. Understanding Recurring Payments
The best practice for handling recurring payments involves keeping track of
the initial payment and using it as a source for subsequent recurring
payments. This ensures that credit card information is not stored beyond
the allowed time, enhancing security and compliance.
#### **Bad Way Example:**
- Initial Payment: 01.01.2013, Amount: 15 Euros, Order Number: 12345
- Recurring Payment 1: 01.05.2013, Amount: 20 Euros, Source Order Number:
12345, Order Number: 23456
- Recurring Payment 2: 01.10.2013, Amount: 20 Euros, Source Order Number:
12345, Order Number: 34567
- Recurring Payment 3: 01.03.2014, Amount: 10 Euros, Source Order Number:
12345, Order Number: 45678
Here, the initial transaction is older than 400 days, so the credit card
data is no longer valid in the system.
#### **Good Way Example:**
- Initial Payment: 01.01.2013, Amount: 15 Euros, Order Number: 12345
- Recurring Payment 1: 01.05.2013, Amount: 20 Euros, Source Order Number:
12345, Order Number: 23456
- Recurring Payment 2: 01.10.2013, Amount: 20 Euros, Source Order Number:
23456, Order Number: 34567
- Recurring Payment 3: 01.03.2014, Amount: 10 Euros, Source Order Number:
34567, Order Number: 45678
Here, the last transaction is within 150 days, so everything remains valid.
### 2. Implementing in Code
#### **Controller for Handling Payments**
The following code shows how to perform a one-time payment and manage
recurring payments using Wirecard (Qpay):
```php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
class CheckoutController
public function paymentAction(Request $request): Response
$factory = Factory::getInstance();
$checkoutManager = $factory->getCheckoutManager($this->cart);
$user = $this->getUser();
// Open payment or submit recurring payment
if ($request->getMethod() == 'POST') {
if ($sourceOrderId = $request->get("recurring-payment")) {
/* Recurring Payment */
if ($user && $sourceOrderId) {
$sourceOrder = \Pimcore\Model\DataObject\
OnlineShopOrder::getById($sourceOrderId);
try {
$targetOrder = $checkoutManager-
>startAndCommitRecurringOrderPayment($sourceOrder, $user->getId());
return $this->redirect($this-
>generateUrl('checkout', ['action' => 'completed']));
} catch (\Exception $exception) {
// show warning
$templateParams = [];
$paymentMethods = ["SEPA-DD", "CCARD"]; // supported payment
methods
if ($user) {
$sourceOrders = [];
foreach ($paymentMethods as $paymentMethod) {
$orderManager = $factory->getOrderManager();
$sourceOrder = $orderManager-
>getRecurringPaymentSourceOrder($user->getId(), $checkoutManager-
>getPayment(), $paymentMethod);
$sourceOrders[$paymentMethod] = $sourceOrder;
}
$templateParams['sourceOrders'] = $sourceOrders;
$templateParams['paymentMethods'] = $paymentMethods;
return $this->render('checkout/payment.html.twig',
$templateParams);
```
#### **Twig Template for Payment Options**
```twig
<form method="post" action="{{ pimcore_url({action: 'confirm'}, 'checkout',
true) }}">
{% if sourceOrders is not empty %}
<h4>{{ 'checkout.use-recurring-payment'|trans }}</h4>
{% for paymentMethod in paymentMethods %}
{% if sourceOrders[paymentMethod] is defined %}
{% set sourceOrder = sourceOrders[paymentMethod] %}
{% set paymentProvider =
sourceOrder.paymentProvider.paymentProviderQpay %}
{% if paymentProvider %}
{% set currentPaymentMethod =
paymentProvider.Auth_paymentType %}
<p>
<input name="recurring-payment"
value="{{ sourceOrder.id }}" type="radio">
<strong>{{ currentPaymentMethod }}</strong>
{% if currentPaymentMethod is same as('SEPA-DD') %}
{{ paymentProvider.Auth_bankAccountOwner }}
{{ paymentProvider.Auth_bankAccountIBAN }}
{% elseif currentPaymentMethod is same as('CCARD')
%}
{{ paymentProvider.Auth_maskedPan }}
{{ paymentProvider.Auth_expiry }}
{% endif %}
</p>
{% endif %}
{% endif %}
{% endfor %}
<hr>
{% endif %}
</form>
```
#### **Configuration (ecommerce.yaml)**
```yaml
pimcore_ecommerce_framework:
payment_manager:
providers:
qpay:
profiles:
sandbox:
secret:
'CHCSH7UGHVVX2P7EHDHSY4T2S4CGYK4QBE4M5YUUG2ND5BEZWNRZW5EJYVJQ'
customer: 'D200411'
toolkit_password: 'XXXXXXX' # necessary for
recurPayment operation
optional_payment_properties:
- paymentType
- transactionIdentifier # necessary for
recurPayment based on SEPA DIRECT DEBIT
recurring_payment_enabled: true # enable recurring
payment
```
### Best Practices
- **Keep Payment Information Secure:** Ensure that sensitive payment data
is never stored in a way that violates security compliance.
- **Follow Payment Provider Guidelines:** Adhere to the guidelines provided
by your payment provider for recurring payments.
- **Handle Failures Gracefully:** Ensure that your system can handle
failures and retry logic appropriately for recurring payments.
By following these practices and integrating the provided code, you can
effectively manage one-time and recurring payments in Pimcore's E-Commerce
Framework.
User
Order Manager
The Order Manager is responsible for all aspects of working with orders
except committing them (which is the responsibility of the Commit Order
Processor). These aspects contain among other things:
Creating orders based on carts
Order Storage (by default as Pimcore objects)
Loading orders
Loading order lists and filter them (Order List)
Working with orders after order commit (Order Agent)
Configuration
The configuration takes place in the
pimcore_ecommerce_framework.order_manager config section and is tenant
aware.
pimcore_ecommerce_framework:
order_manager:
tenants:
_defaults:
# service ID of order manager implementation
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager
# options for oder manager
options:
# Pimcore object class for orders
order_class: \Pimcore\Model\DataObject\OnlineShopOrder
# Pimcore object class for order items
order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem
# Class for order listing
list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing
# Class for order item listing
list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item
# Default parent folder for new orders, will be parsed
by strftime()
# @deprecated since pimcore/ecommerce-framework-bundle
v1.1.0, please use `order_parent_path` instead
# NB: this configuration node will be ignored when the
new one is set
parent_order_folder: /order/%%Y/%%m/%%d # deprecated
and discouraged
# Default parent folder for new order items, can use
Carbon date format parameters wrapped by `*` eg. *D*
order_parent_path: /order/*Y*/*M*/*D*
# Options for oder agent
order_agent:
# service ID of order agent factory - builds order
agents individual to each order
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory
# options for order agent factory - available options
vary by factory implementation
factory_options:
agent_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\V7\OrderAgent
# inherits from _defaults
default: ~
# inherits from _defaults, but sets another order folder
otherFolder:
options:
# parent_order_folder: /order_otherfolder/%%Y/%%m/%%d #
deprecated and discouraged
order_parent_path: /order_otherfolder/*Y*/*M*/*D*
ChatGPT
## Order Manager in Pimcore E-Commerce Framework
### Overview
The Order Manager handles all aspects of working with orders, except for
committing them (which is the responsibility of the Commit Order
Processor). The functionalities include:
- Creating orders from carts.
- Storing orders (by default as Pimcore objects).
- Loading orders and order lists.
- Filtering orders.
- Managing orders after they are committed (using Order Agent).
### Configuration
The configuration of the Order Manager is tenant-aware and takes place in
the `pimcore_ecommerce_framework.order_manager` configuration section.
Below is an example configuration:
```yaml
pimcore_ecommerce_framework:
order_manager:
tenants:
_defaults:
# Service ID of the order manager implementation
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager
# Options for the order manager
options:
# Pimcore object class for orders
order_class: \Pimcore\Model\DataObject\OnlineShopOrder
# Pimcore object class for order items
order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem
# Class for order listing
list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing
# Class for order item listing
list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item
# Default parent folder for new orders, parsed by
strftime()
# Deprecated in favor of order_parent_path
# parent_order_folder: /order/%%Y/%%m/%%d # deprecated
# Default parent folder for new order items, can use
Carbon date format parameters wrapped by `*` eg. *D*
order_parent_path: /order/*Y*/*M*/*D*
# Options for the order agent
order_agent:
# Service ID of the order agent factory, which builds
order agents individual to each order
factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory
# Options for the order agent factory, available
options vary by factory implementation
factory_options:
agent_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\V7\OrderAgent
# Tenant configuration, inherits from _defaults
default: ~
# Tenant configuration, inherits from _defaults, but sets
another order folder
otherFolder:
options:
# parent_order_folder: /order_otherfolder/%%Y/%%m/%%d #
deprecated and discouraged
order_parent_path: /order_otherfolder/*Y*/*M*/*D*
```
### Explanation of Configuration Elements
- **order_manager_id:** Service ID for the order manager implementation.
- **order_class:** Pimcore data object class for orders.
- **order_item_class:** Pimcore data object class for order items.
- **list_class:** Class for order listing.
- **list_item_class:** Class for order item listing.
- **order_parent_path:** Default parent folder for new orders using Carbon
date format.
- **order_agent:** Configuration for the order agent, which includes the
factory ID and options for the order agent factory.
### Usage Examples
#### Creating an Order
To create an order based on a cart, you typically use the Commit Order
Processor, which calls the Order Manager:
```php
$checkoutManager = Factory::getInstance()->getCheckoutManager($cart);
$order = $checkoutManager->commitOrder();
```
#### Loading an Order
To load an order, you can use the Order Manager:
```php
$orderManager = Factory::getInstance()->getOrderManager();
$order = $orderManager->getOrderById($orderId);
```
#### Loading Order List
To load and filter order lists:
```php
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->getOrderList();
$orderList->setOrderKey('creationDate');
$orderList->setOrder('DESC');
$orderList->load();
```
### Custom Extensions
Typically, a project-specific implementation might involve extending the
Order Manager or Order Agent to include additional custom fields or
functionalities:
#### Extending Order Manager
For example, to add custom fields to an order:
```php
class CustomOrderManager extends \Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager
protected function applyCustomCheckoutDataToOrder(CartInterface $cart,
AbstractOrder $order): AbstractOrder
$order = parent::applyCustomCheckoutDataToOrder($cart, $order);
$checkout = Factory::getInstance()->getCheckoutManager($cart);
$deliveryAddress = $checkout->getCheckoutStep('deliveryaddress') ?
$checkout->getCheckoutStep('deliveryaddress')->getData() : null;
if ($deliveryAddress) {
$order->setCustomerFirstname($deliveryAddress->firstname);
$order->setCustomerLastname($deliveryAddress->lastname);
$order->setCustomerCompany($deliveryAddress->company);
$order->setCustomerStreet($deliveryAddress->address);
$order->setCustomerZip($deliveryAddress->zip);
$order->setCustomerCity($deliveryAddress->city);
$order->setCustomerCountry($deliveryAddress->country);
$order->setCustomerEmail($deliveryAddress->email);
return $order;
```
#### Extending Order Agent
To integrate specific functionality during order processing:
```php
class CustomOrderAgent extends \Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderAgent
public function customFunction(AbstractOrder $order): void
// Custom functionality
```
### Conclusion
By configuring and extending the Order Manager and Order Agent, you can
effectively manage and customize the order processing workflows in
Pimcore's E-Commerce Framework to suit specific project requirements.
User
Working with Order Lists
The Order List are a one stop API for filtering and listing order objects.
Of course default Pimcore object lists also can be used for listing order
objects. But Order Lists provide additional functionality in terms of
predefined filters etc.
Basic - Get Newest Orders
<?php
// create new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// get the newest 10 orders
$orderList->setOrder( 'order.orderDate desc' );
$orderList->setLimit( 10, 0 );
// iterate
/** @var \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\
OrderListItemInterface $order */
foreach($orderList as $order) {
echo $order->getOrdernumber();
// ALTERNATE: use knp paginator service: PaginatorInterface $paginator
$paginator = $paginator->paginate(
$orderList,
$request->get('page', 1),
10
);
foreach($paginator as $order) {
...
Basic - Using Filter
<?php
// create new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// create date time filter
$filterDate = new \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\
Order\Listing\Filter\OrderDateTime();
$filterDate->setFrom( new DateTime('20.01.2015') );
$filterDate->setTill( new DateTime('31.01.2015') );
// add filter
$orderList->addFilter( $filterDate );
Basic - list Order Items
<?php
// create new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// get only orders that are committed
$orderList->setListType( $orderList::LIST_TYPE_ORDER_ITEM );
$orderList->setOrderState( AbstractOrder::ORDER_STATE_COMMITTED );
Advanced - Custom Condition
<?php
// create new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// e.g. - search for a specify order number
$query = $orderList->getQuery();
$query->where('order.ordernumber = ?', 'ord_554b425dcae53');
// e.g. - search for a user comment
$query = $orderList->getQuery();
$query->where('order.comment like ?', '%hallo world%');
Expert - High Performance
avoid loading of Pimcore object's for higher performance
<?php
// create new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// add all required fields to the select
$orderList->addSelectField(['OrderNumber' => 'order.orderNumber']);
$orderList->addSelectField(['TotalPrice' => 'order.totalPrice']);
$orderList->addSelectField(['Items' => 'count(orderItem.id)']);
Expert - Extended Conditions via Joins
<?php
// e.g. get all orderings for a customer
$orderList->joinCustomer( \Pimcore\Model\DataObject\Customer::classId() );
$orderList->getQuery()->where('customer.id = ?', 12345);
// e.g. filter product number
$orderList->joinProduct( \Pimcore\Model\DataObject\Product::classId() );
$orderList->getQuery()->where('product.productNumber = ?', 'CMD1191');
Generic Filter
Namespace: \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\Order\
Listing\Filter
Filter Description
OrderDateTime Date Range Filter
OrderSearch Search order for a specified keyword
Payment Filter by payment state (ok or fail)
Product Filter by product and its variants
ProductType Filter ordered products for the given class names
CustomerObject Filter orders by given Customer Object
Search Generic search filter for searches against a given DB column
Search\Customer Search for customer name
Search\CustomerEmail Search for customer email
Search\PaymentReference Search for a payment reference
ChatGPT
## Working with Order Lists in Pimcore E-Commerce Framework
The Order List API in Pimcore provides a streamlined way to filter and list
order objects, offering predefined filters and additional functionalities
over the default Pimcore object lists.
### Basic Usage: Get Newest Orders
To get the newest orders, create an order list and set the desired order
and limit.
```php
<?php
// Create a new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// Get the newest 10 orders
$orderList->setOrder('order.orderDate desc');
$orderList->setLimit(10, 0);
// Iterate through the orders
/** @var \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\
OrderListItemInterface $order */
foreach ($orderList as $order) {
echo $order->getOrdernumber();
// ALTERNATE: use knp paginator service: PaginatorInterface $paginator
$paginator = $paginator->paginate(
$orderList,
$request->get('page', 1),
10
);
foreach ($paginator as $order) {
// Do something with each order
?>
```
### Basic Usage: Using Filters
To filter orders by specific criteria, create a filter and add it to the
order list.
```php
<?php
// Create a new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// Create a date time filter
$filterDate = new \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\
Order\Listing\Filter\OrderDateTime();
$filterDate->setFrom(new DateTime('20.01.2015'));
$filterDate->setTill(new DateTime('31.01.2015'));
// Add the filter to the order list
$orderList->addFilter($filterDate);
?>
```
### Basic Usage: List Order Items
To list only order items and filter orders that are committed:
```php
<?php
// Create a new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// Get only orders that are committed
$orderList->setListType($orderList::LIST_TYPE_ORDER_ITEM);
$orderList->setOrderState(AbstractOrder::ORDER_STATE_COMMITTED);
?>
```
### Advanced Usage: Custom Conditions
To apply custom conditions to the order list:
```php
<?php
// Create a new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// Example: Search for a specific order number
$query = $orderList->getQuery();
$query->where('order.ordernumber = ?', 'ord_554b425dcae53');
// Example: Search for a user comment
$query = $orderList->getQuery();
query->where('order.comment like ?', '%hello world%');
?>
```
### Expert Usage: High Performance
To avoid loading Pimcore objects for higher performance:
```php
<?php
// Create a new order list
$orderManager = Factory::getInstance()->getOrderManager();
$orderList = $orderManager->createOrderList();
// Add all required fields to the select
$orderList->addSelectField(['OrderNumber' => 'order.orderNumber']);
$orderList->addSelectField(['TotalPrice' => 'order.totalPrice']);
$orderList->addSelectField(['Items' => 'count(orderItem.id)']);
?>
```
### Expert Usage: Extended Conditions via Joins
To join tables and filter by extended conditions:
```php
<?php
// Example: Get all orders for a customer
$orderList->joinCustomer(\Pimcore\Model\DataObject\Customer::classId());
$orderList->getQuery()->where('customer.id = ?', 12345);
// Example: Filter by product number
$orderList->joinProduct(\Pimcore\Model\DataObject\Product::classId());
$orderList->getQuery()->where('product.productNumber = ?', 'CMD1191');
?>
```
### Generic Filters
The namespace for filters is `\Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing\Filter`. Some of the filters include:
- **OrderDateTime**: Date range filter.
- **OrderSearch**: Search order for a specified keyword.
- **Payment**: Filter by payment state (ok or fail).
- **Product**: Filter by product and its variants.
- **ProductType**: Filter ordered products by the given class names.
- **CustomerObject**: Filter orders by a given customer object.
- **Search**: Generic search filter for searches against a given DB column.
- **Search\Customer**: Search for customer name.
- **Search\CustomerEmail**: Search for customer email.
- **Search\PaymentReference**: Search for a payment reference.
### Conclusion
The Order List API provides a comprehensive tool for managing and filtering
order data in the Pimcore E-Commerce Framework, allowing for efficient
order processing and retrieval through various predefined and custom
filters.
User
Working with Order Agent
The Order Agent is a one stop API for working with orders, e.g. changing
state of orders, modifying quantity of items, etc. and keeps track of these
changes in a change log.
See following examples for how Order Agent can be used:
Change item quantity
<?php
// load order item
$orderItem = DataObject\OnlineShopOrderItem::getById($this-
>getParam('id'));
$order = $orderItem->getOrder();
// create new order agent
$orderManager = Factory::getInstance()->getOrderManager();
$orderAgent = $orderManager->createOrderAgent($order);
// change amount to 5
/** @var \Pimcore\Model\Element\Note $log */
$log = $orderAgent->itemChangeAmount($orderItem, 5);
// add user comment
$log->addData('message', 'text', 'customer has changed the order by
phone');
$log->save();
Changelog Usage
<?php
// load order
$order = DataObject\OnlineShopOrder::getById($this->getParam('id'));
// create new order agent
$orderManager = Factory::getInstance()->getOrderManager();
$orderAgent = $orderManager->createOrderAgent($order);
// get changelog
/** @var \Pimcore\Model\Element\Note $log */
foreach($orderAgent->getFullChangeLog() as $log) {
...
ChatGPT
## Working with Order Agent in Pimcore E-Commerce Framework
The Order Agent provides a comprehensive API for working with orders,
including changing the state of orders, modifying the quantity of items,
and keeping track of these changes in a changelog.
### Change Item Quantity
To change the quantity of an order item:
```php
<?php
// Load order item
$orderItem = DataObject\OnlineShopOrderItem::getById($this-
>getParam('id'));
$order = $orderItem->getOrder();
// Create a new order agent
$orderManager = Factory::getInstance()->getOrderManager();
$orderAgent = $orderManager->createOrderAgent($order);
// Change the amount to 5
/** @var \Pimcore\Model\Element\Note $log */
$log = $orderAgent->itemChangeAmount($orderItem, 5);
// Add user comment
$log->addData('message', 'text', 'customer has changed the order by
phone');
$log->save();
?>
```
In this example:
1. The order item is loaded using its ID.
2. The corresponding order is retrieved from the order item.
3. A new order agent is created using the order.
4. The quantity of the order item is changed to 5 using the
`itemChangeAmount` method.
5. A user comment is added to the changelog entry and saved.
### Changelog Usage
To retrieve and work with the changelog of an order:
```php
<?php
// Load order
$order = DataObject\OnlineShopOrder::getById($this->getParam('id'));
// Create a new order agent
$orderManager = Factory::getInstance()->getOrderManager();
$orderAgent = $orderManager->createOrderAgent($order);
// Get changelog
/** @var \Pimcore\Model\Element\Note $log */
foreach ($orderAgent->getFullChangeLog() as $log) {
// Do something with each log entry
...
?>
```
In this example:
1. The order is loaded using its ID.
2. A new order agent is created using the order.
3. The full changelog of the order is retrieved using the
`getFullChangeLog` method.
4. Each log entry can be processed as needed.
### Summary
The Order Agent API in Pimcore's E-Commerce Framework simplifies managing
order data and tracking changes through a changelog. This makes it easier
to handle various order-related operations programmatically while
maintaining a history of modifications.
User
Tracking Manager
The Tracking Manager enables e-commerce transaction tracking for e-commerce
websites built with the framework. Due to different tracker
implementations, it supports different tracking services.
Current implementations of trackers are
Google Tag Manager (GTM): \\Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\Tracker\GoogleTagManager
Google Analytics Classic: \Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\Tracker\Analytics\Ecommerce
Google Analytics Universal: \Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\Tracker\Analytics\UniversalEcommerce
Google Analytics Enhanced E-Commerce: \Pimcore\Bundle\
EcommerceFrameworkBundle\Tracking\Tracker\Analytics\EnhancedEcommerce
Supported Tracking Actions
The Tracking Manager supports several tracking actions that can be used.
These tracking actions are delegated to the trackers.
Product Impression
Tracks product impression
$trackingManager->trackProductImpression($product)
Product View
Tracks product view (of detail page)
$trackingManager->trackProductView($product)
Category View
Tracks a category page view
$trackingManager->trackCategoryPageView($category)
Cart Product Action Add
Tracks action for adding product to cart
$trackingManager->trackCartProductActionAdd($cart, $product, $quantity)
Cart Product Action Remove
Tracks action for removing product from cart
$trackingManager->trackProductActionRemove($cart, $product, $quantity)
Cart Update
Tracks a generic cart update for trackers not supporting add/remove. This
can be sent on every cart list or cart change.
$trackingManager->trackProductActionRemove($cart, $product, $quantity)
Checkout
Tracks start of checkout with first step
$trackingManager->trackCheckout($cart)
Checkout Step
Tracks checkout step
$trackingManager->trackCheckoutStep($step, $cart, $stepNumber,
$checkoutOption)
Checkout Complete
Tracks checkout complete
$trackingManager->trackCheckoutComplete($order)
There are 2 deprecated actions which are still supported by should be
replaced with their new counterparts:
Product Action Add (use trackCartProductActionAdd instead)
Tracks action for adding product to cart
$trackingManager->trackProductActionAdd($product, $quantity)
Product Action Remove (use trackCartProductActionRemove instead)
Tracks action for removing product from cart
$trackingManager->trackProductActionRemove($product, $quantity)
Be aware: Depending on the used tracking service some of these actions
might not be available. If so, the tracking action is ignored for this
tracker.
Configuration
The configuration takes place in the
pimcore_ecommerce_framework.tracking_manager config section. If no
TrackingItemBuilder is configured, the TrackingItemBuilder will fall back
to the default implementation \Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingItemBuilder. Further information about TrackingItemBuilder
see below.
pimcore_ecommerce_framework:
# tracking manager - define which trackers (e.g. Google Analytics
Universal Ecommerce) are active and should
# be called when you track something via TrackingManager
tracking_manager:
# service ID of tracking manager - the following is the default
value and can be omitted
tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager
trackers:
# enable the core enhanced_ecommerce tracker with default
options
enhanced_ecommerce:
enabled: true
my_custom_tracker:
# use already defined enhanced ecommerce tracker
id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce
# options vary by tracker implementation
options:
template_prefix: App:Tracking/analytics/enhanced
# service id for item builder
item_builder_id: App\Ecommerce\Tracking\TrackingItemBuilder
# List of assortment and checkout tenants where this
tracker should be activated for.
tenants:
# Add list of assortment tenants where the tracker
should be activated for. Empty array means activated for all tenants.
assortment: []
# Add list of checkout tenants where the tracker should
be activated for. Empty array means activated for all tenants.
checkout: []
Tracking Manager With Tenants
The Tracking Manager supports tenants in a different way than the other
framework modules. While with the other modules, the tenant configuration
takes place on the highest level of configuration and each configuration is
only valid for one tenant, the tenant configuration in the tracking manager
takes place within the trackers them self. There a list of assortment and
checkout tenants for which the tracker should be enabled can be provided
(see configuration above).
If nothing is set or an empty array is provided, the tracker is active for
all tenants.
Working with Tracking Manager
For utilizing the Tracking Manager, just call the corresponding methods of
the TrackingManager in your controller. The framework does the rest (adding
necessary code snippets to your view, etc.).
See the following examples
Product Impression
<?php
namespace App\Controller;
use Knp\Component\Pager\PaginatorInterface;
use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;
use Pimcore\Controller\FrontendController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ShopController extends FrontendController
public function listAction(Request $request, TrackingManager
$trackingManager, PaginatorInterface $paginator): Response
// ...
$paginator = $paginator->paginate($products, $request->get('page',
1));
foreach ($paginator as $product) {
$trackingManager->trackProductImpression($product);
// ...
Checkout
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;
class CheckoutController extends AbstractCartAware
public function startCheckoutAction(TrackingManager $trackingManager) {
...
$trackingManager->trackCheckout($this->getCart());
...
Project Specific Data
Adding project specific data to tracking items by extending the
TrackingItemBuilder class. The extending class has to be defined as service
and configured on the tracker configuration (see above).
Example for Additional Data in Product Impressions
Define a custom item builder:
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\ProductInterface;
use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
ProductImpressionInterface;
class TrackingItemBuilder extends \Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingItemBuilder
private static int $impressionPosition = 0;
public function buildProductImpressionItem(ProductInterface $product):
ProductImpression
$item = parent::buildProductImpressionItem($product);
$item->setId($product->getOSProductNumber());
$item->setList($this->getImpressionListName());
self::$impressionPosition++;
$item->setPosition(self::$impressionPosition);
return $item;
}
}
And define it as service:
services:
App\Ecommerce\Tracking\TrackingItemBuilder: ~
External Links
Google Documentation Enhanced E-Commerce
ChatGPT
## Tracking Manager in Pimcore E-Commerce Framework
The Tracking Manager in Pimcore enables e-commerce transaction tracking for
websites built with the framework. It supports various tracking services
through different tracker implementations.
### Supported Tracker Implementations
- **Google Tag Manager (GTM):** `\\Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\Tracker\GoogleTagManager`
- **Google Analytics Classic:** `\\Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\Tracker\Analytics\Ecommerce`
- **Google Analytics Universal:** `\\Pimcore\Bundle\
EcommerceFrameworkBundle\Tracking\Tracker\Analytics\UniversalEcommerce`
- **Google Analytics Enhanced E-Commerce:** `\\Pimcore\Bundle\
EcommerceFrameworkBundle\Tracking\Tracker\Analytics\EnhancedEcommerce`
### Supported Tracking Actions
The Tracking Manager supports various tracking actions, which are delegated
to the trackers. Here are some examples:
- **Product Impression:** Tracks product impression.
```php
$trackingManager->trackProductImpression($product);
```
- **Product View:** Tracks product view (detail page).
```php
$trackingManager->trackProductView($product);
```
- **Category View:** Tracks a category page view.
```php
$trackingManager->trackCategoryPageView($category);
```
- **Cart Product Action Add:** Tracks action for adding product to cart.
```php
$trackingManager->trackCartProductActionAdd($cart, $product, $quantity);
```
- **Cart Product Action Remove:** Tracks action for removing product from
cart.
```php
$trackingManager->trackCartProductActionRemove($cart, $product,
$quantity);
```
- **Cart Update:** Tracks a generic cart update for trackers not supporting
add/remove.
```php
$trackingManager->trackCartUpdate($cart);
```
- **Checkout:** Tracks start of checkout with the first step.
```php
$trackingManager->trackCheckout($cart);
```
- **Checkout Step:** Tracks a checkout step.
```php
$trackingManager->trackCheckoutStep($step, $cart, $stepNumber,
$checkoutOption);
```
- **Checkout Complete:** Tracks checkout completion.
```php
$trackingManager->trackCheckoutComplete($order);
```
### Configuration
Configuration is done in the `pimcore_ecommerce_framework.tracking_manager`
config section. If no `TrackingItemBuilder` is configured, it will fall
back to the default implementation `\\Pimcore\Bundle\
EcommerceFrameworkBundle\Tracking\TrackingItemBuilder`.
```yaml
pimcore_ecommerce_framework:
tracking_manager:
tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager
trackers:
enhanced_ecommerce:
enabled: true
my_custom_tracker:
id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce
options:
template_prefix: App:Tracking/analytics/enhanced
item_builder_id: App\Ecommerce\Tracking\TrackingItemBuilder
tenants:
assortment: []
checkout: []
```
### Tracking Manager with Tenants
The Tracking Manager supports tenants. Each tracker can be configured with
a list of assortment and checkout tenants where the tracker should be
activated. If nothing is set or an empty array is provided, the tracker is
active for all tenants.
### Working with Tracking Manager
To utilize the Tracking Manager, call the corresponding methods in your
controller. The framework handles adding the necessary code snippets to
your view.
#### Example: Product Impression
```php
<?php
namespace App\Controller;
use Knp\Component\Pager\PaginatorInterface;
use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;
use Pimcore\Controller\FrontendController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ShopController extends FrontendController
public function listAction(Request $request, TrackingManager
$trackingManager, PaginatorInterface $paginator): Response
// ...
$paginator = $paginator->paginate($products, $request->get('page',
1));
foreach ($paginator as $product) {
$trackingManager->trackProductImpression($product);
// ...
}
}
```
#### Example: Checkout
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;
class CheckoutController extends AbstractCartAware
public function startCheckoutAction(TrackingManager $trackingManager) {
...
$trackingManager->trackCheckout($this->getCart());
...
```
### Project Specific Data
You can add project-specific data to tracking items by extending the
`TrackingItemBuilder` class. Define the extending class as a service and
configure it in the tracker configuration.
#### Example: Additional Data in Product Impressions
Define a custom item builder:
```php
<?php
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\ProductInterface;
use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
ProductImpressionInterface;
class TrackingItemBuilder extends \Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingItemBuilder
private static int $impressionPosition = 0;
public function buildProductImpressionItem(ProductInterface $product):
ProductImpression
$item = parent::buildProductImpressionItem($product);
$item->setId($product->getOSProductNumber());
$item->setList($this->getImpressionListName());
self::$impressionPosition++;
$item->setPosition(self::$impressionPosition);
return $item;
}
```
And define it as a service:
```yaml
services:
App\Ecommerce\Tracking\TrackingItemBuilder: ~
```
### External Links
- [Google Documentation Enhanced
E-Commerce](https://developers.google.com/analytics/devguides/collection/
analyticsjs/enhanced-ecommerce)
User
Events and Event Listeners
General
This bundle provides additional Events.
It's recommended to have a look into the Pimcore Events and Event Listeners
documentation
Available Events
Ecommerce::Index Service
Ecommerce::Checkout Manager
Ecommerce::Commit Order Processor
Ecommerce::Order Agent
Ecommerce::Order Manager
ChatGPT
## Events and Event Listeners in Pimcore E-Commerce Framework
The Pimcore E-Commerce Framework provides various events to enable
developers to extend and customize the behavior of the e-commerce
processes. It's recommended to review the Pimcore documentation on [Events
and Event
Listeners](https://pimcore.com/docs/10.x/Development_Documentation/
Best_Practices/Event_Listeners.html) for foundational understanding.
### Available Events
Here are the specific events provided by the Pimcore E-Commerce Framework:
### Ecommerce::Index Service
These events relate to the indexing service used for the e-commerce product
data.
### Ecommerce::Checkout Manager
These events are associated with the checkout manager, which handles the
checkout process in the e-commerce system.
### Ecommerce::Commit Order Processor
These events are triggered by the commit order processor, which is
responsible for finalizing orders after payment.
### Ecommerce::Order Agent
These events pertain to the order agent, which is used for managing and
modifying orders after they have been created.
### Ecommerce::Order Manager
These events are linked to the order manager, which handles the overall
order management functionalities, including creating, loading, and
filtering orders.
### Examples
Here are some examples of how to listen to and handle these events in your
Pimcore project.
#### Example: Listening to an Event
First, create an event listener service class:
```php
namespace App\EventListener;
use Pimcore\Event\Model\DataObjectEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProductIndexListener implements EventSubscriberInterface
public static function getSubscribedEvents(): array
return [
'ecommerce.index_service.update' => 'onIndexServiceUpdate',
];
public function onIndexServiceUpdate(DataObjectEvent $event): void
// Your custom logic here
$object = $event->getObject();
// Perform operations with the object
```
Then, register your event listener as a service in your `services.yaml`
file:
```yaml
services:
App\EventListener\ProductIndexListener:
tags:
- { name: 'kernel.event_subscriber' }
```
#### Example: Custom Checkout Step
Suppose you want to add a custom checkout step and perform some actions
when this step is committed:
```php
namespace App\Ecommerce\Checkout;
use Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\AbstractStep;
use Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CheckoutStepInterface;
class CustomCheckoutStep extends AbstractStep implements
CheckoutStepInterface
const PRIVATE_NAMESPACE = 'custom_checkout_step';
public function getName(): string
return 'customcheckout';
public function commit($data): bool
$this->cart->setCheckoutData(self::PRIVATE_NAMESPACE,
json_encode($data));
// Perform custom actions here
return true;
public function getData()
$data = json_decode($this->cart-
>getCheckoutData(self::PRIVATE_NAMESPACE));
return $data;
```
Register the custom checkout step in your configuration:
```yaml
pimcore_ecommerce_framework:
checkout_manager:
tenants:
default:
steps:
customcheckout:
class: \App\Ecommerce\Checkout\CustomCheckoutStep
```
#### Example: Handling Order Commit
Create an event listener to handle actions when an order is committed:
```php
namespace App\EventListener;
use Pimcore\Bundle\EcommerceFrameworkBundle\Event\CommitOrderEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OrderCommitListener implements EventSubscriberInterface
public static function getSubscribedEvents(): array
return [
CommitOrderEvent::NAME => 'onOrderCommit',
];
public function onOrderCommit(CommitOrderEvent $event): void
$order = $event->getOrder();
// Perform actions with the committed order
```
Register the event listener:
```yaml
services:
App\EventListener\OrderCommitListener:
tags:
- { name: 'kernel.event_subscriber' }
```
### Conclusion
Using events and event listeners in the Pimcore E-Commerce Framework allows
for flexible and extensible handling of various e-commerce processes. By
subscribing to specific events, you can customize the behavior and
implement additional logic tailored to your project requirements.
User
I have few questions for the above Pimcore E-commerce Framework, can I ask?
ChatGPT
Absolutely! Feel free to ask any questions you have about the Pimcore E-
Commerce Framework. I'll do my best to provide detailed and accurate
answers.
User
I need answers from the above content.
ChatGPT
Sure, I can help with that. Please go ahead and ask your specific questions
related to the Pimcore E-commerce Framework.
User
give me the list of Out Of The Box features in the Pimcore E-Commerce
Framework
ChatGPT
The Pimcore E-Commerce Framework provides a comprehensive set of out-of-
the-box features designed to help developers build sophisticated e-commerce
solutions. Here is a list of these features:
1. **Data Modeling**:
- Flexible data modeling capabilities to define custom data objects and
relationships.
- Support for product variations and attributes.
- Classification store support for structured data.
2. **Product Indexing**:
- Simple MySQL architecture for direct indexing.
- Optimized architecture with store table for efficient indexing and
updates.
- Support for Elasticsearch for advanced search capabilities.
- Indexing of classification store attributes.
- Support for nested documents in Elasticsearch.
3. **Assortment Management**:
- Two-level assortment tenant system: Assortment Tenant and Assortment
Subtenant.
- Configuration of assortment tenants within the system.
- Mockup objects for performance optimization in product lists.
4. **Pricing and Tax Management**:
- Flexible pricing systems for retrieving and calculating prices.
- Tax management components to handle complex tax calculations.
- Pricing rules and voucher support for marketing actions.
5. **Checkout Process**:
- Modular checkout steps for customized checkout flows.
- Commit order processor for handling order finalization.
- Integration with various payment providers.
- Checkout tenants for different cart and checkout manager
configurations.
6. **Order Management**:
- Order manager for creating and managing orders.
- Order agent for modifying orders and tracking changes.
- Advanced order listing and filtering capabilities.
7. **Cart Management**:
- Multi-cart management for different types of product collections
(e.g., cart, wishlist).
- Session-based and database-based cart implementations.
- Price calculation with cart price calculators.
8. **Tracking and Analytics**:
- Tracking manager for e-commerce transaction tracking.
- Support for multiple tracking services (e.g., Google Tag Manager,
Google Analytics).
- Various tracking actions for product impressions, views, cart actions,
checkout steps, and more.
9. **Payment Integration**:
- Support for multiple payment providers.
- Recurring payments management.
- Handling of payment responses and pending payments.
10. **Events and Event Listeners**:
- Support for additional events specific to e-commerce operations.
- Integration with Pimcore's event system for custom event handling.
11. **Backend Configuration and Management**:
- Comprehensive backend UI for managing product data, tax classes,
voucher series, and more.
- Configuration options for customizing the behavior of various
components.
These features are designed to provide a robust and flexible foundation for
building customized e-commerce solutions using the Pimcore platform.
User
list of features offered in the Pimcore E-Commerce Framework
ChatGPT
The Pimcore E-Commerce Framework offers a wide range of features to support
the development of robust and flexible e-commerce solutions. Here is a
comprehensive list of the features provided:
### General Features:
- **Flexible Data Modeling**: Custom data objects and relationships,
product variations, attributes, and classification store support.
- **Product Indexing**: MySQL and Elasticsearch support, optimized indexing
architecture, classification store attributes indexing, nested documents
support in Elasticsearch.
- **Assortment Management**: Two-level assortment tenant system, mockup
objects for performance optimization.
- **Pricing and Tax Management**: Flexible pricing systems, tax management
components, pricing rules, and vouchers.
- **Checkout Process**: Modular checkout steps, commit order processor,
integration with various payment providers, checkout tenants.
- **Order Management**: Order manager for creation and management, order
agent for modifications and tracking changes, advanced listing, and
filtering capabilities.
- **Cart Management**: Multi-cart management, session-based and database-
based cart implementations, price calculation with cart price calculators.
- **Tracking and Analytics**: E-commerce transaction tracking, support for
multiple tracking services, various tracking actions.
- **Payment Integration**: Multiple payment providers, recurring payments,
handling of payment responses, and pending payments.
- **Events and Event Listeners**: Support for additional events specific to
e-commerce operations, integration with Pimcore's event system.
- **Backend Configuration and Management**: Comprehensive backend UI,
configuration options for customizing component behavior.
### Specific Features:
- **Data Architecture and Indexing Process**: Simple MySQL and optimized
architectures, console commands for indexing.
- **Assortment Tenant Configuration**: Implementation of tenant config,
configuring assortment tenants within the configuration, setting current
assortment tenant for frontend.
- **Filter Service**: Configuration of available filters, filter
definitions, integration with Elasticsearch.
- **Working with Prices**: Decimal value objects for prices, rounding
logic, database storage as DECIMAL data type.
- **Availability Systems**: Retrieving or calculating product availability,
configuration of availability systems.
- **Cart Manager**: Creating carts, adding/removing products, listing
products, cart price calculation, configuration of cart manager.
- **Checkout Manager**: One-stop API for checkout process, modular checkout
steps, committing orders, payment integration.
- **Order Manager**: Creating orders based on carts, order storage, loading
orders, order lists and filtering, working with orders after commit.
- **Tracking Manager**: Product impressions, product views, category views,
cart product actions, checkout tracking.
- **Pricing Rules and Vouchers**: Configurable pricing rules, voucher
series, creating and managing vouchers, applying vouchers to carts.
- **Recurring Payments**: Management of recurring payments, handling
payment failures and successes.
### Integration and Customization:
- **Payment Providers**: Integration with Datatrans, PayPal, Klarna, OGone,
MPay24, PayU, Unzer, Hobex, BS PAYONE.
- **Custom Mockup Object Implementation**: Overwriting `createMockupObject`
method in config implementation.
- **Custom Properties to Cart Items**: Extending `CartItem` implementation,
adding custom properties.
- **Project Specific Data in Tracking**: Extending `TrackingItemBuilder`
class, adding additional data to tracking items.
- **Custom Checkout Steps**: Extending `AbstractStep`, implementing
`CheckoutStepInterface`.
These features enable developers to build highly customized and scalable e-
commerce applications using the Pimcore platform, leveraging its robust
data modeling, indexing, cart management, order processing, and tracking
capabilities.
User
prepare and give me a PPT on the Pimcore E-Commerce Framework to present it
officially
ChatGPT
Sure! Below is an outline for a PowerPoint presentation on the Pimcore E-
Commerce Framework. I'll provide the content for each slide, and you can
use this to create a professional presentation.
---
### Slide 1: Title Slide
**Title:** Introduction to the Pimcore E-Commerce Framework
**Subtitle:** Unlocking the Potential of Flexible and Scalable E-Commerce
Solutions
**Presenter's Name:** [Your Name]
**Date:** [Presentation Date]
---
### Slide 2: Agenda
1. Overview of Pimcore E-Commerce Framework
2. Key Features
3. Data Architecture and Indexing
4. Assortment Management
5. Pricing and Tax Management
6. Checkout Process
7. Order Management
8. Cart Management
9. Tracking and Analytics
10. Payment Integration
11. Customization and Extensibility
12. Q&A
---
### Slide 3: Overview of Pimcore E-Commerce Framework
**Content:**
- Introduction to Pimcore
- E-Commerce Framework Overview
- Benefits of Using Pimcore for E-Commerce
- Flexibility
- Scalability
- Integration Capabilities
---
### Slide 4: Key Features
**Content:**
- Flexible Data Modeling
- Product Indexing
- Assortment Management
- Pricing and Tax Management
- Checkout Process
- Order Management
- Cart Management
- Tracking and Analytics
- Payment Integration
---
### Slide 5: Data Architecture and Indexing
**Content:**
- Simple MySQL and Optimized Architectures
- Console Commands for Indexing
- Support for Classification Store Attributes
- Filtering for Nested Documents
---
### Slide 6: Assortment Management
**Content:**
- Two-Level Assortment Tenant System
- Mockup Objects for Performance Optimization
- Setting Up Assortment Tenants
- Configuration and Management
---
### Slide 7: Pricing and Tax Management
**Content:**
- Pricing Systems and PriceInfo Objects
- Tax Management Components
- Pricing Rules and Vouchers
- Integration with ERP Systems
---
### Slide 8: Checkout Process
**Content:**
- Modular Checkout Steps
- Commit Order Processor
- Integration with Payment Providers
- Checkout Tenants
---
### Slide 9: Order Management
**Content:**
- Creating and Managing Orders
- Order Storage and Retrieval
- Advanced Listing and Filtering
- Working with Orders After Commit
---
### Slide 10: Cart Management
**Content:**
- Multi-Cart Management
- Session-Based and Database-Based Cart Implementations
- Price Calculation with Cart Price Calculators
- Adding Custom Properties to Cart Items
---
### Slide 11: Tracking and Analytics
**Content:**
- E-Commerce Transaction Tracking
- Support for Multiple Tracking Services
- Tracking Actions: Product Impressions, Cart Actions, Checkout Steps
- Custom Tracking Item Builders
---
### Slide 12: Payment Integration
**Content:**
- Integration with Various Payment Providers
- Handling Payment Responses
- Recurring Payments
- Custom Strategies for Handling Pending Payments
---
### Slide 13: Customization and Extensibility
**Content:**
- Custom Mockup Object Implementations
- Extending Decimal Class for Custom Calculations
- Creating Custom Checkout Steps
- Project-Specific Data in Tracking Items
---
### Slide 14: Summary
**Content:**
- Recap of Key Features
- Benefits of Using Pimcore E-Commerce Framework
- Flexibility and Scalability for Any E-Commerce Solution
- Q&A Session
---
### Slide 15: Q&A
**Content:**
- Open the floor for questions from the audience
---
### Slide 16: Thank You
**Content:**
- Thank the audience for their time and participation
- Provide contact information for follow-up questions
---
You can use this outline to create your PowerPoint presentation. Each slide
should have the corresponding content mentioned above, formatted
professionally to fit your presentation style. Let me know if you need
further details or additional content for any of the slides.
User
elaborate the above slides and topics for my understanding to present it
ChatGPT
Sure, here's an expanded version of each slide with detailed explanations
to help you understand the content better and present it effectively:
### Slide 1: Title Slide
**Title:** Introduction to the Pimcore E-Commerce Framework
**Subtitle:** Unlocking the Potential of Flexible and Scalable E-Commerce
Solutions
**Presenter's Name:** [Your Name]
**Date:** [Presentation Date]
---
### Slide 2: Agenda
**Content:**
- **Overview of Pimcore E-Commerce Framework**: Brief introduction to
Pimcore and its E-Commerce capabilities.
- **Key Features**: Highlight the major functionalities and benefits.
- **Data Architecture and Indexing**: Explain the data handling mechanisms.
- **Assortment Management**: Discuss how products are organized and
managed.
- **Pricing and Tax Management**: Cover pricing rules and tax handling.
- **Checkout Process**: Walk through the checkout flow.
- **Order Management**: Detail how orders are managed post-purchase.
- **Cart Management**: Describe cart functionalities.
- **Tracking and Analytics**: Explain how tracking and analytics are
handled.
- **Payment Integration**: Discuss integration with payment providers.
- **Customization and Extensibility**: Highlight the framework's
flexibility.
- **Q&A**: Open the floor for questions.
---
### Slide 3: Overview of Pimcore E-Commerce Framework
**Content:**
- **Introduction to Pimcore**: Pimcore is a leading open-source platform
for managing digital experiences.
- **E-Commerce Framework Overview**: Pimcore's E-Commerce Framework offers
robust tools for building flexible and scalable e-commerce solutions.
- **Benefits of Using Pimcore for E-Commerce**:
- **Flexibility**: Customizable to fit any e-commerce needs.
- **Scalability**: Handles small to enterprise-level e-commerce
solutions.
- **Integration Capabilities**: Easily integrates with existing systems
and third-party services.
---
### Slide 4: Key Features
**Content:**
- **Flexible Data Modeling**: Create custom data structures for products,
categories, and other entities.
- **Product Indexing**: Efficiently index products for fast search and
retrieval.
- **Assortment Management**: Manage different assortments and product
groupings.
- **Pricing and Tax Management**: Implement complex pricing rules and tax
calculations.
- **Checkout Process**: Modular and customizable checkout flow.
- **Order Management**: Comprehensive order handling and processing.
- **Cart Management**: Manage multiple carts and user-specific collections.
- **Tracking and Analytics**: Built-in support for tracking user
interactions and e-commerce events.
- **Payment Integration**: Seamless integration with various payment
providers.
---
### Slide 5: Data Architecture and Indexing
**Content:**
- **Simple MySQL and Optimized Architectures**:
- **Simple MySQL**: Direct transfer of Pimcore object data to the product
index.
- **Optimized Architecture**: Uses a store table for efficient indexing,
asynchronous updates, and better performance.
- **Console Commands for Indexing**: Commands to update the index and
manage indexing structures.
- **Support for Classification Store Attributes**: Index classification
store attributes without separate definitions.
- **Filtering for Nested Documents**: Efficiently query nested documents
for complex data structures.
---
### Slide 6: Assortment Management
**Content:**
- **Two-Level Assortment Tenant System**:
- **Assortment Tenant**: Heavy-weight, independent shop instances.
- **Assortment Subtenant**: Light-weight, subset of products within a
shop instance.
- **Mockup Objects for Performance Optimization**: Lightweight
representations of products to improve performance.
- **Setting Up Assortment Tenants**: Steps to configure assortment tenants,
including tenant config class and service declarations.
- **Configuration and Management**: Define assortment tenants in the
configuration and manage them through the E-Commerce Framework.
---
### Slide 7: Pricing and Tax Management
**Content:**
- **Pricing Systems and PriceInfo Objects**: Customizable pricing systems
that return PriceInfo objects containing calculated prices.
- **Tax Management Components**:
- **OnlineShopTaxClass**: Configure tax classes for different countries
and product groups.
- **TaxCalculationService**: Calculate taxes based on the configured tax
classes.
- **Pricing Rules and Vouchers**:
- **Pricing Rules**: Automatically apply discounts, free shipping, and
other benefits.
- **Vouchers**: Create and manage voucher series, generate tokens, and
apply voucher benefits.
- **Integration with ERP Systems**: Extend default implementations to send
orders to ERP systems or other integrations.
---
### Slide 8: Checkout Process
**Content:**
- **Modular Checkout Steps**: Implement steps like delivery address,
payment options, and order confirmation.
- **Commit Order Processor**: Handles the finalization of the order,
including sending to ERP systems and sending confirmation emails.
- **Integration with Payment Providers**: Seamlessly integrate with payment
gateways for processing payments.
- **Checkout Tenants**: Configure different checkout processes and payment
options based on tenant settings.
---
### Slide 9: Order Management
**Content:**
- **Creating and Managing Orders**: Convert carts to orders and manage them
through the Order Manager.
- **Order Storage and Retrieval**: Store orders as Pimcore objects and
retrieve them as needed.
- **Advanced Listing and Filtering**: Use Order Lists for filtering and
listing orders efficiently.
- **Working with Orders After Commit**: Use Order Agents to modify order
items, track changes, and handle order states.
---
### Slide 10: Cart Management
**Content:**
- **Multi-Cart Management**: Handle multiple carts (e.g., shopping cart,
wish list) for each user.
- **Session-Based and Database-Based Cart Implementations**: Store carts in
user sessions or in the database for persistent storage.
- **Price Calculation with Cart Price Calculators**: Calculate cart totals,
including shipping costs and discounts.
- **Adding Custom Properties to Cart Items**: Extend cart items with custom
properties and manage them through the Cart Manager.
---
### Slide 11: Tracking and Analytics
**Content:**
- **E-Commerce Transaction Tracking**: Track user interactions, product
impressions, and transactions.
- **Support for Multiple Tracking Services**:
- **Google Tag Manager**
- **Google Analytics (Classic, Universal, Enhanced E-Commerce)**
- **Tracking Actions**:
- **Product Impressions**
- **Product Views**
- **Category Views**
- **Cart Actions (Add/Remove)**
- **Checkout Steps**
- **Checkout Completion**
- **Custom Tracking Item Builders**: Extend tracking capabilities to
include project-specific data.
---
### Slide 12: Payment Integration
**Content:**
- **Integration with Various Payment Providers**:
- **Datatrans**
- **PayPal**
- **Klarna**
- **MPay24**
- **Hobex**
- **Handling Payment Responses**: Process payment responses and handle
successful or failed payments.
- **Recurring Payments**: Support for recurring payments and handling
multiple payment attempts.
- **Custom Strategies for Handling Pending Payments**: Implement strategies
to handle pending payments efficiently.
---
### Slide 13: Customization and Extensibility
**Content:**
- **Custom Mockup Object Implementations**: Create custom lightweight
representations of products.
- **Extending Decimal Class for Custom Calculations**: Implement custom
calculation logic while maintaining immutability.
- **Creating Custom Checkout Steps**: Develop project-specific checkout
steps to meet unique requirements.
- **Project-Specific Data in Tracking Items**: Extend tracking items to
include additional data relevant to your project.
---
### Slide 14: Summary
**Content:**
- **Recap of Key Features**: Summarize the major functionalities discussed.
- **Benefits of Using Pimcore E-Commerce Framework**:
- **Flexibility**: Customizable to fit any business needs.
- **Scalability**: Suitable for small to large-scale e-commerce
solutions.
- **Integration**: Easily integrates with existing systems and third-
party services.
- **Q&A Session**: Invite questions from the audience.
---
### Slide 15: Q&A
**Content:**
- **Open the Floor for Questions**: Encourage audience participation and
address their queries.
---
### Slide 16: Thank You
**Content:**
- **Thank the Audience for Their Time and Participation**: Express
gratitude for their attention.
- **Provide Contact Information for Follow-Up Questions**: Share your
contact details for further queries.
---
Use this expanded content to create your PowerPoint presentation. Each
slide should have the corresponding detailed content, formatted to fit your
presentation style. This will help you deliver a comprehensive and engaging
presentation on the Pimcore E-Commerce Framework.
User
Describe in detail below topics from the above Pimcore E-Commerce Framework
Overview of Pimcore E-Commerce Framework
Key Features
Data Architecture and Indexing
Assortment Management
Pricing and Tax Management
Checkout Process
Order Management
Cart Management
Tracking and Analytics
Payment Integration
Customization and Extensibility
ChatGPT
Sure, here’s a detailed description of each topic from the Pimcore E-
Commerce Framework:
### 1. Overview of Pimcore E-Commerce Framework
**Pimcore** is an open-source platform known for its ability to manage
digital experiences, including CMS, DAM, PIM, and e-commerce. The Pimcore
E-Commerce Framework provides a comprehensive set of tools to build
flexible and scalable e-commerce solutions.
**Benefits of Using Pimcore for E-Commerce:**
- **Flexibility**: Highly customizable to meet specific business needs.
- **Scalability**: Capable of handling both small and large-scale e-
commerce applications.
- **Integration**: Easily integrates with other systems, making it a
versatile solution for various business requirements.
---
### 2. Key Features
**Flexible Data Modeling**: Allows creation of custom data structures for
products, categories, and other entities.
- **Product Indexing**: Efficient indexing system for fast search and
retrieval of product data.
- **Assortment Management**: Manage different product assortments and
groupings.
- **Pricing and Tax Management**: Complex pricing rules and tax
calculations are supported.
- **Checkout Process**: Modular checkout process that can be customized.
- **Order Management**: Comprehensive management of orders from creation to
fulfillment.
- **Cart Management**: Ability to manage multiple carts per user, such as
wish lists and shopping carts.
- **Tracking and Analytics**: Built-in support for tracking user
interactions and e-commerce events.
- **Payment Integration**: Seamless integration with various payment
providers.
---
### 3. Data Architecture and Indexing
**Simple MySQL and Optimized Architectures**:
- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to
the product index.
- **Optimized Architecture**: Uses a store table for efficient indexing,
asynchronous updates, and better performance.
**Indexing Commands**:
- Use console commands to update the index and manage indexing structures.
- Support for classification store attributes and filtering for nested
documents.
**Optimized Architecture**:
- Reduces load on the index and improves performance by using a store
table.
- Updates are written to the store table and processed asynchronously.
---
### 4. Assortment Management
**Two-Level Assortment Tenant System**:
- **Assortment Tenant**: Independent shop instances with unique product
sets.
- **Assortment Subtenant**: Subsets of products within a shop instance.
**Mockup Objects**:
- Lightweight representations of products to improve performance by
reducing load times.
- Custom mockup implementations can be created for specific needs.
**Configuration**:
- Set up assortment tenants with specific tenant config classes and service
declarations.
- Manage assortments through the E-Commerce Framework configuration.
---
### 5. Pricing and Tax Management
**Pricing Systems and PriceInfo Objects**:
- Customizable pricing systems that return PriceInfo objects containing
calculated prices.
- Support for complex pricing rules and discount schemes.
**Tax Management**:
- **OnlineShopTaxClass**: Configure tax classes for different regions and
product groups.
- **TaxCalculationService**: Calculate taxes based on configured tax
classes.
**Pricing Rules and Vouchers**:
- Implement rules to automatically apply discounts, free shipping, and
other benefits.
- Create and manage voucher series and tokens to offer promotional
benefits.
---
### 6. Checkout Process
**Modular Checkout Steps**:
- Implement customizable steps like delivery address, payment options, and
order confirmation.
- Each step is responsible for storing and validating necessary data.
**Commit Order Processor**:
- Finalizes the order by sending it to ERP systems, sending confirmation
emails, etc.
- Default implementation creates Pimcore order objects and handles basic
functionalities.
**Checkout Tenants**:
- Allows for different checkout processes and payment options based on
tenant settings.
- Configure different steps and providers for each tenant.
---
### 7. Order Management
**Creating and Managing Orders**:
- Convert carts to orders and manage them through the Order Manager.
- Store orders as Pimcore objects and retrieve them efficiently.
**Advanced Listing and Filtering**:
- Use Order Lists to filter and list orders with predefined filters.
- Load order items and apply advanced filtering conditions.
**Working with Orders After Commit**:
- Use Order Agents to modify order items, track changes, and manage order
states.
- Change item quantities and add custom properties to orders post-commit.
---
### 8. Cart Management
**Multi-Cart Management**:
- Handle multiple carts per user, such as shopping carts, wish lists, and
compare lists.
- Manage carts efficiently with session-based or database-based storage.
**Price Calculation**:
- Cart Price Calculators compute totals, including shipping costs and
discounts.
- Use price modificators to apply cart-level discounts and charges.
**Adding Custom Properties**:
- Extend cart items with custom properties and manage them through the Cart
Manager.
- Customize the cart functionalities to fit specific business needs.
---
### 9. Tracking and Analytics
**E-Commerce Transaction Tracking**:
- Track user interactions, product impressions, and transactions.
- Use tracking actions like product impressions, product views, category
views, cart actions, checkout steps, and checkout completion.
**Support for Multiple Tracking Services**:
- Integrate with Google Tag Manager, Google Analytics (Classic, Universal,
Enhanced E-Commerce).
**Custom Tracking Item Builders**:
- Extend tracking capabilities to include project-specific data.
- Customize tracking actions to fit the specific requirements of the
business.
---
### 10. Payment Integration
**Integration with Payment Providers**:
- Support for various payment providers, including Datatrans, PayPal,
Klarna, MPay24, and Hobex.
**Handling Payment Responses**:
- Process payment responses and handle successful or failed payments.
- Ensure smooth payment flow and secure transactions.
**Recurring Payments**:
- Support for recurring payments and managing multiple payment attempts.
- Implement strategies to handle pending payments efficiently.
---
### 11. Customization and Extensibility
**Custom Mockup Object Implementations**:
- Create lightweight product representations for better performance.
- Implement custom mockup objects tailored to specific business needs.
**Extending Decimal Class**:
- Implement custom calculation logic while maintaining immutability.
- Use Decimal class for precise calculations without floating-point errors.
**Creating Custom Checkout Steps**:
- Develop project-specific checkout steps to meet unique requirements.
- Customize the checkout process to enhance user experience.
**Project-Specific Data in Tracking Items**:
- Extend tracking items to include additional data relevant to your
project.
- Ensure comprehensive tracking and analytics tailored to business needs.
---
Use these detailed descriptions to deepen your understanding of each topic
and present them effectively.
User
Explain me in detail for the below topics in Pimcore E-Commerce Framework
1. Introduction E-commerce Framework
2. Products (Product Index Config.)/Index List Product Service/Elastic
Search
3. Cart Manager
4. Payment Manager/Price Management/Pricing/ Tax Management/Pricing
Rules/Advanced Pricing System
5. Voucher/Offers/Promotions/Promo Codes
6. Customer Account
7. Tracking Manager
8. Checkout Manager
9. Authentication Login/Logout Listeners
ChatGPT
### 1. Introduction to E-commerce Framework
The **Pimcore E-Commerce Framework** is a comprehensive, open-source
platform designed to build flexible and scalable e-commerce solutions. It
is part of the larger Pimcore ecosystem, which includes capabilities for
content management (CMS), digital asset management (DAM), product
information management (PIM), and customer data management (CDP).
**Key Benefits:**
- **Flexibility:** Highly customizable to meet specific business needs.
- **Scalability:** Suitable for small to large-scale e-commerce operations.
- **Integration:** Easily integrates with other systems, enhancing its
versatility.
- **Unified Platform:** Combines multiple functionalities like PIM, DAM,
CMS, and e-commerce in one platform, simplifying data management and
reducing complexity.
### 2. Products (Product Index Configuration) / Index List Product
Service / Elastic Search
**Product Index Configuration:**
- **Data Architecture:** Pimcore supports both Simple MySQL and Optimized
Architectures. The Simple MySQL Architecture transfers Pimcore object data
directly to the Product Index, while the Optimized Architecture uses a
store table for efficient indexing.
- **Indexing Commands:** Console commands are used to update and manage
index structures, ensuring fast and accurate product searches.
**Index List Product Service:**
- This service provides an API for retrieving and filtering products from
the Product Index. The service is tailored to the specific implementation
of the Product Index (e.g., MySQL or Elasticsearch).
**Elasticsearch:**
- **Integration:** Elasticsearch 8 is supported for fast and scalable
search capabilities.
- **Configuration:** Customizable through configuration options like index
settings and client configuration.
- **Reindexing Mode:** Automatically reindexes when necessary to
accommodate changes in data types or schema.
### 3. Cart Manager
**Cart Manager Overview:**
- Responsible for handling all aspects of the shopping cart, including
multiple carts per user (e.g., shopping cart, wish list).
- **Creating Carts:** Carts can be created programmatically and associated
with users or sessions.
- **Adding/Removing Products:** Products can be added or removed from carts
through the Cart Manager API.
- **Price Calculation:** Utilizes Cart Price Calculators to compute totals,
including sub-totals and grand totals, with modifications for discounts,
shipping costs, etc.
- **Configuration:** Defined in the
`pimcore_ecommerce_framework.cart_manager` configuration section,
supporting tenant-specific settings.
### 4. Payment Manager / Price Management / Pricing / Tax Management /
Pricing Rules / Advanced Pricing System
**Payment Manager:**
- Manages payment integrations, supporting various payment providers like
Datatrans, PayPal, Klarna, and more.
- **Workflow:** Involves initializing payment, redirecting to the payment
provider, handling payment response, and committing the order.
**Price Management:**
- **Price Systems:** Configurable pricing systems return PriceInfo objects
containing calculated prices.
- **Tax Management:** Utilizes tax classes (OnlineShopTaxClass) and the
TaxCalculationService to manage and calculate taxes.
- **Pricing Rules:** Define rules for applying discounts, free shipping,
and other benefits automatically.
- **Advanced Pricing System:** Supports complex pricing structures and
custom price calculations.
### 5. Voucher / Offers / Promotions / Promo Codes
**Vouchers:**
- **OnlineShopVoucherSeries:** Manage voucher series, generate tokens, and
define benefits through pricing rules.
- **Integration:** Vouchers can be added to the cart by users and managed
through the cart API.
**Offers and Promotions:**
- Implemented through Pricing Rules, allowing for various marketing actions
like discounts and gift items.
- **Promo Codes:** Managed similarly to vouchers, with tokens and rules
defining their application and benefits.
### 6. Customer Account
**Customer Account Management:**
- **User Data:** Manage customer data, including personal details, order
history, and preferences.
- **Authentication:** Handles login, registration, and account management.
- **Customer-Specific Features:** Support for features like wish lists,
saved carts, and personalized recommendations.
### 7. Tracking Manager
**Tracking E-commerce Transactions:**
- Supports tracking actions such as product impressions, product views,
category views, cart actions, checkout steps, and order completions.
- **Trackers:** Integrates with services like Google Tag Manager, Google
Analytics (Classic, Universal, Enhanced E-Commerce).
- **Configuration:** Set up in
`pimcore_ecommerce_framework.tracking_manager`, enabling specific trackers
for different tenants.
### 8. Checkout Manager
**Checkout Process Management:**
- **Checkout Steps:** Modular steps like delivery address, payment options,
and order confirmation, customizable per project.
- **Commit Order Processor:** Finalizes orders by sending them to ERP
systems, sending confirmation emails, etc.
- **Checkout Tenants:** Allows different checkout configurations for
different scenarios or user types.
### 9. Authentication Login/Logout Listeners
**Authentication Management:**
- **Login/Logout Listeners:** Event listeners that handle actions on user
login and logout.
- **Security:** Ensures secure user authentication and session management.
- **Customization:** Custom listeners can be implemented to extend default
behavior, such as logging activities, updating user data, or triggering
other processes.
These detailed descriptions provide a comprehensive understanding of each
aspect of the Pimcore E-Commerce Framework, helping you effectively present
and utilize its capabilities in your projects.
User
Multi-Language Multi Shop Product Index?
ChatGPT
### Multi-Language Multi-Shop Product Index in Pimcore E-Commerce Framework
Pimcore's E-Commerce Framework is designed to support multi-language and
multi-shop scenarios seamlessly. This capability allows businesses to
manage multiple online stores, each targeting different markets or regions,
and to provide localized content for each market. Here’s an in-depth look
at how this can be achieved:
### 1. Overview
The multi-language, multi-shop functionality in Pimcore leverages its
robust data modeling and indexing capabilities. It ensures that each shop
can have a distinct set of products, languages, and configurations, yet all
managed from a unified backend.
### 2. Product Index Configuration
#### Multi-Language Support
- **Locale-Based Attributes:** Each product attribute can be configured to
support multiple locales. This allows different translations of product
names, descriptions, and other relevant data.
- **Localization:** Content for each product can be localized to meet the
cultural and linguistic needs of different regions.
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
attributes:
name:
locale: '%%locale%%'
type: keyword
```
#### Multi-Shop Support
- **Assortment Tenants:** The framework supports multiple assortment
tenants, which are heavy-weight tenants representing different shop
instances. Each tenant can have completely independent product sets, index
attributes, and even different product index implementations.
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
shop1:
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql
config_options:
client_config:
indexName: 'shop1_index'
shop2:
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
client_config:
indexName: 'shop2_index'
```
### 3. Assortment Management
#### Assortment Tenants
- **Heavy-Weight Tenants:** These tenants allow for completely independent
shop instances within one system. Each shop can have a unique set of
products, attributes, and configurations.
- **Subtenants:** Light-weight tenants within a shop instance allow for
different product assortments within the same shop, using the same product
index but with subsets of products.
### 4. Data Architecture and Indexing
#### Simple MySQL Architecture
- **Direct Indexing:** Pimcore object data is directly transferred to the
Product Index, suitable for simple implementations with fewer product
updates.
#### Optimized Architecture
- **Store Table:** Uses a store table between Pimcore objects and the
Product Index to reduce load on the index and support asynchronous updates.
- **Elasticsearch Integration:** Provides fast and scalable search
capabilities with support for advanced indexing features.
### 5. Implementation Steps
#### Configuration of Assortment Tenants
- **Tenant Config Class:** Implement a tenant config class that defines
which products are available for the tenant and connects to the product
index implementation.
- **Service Declaration:** Declare the tenant config class as a service.
```yaml
services:
MyBundle\Service\MyTenantConfig:
calls:
- [setAttributeFactory, ['@Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\AttributeFactory']]
```
#### Setting Current Assortment Tenant
- **Set in Controllers:** Set the current assortment tenant in application
controllers, especially after customer login, to ensure the correct product
list is used.
```php
$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance();
$environment = $factory->getEnvironment();
$environment->setCurrentAssortmentTenant("shop1_tenant");
```
### 6. Example Code
#### Setting Up Multi-Shop Index
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
shop1:
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
client_config:
indexName: 'shop1_index'
es_client_name: shop1_es_client
shop2:
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8
config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch
config_options:
client_config:
indexName: 'shop2_index'
es_client_name: shop2_es_client
```
#### Localized Product Index
```yaml
pimcore_ecommerce_framework:
index_service:
tenants:
MyEsTenant:
attributes:
name:
locale: '%%locale%%'
type: text
options:
mapping:
type: text
store: true
index: not_analyzed
fields:
analyzed:
type: text
analyzer: english
analyzed_ngram:
type: text
analyzer: my_ngram_analyzer
```
### 7. Key Considerations
- **Performance:** Ensure that the indexing process is optimized for
performance, especially when dealing with large datasets and multiple
tenants.
- **Consistency:** Regularly update and synchronize the product index to
maintain data consistency across different shops and languages.
- **Customization:** Leverage Pimcore’s extensibility to customize the
product index and assortment management according to specific business
requirements.
By following these detailed steps and configurations, businesses can
effectively manage a multi-language, multi-shop e-commerce setup using the
Pimcore E-Commerce Framework. This enables them to provide localized
shopping experiences across different markets while maintaining centralized
control and management of their e-commerce operations.
User
prepare a complete report document on the Pimcore E-Commerce Framework
ChatGPT
## Report on Pimcore E-Commerce Framework
### Table of Contents
1. **Introduction**
2. **Overview of Pimcore E-Commerce Framework**
3. **Key Features**
4. **Data Architecture and Indexing**
5. **Assortment Management**
6. **Pricing and Tax Management**
7. **Checkout Process**
8. **Order Management**
9. **Cart Management**
10. **Tracking and Analytics**
11. **Payment Integration**
12. **Customization and Extensibility**
13. **Multi-Language Multi-Shop Product Index**
14. **Conclusion**
---
### 1. Introduction
The Pimcore E-Commerce Framework is a comprehensive solution designed to
support complex e-commerce operations. It integrates seamlessly with
Pimcore's powerful data management capabilities, providing a robust
platform for managing products, orders, pricing, checkout processes, and
more. This report provides an in-depth look at the various features and
functionalities of the Pimcore E-Commerce Framework.
---
### 2. Overview of Pimcore E-Commerce Framework
The Pimcore E-Commerce Framework offers a flexible and extensible solution
for building and managing e-commerce websites. It supports a wide range of
e-commerce functionalities including product management, cart and checkout
processes, order management, and integration with various payment
providers. The framework is designed to handle multi-language and multi-
shop setups, making it ideal for businesses operating in diverse markets.
---
### 3. Key Features
- **Product Management**: Advanced product indexing and management
capabilities.
- **Cart and Checkout**: Comprehensive cart management and customizable
checkout process.
- **Order Management**: Efficient order creation, storage, and management.
- **Pricing and Tax Management**: Flexible pricing systems and tax
management.
- **Tracking and Analytics**: Integration with tracking tools for detailed
analytics.
- **Payment Integration**: Support for multiple payment providers and
recurring payments.
- **Customization**: Highly extensible to fit specific business needs.
---
### 4. Data Architecture and Indexing
The Pimcore E-Commerce Framework supports two main data architectures for
product indexing: Simple MySQL Architecture and Optimized Architecture.
- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to
the Product Index, suitable for simpler setups.
- **Optimized Architecture**: Utilizes a store table to manage data between
Pimcore objects and the Product Index, reducing load and supporting
asynchronous updates.
Indexing can be performed using the provided Pimcore console commands,
ensuring efficient data management and retrieval.
---
### 5. Assortment Management
The framework supports a two-level Assortment Tenant system:
- **Assortment Tenant**: Heavy-weight tenants for completely independent
shop instances.
- **Assortment Subtenant**: Light-weight tenants within a shop instance,
sharing the same Product Index but with different product subsets.
This structure allows for flexible product assortment management across
multiple shops and product categories.
---
### 6. Pricing and Tax Management
#### Pricing Systems
- **Price Systems**: Responsible for retrieving or calculating prices and
returning PriceInfo objects.
- **Configuration**: Price systems can be customized and mapped to specific
products.
#### Tax Management
- **Tax Classes**: Configured using OnlineShopTaxClass objects to manage
different tax rates and structures.
- **Tax Calculation**: Handled by the TaxCalculationService, ensuring
accurate tax computation based on configured tax classes.
#### Pricing Rules and Vouchers
- **Pricing Rules**: Configurable rules for discounts, promotions, and
other pricing adjustments.
- **Vouchers**: Support for voucher series and tokens, integrated with
pricing rules to offer discounts and promotions.
---
### 7. Checkout Process
The Checkout Manager handles the checkout process, including payment
integration and order commitment. Key components include:
- **Checkout Steps**: Configurable steps for capturing necessary checkout
data.
- **Commit Order Processor**: Manages the finalization of orders, including
ERP integration and order confirmation emails.
---
### 8. Order Management
The Order Manager provides tools for:
- **Order Creation**: Creating orders based on cart data.
- **Order Storage**: Storing orders as Pimcore objects.
- **Order Lists**: Filtering and listing orders using predefined filters.
- **Order Agent**: API for manipulating orders and managing order states.
---
### 9. Cart Management
The Cart Manager handles all aspects of cart functionality:
- **Creating Carts**: Initialize and manage multiple carts per user.
- **Adding/Removing Products**: Manage products within carts.
- **Price Calculation**: Calculate subtotal and total prices, including
price modifications.
- **Checkout Tenants**: Configure different cart and checkout settings
based on active tenants.
---
### 10. Tracking and Analytics
The Tracking Manager integrates with various tracking services to provide
detailed e-commerce analytics:
- **Supported Trackers**: Includes Google Tag Manager, Google Analytics
(Classic, Universal, Enhanced E-Commerce).
- **Tracking Actions**: Product impressions, views, cart actions, checkout
steps, and order completion.
Customization options allow for the addition of project-specific tracking
data.
---
### 11. Payment Integration
The Payment Manager facilitates integration with various payment providers:
- **Supported Providers**: Includes Datatrans, PayPal, Klarna, OGone,
MPay24, Unzer, Hobex.
- **Payment Workflow**: From payment initialization to handling payment
responses and clearing payments.
- **Recurring Payments**: Support for recurring payment setups and
management.
---
### 12. Customization and Extensibility
The Pimcore E-Commerce Framework is highly extensible:
- **Custom Services**: Define custom services for specific functionalities.
- **Event Listeners**: Utilize events and event listeners to customize
behavior.
- **Custom Price and Availability Systems**: Implement custom logic for
pricing and product availability.
---
### 13. Multi-Language Multi-Shop Product Index
The framework supports multi-language and multi-shop setups:
- **Locale-Based Attributes**: Manage product attributes for different
locales.
- **Assortment Tenants**: Configure independent shop instances with unique
product sets and index configurations.
- **Configuration**: Define index configurations for different tenants and
locales to ensure localized content and seamless shop management.
### 14. Conclusion
The Pimcore E-Commerce Framework provides a robust and flexible solution
for managing complex e-commerce operations. Its extensive features, coupled
with the ability to customize and extend functionalities, make it an ideal
choice for businesses looking to deliver a seamless and personalized online
shopping experience across multiple markets and languages.
---
This report provides a comprehensive overview of the Pimcore E-Commerce
Framework, highlighting its key features, architecture, and capabilities.
The framework’s flexibility and extensibility ensure that it can meet the
diverse needs of modern e-commerce businesses.
User
Prepare a report for the understanding of a Business Analyst to conduct
Business Consultation on the Pimcore E-Commerce Framework
ChatGPT
# Business Consultation Report on Pimcore E-Commerce Framework
## Table of Contents
1. **Introduction**
2. **Understanding the Pimcore E-Commerce Framework**
3. **Key Features and Benefits**
4. **Technical Architecture and Data Management**
5. **Assortment Management**
6. **Pricing and Tax Management**
7. **Checkout Process**
8. **Order Management**
9. **Cart Management**
10. **Tracking and Analytics**
11. **Payment Integration**
12. **Customization and Extensibility**
13. **Multi-Language and Multi-Shop Support**
14. **Use Cases and Business Applications**
15. **Conclusion**
---
### 1. Introduction
This report aims to provide a comprehensive understanding of the Pimcore E-
Commerce Framework for a Business Analyst to conduct effective business
consultations. The Pimcore E-Commerce Framework offers a robust and
flexible platform for managing various e-commerce operations, supporting
complex business requirements and customization needs.
---
### 2. Understanding the Pimcore E-Commerce Framework
The Pimcore E-Commerce Framework integrates seamlessly with Pimcore's data
management capabilities, offering a full suite of tools for e-commerce
businesses. It supports product management, cart and checkout processes,
order handling, pricing strategies, and integration with multiple payment
providers.
---
### 3. Key Features and Benefits
- **Product Management**: Efficient product indexing and management with
advanced search capabilities.
- **Flexible Pricing**: Customizable pricing systems and rules for dynamic
pricing strategies.
- **Comprehensive Checkout**: Configurable multi-step checkout process with
payment integration.
- **Order Handling**: Efficient order management and tracking.
- **Analytics and Tracking**: Integration with various tracking tools for
detailed e-commerce analytics.
- **Multi-Language Support**: Manage multiple languages and locales
seamlessly.
- **Extensibility**: Highly customizable to fit specific business needs.
---
### 4. Technical Architecture and Data Management
The Pimcore E-Commerce Framework supports two primary data architectures
for product indexing:
- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to
the Product Index, suitable for simpler setups.
- **Optimized Architecture**: Utilizes a store table to manage data between
Pimcore objects and the Product Index, reducing load and supporting
asynchronous updates.
Indexing can be managed using Pimcore console commands to ensure efficient
data handling.
---
### 5. Assortment Management
Assortment management in the Pimcore E-Commerce Framework is achieved
through a two-level Assortment Tenant system:
- **Assortment Tenant**: Heavy-weight tenants for independent shop
instances with unique products and index attributes.
- **Assortment Subtenant**: Light-weight tenants within a shop instance,
sharing the same Product Index but with different product subsets.
This structure supports flexible product assortment management across
multiple shops and product categories.
---
### 6. Pricing and Tax Management
#### Pricing Systems
The framework supports advanced pricing systems to retrieve or calculate
prices and return detailed price information:
- **Price Systems**: Customizable and mappable to specific products for
complex pricing structures.
- **Pricing Rules**: Configurable rules for discounts, promotions, and
other pricing adjustments.
#### Tax Management
The Tax Management component includes:
- **Tax Classes**: Configured using OnlineShopTaxClass objects to manage
different tax rates and structures.
- **Tax Calculation**: Handled by the TaxCalculationService for accurate
tax computation.
---
### 7. Checkout Process
The Checkout Manager handles the entire checkout process, integrating
payment and finalizing orders. Key components include:
- **Checkout Steps**: Configurable steps for capturing necessary checkout
data.
- **Commit Order Processor**: Manages order finalization, including ERP
integration and order confirmation emails.
---
### 8. Order Management
The Order Manager provides tools for:
- **Order Creation**: Creating orders based on cart data.
- **Order Storage**: Storing orders as Pimcore objects.
- **Order Lists**: Filtering and listing orders using predefined filters.
- **Order Agent**: API for manipulating orders and managing order states.
---
### 9. Cart Management
The Cart Manager handles all aspects of cart functionality:
- **Creating Carts**: Initialize and manage multiple carts per user.
- **Adding/Removing Products**: Manage products within carts.
- **Price Calculation**: Calculate subtotal and total prices, including
price modifications.
- **Checkout Tenants**: Configure different cart and checkout settings
based on active tenants.
---
### 10. Tracking and Analytics
The Tracking Manager integrates with various tracking services to provide
detailed e-commerce analytics:
- **Supported Trackers**: Includes Google Tag Manager, Google Analytics
(Classic, Universal, Enhanced E-Commerce).
- **Tracking Actions**: Product impressions, views, cart actions, checkout
steps, and order completion.
Customization options allow for the addition of project-specific tracking
data.
---
### 11. Payment Integration
The Payment Manager facilitates integration with various payment providers:
- **Supported Providers**: Includes Datatrans, PayPal, Klarna, OGone,
MPay24, Unzer, Hobex.
- **Payment Workflow**: From payment initialization to handling payment
responses and clearing payments.
- **Recurring Payments**: Support for recurring payment setups and
management.
---
### 12. Customization and Extensibility
The Pimcore E-Commerce Framework is highly extensible:
- **Custom Services**: Define custom services for specific functionalities.
- **Event Listeners**: Utilize events and event listeners to customize
behavior.
- **Custom Price and Availability Systems**: Implement custom logic for
pricing and product availability.
---
### 13. Multi-Language and Multi-Shop Support
The framework supports multi-language and multi-shop setups:
- **Locale-Based Attributes**: Manage product attributes for different
locales.
- **Assortment Tenants**: Configure independent shop instances with unique
product sets and index configurations.
- **Configuration**: Define index configurations for different tenants and
locales to ensure localized content and seamless shop management.
---
### 14. Use Cases and Business Applications
The Pimcore E-Commerce Framework can be applied to various business
scenarios, including:
- **B2C E-Commerce**: Comprehensive features for managing a consumer-facing
online store.
- **B2B E-Commerce**: Advanced pricing, tax, and product management
capabilities for business-to-business operations.
- **Multi-Vendor Marketplaces**: Support for multiple vendors and product
assortments within a single platform.
- **International E-Commerce**: Multi-language and multi-currency support
for global e-commerce operations.
---
### 15. Conclusion
The Pimcore E-Commerce Framework offers a robust and flexible solution for
managing complex e-commerce operations. Its extensive features, coupled
with the ability to customize and extend functionalities, make it an ideal
choice for businesses looking to deliver a seamless and personalized online
shopping experience across multiple markets and languages. This report
provides a comprehensive overview of the framework, highlighting its key
features, architecture, and capabilities to aid business analysts in
conducting effective consultations.
User
Prepare a one-source of document for the understanding of a Business
Analyst to conduct Business Consultation on the Pimcore E-Commerce
Framework
ChatGPT
# Business Consultation Document on the Pimcore E-Commerce Framework
## Table of Contents
1. **Introduction**
2. **Overview of Pimcore E-Commerce Framework**
3. **Key Features and Benefits**
4. **Technical Architecture and Data Management**
5. **Assortment Management**
6. **Pricing and Tax Management**
7. **Checkout Process**
8. **Order Management**
9. **Cart Management**
10. **Tracking and Analytics**
11. **Payment Integration**
12. **Customization and Extensibility**
13. **Multi-Language and Multi-Shop Support**
14. **Use Cases and Business Applications**
15. **Conclusion**
---
### 1. Introduction
This document aims to provide a comprehensive understanding of the Pimcore
E-Commerce Framework for Business Analysts. It will facilitate effective
business consultations by detailing the framework's features, architecture,
and capabilities. Pimcore E-Commerce Framework offers a robust and flexible
platform that supports complex business requirements and customization
needs.
---
### 2. Overview of Pimcore E-Commerce Framework
The Pimcore E-Commerce Framework integrates seamlessly with Pimcore's data
management capabilities, providing a comprehensive suite of tools for e-
commerce businesses. It includes product management, cart and checkout
processes, order handling, pricing strategies, and integration with
multiple payment providers.
---
### 3. Key Features and Benefits
- **Product Management**: Efficient product indexing and management with
advanced search capabilities.
- **Flexible Pricing**: Customizable pricing systems and rules for dynamic
pricing strategies.
- **Comprehensive Checkout**: Configurable multi-step checkout process with
payment integration.
- **Order Handling**: Efficient order management and tracking.
- **Analytics and Tracking**: Integration with various tracking tools for
detailed e-commerce analytics.
- **Multi-Language Support**: Manage multiple languages and locales
seamlessly.
- **Extensibility**: Highly customizable to fit specific business needs.
---
### 4. Technical Architecture and Data Management
The Pimcore E-Commerce Framework supports two primary data architectures
for product indexing:
- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to
the Product Index, suitable for simpler setups.
- **Optimized Architecture**: Utilizes a store table to manage data between
Pimcore objects and the Product Index, reducing load and supporting
asynchronous updates.
Indexing can be managed using Pimcore console commands to ensure efficient
data handling.
---
### 5. Assortment Management
Assortment management in the Pimcore E-Commerce Framework is achieved
through a two-level Assortment Tenant system:
- **Assortment Tenant**: Heavy-weight tenants for independent shop
instances with unique products and index attributes.
- **Assortment Subtenant**: Light-weight tenants within a shop instance,
sharing the same Product Index but with different product subsets.
This structure supports flexible product assortment management across
multiple shops and product categories.
---
### 6. Pricing and Tax Management
#### Pricing Systems
The framework supports advanced pricing systems to retrieve or calculate
prices and return detailed price information:
- **Price Systems**: Customizable and mappable to specific products for
complex pricing structures.
- **Pricing Rules**: Configurable rules for discounts, promotions, and
other pricing adjustments.
#### Tax Management
The Tax Management component includes:
- **Tax Classes**: Configured using OnlineShopTaxClass objects to manage
different tax rates and structures.
- **Tax Calculation**: Handled by the TaxCalculationService for accurate
tax computation.
---
### 7. Checkout Process
The Checkout Manager handles the entire checkout process, integrating
payment and finalizing orders. Key components include:
- **Checkout Steps**: Configurable steps for capturing necessary checkout
data.
- **Commit Order Processor**: Manages order finalization, including ERP
integration and order confirmation emails.
---
### 8. Order Management
The Order Manager provides tools for:
- **Order Creation**: Creating orders based on cart data.
- **Order Storage**: Storing orders as Pimcore objects.
- **Order Lists**: Filtering and listing orders using predefined filters.
- **Order Agent**: API for manipulating orders and managing order states.
---
### 9. Cart Management
The Cart Manager handles all aspects of cart functionality:
- **Creating Carts**: Initialize and manage multiple carts per user.
- **Adding/Removing Products**: Manage products within carts.
- **Price Calculation**: Calculate subtotal and total prices, including
price modifications.
- **Checkout Tenants**: Configure different cart and checkout settings
based on active tenants.
---
### 10. Tracking and Analytics
The Tracking Manager integrates with various tracking services to provide
detailed e-commerce analytics:
- **Supported Trackers**: Includes Google Tag Manager, Google Analytics
(Classic, Universal, Enhanced E-Commerce).
- **Tracking Actions**: Product impressions, views, cart actions, checkout
steps, and order completion.
Customization options allow for the addition of project-specific tracking
data.
---
### 11. Payment Integration
The Payment Manager facilitates integration with various payment providers:
- **Supported Providers**: Includes Datatrans, PayPal, Klarna, OGone,
MPay24, Unzer, Hobex.
- **Payment Workflow**: From payment initialization to handling payment
responses and clearing payments.
- **Recurring Payments**: Support for recurring payment setups and
management.
---
### 12. Customization and Extensibility
The Pimcore E-Commerce Framework is highly extensible:
- **Custom Services**: Define custom services for specific functionalities.
- **Event Listeners**: Utilize events and event listeners to customize
behavior.
- **Custom Price and Availability Systems**: Implement custom logic for
pricing and product availability.
---
### 13. Multi-Language and Multi-Shop Support
The framework supports multi-language and multi-shop setups:
- **Locale-Based Attributes**: Manage product attributes for different
locales.
- **Assortment Tenants**: Configure independent shop instances with unique
product sets and index configurations.
- **Configuration**: Define index configurations for different tenants and
locales to ensure localized content and seamless shop management.
---
### 14. Use Cases and Business Applications
The Pimcore E-Commerce Framework can be applied to various business
scenarios, including:
- **B2C E-Commerce**: Comprehensive features for managing a consumer-facing
online store.
- **B2B E-Commerce**: Advanced pricing, tax, and product management
capabilities for business-to-business operations.
- **Multi-Vendor Marketplaces**: Support for multiple vendors and product
assortments within a single platform.
- **International E-Commerce**: Multi-language and multi-currency support
for global e-commerce operations.
---
### 15. Conclusion
The Pimcore E-Commerce Framework offers a robust and flexible solution for
managing complex e-commerce operations. Its extensive features, coupled
with the ability to customize and extend functionalities, make it an ideal
choice for businesses looking to deliver a seamless and personalized online
shopping experience across multiple markets and languages. This report
provides a comprehensive overview of the framework, highlighting its key
features, architecture, and capabilities to aid business analysts in
conducting effective consultations.