Symfony2 overriding bundle HTML form input constraints - forms

I am trying to override FOSUserBundle's max username length. Seems simple enough but I can't manage to do it.
validation.yml
AppBundle\Entity\User:
properties:
username:
- Length: { max: 5, groups: [CustomRegistration] }
config.yml
fos_user:
[...]
user_class: AppBundle\Entity\User
registration:
form:
validation_groups: [CustomRegistration]
Validation itself works fine. If user provides username longer than 5 characters Symfony shows an error that it should not be longer than 5 characters. The problem is that the HTML form input still uses default FOSUserBundle value (255). Form builder seems to totally ignore validation groups. Is there any way I can tell form builder to use my constraints?
I want to mention that HTML validation works when I use XML format but I need to use YAML and it works only by coincidence so I would not like to rely on such quirk.
I also tried to provide custom type in hope that it will change anything but it didn't. Username input still uses maxlength value of 255. For reference:
getDefaultOptions # AppBundle/Form/RegistrationFormType.php
public function getDefaultOptions(array $options)
{
return [
'data_class' => 'AppBundle\Entity\User',
'validation_groups' => ['Default', 'CustomRegistration']
];
}
config.yml
fos_user:
[...]
user_class: AppBundle\Entity\User
registration:
form:
type: appbundle_registration
services.yml
services:
appbundle.registration.form.type:
class: AppBundle\Form\RegistrationFormType
tags:
- { name: form.type, alias: appbundle_registration }

You should add max-length HTML attribute manually to the field.
Validation has no effect on HTML attributes.
buildForm # AppBundle\Form\RegistrationFormType
$builder->add("username", "text", array("attr" => array("maxlength" => "5")));
See: http://symfony.com/doc/current/reference/forms/types/text.html#max-length
If it doesnt solve the issue, take a look at your template. It can be setted there too..

Related

Using Symfony Form component standalone with security-csrf - error on submission

I have a question regarding symfony/form using as a standalone component and security-csrf running with PHP build-in server. I hardly remember having such issue with the Symfony framework.
When setting symfony/form as a standalone component I tried this code for both v4.2 and v5.1 https://github.com/xmgcoyi/standalone-forms/tree/4.2+twig. A rewrite of webmozart's example mentioned here https://symfony.com/doc/current/components/form.html
The csrf token is generated with twig-bridge, but when submitting the form - on calling$form->isValid() - invalid csrf error appears.
By default csrf protection is enabled, setting to false - the form submits.
Tried CSRF component with both setups with NativeSessionTokenStorage and SessionTokenStorage + Session of HttpFoundation.
Could you give any hint on what I'm doing wrong and where to look at?
P.S.
Code samples with csrf error on submission:
https://github.com/xmgcoyi/standalone-forms/tree/4.2+twig
https://github.com/liorchamla/pratique-symfony-form/tree/06-protection-csrf
UPD
The apps above work well, the problem was in browser storage filled with garbage.
Setting to false in $formFactory->createBuilder(FormType::class, null, ['csrf_protection' => false]) submits the form
This is a bit of a guess but the 4.2 linked repo has:
$csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);
$csrfTokenManager = new CsrfTokenManager();
Two token managers. One is used in the twig form engine and one is used in the form factory extension. Does not seem like a reasonable thing to do.
Here is an updated 5.1 working example. I stripped it down even more from your linked repo. But the only thing that I really changed was the token manager.
# index.php
require_once '../vendor/autoload.php';
$app = new App();
$app->run();
final class App
{
public function run()
{
$csrfGenerator = new UriSafeTokenGenerator();
$csrfStorage = new NativeSessionTokenStorage();
$csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);
$twig = new Environment(new FilesystemLoader([
'../templates',
'../vendor/symfony/twig-bridge/Resources/views/Form',
]));
$formEngine = new TwigRendererEngine(['form_div_layout.html.twig'], $twig);
$twig->addRuntimeLoader(new FactoryRuntimeLoader([
FormRenderer::class => function () use ($formEngine,$csrfManager) {
return new FormRenderer($formEngine, $csrfManager);
},
]));
$twig->addExtension(new TranslationExtension());
$twig->addExtension(new FormExtension());
$formFactory = Forms::createFormFactoryBuilder()
->addExtension(new CsrfExtension($csrfManager))
//->addExtension(new ValidatorExtension($validator))
->getFormFactory();
$form = $formFactory->createBuilder()
->add('firstName', TextType::class)
->getForm();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$form->submit($_POST[$form->getName()]); // form
if ($form->isValid()) {
dump('form is valid');
}
}
echo $twig->render('index.html.twig', [
'form' => $form->createView(),
]);
}
}
The composer.json is simply:
{
"require": {
"symfony/form": "^5.1",
"symfony/twig-bridge": "^5.1",
"symfony/translation": "^5.1",
"symfony/security-csrf": "^5.1"
},
"require-dev": {
"symfony/var-dumper": "^5.1"
}
}
If you still have trouble then I would suggest tracking down where the sessions are stored and then verifying the that csrf token is being properly stored. It should look something like:
_csrf|a:1:{s:4:"form";s:43:"9v1tUNe3J3eYVOmEPwVdz5_iISfzBg8Qa9pLMV8tSN4";}
This was actually kind of an interesting exercise in using the twig system for standalone forms. Thanks.

