barryvdh / laravel-form-bridge

Laravel Bridge for the Symfony Form Component
152 stars 29 forks source link

Laravel validation #13

Open barryvdh opened 7 years ago

barryvdh commented 7 years ago

To make it easy to validate, we can use the Laravel validator with Symfony forms:

 $form = $factory->create(FormType::class, $user)
        ->add('name', TextType::class, [
            'rules' => 'required',
        ])
        ->add('email', EmailType::class, [
            'rules' => 'email|unique'
        ]);

This would run the validator post-submit, so you can check $form->isValid() after submitting the form. When failed, the errors on the form are added.

This seems to work already with this commit: https://github.com/barryvdh/laravel-form-bridge/commit/811ca4c39b536f1022084e38cb5bac69436f0906

Next step would be to:

barryvdh commented 7 years ago

So I can add the required rule when the required option is set, but the other way around doesn't seem to work; https://github.com/barryvdh/laravel-form-bridge/commit/b4a43486f6173503b81812026f3dd42383b85217

barryvdh commented 7 years ago

So front-end validation is roughly working: https://github.com/barryvdh/laravel-form-bridge/commit/64ff0cbe6c30d46751ff013f7b4d413531e47ff6 And setting default required state with the config: https://github.com/barryvdh/laravel-form-bridge/commit/f1ccbc11960bd739b6bbd99bddd8cab20a66ca6f

Could perhaps add some rules based on the type (eg Emailtype -> add email rules), but not really sure if that's possible.

barryvdh commented 7 years ago

https://laravel.com/docs/5.4/upgrade#upgrade-5.4.0

Validation: Method Names The addError method has been renamed to addFailure. In addition, the doReplacements method has been renamed to makeReplacements. Typically, these changes will only be relevant if you are extending the Validator class.

alejobit commented 7 years ago

When no rules defined:

BadMethodCallException in Validator.php line 3295:
Method [validateNullable] does not exist.

This is my composer dependencies:

    "require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.2.*",
        "barryvdh/laravel-form-bridge": "^0.3.2"
    },

Temporary solution: comment lines 49-51 in ValidationTypeExtension

            if (!in_array('required', $rules) && !in_array('nullable', $rules)){
                $rules[] = 'nullable';
            }
barryvdh commented 7 years ago

Ah, nullable doesn't exist in 5.2 we should probably add a check indeed.

barryvdh commented 7 years ago

Should be fixed with latest v0.3.3

bobmulder commented 4 years ago

Since #30 got closed, I'd like to mention that I got an issue with validation using the CollectionType in my parent form. Figured out that constraints (validation by Symfony Form itself) is working well. It seems that rules (implemented by @barryvdh ) don't work on child forms...

Any hint @barryvdh? I have no clue XD

Regards, Bob

barryvdh commented 4 years ago

Do you have a test case?

bobmulder commented 4 years ago

I'll post some code tomorow. Or do you prefer unit tests?

barryvdh commented 4 years ago

Nee a simple thing I can put in my own Laravel app is fine

bobmulder commented 4 years ago

What about this? Simplified it but should work...

Parent

<?php

namespace App\Core\Http\Forms\Types;

use Illuminate\Validation\Rule;
use Laravel\Nova\Fields\Number;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class ParentFormType extends AbstractType
{

    public function __construct()
    {
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $auth = auth();

        $builder
            ->add('sizeTo', NumberType::class, [
                'required' => true,
                'rules' => [
                    'min:00',
                    'max:99'
                ]
            ])
            ->add('weight', NumberType::class, [
                'required' => false,
                'rules' => [
                    'numeric'
                ]
            ])
            ->add('weightUnit', TextType::class, [
                'required' => false,
                'rules' => [
                    Rule::in(['kg', 'ha'])
                ]
            ])
            ->add('childs', CollectionType::class, [
                'label' => false,
                'entry_type' => ChildType::class,
                'allow_add' => true,
            ])
            ->add('submit', SubmitType::class);
    }
}

Child

<?php

namespace App\Core\Http\Forms\Types;

use Illuminate\Validation\Rule;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ChildType extends AbstractType
{

    public function __construct()
    {
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $auth = auth();

        $builder
            ->add('class', TextType::class, [
                'required' => true,
            ])
            ->add('size', NumberType::class, [
                'required' => true,
                'rules' => [
                    'min:00',
                    'max:99'
                ]
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => ParentData::class,
        ]);
    }
}
barryvdh commented 4 years ago

I recreated this and added a level deeper. I made some changes (see https://github.com/barryvdh/laravel-form-bridge/commit/746fae0473a2ebc311497528f772de774bbf72b4) and now I get this rule set:

Screen Shot 2019-11-02 at 14 15 04

It should add the validation for the children when at least 1 of the children is in the form input.

You can test this with 0.5@dev, can you check it out?

bobmulder commented 4 years ago

Great work Barry! I'll check it out Monday morning! Have a nice weekend.

bobmulder commented 4 years ago

Hi there! It's me again :) last week I got some new validation issues with collections combined with Laravel's rules. I'll dig into this and I'll try to create a reproduction.