I'm struggling to make a custom action in Sonata Admnin, I followed the guide Sonata documentation and tried to copy the code from another of my projects where it worked fine.
My Admin class is:
namespace BlogBundle\Admin;
use AppBundle\Form\Type\FacebookType;
use Sonata\AdminBundle\Route\RouteCollection;
use Sonata\CoreBundle\Form\Type\BooleanType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Knp\Menu\ItemInterface as MenuItemInterface;
use Sonata\AdminBundle\Admin\AdminInterface;
class PostAdmin extends AbstractAdmin
{
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('facebookAction');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('id',TextType::class,[
'label' => 'entity.post.id'
])
->add('active',BooleanType::class,[
'label' => 'entity.post.active'
])
->add('_action', null, [
'actions' => [
'show' => [],
'edit' => [],
'delete' => [],
'facebook' => [
'template' => 'BlogBundle:Admin:empty.html.twig'
]
]
]);
;
}
//...
}
Service declaration:
services:
admin.blog.post:
class: BlogBundle\Admin\PostAdmin
arguments: [~, BlogBundle\Entity\Post, BlogBundle:PostAdmin]
tags:
- { name: sonata.admin, manager_type: orm, label: 'admin.name.post', group: 'admin.group.blog'}
And the CRUD Controller:
namespace BlogBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
class PostAdminController extends Controller
{
public function facebookAction()
{
}
}
Looking at the profiler the route is not being generated and the button for my custom route is not displayed on the list even if it is set on the configureListFields function.
Symfony's version is 3.2.2 and Sonata 3.10.3
Related
I added a large entity filter to one of my Sylius grid configurations. I haven't found any configuration options besides class name and from the looks of it, option values are just ordered by ID. Is there a way to use a repository method or at least provide sort field? Do I need to use a custom filter for this?
You can define what repository method to use on your YAML file and what arguments you want to send to that method:
sylius_grid:
grids:
app_user: # Your grid name
driver:
name: doctrine/orm
options:
class: "%app.model.user%"
repository:
method: myCustomMethod
arguments:
id: resource.id
sorting:
name: asc
limits: [10, 25, 50, 100]
Check the Sylius Grid Bundle documentation for more information: Configuration Reference
Here's how to define a new type :
final class CustomFilterType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'shop',
EntityType::class,
[
'class' => Shop::class,
'label' => false,
'multiple' => true, //if you need multiple selection
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('s');
// define your query builder here
},
'choice_label' => function ($shop) { /** #var $shop Shop */
return $shop->getName();
},
]
);
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'sylius_grid_filter_entity_multiple';
}
}
Then in your services.yaml :
app.grid_filter.custom_filter:
class: Sylius\Component\Grid\Filter\SelectFilter
tags: [{
name: 'sylius.grid_filter',
type: 'custom_type',
form_type: App\Form\Grid\Filter\CustomFilterType
}]
And finally, in your grid definition:
filters:
shops:
type: custom_type
label: app.ui.shops
I used a Sylius 1.0.0-beta1 and ported EntityFilter from dev-master due to lack of this functionality in last stable version. Everything works fine but is there any way of choosing not from all resources but only from part of them?
I need to make a filter based on Taxonomies. I have a few taxons which are city names and all of them have parent taxon called City (code: city). So I want to display in that filter all children of city taxon.
My grid configuration is shown below:
sylius_grid:
grids:
smartbyte_admin_products_by_event_archetype:
...
filters:
...
taxon:
type: app_entity
options:
fields: [taxon.id]
class: "%sylius.model.taxon.class%"
city:
type: app_taxon
The first filter from configuration works and filters fine, except it takes all taxons, but I need to show only some.
I tried also make my own filter (the second one) but I get a text field instead of entity field in filter. Following the docs I created custom one. Here is my try:
<?php
namespace SyliusExtensionBundle\Form\Type\Filter;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class TaxonFilterType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('city', EntityType::class, array(
'class' => 'Sylius\Component\Core\Model\Taxon',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('t')
->leftJoin('t.parent', 'taxon')
->where("taxon.code = 'city'");
},
'label' => 'Miasto',
'required' => false
));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'label' => false,
'placeholder' => 'sylius.ui.all',
])
->setDefined('fields')
->setAllowedTypes('fields', 'array')
;
}
/**
* {#inheritdoc}
*/
public function getName()
{
return 'sylius_grid_filter_taxon';
}
}
Service configuration:
services:
sylius.grid_filter.entity:
class: SyliusExtensionBundle\Grid\Filter\EntityFilter
tags:
- { name: sylius.grid_filter, type: app_entity, form-type: SyliusExtensionBundle\Form\Type\Filter\EntityFilterType }
- { name: sylius.grid_filter, type: app_taxon, form-type: SyliusExtensionBundle\Form\Type\Filter\EntityFilterType }
sylius.form.type.grid_filter.entity:
class: SyliusExtensionBundle\Form\Type\Filter\EntityFilterType
tags:
- { name: form.type, alias: sylius_grid_filter_entity }
app.form.type.grid_filter.taxon:
class: SyliusExtensionBundle\Form\Type\Filter\TaxonFilterType
tags:
- { name: form.type, alias: sylius_grid_filter_taxon }
And lastly filter templates:
sylius_grid:
templates:
filter:
app_entity: "SyliusExtensionBundle:Grid/Filter:entity.html.twig"
app_taxon: "SyliusExtensionBundle:Grid/Filter:entity.html.twig"
Please guide my how can I restrict EntityFilter or how to make the custom filter work. I spent many hours on this subject and cannot see whereis the error.
Current effect below:
EDIT:
Current TaxonFilterType according to Paweł Jędrzejewski tips. Still doesn't work and dont detect fields option in configuration.
<?php
/**
* Created by PhpStorm.
* User: Krzysztof Wędrowicz krzysztof#wedrowicz.me
* Date: 23.01.17
* Time: 14:56
*/
namespace SyliusExtensionBundle\Form\Type\Filter;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class TaxonFilterType extends AbstractType {
public function getParent()
{
return EntityType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'label' => false,
'placeholder' => 'sylius.ui.all',
'class' => 'Sylius\Component\Core\Model\Taxon',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('t')
->leftJoin('t.parent', 'taxon')
->where("taxon.code = 'city'")
;
},
'required' => false
])
->setDefined('fields')
->setAllowedTypes('fields', 'array')
;
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'sylius_grid_filter_city';
}
}
Currently this is not possible via configuration. I will add it to the backlog, but not sure when it can be implemented. That being said, your custom filter is a good idea. You should do a small change and it should work: The form type should have EntityType::class in getParent() instead of using the buildForm method. And the custom query builder should be configured in configureOptions method, then it will render a proper field. Here is full code that should work:
<?php
namespace AcmeExtension\Form\Type\Filter;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class CityFilterType extends AbstractType
{
public function getParent()
{
return EntityType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'label' => false,
'placeholder' => 'sylius.ui.all',
'class' => 'Sylius\Component\Core\Model\Taxon',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('t')
->leftJoin('t.parent', 'taxon')
->where("taxon.code = 'city'")
;
},
'required' => false
])
->setDefined('fields')
->setAllowedTypes('fields', 'array')
;
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'sylius_grid_filter_city';
}
}
I got the following error when I add a custom action in Sonata Admin
FatalErrorException: Error: Class 'Symfony\Component\Debug\Exception\FlattenException' not found in /myproject_path/AppBundle/Admin/BalticsAdmin.php line 106
What is this problem please share me
HERE IS THE CODE
In admin class
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
................................
.................
->add('_action', 'actions', array(
'actions' => array(
'show' => array(),
'edit' => array(),
'delete' => array(),
'upload' => array('template' => 'SteelGuruBundle:CRUD:list__action_upload.html.twig'),
)
));
}
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('upload', $this->getRouterIdParameter().'/upload');
}
THEN I cREATE a controller class in src/.../.../Controller/CRUDController.php with following codes
namespace ...\AppBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
class CRUDController extends Controller
{
public function uploadAction()
{
$id = $this->get('request')->get($this->admin->getIdParameter());
$object = $this->admin->getObject($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}
}
}
Then I create a template in src/.../AppBundle/Resources/views/CRUD/list__action_upload.html.twig with the following code
<a class="btn btn-small" href="{{ admin.generateObjectUrl('upload', object) }}">Upload</a>
and then in services.yml I added the following
sg_app.admin.baltic:
class: ...\AppBundle\Admin\BalticsAdmin
tags:
- { name: sonata.admin, manager_type: orm, audit:false, group: Test, label: Upload}
arguments: [null, ...\AppBundle\Entity\Baltics, ...AppBundle:CRUD]
Thanks for your response
i had a similar problem and found out that i had to add
use Sonata\AdminBundle\Route\RouteCollection;
to the Admin (in your case BalticAdmin).
In Symfony 2.4, I want to create a registration form through a service. I played around with the service configuration and the form components factories but everytime i got the following exception:
Catchable Fatal Error: Argument 1 passed to Symfony\Component\Form\Form::__construct() must be an instance of Symfony\Component\Form\FormConfigInterface, instance of Bestxtech\UserBundle\Form\RegistrationType given
code as follow:
services:
bestxtech.form.type.registration:
class: Bestxtech\UserBundle\Form\RegistrationType
arguments: [null]
tags:
- { name: form.type, alias: registration }
public: flase
bestxtech.form.registration:
factory-method: create
factory-service: form.factory
class: Symfony\Component\Form\Form
arguments: ["#bestxtech.form.type.registration"]
RegistrationType as
//Bestxtech\UserBundle\Form\RegistrationType
<?php
namespace Bestxtech\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username')
->add('plainPassword', 'repeated', array(
'type' => 'password',
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Confirm password'),
'invalid_message' => 'Password mismatch'
))
->add('email', 'email', array('label' => 'Email address'));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bestxtech\UserBundle\Entity\User',
'validation_groups' => array('Registration')
));
}
public function getName()
{
return 'user';
}
}
Would be nice if someone can give me some advice, thank you.
Your form factory service definition is wrong. Try to look at this: http://symfony.com/doc/current/components/dependency_injection/factories.html.
But. Are you sure it is good idea? Pay attention that create method from FormFactory takes two additional arguments: $data and $options. If you define building your form as you've showed you won't be able to pass these arguments to create method.
I would use form.factory service directly if I was you. Like this:
$formFactory = $container->get('form.factory');
$form = $formFactory->create($container->get('form.type.registration'));
edit:
The problem was you've used dashes instead of underscores, try below:
services:
bestxtech.form.type.registration:
class: Bestxtech\UserBundle\Form\RegistrationType
arguments: [null]
tags:
- { name: form.type, alias: registration }
public: flase
bestxtech.form.registration:
factory_method: create
factory_service: form.factory
class: Symfony\Component\Form\Form
arguments: ["#bestxtech.form.type.registration"]
I overrided registration form from FOSUserBundle with additionals fields: it works well.
When I apply the same logic to override Profile Form : the form appears well with my additionals fields but all is empty (the fields do not contain values of the connected user).
Note: when I use the default form from the bundle the profile form contains the values of the connected user.
Is there a specific action compared to override the registration form to retrieve the values of the connected user ?
HERE IS CODE :
src/Vn/UserBundle/Resources/config/services.yml
services:
...
vn_user.profile.form.type:
class: Vn\UserBundle\Form\Type\ProfileFormType
arguments: [%fos_user.model.user.class%]
tags:
- { name: form.type, alias: vn_user_profile }
vn_user.form.handler.profile:
class: Vn\UserBundle\Form\Handler\ProfileFormHandler
arguments: ["#fos_user.profile.form", "#request", "#fos_user.user_manager"]
scope: request
public: false
symfony/app/config/config.yml
fos_user:
...
profile:
form:
type: vn_user_profile
handler: vn_user.form.handler.profile
src/Vn/UserBundle/Form/Type/ProfileFormType.php
namespace Vn\UserBundle\Form\Type;
use Symfony\Component\Form\FormBuilder;
use FOS\UserBundle\Form\Type\ProfileFormType as BaseType;
class ProfileFormType extends BaseType
{
public function buildUserForm(FormBuilder $builder, array $options)
{
parent::buildUserForm($builder, $options);
// custom field
$builder->add('profile',new MyProfileFormType(),array(
'label' => 'PROFILE'
));
}
public function getName()
{
return 'vn_user_profile';
}
}
src/Vn/UserBundle/Form/Type/MyProfileFormType.php
namespace Vn\UserBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class MyProfileFormType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('birthday','birthday', array(
'input' => 'array',
'widget' => 'choice',
'label' => 'Birthday',
))
->add('firstname','text', array(
'trim' => true,
'label' => 'Firstname',
))
->add('lastname','text', array(
'trim' => true,
'label' => 'Lastname',
))
->add('gender','choice', array(
'choices' => array('1' => 'Male', '2' => 'Female'),
'expanded' => true,
'required' => true,
'label' => 'Vous êtes',
));
}
public function getName()
{
return 'vn_user_myprofile';
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Vn\UserBundle\Document\Profile',
);
}
}
I found the mistake in my file ProfilFormeHandler.php : in the function process() I called parent::onSucess() instead of parent::process() ...
The result is a "silent" bug (silent because not fatal error appears) due to my fault of course
Thanks for time you spent to try to help me, very sorry !
<?php
// src/Vn/UserBundle/Form/Handler/RegistrationFormHandler.php
namespace Vn\UserBundle\Form\Handler;
use FOS\UserBundle\Form\Handler\ProfileFormHandler as BaseHandler;
use FOS\UserBundle\Model\UserInterface;
class ProfileFormHandler extends BaseHandler
{
public function process(UserInterface $user)
{
//parent::onSuccess($user);
parent::process($user); // sound better of course : )
}
protected function onSuccess(UserInterface $user)
{
$this->userManager->updateUser($user);
}
}