setQueryBuilder sort by name easy admin - symfony

I am developping a Symfony 5.4 application with easy admin (v3.5). I have an entity Article and an entity Category. I have a ManyToMany relationship between my two entities. In my easy admin Article crud controller, I can create new Article entities and add a Category to my entity. Everything works fine. Now what I would like to do is to sort the result given by the select tag for my Category association by name.
In my code i have tried this :
//App\Controller\Admin\ArticleCrudController.php
AssociationField::new('categories')->setQueryBuilder(
function (QueryBuilder $queryBuilder) {
return $queryBuilder->getEntityManager()->getRepository(Category::class)->findBy([], ['name' => 'ASC']);
}
)->setFormTypeOptions([
"by_reference" => false,
]),
based on easy admin association field documention.
When i dump my $queryBuilder line, i do have all my entites sorted by name. But when I open the select tag, they do not appear sorted. (I would expect "Espace métiers" to appear first, then "Gourvernance et pilotage" and so on).
I have noticed that the documentation I am using is for version 4.x and that mine is 3.5 but as I have a result when I dump I am still asking just in case.

Related

How do I query a Drupal Shortcut (8.x/9.x) by its URL or Menu Path?

We're rolling out an update to an in-house Drupal installation profile, and one of the menu paths that is used frequently is getting changed. Most of our installations reference that menu path in a shortcut (via the "Shortcut" module in core). In an update hook, we'd like to be able to query for those shortcuts and update them.
It feels like this should be straightforward, but for some reason we're finding it difficult to query for shortcuts by their url. We can query them by title, but that seems fragile (since the title could be different between installations, might be different by localization, etc.).
We tried the following, but this lead to the error message 'link' not found:
// This does NOT work.
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link' => [
'internal:/admin/timeline-management',
],
]);
// This works, but is fragile.
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'title' => 'My shortcut',
]);
Based on the code in \Drupal\shortcut\Entity\Shortcut::baseFieldDefinitions() and \Drupal\shortcut\Controller\ShortcutSetController::addShortcutLinkInline() it's obvious that Shortcut entities have a property called link that can be set like an array containing a uri key, yet it does not seem possible to query by this property even though it's a base field.
Looking at the database, it appears that Drupal stores the URL in a database column called link__uri:
TL;DR That means that this works:
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link__uri' => 'internal:/admin/old/path',
]
);
Read on if you want to know the subtle reason why this is the case.
Drupal's database layer uses pluggable "table mapping" objects to tell it how to map an entity (like a Shortcut) to one or more database tables and database table columns. The logic for generating a column name for a field looks like this in the default table mapping (\Drupal\Core\Entity\Sql\DefaultTableMapping):
As shown above, if a field indicates it allows "shared" table storage, and the field has multiple properties (uri, title, etc.), then the mapping flattens the field into distinct columns for each property, prefixed by the field name. So, a Shortcut entity with link => ['uri' => 'xyz']] becomes the column link__uri with a value of xyz in the database.
You don't see this often with entities like nodes, which is why this seems strange here. I'm usually accustomed to seeing a separate database table for things like link fields. That's because nodes and other content entities don't usually allow shared table storage for their fields.
How does the mapping determine if a field should use shared table storage? That logic looks like this:
So, the default table mapping will use shared table storage for a field only under specific circumstances:
The field can't have a custom storage handler (checks out here since shortcuts don't provide their own storage logic).
The field has to be a base field (shortcuts are nothing without a link, so that field is defined as a base field as mentioned in the OP).
The field has to be single-valued (checks out -- shortcuts have only one link).
The field must not have been deleted (checks out; again, what is a shortcut without a link field?).
This specific set of circumstances aren't often satisfied by nodes or other content entities, which is why it's a bit surprising here.
We can confirm this by using Devel PHP to ask the table mapping for shortcuts directly, with code like the following:
$shortcut_table_mapping =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->getTableMapping();
$efm = \Drupal::service('entity_field.manager');
$storage_definitions = $efm->getFieldStorageDefinitions('shortcut');
$link_storage_definition = $storage_definitions['link'];
$has_dedicated_storage = $shortcut_table_mapping->requiresDedicatedTableStorage($link_storage_definition);
$link_column = $shortcut_table_mapping->getFieldColumnName($link_storage_definition, 'url');
dpm($has_dedicated_storage, 'has_dedicated_storage(link)');
dpm($link_column, 'link_column');
This results in the following:

How to store array of key => value data in on ORM and allow edits via Sonata admin bundle

Coming over from Python to do an application in SF2 and would love some help
I need to create a list of books, this has been easy and Sonata admin bundle has been really easy to setup but now I'm stuck one one section
I need the following fields:
Title
ie. Harry Potter
Description
ie. Book about wizards
Themes
ie. ['Animals' => ['Donkey', 'Cat'], 'Seasons' => ['Winter', 'Summer']]
Grammar
ie. ['Possessive pronoun' => ['my']]
The Themes and Grammar I would identify as:
Area
Target: The target (string)
Examples: list of examples (array)
Is there any Doctrine & Sonata admin related data structure that would be good to use in this situation? I do not need the "areas" to be their own models but would like to list each area target and it's examples on a template.
Thankyou!
The simplest solution is to store Area as an Entity and also Example as an entity. Then you can make many-to-one relations called "grammar" and one-to-many relation called themes both pointing to Area entity and also one-to-many relation in Area entity that points to Example entity. In Area entity I advise you to write __toString function in Area Entity. This function can return string composed with target and examples. This will let you print Area properly - for example on sonata admin list.
If you build query in Sonata Admin make sure you extend default query with left joins to Area and Example entities.

