Symfony2 FOSUserBundle override profile form : field form empty? - symfony

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

Related

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 }

Symfony 2.4 create form through a service

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

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 do you default to the empty_value choice in a custom symfony form field type?

I have a created a custom form field dropdown list for filtering by year. One of the things I want to do is to allow the user to filter by all years, which is the default option. I am adding this as an empty_value. However, when I render the form, it defaults on the first item that's not the empty value. The empty value is there, just above it in the list. How do I make the page default to, in my case 'All' when the page initially loads? Code is below.
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class YearType extends AbstractType
{
private $yearChoices;
public function __construct()
{
$thisYear = date('Y');
$startYear = '2012';
$this->yearChoices = range($thisYear, $startYear);
}
public function getDefaultOptions(array $options)
{
return array(
'empty_value' => 'All',
'choices' => $this->yearChoices,
);
}
public function getParent(array $options)
{
return 'choice';
}
public function getName()
{
return 'year';
}
}
I'm rendering my form in twig with a simple {{ form_widget(filter_form) }}
Try adding empty_data option to null, so it comes first. I have many fields of this type and it's working, for example:
class GenderType extends \Symfony\Component\Form\AbstractType
{
public function getDefaultOptions(array $options)
{
return array(
'empty_data' => null,
'empty_value' => "Non specificato",
'choices' => array('m' => 'Uomo', 'f' => 'Donna'),
'required' => false,
);
}
public function getParent(array $options) { return 'choice'; }
public function getName() { return 'gender'; }
}
EDIT: Another possibility (i suppose) would be setting preferred_choices. This way you'll get "All" option to the top. But i don't know if it can work with null empty_data, but you can change empty_data to whatever you want:
public function getDefaultOptions(array $options)
{
return array(
'empty_value' => 'All',
'empty_data' => null,
'choices' => $this->yearChoices,
'preferred_choices' => array(null) // Match empty_data
);
}
When I've needed a simple cities dropwdown from database without using relations, I've ended up using this config for city field (adding null as first element of choices array), as empty_data param didn't do work for me:
$builder->add('city',
ChoiceType::class,
[
'label' => 'ui.city',
'choices' => array_merge([null], $this->cityRepository->findAll()),
'choice_label' => static function (?City $city) {
return null === $city ? '' : $city->getName();
},
'choice_value' => static function(?City $city) {
return null === $city ? null : $city->getId();
},
]);

How to dynamically add's collections within collections in Symfony2 form types

I have 3 form types in symfony2
FaultType which is the parent of all next collections
<?php
namespace My\FaultBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class FaultType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('title')
->add('steps', 'collection', array(
'type' => new StepType(),
'allow_add' => true,
'prototype' => true,
'by_reference' => false,
))
->add('created')
->add('updated')
;
}
public function getDefaultOptions()
{
return array(
'data_class' => 'My\FaultBundle\Entity\Fault'
);
}
public function getName()
{
return 'my_fault_fault';
}
}
StepType:
<?php
namespace My\FaultBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class StepType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('body')
->add('photos', 'collection', array(
'type' => new PhotoType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
))
;
}
public function getDefaultOptions()
{
return array(
'data_class' => 'My\FaultBundle\Entity\Step'
);
}
public function getName()
{
return 'my_fault_step';
}
}
and the last PhotoType:
<?php
namespace My\FaultBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class PhotoType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name')
->add('description')
->add('filename')
;
}
public function getDefaultOptions()
{
return array(
'data_class' => 'My\FaultBundle\Entity\Photo'
);
}
public function getName()
{
return 'my_fault_photo';
}
}
I found excelent article link about prototype, and with one nested form type is very good, but I have a problem when a want to get this to work with third nest mean PhotoType... Photos are in collection of Steps, which is collection of Fault..., how can I achive dynamically add/remove photos for steps with this example...?
I made a JS snippet that can be of help here. you just have to add two buttons [add new, delete last].
https://gist.github.com/juanmf/10483041
it can handle recursive/nested prototypes.
It's coupled with a mediator (same as Symfony event Dispatcher) that allows you to bind generated controls to events. If you dont need the mediator delete these lines:
docdigital.mediatorInstance.send(
docdigital.constants.mediator.messages.clonePrototype_prototypeAdded,
$clone
);
You have to make you own prototype.
There are 2 solutions:
Find with regex all digit segments of a property_path, and replace them with placeholder
$segments_found = preg_match('/\[(\d+)\]/', $prototype, $matches);
Use recursion to find top collection parent and build path manually from there.
Did you try reordering items? This is total disaster;)

Resources