extending sonata user bundle with more form fields, get Could not load type "Application\Sonata\UserBundle\Form\RegistrationType"

I'm trying to extend the registration form to show more fields, but after trying multiple variations, I think either there's a bug, or the configuration settings I'm seeing on tutorials and posts are not correct for symfony 2.7 it's driving me nuts, thinking maybe wait till I upgrade to version 3.4, but upgrade isn't going smoothly so far.
error -
Could not load type
"Application\Sonata\UserBundle\Form\RegistrationType"
Form -
namespace Application\Sonata\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array
$options)
{
$builder->add('firstname')
->add('dateOfBirth');
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'app_user_registration';
}
// For Symfony 2.x
public function getName()
{
return $this->getBlockPrefix();
}
}
config_dev.yml
fos_user:
db_driver: orm
firewall_name: secured_area
user_class: Application\Sonata\UserBundle\Entity\User
registration:
form:
type: Application\Sonata\UserBundle\RegistrationType
group:
group_class: Application\Sonata\UserBundle\Entity\User
services.yml
services:
app.form.registration:
class: Application\Sonata\UserBundle\Form\RegistrationType
arguments: [%fos_user.model.user.class%]
tags:
- { name: form.type, alias: app_user_registration }
So as mentioned it's symfony 2.7 and Sonata user-bundle 3.2 any help would be appreciated with this one
The part of code where it errors is this line in config_dev.yml
registration:
form:
type: Application\Sonata\UserBundle\RegistrationType
routing.yml
fos_user_register:
resource:
"#FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /register
# sonata_user_register:
# resource:
#
#SonataUserBundle/Resources/config/routing/sonata_registration_1.xml"
# prefix: /register
full config
fos_user:
db_driver: orm # other valid values are
'mongodb', 'couchdb' and 'propel'
firewall_name: secured_area
registration:
form:
type: eventsBundle\Form\RegistrationType
user_class:
Application\Sonata\UserBundle\Entity\User
group:
group_class: Application\Sonata\UserBundle\Entity\User
#group_manager: sonata.user.orm.group_manager
# If you're using doctrine orm (use
Sonata.user.mongodb.group_manager for mongodb)
service:
user_manager: sonata.user.orm.user_manager
# If you're using doctrine orm (use
sonata.user.mongodb.user_manager for mongodb)
If you want to make it simply, you have to override the correct base registration form, from FOS\UserBundle, like the Official FOSUSerBundle documentation :
namespace YourBundle\Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
use YourBundle\Entity\User;
class RegistrationType extends BaseType
{
public function __construct()
{
parent::__construct(User::class);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('firstname')
->add('dateOfBirth');
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
// Or for Symfony < 2.8
// return 'fos_user_registration';
}
public function getBlockPrefix()
{
return 'app_user_registration';
}
// For Symfony 2.x
public function getName()
{
return $this->getBlockPrefix();
}
}
Then you have to configure your form type as a service :
# app/config/services.yml
services:
app.form.registration:
class: YourBundle\Form\RegistrationType
tags:
- { name: form.type, alias: app_user_registration }
Finally, you must update the configuration of the FOSUserBundle :
# app/config/config.yml
fos_user:
# ...
registration:
form:
type: YourBundle\Form\RegistrationType
# if you are using Symfony < 2.8 you should use the type name instead
# type: app_user_registration
Hope this will helps you...
Nothing from above worked in Symfony 2.7 for me. I upgraded to Symfony 3.4 and it now works!! perfectly following the standard guide https://symfony.com/doc/master/bundles/FOSUserBundle/overriding_forms.html an upgrade really was needed, probably the autowiring features helped.
Try that:
config.yml
registration:
form:
type: eventsBundle\Form\RegistrationType
service.yml
app.form.registration:
class: eventsBundle\Form\RegistrationType
tags:
- { name: form.type, alias: app_user_registration }

Symfony upgrading 2.1 FOSUserBundle custom registration form Exception

My custom registration form was working well with the version 1.2.* but when i update symfony in 2.1 and FOSUserBundle in 2.0.*, I've got this problem that I don't know how to resolve.
The error :
The type name specified for the service "kairos_user.registration_form_type" does not match the actual name. Expected "kairos_user_registration", given "fos_user_registration"
My service definition :
services:
kairos_user.registration_form_type:
class: Kairos\UserBundle\Form\Type\RegistrationFormType
arguments: [%fos_user.model.user.class%]
tags:
- { name: form.type, alias: kairos_user_registration }
And my config.yml
fos_user:
db_driver: orm #cf kairos doctrine admin
firewall_name: main
user_class: Kairos\UserBundle\Entity\User
registration:
form:
type: kairos_user_registration
The alias of your registration form service must match the name returned by your registration form type class. In Kairos\UserBundle\Form\Type\RegistrationFormType try to change the return value of getName() method
class RegistrationFormType extends AbstractType
{
// ...
public function getName()
{
return 'kairos_user_registration';
}
}

