Custom query in sonata admin - php

I'm new to sonata and symfony and I was wondering if there is a way to create a custom query for one of the entities in configureFormFileds()?
I need it to build a rather complex admin view over several entities that are many-to-many related via a single intermediate table in a star-like fashion (many joins). My idea was to build a complex query that fetches all the data and then pass it to my form.
I've also tried to map all these relations in doctrine and fetch them one by one in a series of custom forms, but unfortunately, entities must be checked against each other, so that didn't work.

Yes, you can create custom query for Entity. (example for Doctrine)
->add(
'manager',
EntityType::class,
[
'label' => 'Manager',
'class' => 'MainBundle\Entity\Manager',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('m')
->where('m.username LIKE :username')
->setParameter('username', $this->getConfigurationPool()
->getContainer()
->get('security.token_storage')->getToken()->getUser()->getName()
)
->orderBy('m.id', 'ASC');
},
]
)
How create query - lock at the official documentation .

you need to provide some more information to get a precise answer, but regarding your main question:
I'm new to sonata and symfony and I was wondering if there is a way to
create a custom query for one of the entities in
configureFormFileds()?
I can answer. In general this is possible, yes. Check out the query config parameter of the sonata_type_model or the callback option of the sonata_type_model_autocomplete field type.

Related

Optimize query in Laravel Backpack n-n relationships

I am building a backend panel for a website with Laravel Backpack. It is really nice, but I have noticed that relationship queries are very expensive.
I have two models: Product and Center with a many to many relationship between them. In my CenterCrudController I have defined a field this way:
$this->crud->addColumns([
// More fields...
[
'label' => 'Products',
'type' => 'select2_multiple',
'name' => 'products', // the method that defines the relationship in your Model
'entity' => 'products', // the method that defines the relationship in your Model
'attribute' => 'name', // foreign key attribute that is shown to user
'model' => 'App\Models\Product', // foreign key model
'pivot' => true, // on create&update, do you need to add/delete pivot table entries?
],
// More fields...
]);
It works fine, showing a select multiple field with related models. But the query used is SELECT * FROM products, which is highly expensive (table products have thousands of records with about 25 columns).
In this example I only need id and name fields. I am looking for something like Query Builder select() method.
Is there a way for optimizing this type of query?
Thanks in advance!
Not sure if this is actually an answer, but I'll post it anyway.
The best solution (as pointed by #tabacitu) was using select2_from_ajax field. It doesn't slow page load and make an ajax request for retrieving data only when user clicks on the select field.

How to use a many to many relationship in Symfony2

I am working on a Symfony 2 based web app and struggling to create a many to many relationship between to entities:
Each Task entity should be assigned to any number of Categories. Of course each Category can be used by any number of Task entities. While a Task needs to know its Categories the Category class has no relationship back to the Tasks.
Following this tutorial I created:
class Task {
/**
* #ORM\Column(name="categories")
* #ORM\ManyToMany(targetEntity="MyBundle\Entity\Category")
*/
protected $categories;
public function __construct() {
$this->productVariations = new \Doctrine\Common\Collections\ArrayCollection();
...
}
}
Which results in the following SQL table:
CREATE TABLE task ... categories VARCHAR(255) NOT NULL, ...
A new Task is created use a form with the following type:
class TaskType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('categories', EntityType::class, array(
'class' => 'MyBundle:Category',
'choice_label' => 'name',
'multiple' => true,
'expanded' => true,
))
...
}
}
Submitting the form and persiting the new Taskinstance result in a SQL row with the following content in the categoriescolumn:
Doctrine\Common\Collections\ArrayCollection#000000007448a17a0000000048941f2f
What does this mean? Storing the referenced Category entities as array is not normal form but of course valid (in fact I would prefer this solution over adding a relationship table since in practice the number of categories per task will be quite small, thus a third table would be more overhead).
However I would assume that the array stores the IDs of the referenced objects/rows in some form. How would it be possible to store any number of references in a VARCHAR(255) column?
While submitting and persisting creates a DB entry, the Category references are not stored correctly. When I try to re-read this entry, the categories property is empty.
You have redundant column definition. Try to simply remove following line:
* #ORM\Column(name="categories")
Then you need to update you database schema.
This line creates a varchar field in task table which shouldn't be there. Many to many relations are implemented via separate table.
If you want to store ids in a single field instead of separate table, then you will handle it on your own. That's because it won't be able to be a relation anymore. You loose possibility to create foreign key or doing any join queries. Also filtering records will be harder to achieve.
I think you're missing something here.
Like you said, a Task can be associated to many Category(ies) AND the Category class DOES NOT need a relational mapping to the Task class.
All you need in your Task class is a property to reference your Categories.
I think what you're looking for is this.

