The Problem Every Pimcore Developer Faces
You need a calculated field that displays a product SKU in uppercase. Simple, right?
Until now, you had to write this:
<?php
namespace App\Calculator;
use Pimcore\Model\DataObject\Concrete;
use Pimcore\Model\DataObject\ClassDefinition\CalculatorClassInterface;
use Pimcore\Model\DataObject\Data\CalculatedValue;
class UppercaseSkuCalculator implements CalculatorClassInterface
{
public function compute(Concrete $object, CalculatedValue $context): string
{
return strtoupper($object->getSku());
}
public function getCalculatedValueForEditMode(
Concrete $object,
CalculatedValue $context
): string {
return $this->compute($object, $context);
}
}
25 lines of code for strtoupper().
Need to trim whitespace? Another calculator class. Format a date? Another class. Convert to lowercase? You get the idea.
The Solution: Expression Functions (Now in Pimcore Core)
We've contributed a feature to Pimcore that lets you register expression functions once and use them everywhere. No more calculator classes for simple operations.
Live Code: See the actual implementation in:
- Pimcore Core PR #18754 - The feature addition to Pimcore
- Torq Skeleton PR - Generic expression providers we added to our skeleton repo
How It Works
1. Register Functions Once
Create a provider with the functions you need:
<?php
namespace App\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
class BasicExpressionProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions(): array
{
return [
new ExpressionFunction(
"upper",
function ($str) {
return sprintf("strtoupper(%s)", $str);
},
function ($variables, $value) {
return strtoupper($value);
}
),
new ExpressionFunction(
"trim",
function ($str) {
return sprintf("trim(%s)", $str);
},
function ($variables, $value) {
return trim($value);
}
),
];
}
}
2. Register as Service
services:
App\ExpressionLanguage\BasicExpressionProvider:
tags:
- { name: 'pimcore.calculated_value.expression_language_provider' }
3. Use Everywhere
Now in ANY calculated field:
upper(object.getSku())
lower(object.getCode())
trim(object.getName())
Add Your Own Functions
Need more functions? Add them to your provider:
// SEO-friendly slug
new ExpressionFunction(
'slug',
function ($str) {
return sprintf('preg_replace("/[^a-z0-9-]/", "-", strtolower(%s))', $str);
},
function ($variables, $value) {
$slug = strtolower(trim($value));
return preg_replace('/[^a-z0-9-]+/', '-', $slug);
}
),
// Format price with currency
new ExpressionFunction(
'price',
function ($amount, $symbol = '$') {
return sprintf('%s . number_format(%s, 2)', $symbol, $amount);
},
function ($variables, $amount, $symbol = '$') {
return $symbol . number_format($amount, 2);
}
),
// Date formatting
new ExpressionFunction(
'format_date',
function ($date, $format = '"Y-m-d"') {
return sprintf('%s ? %s->format(%s) : ""', $date, $date, $format);
},
function ($variables, $date, $format = 'Y-m-d') {
return $date ? $date->format($format) : '';
}
),
When to Still Use Calculator Classes
Keep calculator classes for:
- Complex business logic requiring multiple steps
- Operations needing dependency injection
- External API calls or database queries
Use expression functions for:
- String transformations (upper, lower, trim, slug)
- Number formatting (currency, percentage)
- Date formatting
- Any single-line transformation
Try It In Your Project
- Copy the BasicExpressionProvider code above (or write your own functions)
- Register it in your services.yaml with the tag: pimcore.calculated_value.expression_language_provider
- Clear cache: php bin/console cache:clear
- Start using the functions in your calculated fields!
That's it. No more calculator classes for simple operations.
This feature is available in Pimcore 2025.4 and later. See the official documentation for more details.