Is there any way to show/hide actions based on the underlying entity? For example, I need to show the delete action of a Category entity if and only if it doesn't have any children post.
I tried to remove that from configureActions method in my CRUD controller, but I haven't access to the AdminContext object when that method is being called.
How can I do that?
After tracing in EasyAdmin's code base I found this solution:
Consider I have a Category entity with a OneToMany relation to posts. I need to show delete action of each category if the category doesn't have any post.
public function configureActions(Actions $actions): Actions
{
$action = parent::configureActions($actions)->getAsDto(Crud::PAGE_INDEX)->getAction(Crud::PAGE_INDEX, Action::DELETE);
if (!\is_null($action)) {
$action->setDisplayCallable(function (Category $category) {
return $category->getPosts()->count() === 0;
});
}
return $actions;
}
Related
I'm learning Symfony and EasyAdmin, my next task on the list is to add a button which will print (generate PDF) selected rows from the table. I've checked in the EasyAdmin docs if there maybe is a tutorial or more info, but without luck. https://symfony.com/bundles/EasyAdminBundle/current/crud.html
How I should approach it? Is there a method I should use or a bundle?
I've found this thread:
PDF document creation EasyAdmin symfony 5 But no one replied. There is not much info regarding this matter.
Symfony 5.4, EasyAdmin 4
I think that you should create a customs actions for this.
Let say that you have setup a ProductCrudController class. In that class, you will have to override this :
public function configureActions(Actions $actions): Actions
{
$viewProductInPDFFormat = Action::new('viewPDF', 'View in PDF', 'fa fa-file-pdf-o')
->linkToRoute('name_of_route_that_generate_pdf_on_one_product',
function (Product $product): array {
return [
'id' => $product->getId(),
];
});
return $actions
//will add the action in the page index view
->add(Crud::PAGE_INDEX, $viewProductInPDFFormat)
//will add the action in the page detail view
->add(Crud::PAGE_DETAIL, $viewProductInPDFFormat)
;
}
Is possible to get some list of fields in FormEvents::PRE_SET_DATA?
I need edit entity which I put to Form by Event. Entity contains PersistCollection which I need transform to ArrayObject.
I would like created on automatic for many entities. I need list of fields (names) for data mapping.
My idea:
$fields = $event->getFormFields();
foreach ($fields as $field) {
dump($field); --> return 'name'
}
It's not completely clear what you're trying to achieve, but yes, you can get all child forms from parent form easily:
You can either use:
foreach ($event->getForm()->all() as $childForm) {
// ...
}
or, since Symfony Form implements IteratorAggregate interface:
foreach ($event->getForm() as $childForm) {
}
Is it bad practice to get data from db in twig function or I should pass it to view in controller?
My function is some kind of interface widget that is used on all pages of site admin section. Then on data change I will have to make changes in all actions. But when I get data directly in extension class our teamlead tells that it's bad MVC.
It would be best if you pass it to a view from a controller.
Your team leader is right. What you can do is create an action specific to render that widget. I.e create a custom widget, let's say you want to show the number of current active users:
class WidgetController extends Controller
{
public function usersCountWidgetAction()
{
return $this->render('widget/usersCount.html.twig', array(
"usersCount" => $this->getUsersCount();
));
}
public function getUsersCount()
{
// call the manager and get the result
}
}
Now in all your other twigs you can use
{{ render(controller('AppBundle:Widget:usersCountWidget')) }}
I have 2 forms. One is the main form with fields and a collection and inside this fields the other form. On each form (the parent and the child) I add a PRE_SUBMIT subscriber. Now, my problem is, I want to load a method specific to the parent form after execution of the PRE_SUBMIT on the child event.
Actually, following the documentation, in spite I give priority, I have always this order :
parent::PRE_SUBMIT -> child::PRE_SUBMIT
and by the way I want :
parent::PRE_SUBMIT -> child::PRE_SUBMIT -> parent::PRE_SUBMIT(other)
Do you have an idea if it's possible to do that and in what way ?
Remove the event PRE_SUBMIT on your children (only add it for the parent), and inside your event handler do the specific code for your children.
E.g.
public function yourPresubmitMethod(FormEvent $event)
{
$form = $event->getForm();
// Code before
// Code for each child
foreach ($form as $child)
{
$child->theChildPreSubmitMethod();
}
// Code after
}
In my project I have an abstract entity, let's call it Parent, and two child entities: ChildA and ChildB that extend Parent class. I'm using doctrine and a single table strategy, has ChildA and ChildB are similiar. This part is working ok, now my problem is with the form.
I want to have a single form that can be used to create an entity of one of those classes (ChildA or ChildB), so I want to have a first field in the form to select which kind of entity the user wants to create, and show the fields for that class (has there are only one different field, I'm using javascript to show/hide the field according to the selected class)
To accomplish this I have created a form with all the fields of both ChildA and ChildB plus the field to select the type, and my idea was in controller check the type, and then create a specific form associated with ChildA or ChildB according to the selected type, and bind it with the valus received from the main form, but the problem here is how to display the errors in this form
Anyone have a good solution for this problem?
I think you make it very difficult this way.
For this problem i would create 2 forms (FormChildA, FormChildB) with the associated fields accordingly.
Because you are using javascript anyway, just render the page with a choice and get the form with ajax:
<div id="select-type">
<button value="child_a" type="button">Select ChildA</button>
<button value="child_b" type="button">Select ChildB</button>
</div>
<div id="form-container"></div>
<script>
$('#select-type button').on('click', function(event) {
event.preventDefault();
$.get('path/to/get_ajax_form', {type: $(this).val()}, function(data) {
$('#form-container').html(data);
});
});
</script>
Create a Controller method to retrieve the form:
public function getAjaxFormAction()
{
$type = $this->get('request')->query->get('type');
switch( $type ) {
case 'child_a':
$form = $this->createForm(new FormChildA, new ChildA);
break;
case 'child_b':
$form = $this->createForm(new FormChildB, new ChildB);
break;
}
return $this->render('AcmeBundle:Forms:_type_form.html.twig', array(
'form' => $form->createView(),
'type' => $type,
));
}
Add to each form a hidden field with the form type value,
this way you can validate these forms in one method (same way as you retrieve them).
This makes it easier to modify and validate each form separately!