A best way to protect entity field in Symfony forms

In my Symfony2 app there are users end hotels, for each user it's esay to define his hotels.
In order to list user's hotels I use
class HotelVoter implements VoterInterface
which works fine.
In application there are forms of Order to a Hotel (so order.hotel_id = hotel.id). For this reason there is a field Hotel in Order's form:
$builder->add('hotel', 'entity', array(
'class' => 'AcmeHelloBundle:Hotel',
'property' => 'name',
'query_builder' => ...,
...
));
The problem is that form shows me all existing hotels regardless security voter.
What is the best way to leverage my existing voter. I don't feel like using query_builder for this aim.
Thanks

How to customize entity Field Type in Symfony 2.1 so it uses specific repository method?

I am new to symfony (2.1) and I have simple problem, I want to change the way that "entity Field Type" generates choice list in select tag in form.
In my categoryType.php, in buildForm method I have something like this:
$builder
->add('parent', 'entity', array(
'class' => 'TestAdvBundle:Category',
'property' => 'name',
'label' => 'label.parent',
))
;
This works fine, all Category entities which are persisted in db are present in select tag in generated form. But what I want to do is to slightly change this generated choice list. Actually, I want one "fake" choice in list which represents "root category" and I do not want object that I edit to be listed here (this field is a parent id, and it points to same object type as the edited object is, etc. this field is parent category of category that I edit, so practically I don't want to be able to select self as a parent category).
I guess that this "entity Field Type" uses findAll() repository method to fetch its results. So I made specific findAllForList() method where I return wanted array. But I can not find a way to tell "entity Field Type" to use my repository method instead of findAll().
You can use the Querybuilder option and the empty_field Method provided with the entity field type.
http://symfony.com/doc/master/reference/forms/types/entity.html#query-builder
The querybuilder is explained in the linked URL under "Using a Custom Query for the Entities"

One-to-one association in form?

In symfony 2.0, how to create a drop down list using one-to-one association in form? Can you guys put good example please?
I will try to answer your question the way I understand it. Let's say I have a Faculty object bound to a single University object. So in the form used to create or edit a faculty, I display a combo box of all the university in the database and the user choose one among them. There is one special Symfony field type that does exactly this: the entity type. Below is the code of the buildForm method that I use in my FacultyType object used to create the faculty form:
// Application\AcmeBundle\Form\Type\FacultyType
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name');
$builder->add('university', 'entity', array(
// The class of the entity used as a combo box item
'class' => 'AcmeBundle:University',
// The property of the entity displaying the entity as text
'property' => 'name',
// The query builder used to populate the combo box, accepts
// a QueryBuilder object or a \Closure like below
'query_builder' => function(EntityRepository $repository) {
// This will return a query builder selecting all universities
return $repository->createQueryBuilder('u');
}
));
}
Note: There are other properties that can be set for the entity field type, I invite you to take a look at this page for more information on it.
Rendered, this will show a combo box with all the universities I have set in the database. When the user save the form, the university chose is assigned to the faculty object bound to the form via a setter. You could probably render a drop-down list instead of a combo box. If you need to select multiple entities, the 'multiple' option of the field type entity could be useful.
This being said, the example I showed is not a One-to-One relation but rather a Many-to-One for the Faculty object and a One-to-Many for the University object. A One-to-One relation would be something more like a relation where a University has a unique Address. In this case, a combo box wouldn't be useful since the university can only have one adress so a sub-form would be more appropriate. If it has many adresses, then it becomes a One-to-Many relation like the relation between the university and its faculties.
Not sure if this will answer your question correctly but I hope it will lead you to a final solution.
Regards,
Matt
You need to use the entity field type in Symfony2. A good example is found at http://symfony.com/doc/current/reference/forms/types/entity.html

Categories