Symfony2 - how to extend a vendor bundle (e.g. of FOSFacebookBundle)

Scenario:
I'm using a bundle (FOSFacebookBundle) that allows me to set parameters for exactly one facebook app in my configuration. Everything works perfectly fine, but now I need to set not only one app, but multiple.
My approach:
I've created a AcmeFacebookBundle, which allows multiple apps to be defined (configuration defined in Acme\FacebookBundle\DependencyInjection\Configuration) in an array like so:
acme_facebook:
apps:
some_competition:
server_url: %acme.facebook.some_competition.server_url%
file: %kernel.root_dir%/../vendor/facebook/php-sdk/src/base_facebook.php
alias: facebook
app_id: %acme.facebook.some_competition.app_id%
secret: % acme .facebook.some_competition.secret%
cookie: true
permissions: [email, user_birthday, user_location]
some_other_competition:
server_url: %acme.facebook. some_other_competition.server_url%
file: %kernel.root_dir%/../vendor/facebook/php-sdk/src/base_facebook.php
alias: facebook
app_id: %acme.facebook. some_other_competition.app_id%
secret: % acme .facebook. some_other_competition.secret%
cookie: true
permissions: [email, user_birthday, user_location]
In Acme\FacebookBundle\DependencyInjection\AcmeFacebookExtension I am then looping through all apps. The idea is to compare the server_url parameter against the current URL and override the fos_facebook configuration with mine.
class AcmeFacebookExtension extends Extension
{
...
/**
* {#inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
foreach ($config['apps'] as $app)
{
// check for matching path here?
foreach (array('file', 'app_id', 'secret', 'cookie', 'domain', 'logging', 'culture', 'permissions') as $attribute)
{
$container->setParameter('fos_facebook.' . $attribute, $app[$attribute]);
}
}
}
Problem:
But this is exactly where I'm stuck. Obviously, I have no access to the Request object or the DiC from within AcmeFacebookExtension to do this comparison.
Am I going completely wrong in my approach? Do you have any better idea on how to tackle this problem?
What you want to create is a CompilerPass so that you can manipulate the Container after all other configuration has loaded. These should get you started:
Symfony2: Service Container Compiler Passes
Symfony2: Manipulating Service Parameters and Definitions
Create a CompilerPass

Symfony2 TinymceBundle

I created an ArticleController to render a form with fields: title (text) and content (textarea), and everything works well until I add class="tinymce" to the textarea field in the template. then I get this error:
'An invalid form control with name='form[content]' is not focusable.'
I followed the documentation to add the 'class' attribute and the editor renders fine in the browser, its just when I submit the form I get the error.
Any ideas what could be causing this?
{{ form_errors(form) }}
{{ form_widget(form.title) }}
{{ form_widget(form.content, { 'attr': {'class': 'tinymce' }} ) }}
{{ form_rest(form) }}
<input type="submit" />
Apparently there is an issue with chrome regarding the attribute 'required = "true"'.
http://code.google.com/p/chromium/issues/detail?id=45640
I added 'formnovalidate = "true"' attribute to the submit button input field and it works fine
tinyMCE.init({
mode : "specific_textareas",
editor_selector : "mceEditor",
setup : function(ed) {
ed.onChange.add(function(ed, l) {
tinyMCE.activeEditor.getElement().value = tinyMCE.activeEditor.getContent();
});
}
});
I tried the suggestion from Musefan, and it only partly worked, but it got me experimenting.
Here's something that works for me. Tested on Firefox 10.0.1, IE9, and Chrome 17.
Where I'm setting tinyMCE.activeEditor.getElement().value = 'test' it can be any value other than ''. Not sure why that's true.
tinyMCE.init({
mode : "specific_textareas",
editor_selector : "tinymce",
setup : function(ed)
{
// This is needed when the textarea is required for html5
ed.onInit.add(function(ed)
{
tinyMCE.activeEditor.getElement().value = 'test'
});
},
});
The error happens when the WYSIWYG hides your textarea but the textarea is set to required field. You can set 'required' => false on your content textarea control when you build the form in order to disable browser's required check.
$builder->add("content", "textarea", array('required' => false));
tinyMCE will normally update the contents of the hidden textarea during the onsubmit-Event.
This event, however, is not fired when html5-validation is used and any input is invalid.
Therefore you will never get an empty and required textarea with tinyMCE on top to validate correctly unless you enforce the textarea to be updated before html5-validation starts.
I built a workaround for this bug which hopefully will be merged into the original repo anytime soon: https://github.com/stfalcon/TinymceBundle/pull/19
Building on musefans's response above.
I came here because I'm using Simple Form, Twitter Bootstrap, and tinymce-rails. If you're using tinymce-rails this setup you need to edit the line noted in is answer to your tinymce.yml file. Your final file should look similar to this.
theme_advanced_toolbar_location: top
theme_advanced_toolbar_align: left
theme_advanced_statusbar_location: bottom
theme_advanced_buttons3_add:
- tablecontrols
- fullscreen
plugins:
- table
- fullscreen
mode:
- specific_textareas