Easyadmin 4: How to display edit view related collection as a table - symfony

I've two entities: A_ and B_, where B_ is a collection of the A_.
Now in EA edit view B_ collection displays as embedded object:
class A_CrudController extends AbstractCrudController {
public function configureFields(string $pageName): iterable {
...
yield CollectionField::new('b_', 'B_ Collection')
->useEntryCrudForm(B_CrudController::class)
->setEntryIsComplex();
}
}
Everything works fine but I'd like to have a table view this collection where each row is element of the collection.
How to do it?
I try to use method in Symfony EasyAdmin 3 display relation table in parent details page
but it doesn't work for me.
Thanks

Related

Print selected rows in Symfony EasyAdmin CRUD

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)
;
}

EasyaAmin 3 - Hide/Show actions dynamically based on the underlying entity

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;
}

Symfony Dynamic Form Constraints

Looking for a straightforward way to add constraints dynamically to all of my form fields. So far I've hit upon the idea of using a form type extension, which kind of works: I can modify the form view and then manually check the view on form submission.
However, is there a smarter way to add real Symfony-based constraints in real-time?
(Note that the constraints need to be added to the form in real-time as the form loads based on user configuration in the database.. Predefined form groups and the like won't work.)
I would suggest to use form events.
Use the PRE_SUBMIT event to edit the form before validation.
Recreate your fields with $event->getForm()->add(...) adding your constraints.
Of course you can automatically add the listener to all form using a FormExtension which adds the listener.
EDIT : Some examples from Alsatian67/FormBundle
Your extension should looks like :
class ExtensibleExtension extends AbstractTypeExtension
{
private $extensibleSubscriber;
public function __construct($extensibleSubscriber) {
$this->extensibleSubscriber = $extensibleSubscriber;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Only apply on base form
if($builder->getForm()->isRoot())
{
$builder->addEventSubscriber($this->extensibleSubscriber);
}
}
public function getExtendedType()
{
return FormType::class;
}
}
And your EventListener / EventSubscriber should iterate on all the children :
foreach($event->getForm()->all() as $child){
$childName = $child->getName();
$type = get_class($child->getConfig()->getType()->getInnerType());
$options = $child->getConfig()->getOptions();
$options['constraints'] = array(/* ... */);
$form->add($childName,$type,$options);
}

Symfony - List of form fields in event

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) {
}

Get data in twig function

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')) }}

Resources