custom action in SonataAdminBundle - php

On this page I found how to add route for my custom action.
protected function configureRoutes(RouteCollection $collection) {
$collection->add('ispremium', $this->getRouterIdParameter().'/ispremium');
}
After that I add custom action in my Admin class:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('id')
->add('code', null, array('label' => 'Code'))
->add('_action', 'actions', array(
'actions' => array(
'ispremium' => array(
'template' => 'AppMyBundleBundle:Admin:ispremium.html.twig'
)
)
))
;
}
It generated url like this:
/app_dev.php/admin/mobispot/discodes/discode/300876/ispremium
My template for this link:
Link
I dont' know how to solve this problems:
How to define custom controller for that route pass?
Now I have an error:
Method "Sonata\AdminBundle\Controller\CRUDController::ispremiumAction" does not exist.
Can I change generated url with generateUrl method?

When you are creating service for EntityAdmin class the third argument is the controller name. You can create a class that extends CRUDController and set it in service. e.g
The controller,
//Vendor\YourBundle\Controller\EntityAdminController.php
class EntityAdminController extends CRUDController
{
public function ispremiumAction()
{
//process
}
}
In services.yml,
entity.admin.service:
class: FQCN\Of\EntityAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: your_group, label: Label }
arguments: [null, FQCN\Of\Entity, VendorYourBundle:EntityAdmin]

Related

cannot load the TranslatorInterface in my formType

I try to introduce some translation into a ChatBundle in order to follow the changes of the _locale of the hosting app in Symfony 4.
So in the formBuilder i try to inject the TranslatorInterface as such:
// lib/ChatBundle/Form/ChatMessageType.php
namespace bornToBeAlive\ChatBundle\Form;
use bornToBeAlive\ChatBundle\Entity\ChatMessage;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\TranslatorInterface;
class ChatMessageType extends AbstractType
{
private $trans;
public function __construct(TranslatorInterface $trans)
{
$this->trans = $trans;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('content', null, [
'attr'=> ['placeholder' => $this->trans->trans('placeholder',[],'chat')]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ChatMessage::class,
]);
}
}
but when I try to run my show action:
public function show(): Response
{
$message = new ChatMessage();
$form = $this->createForm(ChatMessageType::class, $message);
return $this->render('#Chat/show.html.twig', [
'form' => $form->createView(),
]);
}
I get the following error :
Too few arguments to function bornToBeAlive\ChatBundle\Form\ChatMessageType::__construct(), 0 passed in ../vendor/symfony/form/FormRegistry.php on line 92 and exactly 1 expected
I'm surprised because I use this technique when I'm in my host app for the other type. did I do something wrong ?
According to the Symfony 4.4 Form documentation :
If you're using the default services.yaml configuration, this example will already work! Otherwise, create a service for this form class and tag it with form.type.
services:
# default configuration for services in *this* file
_defaults:
autowire: true
autoconfigure: true
public: false
If autowiring is not working as expected, you can define form as service, like this
# config/services.yaml
app.form.corporation_type:
class: bornToBeAlive\ChatBundle\Entity\ChatMessageType
arguments: ["#translator"]
tags:
- { name: form.type }

ReflectionException : Class Admin\AdminBundle\Admin\Entity\Produit does not exist

I use symfony 3 and I try to manage an admin side to manage my products and my commands for my ecommerce website, but I always have the same error :
ReflectionException - Class Admin\AdminBundle\Admin\Entity\Product does not exist
this is my services :
services:
app.admin.produit:
class: Admin\AdminBundle\Admin\ProduitAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Content", label: "Produit" }
arguments:
- ~
- Admin\AdminBundle\Admin\Entity\Produit
- ~
calls:
- [ setTranslationDomain, [AdminAdminBundle]]
public: true
app.admin.commande:
class: Admin\AdminBundle\Admin\CommandeAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Content", label: "Commande" }
arguments:
- ~
- Admin\AdminBundle\Admin\Entity\Commande
- ~
calls:
- [ setTranslationDomain, [AdminAdminBundle]]
public: true
This is my CommandAdmin :
<?php
namespace Admin\AdminBundle\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
class CommandeAdmin extends AbstractAdmin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('idProduit', 'entity', array('class' => 'Admin\AdminBundle\Entity\Produit'))
->add('date')
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
// ->add('idProduit')
->add('date')
;
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('idProduit', 'entity', array('class' => 'Admin\AdminBundle\Entity\Produit'))
->add('date')
;
}
// Fields to be shown on show action
protected function configureShowFields(ShowMapper $showMapper)
{
$showMapper
->add('idProduit')
->add('date')
;
}
}
This is my ProduitAdmin :
<?php
namespace Admin\AdminBundle\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
class ProduitAdmin extends AbstractAdmin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('nom')
->add('description')
->add('quantite')
->add('prix')
->add('marque')
->add('fournisseur')
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('nom')
->add('description')
->add('quantite')
->add('prix')
->add('marque')
->add('fournisseur')
;
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('nom')
->add('description')
->add('quantite')
->add('prix')
->add('marque')
->add('fournisseur')
;
}
// Fields to be shown on show action
protected function configureShowFields(ShowMapper $showMapper)
{
$showMapper
->add('nom')
->add('description')
->add('quantite')
->add('prix')
->add('marque')
->add('fournisseur')
;
}
}
This is the Stack Trace :
ReflectionException:
Class Admin\AdminBundle\Admin\Entity\Produit does not exist
at vendor/sonata-project/admin-bundle/Controller/CRUDController.php:480
at ReflectionClass->__construct('Admin\\AdminBundle\\Admin\\Entity\\Produit')
(vendor/sonata-project/admin-bundle/Controller/CRUDController.php:480)
at Sonata\AdminBundle\Controller\CRUDController->createAction()
at call_user_func_array(array(object(CRUDController), 'createAction'), array())
(vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php:153)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
(vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php:68)
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
(vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php:169)
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
(web/app_dev.php:29)
If someone have an idea
The error is pretty explainable: The class Admin\AdminBundle\Admin\Entity\Produit doesn't seem to exists. Take a look at your code, I guess it's not there.
My best guess would be that you mean Admin\AdminBundle\Entity\Produit (note the removed Admin\ subnamespace). The same applies to your Commande class specification just below it.

