Situation
We are running Symfony 2.8 and the latest version of Sonata Admin along with Mongo as a data store. Please consider the following object which has been simplified for the sake of this question; it does work.
class Entry
{
/* @ID */
protected $id;
/* @String */
protected $type;
/* @String */
protected $content;
}
With the above, there will be lots of entries and from the Admin itself, we would like to filter by type.
Here's an example of the dataset
Problem
We can't create a set of selectable filters in the dataGrid function which are UNIQUE for type.
Attempts
Note that where needed, the EntryRepository is included as a namespace at the start of the file
NUMBER 1
With the below, we get the type duplicated many times
->add('type', null, array(), 'document', array(
'expanded' => true,
'class' => 'Application:Entry',
'query_builder' => function(EntryRepository $dr) {
return $dr->createQueryBuilder();
}
))
NUMBER 2
With the below, we get a 500 error with only the message "string". I think this is because when using distinct, Mongo prepares a set of arrays instead of unexecuted QueryBuilder object?
->add('type', null, array(), 'document', array(
'expanded' => true,
'class' => 'Application:Entry',
'query_builder' => function(Entryepository $dr) {
return $dr->createQueryBuilder()
->distinct('type');
}
))
NUMBER 3
The attempt below is to use Map reduce to perform the equivalent of an SQL "GROUP BY" however, the same STRING error as above is provided.
->add('type', '', array(), 'document', array(
'expanded' => true,
'class' => 'Application:Entry',
'query_builder' => function(EntryRepository $dr) {
return $dr->createQueryBuilder()
->group(array(), array('type'))
->reduce('function (obj, prev) { prev.type; }');
}
))
CRUDE WORKAROUND...discouraged
The below is a demonstration using the filter (as listed in the Sonata documentation) and it DOES work...for one type at a time.
->add('type', 'doctrine_mongo_callback', array(
'callback' => function($queryBuilder, $alias, $field, $value) {
if (!$value || $value['value'] == false) {
return true;
}
$queryBuilder
->field('type')->equals('fds');
return true;
},
'field_type' => 'checkbox'
))
Taken this approach, I think I'd have to go ahead and query the whole dataset getting the distinct values for type and then loop around each constructing the filter. This would work but be horribly messy.
QUESTION
What is the "best practise" way of performing this without turning the code in to a ruddy mess? Putting the query in a repository will still go and create a similar effect?
Thanks for reading
I'm posting the answer for anyone else who may be facing the same issue. I realised I was approaching the situation from the wrong angle and instead of any of the above, did the following
/* Prepare the options to be used in the filter */
$tagRepo = $this->getConfigurationPool()->getContainer()->get('repository.tag');
$types = $tagRepo->findTypes();
$choices = array();
/* Create a simple choice compatible array */
foreach ($types as $type) { $choices[$type] = $type; }
/* In the actial filter itself */
$datagridMapper
->add('type', 'doctrine_mongo_choice', array(), 'choice',
array('choices' => $choices))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.