Symfony 2.4 create form through a service - symfony

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"]

Related

Sylius EntityFilter choice from a part of resources

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

Issue to override Subscription Form FOSUser Bundle

I'm trying to override the Subscription Form of FOSUser bundle in a Symfony2 Project but I get this error :
Warning: Missing argument 1 for Utilisateurs\UtilisateursBundle\Form\Type\RegistrationFormType::__construct(), called in C:\wamp\www\biblishare\app\cache\dev\appDevDebugProjectContainer.php on line 3730 and defined
I search for the same issue but can't resolve it...
Here are my codes :
-app/config/config.yml
fos_user:
db_driver: orm
firewall_name: main
user_class: Utilisateurs\UtilisateursBundle\Entity\Utilisateurs
from_email:
address: contact#biblishare.com
sender_name: contact#biblishare.com
registration:
form:
type: utilisateurs_utilisateurs_registration
-.../UtilisateursBundle/Resources/config/services.yml
services:
utilisateurs_utilisateurs.listener.authentication_success_handler:
class: %utilisateurs_utilisateurs.listener.authentication_success_handler.class%
public: false
arguments: ['#router', '#doctrine.orm.entity_manager', '#security.context']
utilisateurs_utilisateurs.registration.form.type:
class: Utilisateurs\UtilisateursBundle\Form\Type\RegistrationFormType
tags:
- { name: form.type, alias: utilisateurs_utilisateurs_registration }
and my form:
<?php
namespace Utilisateurs\UtilisateursBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RegistrationFormType extends AbstractType
{
private $class;
/**
* #param string $class The User class name
*/
public function __construct($class)
{
$this->class = $class;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// add your custom field
$builder
->add('first_name', null, array('label' => 'Prénom :', 'translation_domain' => 'FOSUserBundle'))
->add('family_name', null, array('label' => 'Nom :', 'translation_domain' => 'FOSUserBundle'))
->add('email', 'email', array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'))
->add('plainPassword', 'repeated', array(
'type' => 'password',
'options' => array('translation_domain' => 'FOSUserBundle'),
'first_options' => array('label' => 'form.password'),
'second_options' => array('label' => 'form.password_confirmation'),
'invalid_message' => 'fos_user.password.mismatch',
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => $this->class,
'intention' => 'registration',
));
}
public function getName()
{
return 'utilisateurs_utilisateurs_registration';
}
}
Thank you for your help, I tried to erase the cache but it doesn't work...
You need to add the user class as an argument to your service definition so that it will be called in the __construct method.
utilisateurs_utilisateurs.registration.form.type:
class: Utilisateurs\UtilisateursBundle\Form\Type\RegistrationFormType
arguments:
- %fos_user.model.user.class%
tags:
- { name: form.type, alias: utilisateurs_utilisateurs_registration }

Creating custom form type using sonata form type as parent

I'd like to make my own custom form type of sonata_type_collection, but I'm having trouble doing it.
At first I made my own type class and registered it as a service:
class SonataTypeCollectionWithSearchType extends AbstractType {
public function setDefaultOptions(OptionsResolverInterface $resolver) {
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add($options['type_options']['stcwst_attribute'], 'sonata_type_collection',array('data_class' => $options['type_options']['stcwst_class']));
}
public function getName()
{
return 'sonata_type_collection_with_search';
}
public function getParent()
{
return 'sonata_type_collection';
}
}
The service.yml:
services:
sonata_type_collection_with_search:
class: ASV\CoreBundle\Form\Type\SonataTypeCollectionWithSearchType
tags:
- { name: form.type, alias: sonata_type_collection_with_search }
In an UniversityAdmin class I added this to the formMapper:
->add('studycourses', 'sonata_type_collection_with_search', array(
'type_options' => array('delete' => false,
'stcwst_attribute' => 'studycourse',
'stcwst_class' => 'ASV\UniversityBundle\Entity\University'
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position',
))
But now I'm getting this error:
FatalErrorException: Error: Call to a member function getAdmin() on a
non-object in
vendor/sonata-project/doctrine-phpcr-admin-bundle/Sonata/DoctrinePHPCRAdminBundle/Form/Extension/CollectionTypeExtension.php
line 32
Any ideas what went wrong? Is it even possible to have sonata_type_collection as a parent?

how to check the user role inside form builder in Symfony2?

Okay, i'm trying to check if an user has a specific role, i did this
however, when i do this:
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('nombre',null,array('label' => 'Usuario'))
->add('email')
->add('password', 'repeated', array(
'type' => 'password',
'invalid_message' => 'Los campos deben coincidir',
'first_name' => 'password',
'second_name' => 'confirmar password',
'options' => array('required' => false)
))
->add('cliente', 'entity', array(
'class' => 'ClientesBundle:Cliente',
'empty_value' => 'Company',
'required' => false,
'empty_data' => null)
**)**
$user = $this->securityContext->getToken()->getUser();
**if ($user->getRol() == 'ROLE_SUPER_ADMIN'){**
->add('rol')
**}**
;
}
tried this as well:
**if ($this->securityContext->getToken()->getUser()->getRol() === 'ROLE_SUPER_ADMIN'){**
->add('rol')
**}**
the bolded lines (the ones with **) have the tiny red line that indicates an error, and it's says unexpected if...
How do i fix this?
From controller you have to pass user object to form builder
$form = $this->createForm(
new YourType(),
$data,
array('user' => $this->getUser())
);
Then in form builder you can fetch it from $options:
public function buildForm(FormBuilder $builder, array $options)
{
$user = $options['user']
}
Don't forget to extend setDefaultOptions() with user index:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
...
'user' => null
));
}
If you declare your form type as a service, you can inject the token storage in your class.
So you declare the service in services.yml like this:
my_form:
class: AppBundle\Services\MyFormType
public: true
arguments: ['#security.token_storage']
And the form class like this:
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
class MyFormType extends AbstractType
{
protected $tokenStorage;
public function __construct(TokenStorage $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$user = $this->tokenStorage->getToken()->getUser();
// Use the user object to build the form
}
}
I know this is an old question, but I'd like to put forward a better alternative for checking roles inside a form type.
The issue
The issue with using the TokenInterface and the User object is that it does not check for inheritance. For example, consider the following security.yml:
security:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
If your user has ROLE_SUPER_ADMIN but not ROLE_ADMIN added to their roles, the above solutions will fail if you are using $user->hasRole('ROLE_ADMIN'), as the user does not explicitly have ROLE_ADMIN assigned to their user and hasRole() does not check hierarchy.
The solution
Use the AuthorizationCheckerInterface instead to gain access to the isGranted() function.
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class MyFormType extends AbstractType {
protected $auth;
public function __construct(AuthorizationCheckerInterface $auth) {
$this->auth = $auth;
}
public function buildForm(FormBuilderInterface $builder, array $options) {
// ...
if($this->auth->isGranted('ROLE_ADMIN')) {
// Do the thing here
}
}
}
This will respect any hierarchy defined in security.yml. If we use the same yml file as above, $auth->isGranted('ROLE_ADMIN') will return true if a user has ROLE_SUPER_ADMIN but not ROLE_ADMIN assigned to their profile.
I succeed in doing this thing without pass to a service in symfony 3.4. I know my method is not the most "professionnal" but it is simple and it works.
First, send the user in your formType from your controller
$form = $this->get('form.factory')->create(addPlanExpectedType::class, $business,
array('user' => $this->getUser())
);
Secondly, recover the roles, and verify if "ROLE_AMIN" is in this $roles array
public function buildForm(FormBuilderInterface $builder, array $options)
{
$businessId = $options['data']->getId();
$user = $options['user'];
$roles = $user->getRoles();
$boolAdmin = in_array('ROLE_ADMIN', $roles);

Symfony2 FOSUserBundle override profile form : field form empty?

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

Resources