symfonydoctrine-ormdoctrinesonata-adminsonata

Modify the query that is used to get the list items after filter has been applied


We are using ULIDs in our Symfony 6 project as data type for the ID of all of our entities. The symfony/uid package helps a lot with that. To quickly build an admin interface, we are using Sonata Admin 4.

Unfortunately, as of now, Sonata Admin is not compatible with ULIDs at all. This affects the entity/model filter for the list view: the filter field correctly shows all the available entities that you can filter by, but the filter is not being applied correctly, because as parameter type in the resulting Doctrine query, the default data type string is used instead of Ulid.

The following code results in a select field being shown which displays all available related entities, but the resulting query uses the ULID of the selected entity as a string instead of a binary value, which results in an empty query result.

protected function configureDatagridFilters(DatagridMapper $datagrid): void
{
    $datagrid->add('subject.relatedEntity', ModelFilter::class);
    // ...
}

In the context of a custom controller method, I found a way to alter the query parameter types by using:

public function myCustomControllerAction(
    ProxyQueryInterface $query, 
    AdminInterface $admin
): Response {
    // Find all parameters that are referencing an 'id' property
    // and change their type to the UlidType of the symfony/uid package
    foreach ($query->getQueryBuilder()->getParameters() as $parameter) {
        if (stripos($parameter->getName(), '_id_') !== false) {
            $parameter->setValue($parameter->getValue(), UlidType::NAME);
        }
    }

    // ...
}

However, there does not seem to be a way to modify the query that is being used to fetch all items for the list view after the filters have been applied, so that I cannot alter the parameter types.

There is the method configureQuery(), but this method seems to be called to create the base query, before the filters are being applied. There also is the method configureFilterParameters(), but this method does not work with the Doctrine query at all.

Until the according issue about Ulid support of Sonata Admin is resolved (https://github.com/sonata-project/SonataAdminBundle/issues/7327): is there a way to easily alter the query that is being used to fetch the items for the list view after the filters have been applied? Or do I have to create my own ModelManager and whatnot?


Solution

  • I found out that it is quite easy to use the CallbackFilter with an EntityType form field, so I just created a custom filter, which may not offer as much flexibility as the built-in ModelFilter would, but it does the job:

    protected function configureDatagridFilters(DatagridMapper $datagrid): void
    {
        $datagrid->add('subject.relatedEntity', CallbackFilter::class, [
            'callback' => function(ProxyQueryInterface $query, string $alias, string $field, FilterData $data): bool {
                if (!$data->hasValue()) {
                    return false;
                }
    
                $qb = $query->getQueryBuilder();
                $qb->andWhere(
                    sprintf(
                        'IDENTITY(%s.%s) = :custom_related_entity_filter_selected_id',
                        $alias,
                        $field
                    )
                );
    
                $qb->setParameter(':custom_related_entity_filter_selected_id', $data->getValue()->getId(), UlidType::NAME);
    
                return true;
            },
            'field_type' => EntityType::class
        ]);
        // ...
    }