symfony2 relation between two entities

i am started to learn symfony2, Here i have some basic doubts on entity relations. Totally i have two entities 1.Admission.php and 2.Mstcity.php , just i wanna make relation between these two entities.
mysql Table structure:1.admission= id, name , mst_city_id 2. mst_city = id,city_name .. just i am having simple admission form. in that form i need to load the city_name select box . the relation id is in admission table mst_city_id is foreign key of mst_city table .
admission.mst_city_id=mst_city.id ...... > need city_name by this matching
just help me to understand this process
There's no point for me to repost here the symfony docs, so go ahead and read them HERE There are examples in the docs that show exactly what you want to do.
Assuming you have proper Associations set in place, you can just add the field with entity as widget type
$builder->add('mst_city_id', 'entity', array(
'class' => 'BundleName:mst_city',
'property' => 'city_name',
));
You should check which type of relations you use -One2One, One2Many, Many2Many
Define relations in mappers/annotations and check for owned side
Create form types and bind data from it to entities
Persist and flush entities

want to save multiple records against one entity using sonata admin bundle

I'm using sonata admin bundle and want to save multiple records against one entity. for example; I have three fields in my Entity (id, project, issues). suppose that a project has number of issues, I'm using multiple selection for the issues field, issues has ManyToOne relation with Issue entity, project has ManyToOne relation with Project entity, i expecting prject_issues table something like this after save,
id | project| issues
--------------------
1 | 2 | 23
2 | 2 | 78
3 | 2 | 45
4 | 2 | 64
I'm very new to sonata admin and symfony2, how could I achieve this?
Create three entities: Project, Issue and ProjectIssue. Create three admin classes for each of the entities. Create Doctrine #ORM\OneToMany(targetEntity="ProjectIssue", mappedBy="project", cascade={"persist"}, orphanRemoval=true) relation in Project. Create two ManyToOne relations from ProjectIssue to Project and to Issue. Use app/console doctrine:generate:entities command to generate correct setters and getters for one-to-many relation. Remember to add $projectIssues->setProject($this); in Project::addProjectIssue($projectIssues) method. Finally, do ->add('issues', 'sonata_type_collection', array('by_reference' => null), array('edit' => 'inline','inline' => 'table')) in ProjectAdmin, and ->add('issue') in ProjectIssueAdmin.
This will get you close to solution. Remember to define __toString() methods in your entities.
You've to create (at least) two entities, lets name them Project and Issue, Project should be set up to have relationship OneToMany with Issue.
Having done that you should create admin classes for both entities and set them up according to SonataAdmin documentation. If you want only one of them to be directly accessible you might add show_in_dashboard set on false argument in service definition.
Next you'll wish to add this in your ProjectAdmin
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('issues', 'sonata_type_collection', ['by_reference' => null],
['edit' => 'inline','inline' => 'table']
)
}
You should be able to find reasons why by_refference and other arguments are set up like this in SonataAdmin docs.
If the above snippet does not work try adding admin_code pointing on the IssueAdmin service in the last argument.

Add a search form in a manyToMany Relation interface

How to implement a search form in a many to many relation between entities.
I want to search items from an entity before to add them to my other entity. I am using a long list of items (product) that i need to link to Shops and i can't use a simple listbox to select my items.
I need you to point me to a tutorial or any explaination to deal with this interface problem.
The goal is to use a minimum of javascript
I would suggest to create an view where you could select a category or define your search condition. And a second View where you only display products by the previously selected condition. In your second view you could use an entity Field Type ( http://symfony.com/doc/current/reference/forms/types/entity.html#query-builder ) and provide a custom query for the entities like:
use Doctrine\ORM\EntityRepository;
// ...
$builder->add('users', 'entity', array(
'class' => 'AcmeHelloBundle:Product',
'query_builder' => function(ProductRepository $er) {
return $er->createQueryBuilder('p')
->where('p.category = 1);
},
));
This solution doesn't require JavaScript at all.
I spent lot's of time trying to figure out the best solution to make the compromise between re-usability, performance and ergonomy and i found a nice solution
I did this way :
I created a custom form field that show a collection like entity field type but i pass field names that I want to show in a nice table :
->add('products','reflist',array(
'columns'=>array('name','cost','description'),
'actions'=>array('select'=>true,'remove'=>true),
'entityName'=>'VendorProductBundle:Product',
'searchForm'=> 'Vendor\ProductBundle\Form\ProductSearchType'
));
Then I created a generic searching service that takes in input the entity to search on. The result is sent in a popup paginated.
Finally, I created a controller related to my new field to manage actions like add, remove
Thats's it for the logic.
I can't really share the work since it is really dependent of my framework (depend of search service, layout,etc...)

Resources