Skip to main content
Version: 2026.2

Customer Save Manager

The customer save manager is responsible for all actions and hooks executed when a customer object is saved. It consists of several parts.

Customer Save Handlers

Customer save handlers are PHP classes executed when a customer is saved. Use them to normalize, validate, optimize, or modify customers on save.

Register customer save handlers as Symfony services tagged cmf.customer_save_handler, so a project can add multiple handlers. Implement the CustomerSaveHandlerInterface, which declares a method for each Pimcore object event (preAdd, postAdd, preUpdate, etc.).

A customer save handler can also fetch the original customer object from the database, which is useful for comparing whether a field changed.

Example service definition

services:

appbundle.cmf.customer_save_handler.normalize_zip:
class: CustomerManagementFrameworkBundle\CustomerSaveHandler\NormalizeZip
tags: [cmf.customer_save_handler]

Built-in Customer Save Handlers

CMF ships with the following customer save handlers, all in the CustomerManagementFrameworkBundle\CustomerSaveHandler namespace. Enable one by adding a corresponding service tagged cmf.customer_save_handler to the container. Check each handler's constructor for its configuration options.

Cleanup\Email

Removes invalid characters from an email field.

NormalizeZip

Normalizes zip codes; for example, A-1010 becomes 1010. It ships with zip correction regexes for several countries, and the logic can be extended for others.

SalutationToGender

Maps a salutation field to a gender field. This can automatically adjust the gender based on the salutation.

RemoveBlacklistedEmails

Sets the email field to an empty value if the given email address is in a defined blacklist.

MarkEmailAddressAsValid

Marks an email address as valid if it has a valid format. Marking as valid means that a special checkbox get checked.

AttributeLogic

Allows to setup a logic for overwriting field values based on other field values.

Example:
appbundle.cmf.customer_save_handler.attribute_logic:
class: CustomerManagementFrameworkBundle\CustomerSaveHandler\AttributeLogic
arguments:
- from: profileStreet
to: street
overwriteIfNotEmpty: true
- from: profileZip
to: zip
overwriteIfNotEmpty: true

In this example "street" will be overwritten if "profileStreet" changes (the same for zip and profileZip). If overwriteIfNotEmpty is set to false the to field will be overwritten only when it's empty.

Important: the to-field's value is overwritten only if the from-field changed during the current save process and the to-field's value did not change.

Automatic Object Naming Scheme

CMF can automatically apply a naming scheme to customer objects based on configured logic. Disable this automatic naming scheme if you do not need it.

Example Configuration

pimcore_customer_management_framework:
customer_save_manager:
enableAutomaticObjectNamingScheme: true

customer_provider:
parentPath: /customers
archiveDir: /customers/_archive
namingScheme: '{countryCode}/{zip}/{firstname}-{lastname}'

With this configuration, CMF automatically saves every customer object under /customers, in subfolders starting with the customer's countryCode, then the zip code as the second level, and gives the object itself a key of {firstname}-{lastname}. CMF adds a postfix automatically if a customer object with the same key already exists in that folder.

Configure two customer folders: parentPath for regular customers, and archiveDir for customers who are unpublished and inactive.

Customer Save Validator

When enabled, the customer save validator throws an exception if the customer is invalid according to its implementation. Catch these exceptions in a try/catch block to check whether a customer is valid. In Pimcore Studio, an error message alerts the user when they try to save an invalid customer.

Example configuration

pimcore_customer_management_framework:
customer_save_validator:
checkForDuplicates: true
requiredFields:
- [email],
- [firstname, name, zip]


customer_duplicates_services:
duplicateCheckFields:
- [email]
- [firstname, lastname, zip, street]

This example validates a customer on save in two ways:

  1. First, it checks whether either the email field or the firstname+name+zip combination is filled in. Define as many field combinations as needed.

  2. Second, CMF also searches for duplicate customers and declines the save if a duplicate exists. Configure the field combinations checked for duplicates independently.

Save Customer with Disabled Hooks

In most cases it's sufficient to just call $customer->save() to save a customer object. Sometimes it's needed to save a customer without validation or without applying for example customer save handlers or segment builders.

The CMF offers a special SaveOptions class to handle the enabled state of all hooks when a customer gets saved.

Caution: only disable parts of the save options if you are sure that it is needed!

Examples

<?php
$customer = Customer::getById(1234);

// Disable all hooks and also Pimcore versioning.
$customer->saveDirty();

// Disable all hooks but enable Pimcore versioning.
$customer->saveDirty(false);

// Globally disable on save segment building and also the segment builder queue
$customer->getSaveManager()->getSaveOptions()
->disableOnSaveSegmentBuilders()
->disableSegmentBuilderQueue();

// Save customer with disabled object naming scheme but let the global state untouched
// (`getSaveOptions(true)` will deliver a cloned instance of the save options)
$saveOptions = $customer->getSaveManager()->getSaveOptions(true)
->disableObjectNamingScheme();
$customer->saveWithOptions($saveOptions);

// Save customer with enabled object naming scheme even if it is disabled by default in the config
$saveOptions = $customer->getSaveManager()->getSaveOptions(true)
->enableObjectNamingScheme();
$customer->saveWithOptions($saveOptions);