Skip to main content
Version: 2024.4

Custom Rule Definition

To create a custom rule definition, you need to follow four steps:

  1. Create a new PHP class for your new rule definition;
  2. Register the class as a service;
  3. Create the user interface for your new rule definition;
  4. Register the new rule definition itself.

Create a Custom Rule Definition PHP Class

Let's start by adding a Sample Check rule definition in PHP. Your new rule definition class has to extend the AbstractRuleDefinition:

<?php
declare(strict_types=1);

namespace Foo\Bar;

use Pimcore\Bundle\DataQualityManagementBundle\Installer;
use Pimcore\Bundle\DataQualityManagementBundle\Model\RuleDefinition\AbstractRuleDefinition;
use Pimcore\Bundle\DataQualityManagementBundle\Model\ValidatorResponse;
use Pimcore\Model\DataObject;
use Symfony\Contracts\Translation\TranslatorInterface;

class SampleCheck extends AbstractRuleDefinition
{
protected const FIELD_TYPE = 'sampleCheck';

public function __construct(
private readonly TranslatorInterface $translator
) {
}

public function getType(): string
{
return self::FIELD_TYPE;
}

public function supports(string $type): bool
{
return $type === $this->getType();
}

public function getSuggestion(
array $rule, //the rule definition
string $locale,
array $objectData, //the data of the object passed from the UI
array $ruleData //the data stored in the Data Object which are related to the current rule
): ?string
{
//you can return a string suggestion which will be displayed in the UI:
if (!isset($rule['yourSuggestionField'])) {
return null;
}

return $this->translator->trans(
$rule['yourSuggestionField'],
[],
Installer::TRANSLATION_DOMAIN,
$locale
);

//you can also append additional data to your message:
$message = $this->translator->trans(
'plugin_pimcore_dataqualitymanagement_fixed_suggestion',
[],
Installer::TRANSLATION_DOMAIN,
$locale
);
$message .= ' ' . implode(', ', $ruleData['invalidFields']);

return $message;
}

public function forceRecalculation(): bool
{
return false;
//if true:
//the rule definition will be recalculated for every saved Data Objects (and children)
//every time you save the class definition, even if the data has not changed.
//else:
//the rule definition will be recalculated for every saved Data Objects (and children)
//only if there is a modification in the configuration.
//(behaves like for recommended fields check)
}

public function calculateScore(DataObject\Concrete $dataObject, array $ruleDefinition): ValidatorResponse
{
//your logic here...
return new ValidatorResponse(
true, //true if the rule definition is valid, false otherwise
[], //array of invalid fields
[] //array of additional data (to be used for example in the suggestion)
);
}
}
info

The FIELD_TYPE constant has to match the type in the JS file.

Register the New Class as a Service

After creating the class, it is important to register it as a service and to tag it as pimcore.data_quality_management.rule_definition:

    ...

Foo\Bar\SampleCheck:
tags:
- { name: pimcore.data_quality_management.rule_definition }

...

Create a User Interface for the New Rule Definition

You can then compose a user interface for the new rule definition by creating a JS class that extends pimcore.bundle.dataqualitymanagement.ruleDefinitions.abstractDefinition.

For example:

pimcore.registerNS('foo.bar.sampleCheck');

foo.bar.sampleCheck = Class.create(
pimcore.bundle.dataqualitymanagement.ruleDefinitions.abstractDefinition, {
type: 'sampleCheck',
label: 'sample_check',

//this reflects the default configuration of your fields:
configuration: {
title: '', //mandatory
weight: 1, //mandatory
},
fieldsToCheck: ['title', 'weight'],
fieldsToTranslate: ['title'],

getLayoutFields: function () {
return [
{
xtype: 'textfield',
fieldLabel: t('title'),
name: 'title',
allowBlank: false,
width: 600,
bind: '{title}'
},
{
xtype: 'numberfield',
fieldLabel: t('weight'),
name: 'weight',
allowBlank: false,
bind: '{weight}',
}
]
},
});

foo.bar.sampleCheck.panelName = t('custom sample check');
foo.bar.sampleCheck.type = 'sampleCheck';
caution

As shown in the example above, the title and weight properties are mandatory.

Fields to Translate

You can use fieldsToTranslate to add a translation for the title and/or suggestion labels (fieldLabel) available in your rule definition configuration. The translations will be displayed in the Data Quality Details tab in the Data Object editor.

Suggestion Configuration

You can add a suggestion field to your new rule definition with the following layout:

{
xtype: 'textfield',
fieldLabel: t('suggestion'),
name: 'yourSuggestionField',
allowBlank: false,
width: 600,
bind: '{yourSuggestionField}'
}

This field is optional and should also be called in your rule definition PHP class with the getSuggestion() function.

Data Store

To use the data store, your sampleCheck JS class needs to implement the following function:

//if additional data loading is needed:
initDataStore: function() {
return new Ext.Promise(function (resolve, reject) {
//Whatever you want to do here...
});
}
caution

This function is optional and should be implemented only if the data store is effectively used.

Register the New Rule Definition

After creating the rule definition itself, you can register it via the prepareRuleDefinitionsMenu event. For example, in the startup.js file:

document.addEventListener(pimcore.events.prepareRuleDefinitionsMenu, function (e) {
const definitions = e.detail.definitions;
definitions.push(foo.bar.sampleCheck);
});