I have a Product admin class. The Product entity has a many-to-one relationship with a Category entity, i.e. a product is associated with a category.
In the admin "list" page for products, I need to sort by the category name (alphabetically) that each product is associated with.
Setting the default field to sort by is easy if the field is on the entity itself (see Sonata admin bundle order for how to do this). But I cannot figure out how to sort by a field in a related table.
Any help is appreciated.
It seems a workaround, but it works. You have to add a join overriding createQuery() method, than assign a default sortBy overriding $datagridValues:
<?php
use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery;
class ExpenseAdmin extends Admin
{
protected $datagridValues = array(
'_page' => 1,
'_sort_order' => 'ASC', // sort direction
'_sort_by' => 'c.name' // field name
);
/**
* #return \Sonata\AdminBundle\Datagrid\ProxyQueryInterface
*/
public function createQuery($context = 'list')
{
$query = parent::createQuery($context);
return new ProxyQuery($query
->join(sprintf('%s.category', $query->getRootAlias()), 'c'));
}
}
Asume name is the property of entity Category by wich you want to sort. You may do this in you ProductAdmin.php
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->add('category.name', null, array(
'sortable' => true,
));
...
}
This way you leverage the ordering links in the header of the list, generated by Sonata.
Edit
If you would also like to have a link on the category name in products list to quickly edit the Category entity, assuming you have created a CategoryAdmin class, you should write your code like this:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->add('category', null, array(
'sortable' => 'category.name',
));
...
}
And in your Category class you should implement the __toString() method like this:
public function __toString()
{
return $this->getName();
}
Related
I'm looking to a way to add a textbox filter for searches of facet api in Drupal7. My site has three content type (A,B,C) that is used in searches.
I see that I can activate some filters in Admin -> configuration -> search and metadata -> Search API (edit one and then filters tab), but I can't see one of text. Is there a text field for filter in facet api?
Currently, I use Facet API and Drupal search, but the problem is that if I filter for content A and after I search something ("Andrew" for example) it resets the filter and search in all contents. I would like to filter and if I search something, search on the filtered content, not in a new search.
I have searched on Google, but I don't get a solution. The same problem is reported here, with a temporal solution, but I wnat to know if there is a better solution:
https://www.drupal.org/node/1381524
https://tech-tamer.com/drupal-7-refining-a-faceted-search-with-an-exposed-filter-solved/
Maybe You can deal with urls , reconstruct url from parameters to automatically check facets :
/**
* Implements hook_facetapi_searcher_info().
*
* #see hook_facetapi_searcher_info_alter()
*/
function MYMODULE_facetapi_searcher_info_alter(array &$searcher_info)
{
foreach ($searcher_info as $key => $value) {
if ($value['url processor'] == 'pretty_paths') {
$searcher_info[$key]['url processor'] = 'mymodule_urlprocessor';
}
}
}
/**
* Implements hook_facetapi_url_processors().
*
* #see hook_facetapi_url_processors()
*/
function MYMODULE_facetapi_url_processors()
{
return array(
'mymodule_urlprocessor' => array(
'handler' => array(
'label' => t('My URL processor'),
'class' => 'FacetapiUrlProcessorMyModule',
),
),
);
}
class FacetapiUrlProcessorMyModule extends FacetapiUrlProcessorPrettyPaths {
// overrides methods to construct url
}
In the list field you can make a field editable by setting the attribute "editable" to "true" in the configureListFields action. Is it possible (with onboard sonata admin tools) to make a field editable that contains multiple values as in a one-to-many relation?
Example:
I have a list of pupils listed in the list view. Every pupil has multiple classes listet in the classes column of the pupils list view. Via click on the classes I want a popover open (like it works with a normale string) with a suggest field like you can have it in the edit view.
Using the properties like in the configFormFields action doesn't work:
$listMapper->add(
'classes',null, array(
'editable' => true,
'type' => 'sonata_type_model_autocomplete',
'multiple' => true,
'property' => 'name'
)
);
That snippet is written inside the PupilsAdmin class in the configureListFields action.
Is it possible or do I have to create a custom template?
The documentation doesn't point me in the right direction: https://sonata-project.org/bundles/admin/2-2/doc/reference/field_types.html
If i understand you right, you want to edit a one-to-many relation inline in a list view of sonata. As far as i know, thats only possible for simple types like text, int or choices and so on. They point it out on no 18. in your link
Theses types accept an editable parameter to edit the value from within the list action. This is currently limited to scalar types (text, integer, url...).
So related objects can not be in that list, merely their scalar properties. For all other things you have to write your own template ...
I don't know what you want to achieve with this suggested list, but for me it makes no sense to edit a one-to-many property in the list view like its done in the edit view.
You just need to create new type. Something like "entity"
'header_class' => 'col-lg-1',
'class' => Employee::class,
'editable' => true,
])
Next step is to override fixFieldDescription method in listBuilder and handle it
class EntityListBuilder extends ListBuilder
{
/**
* #var Registry
*/
private $doctrine;
/**
* #param AdminInterface $admin
* #param FieldDescriptionInterface $fieldDescription
*/
public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription)
{
parent::fixFieldDescription($admin, $fieldDescription);
if ($fieldDescription->getType() === 'entity') {
$class = $fieldDescription->getOption('class');
if (!$class) {
throw new RuntimeException("Type entity must contain 'class' argument");
}
$objects = $this->doctrine->getRepository($class)->findAll();
$choices = [];
foreach ($objects as $object) {
$choices[$object->getId()] = $object->__toString();
}
$fieldDescription->setOption('choices', $choices);
$fieldDescription->setType('choice');
}
}
/**
* #param Registry $doctrine
*/
public function setDoctrine(Registry $doctrine)
{
$this->doctrine = $doctrine;
}
/**
* #param string $type
*
* #return string
*/
private function getTemplate($type)
{
return $this->templates[$type] ?? '';
}
Now, you have to override template for your "entity" type
{% extends '#SonataAdmin/CRUD/list_choice.html.twig' %}
{% set value = admin.id(value) %}
It's need to set already chosen value to select box
Okay, last thing is to add our type to xeditable types of Twig
Add it to OverrideServiceCompilerPass :
$definition = $container->getParameter('sonata.admin.twig.extension.x_editable_type_mapping');
$definition['entity'] = 'select';
$container->setParameter('sonata.admin.twig.extension.x_editable_type_mapping', $definition);
And the last one just match your type with template
templates:
types:
list:
...
entity: AppBundle:CRUD:list_entity.html.twig
Now you ready to edit it inline :)
I am using Symfony2.6 with Sonata Admin.In my Entity "Order", i have an array column named "Products". this is "ArrayCollection" type and ManyToMany relation with Product Table
How I can show this field in Sonata Admin listMapper.
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('id')
->add('products')
}
Right now in list It's showing Blank.So How I can show all Products in List Mapper in Order list.
I think you need to pass service name for products admin in 'admin_code' property. Result should look similar to this:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('id')
->add('productProperty', null, array('','admin_code' =>'application.admin.product'))
}
Well, I have a fairly basic problem with Sonata Admin in my Symfony2 project.
I have a "products" list view with every product sold on my web store. On the top right "actions" menu, I have the default actions, with a single action named "Add new".
I just want to add more actions next to "Add new": custom actions like "remove promo prices from all products", or "remove all products evaluations".
I don't want a "batch" action, I want a "global" action leading to a custom DB query.
All I find in the doc is related to batch actions or "single line action". Is there a way to do what I want ?
Thank you for your help !
Create and configure a custom admin extension and override the configureActionButtons(AdminInterface $admin, $list, $action, $object) method to add custom actions:
use Sonata\AdminBundle\Admin\AdminExtension;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Route\RouteCollection;
class CustomGlobalActionsExtension extends AdminExtension
{
public function configureActionButtons(AdminInterface $admin, $list, $action, $object)
{
return array_merge($list, [
['template' => 'admin/custom_action.html.twig']
]);
}
public function configureRoutes(AdminInterface $admin, RouteCollection $collection)
{
$collection->add('custom_action', $admin->getRouterIdParameter().'/custom_action');
}
}
{# app/Resources/views/admin/custom_action.html.twig #}
<a class="btn btn-sm" href="{{ admin.generateObjectUrl('custom_action', object) }}">Custom Action</a>
See also https://sonata-project.org/bundles/admin/2-3/doc/cookbook/recipe_custom_action.html
Is syntax changed a little bit and it is important to call the parent method:
/**
* #param $action
* #param null|object $object
* #return array
*/
public function configureActionButtons($action, $object = null)
{
$buttonList = parent::configureActionButtons($action, $object);
$buttonList['create_custom'] = [
'template' => 'admin/action/button.html.twig'
];
unset($buttonList['not_wanted']);
return $buttonList;
}
How Can I display array value on entitty in sonata admin bundle list action?
I've tried to do something like this:
->add('daysOfWeek', null, array('type' => 'array'))
in configureListFields method but then I get error:
"An exception has been thrown during the rendering of a template ("Notice: Array to string conversion"
You need to add a template for special fields, I don't think there is a such thing as "default" way of displaying array fields.
The anwser was to do it like so:
->add('daysOfWeek', 'array', array('template' => 'WshBackendBundle:EventAdmin:list_days_of_week.html.twig'))
The template method is working well but for simple entity you can use the 'collection' type
I have a Post entity with many tags.
So the $tags variable in the Post entity is collection of Tag.
Now in your PostAdmin:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->addIdentifier('name')
...
->add('tags', ' collection')
...
}
Then you need a toString method in your Tag entity.
function __toString() {
return $this->getName();
}