Catchable Fatal Error: Argument 2 passed to UserBundle\Form\UserType::__construct() must be an instance ?

I am trying to get the current user in a Custom Form Field Type.
My formType
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class UserType extends AbstractType {
protected $doctrine;
protected $tokenStorage;
public function __construct($doctrine,TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
$this->doctrine = $doctrine;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$user = $this->tokenStorage->getToken()->getUser();
$builder
->setAction($options['data']['url'])
->setMethod('GET')
->add('userType', 'choice', array('choices' => array(
'userType_p' => $pId,
'userType_t' => $tId),
'choices_as_values' => true, 'label' => 'Usertype ',
'expanded' => true, 'multiple' => true,
'translation_domain' => 'User',))........
....
Here is my service:
user.form.token:
class: UserBundle\Form\UserType
arguments: ['#security.token_storage']
tags:
- { name: form.type }
In the Controller I am calling the form like this:
$form = $this->createForm(new UserType($em,$this->get('user.form.token')), $data....
I am getting this following error:
Catchable Fatal Error: Argument 2 passed to UserBundle\Form\UserType::__construct() must implement interface Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface, none given, called in......
The UserType::__construct method signature has two parameters here, and you're only passing one in your service declaration ($doctrine), hence the error. If you still need Doctrine in the form type, you should pass it as well:
user.form.token:
class: UserBundle\Form\UserType
arguments: ['#doctrine', '#security.token_storage']
tags:
- { name: form.type }
Also, looks like you're not creating the form itself correctly, instead of instantiating the type itself, you should just pass its class name, as explained by Christophe Coevoet:
$form = $this->createForm(UserType::class, $data);

Sonata Bundle Error when configuring child admin

I'm using Symfony and the Sonata Bundle to generate my admin interface. I have 3 classes:
Restaurant
Service
RestaurantService
With classes Restaurant and Service having a OneToMany relationship with RestaurantService.
I try RestaurantService as a child admin in Restaurant but I've got those errors:
ContextErrorException in RestaurantAdmin.php line 143:
Runtime Notice: Declaration of
GSG\AdminBundle\Admin\RestaurantAdmin::configureSideMenu() should be
compatible with
Sonata\AdminBundle\Admin\Admin::configureSideMenu(Knp\Menu\ItemInterface
$menu, $action, Sonata\AdminBundle\Admin\AdminInterface $childAdmin =
NULL)
and
FileLoaderLoadException in classes.php line 13757:
Runtime Notice: Declaration of
GSG\AdminBundle\Admin\RestaurantAdmin::configureSideMenu() should be
compatible with
Sonata\AdminBundle\Admin\Admin::configureSideMenu(Knp\Menu\ItemInterface
$menu, $action, Sonata\AdminBundle\Admin\AdminInterface $childAdmin =
NULL) in /Volumes/Data/ge0ra/www/admin_gsg/app/config/. (which is
being imported from
"/Volumes/Data/ge0ra/www/admin_gsg/app/config/routing.yml").
Here is my services.yml file:
services:
sonata.admin.restaurant:
class: GSG\AdminBundle\Admin\RestaurantAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Gestion des restaurants", label: "Restaurants" }
arguments:
- ~
- GSG\AdminBundle\Entity\Restaurant
- ~
calls:
- [ addChild, [#sonata.admin.restaurantservice]]
sonata.admin.service:
class: GSG\AdminBundle\Admin\ServiceAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Gestion des restaurants", label: "Services" }
arguments:
- ~
- GSG\AdminBundle\Entity\Service
- ~
sonata.admin.restaurantservice:
class: GSG\AdminBundle\Admin\RestaurantServiceAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Gestion des restaurants", label: "RestaurantServices" }
arguments:
- ~
- GSG\AdminBundle\Entity\RestaurantService
- ~
in my RestaurantAdmin class:
protected function configureSideMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
{
if (!$childAdmin && !in_array($action, array('edit'))) {
return;
}
$admin = $this->isChild() ? $this->getParent() : $this;
$id = $admin->getRequest()->get('id');
$menu->addChild(
'Voir/Editer',
array('uri' => $admin->generateUrl('edit', array('id' => $id)))
);
$menu->addChild(
'Services',
array('uri' => $admin->generateUrl('sonata.admin.restaurantservice.list', array('id' => $id)))
);
}
and my RestaurantServiceAdmin class:
class RestaurantServiceAdmin extends Admin
{
protected $parentAssociationMapping = 'Restaurant';
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('service', 'sonata_type_model')
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
if (!$this->isChild())
$listMapper->addIdentifier('id')->addIdentifier('Restaurant');
$listMapper
->add('service', 'sonata_type_model')
;
}
}
Do someone have an idea from where those errors can come?
Thanks!
Your RestaurantAdmin class has the first parameter of configureSideMenu set as MenuItemInterface $menu when it should be an instance of \Knp\Menu\ItemInterface.
The Menu part of the type hint is wrong.

Entity's id of parent is not saved in a OneToMany relationship in SonataAdmin

I'm using SonataAdmin (and Symfony2) to manage my entities. I have a oneToMany relationship between one Step and many Tasks. Since one Step can contain many Tasks, when I create a Step, I want to be able to create many Tasks and I want those tasks to be linked to this Step. To do so, I created all the proper admin classes (one for Task and one for Step).
Here's what I do that causes my problem. When I try to create a Step, I can create the tasks and even reorder them, which is great and all done automatically by SonataAdminBundle. When I click on save, everything is saved in the database, except that in the database, the id of the step is not set in the row of the Task. Therefore, the tasks are not linked to the Step...
Here's my Step's admin class:
<?php
// src/Acme/DemoBundle/Admin/PostAdmin.php
namespace IMA\ProcessManagementBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
class StepAdmin extends Admin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name', 'text', array('label' => 'Nom de l\'étape'))
->add('tasks', 'sonata_type_collection', array(), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'positionNumber'
))
->add('positionNumber', 'integer', array('label' => 'Position'))
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('name')
;
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name')
->add('slug')
;
}
}
Here's also my Task admin class:
<?php
// src/Acme/DemoBundle/Admin/PostAdmin.php
namespace IMA\ProcessManagementBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
class TaskAdmin extends Admin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name', 'text', array('label' => 'Tâche'))
->add('positionNumber', 'integer', array('label' => 'Position'))
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('name')
;
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name')
->add('slug')
;
}
}
Also, here are the description of my entities
IMA\ProcessManagementBundle\Entity\Step:
type: entity
table: null
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
name:
type: string
length: 255
positionNumber:
type: integer
oneToMany:
tasks:
targetEntity: Task
mappedBy: step
cascade: ["persist", "merge"]
lifecycleCallbacks: { }
IMA\ProcessManagementBundle\Entity\Task:
type: entity
table: null
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
name:
type: string
length: 255
positionNumber:
type: integer
manyToOne:
step:
targetEntity: Step
inversedBy: tasks
lifecycleCallbacks: { }
I'm wondering why the id of the Step is not set in the Task row...
You need to manually attach the step to the tasks, to do so you need to use the prePersist and preUpdate methods in the step admin class...
The reason for this is that the developers of the SonataAdminBundle say it's doctrine's concern to handle this and the Doctrine developers say it is the bundles responsibility... So for now we need to do it for ourselves.
This would be your new stepAdmin class:
<?php
namespace IMA\ProcessManagementBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
class StepAdmin extends Admin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name', 'text', array('label' => 'Nom de l\'étape'))
->add('tasks', 'sonata_type_collection', array(), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'positionNumber'
))
->add('positionNumber', 'integer', array('label' => 'Position'))
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('name')
;
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name')
->add('slug')
;
}
public function prePersist($object)
{
foreach ($object->getTasks() as $task) {
$task->setStep($object);
}
}
public function preUpdate($object)
{
foreach ($object->getTasks() as $task) {
$task->setStep($object);
}
}
}
In your Step entity you have to add in the addTask method :
class Step
{
//...
public function addTask($tasks)
{
$tasks->setStep($this);
$this->tasks[] = $tasks;
return $this;
}
//...
}
As you haven't give your Step.php you should propably adapt this code.

Categories