Precondition Filter
Precondition filters are used to filter the list of available element when a scheduled task is executed. This is useful if you want to limit the list of elements that should be processed by a scheduled task.
Implementing a Precondition Filter
To implement your own precondition filter you must extend AbstractPreconditionFilter
. The abstract class implements the PreconditionFilterInterface
and specifies an abstract method configureCondition()
. You have to implement all the interface methods and the abstract method of the abstract class.
Example:
<?php
declare(strict_types=1);
namespace App\Services\PreconditionFilter;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\ConditionObject;
class MyCustomFilter extends AbstractPreconditionFilter
{
// the name is used to display it in the config
public function getName(): string
{
return 'My Custom Filter';
}
// if you want the condition only to apply for a specific type
public function isValidForType(string $type): bool
{
return $type === 'object'; // or 'asset' or 'document'
}
// you must create a new ConditionObject here with first query and params as input params
// you have to either use placeholder ? or named params like in the example below:
protected function configureCondition(): void
{
$this->conditionObject = new ConditionObject('id = :id', ['id' => 42]);
}
}
Register a Precondition Filter
Every precondition filter must be registered with the pimcore.copilot.automation_action.precondition_filter tag, e.g. in services.yaml. Registering a class without extending the AbstractPreconditionFilter will result in an exception.
App\Services\PreconditionFilter\MyCustomFilter:
tags: ['pimcore.copilot.automation_action.precondition_filter']
Usage Examples for More Complex Conditions
In case you need a more complex query for your precondition, you can always inject other services into the precondition filter.
The following examples show a variety of query builder usages:
V8 Engines Only
You can use the query builder here to execute a query to get only object ids for which the car has a V8 engine.
The result is then used in the condition like the following: id IN (17, 42, 73)
.
<?php
declare(strict_types=1);
namespace App\Services\PreconditionFilter;
use Doctrine\DBAL\Exception;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\ConditionObject;
use Pimcore\Bundle\StaticResolverBundle\Db\DbResolverInterface;
class V8 extends AbstractPreconditionFilter
{
public function __construct(private readonly DbResolverInterface $dbResolver)
{
parent::__construct();
}
/**
* @throws Exception
*/
protected function configureCondition(): void
{
$builder = $this->dbResolver->getConnection()->createQueryBuilder();
$builder
->select('id')
->from('object_brick_query_Engine_CAR')
->where('cylinders = :v8')
->setParameter('v8', 8);
// execute the query builder and use the ids for a sub select
$ids = array_map(static fn($value) => $value, [...$builder->executeQuery()->iterateColumn()]);
$this->conditionObject = new ConditionObject(
'id IN (:ids)',
['ids' => $ids]
);
}
public function getName(): string
{
return 'V8 Engines';
}
public function isValidForType(string $type): bool
{
return $type === 'object';
}
}
Reworked Cars and Soon Available
If you do not want to execute a query beforehand, you can also use the query builder to get a SQL sub-query.
In this case, you can add the parameters to the ConditionObject
params. The sub-query is then executed when the listing is loaded.
<?php
declare(strict_types=1);
namespace App\Services\PreconditionFilter;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\ConditionObject;
use Pimcore\Bundle\StaticResolverBundle\Db\DbResolverInterface;
class Reworked extends AbstractPreconditionFilter
{
public function __construct(private readonly DbResolverInterface $dbResolver)
{
parent::__construct();
}
protected function configureCondition(): void
{
$builder = $this->dbResolver->getConnection()->createQueryBuilder();
$builder
->select('id')
->from('object_brick_query_SaleInformation_CAR')
->where('`condition` = :condition AND (`availabilityType` = :availabilityTypeDays OR `availabilityType` = :availabilityTypeWeeks)');
// build sql with named parameters and inject named parameters into the condition object parameters
$this->conditionObject = new ConditionObject(
"id IN ({$builder->getSql()})",
[
'condition' => 'reworked',
'availabilityTypeDays' => 'couple-days',
'availabilityTypeWeeks' => 'couple-weeks'
]
);
}
public function getName(): string
{
return 'Reworked available in a couple of days/weeks';
}
public function isValidForType(string $type): bool
{
return $type === 'object';
}
}
(Not) Null Check
If you want to check if a field is (not) null, you can use the following example:
<?php
declare(strict_types=1);
namespace App\Services\PreconditionFilter;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\CopilotBundl\AutomationAction\PreconditionFilter\ConditionObject;
final class NotNullCheck extends AbstractPreconditionFilter
{
public function __construct()
{
parent::__construct();
}
protected function configureCondition(): void
{
$this->conditionObject = new ConditionObject(
"title IS NOT NULL",
['title' => ''],
);
}
public function getName(): string
{
return 'Example implementation for a not null check.';
}
public function isValidForType(string $type): bool
{
return $type === 'object';
}
}