Dans cette vidéo je vous propose de découvrir une librairie plutôt intéressante pour la gestion des formulaires sur Laravel : kristijanhusak/laravel-form-builder. Très inspirée du système de Form Builder de Symfony, cette librairie permet de représenter les formulaires sous forme d'objets. Objets qui seront ensuite utilisés pour obtenir le code HTML du formulaire, mais aussi pour gérer la validation et le traitement des données.

Installation & Création

Comme toujours l'installation se fait au travers de composer :

composer require kris/laravel-form-builder

Laravel devrait ensuite détecter automatiquement le service provider, mais vous pouvez toujours l'ajouter dans votre fichier de configuration :

'providers' => [
    // ...
    Kris\LaravelFormBuilder\FormBuilderServiceProvider::class
]

Vous aurez alors la possibilité de créer dynamiquement des formulaires en utilisant les commandes artisan :

php artisan make:form Forms/PostForm 

Ceci vous permettra de générer une classe pour représenter votre formulaire. C'est à l'intérieur de celle-ci que l'on va définir la liste des champs. Vous pouvez générer automatiquement le code correspondant à vos champs en rajoutant un drapeau --fields :

php artisan form:make Http/Forms/LoginForm --fields="name:text, content:textarea" 

L'ensemble des types de champs disponibles sont listés sur la documentation ainsi que les options disponibles pour chacun.

<?php

namespace App\Forms;

use App\Tag;

class PostForm extends \Kris\LaravelFormBuilder\Form
{
    public function buildForm()
    {
        if ($this->getModel() && $this->getModel()->id) {
            $url = route('posts.update', $this->getModel()->id);
            $method = 'PUT';
            $label = "Editer l'article";
        } else {
            $url = route('posts.store');
            $method = 'POST';
            $label = "Créer l'article";
        }

        $this
            ->add('name', 'text', [
                'label' => 'Titre'
            ])
            ->add('content', 'textarea', [
                'label' => 'Contenu'
            ])
            ->add('tags', 'entity', [
                'class' => App\Tag::class,
                'multiple' => true,
                'property' => 'name'
            ])
            ->add('submit', 'submit', ['label' => $label])

        $this->formOptions = [
            'method' => $method,
            'url' => $url
        ];
    }
}

Utilisation

Maintenant que notre class est créée, nous pouvons l'initialiser au niveau de notre controlleren utilisant la façade FormBuilder ou en utilisant l'injection de dépendance.

<?php

namespace App\Http\Controllers;

use App\Forms\PostForm;
use App\Post;
use Illuminate\Http\Request;
use Kris\LaravelFormBuilder\FormBuilder;

class PostsController extends Controller
{

    private $formBuilder;

    public function __construct(FormBuilder $formBuilder)
    {
        $this->formBuilder = $formBuilder;
    }

    public function create()
    {
        $form = $this->getForm();
        return view('posts.create', compact('form'));
    }

    public function store()
    {
        $form = $this->getForm();
        $form->redirectIfNotValid();
        $form->getModel()->save();
        return redirect()->route('posts.index');
    }

    public function edit(Post $post)
    {
        $form = $this->getForm($post);
        return view('posts.edit', compact('form'));
    }

    public function update(Post $post, Request $request)
    {
        $form = $this->getForm($post);
        $form->redirectIfNotValid();
        $post->save();
        $post->tags()->sync($request->get('tags'));
        return redirect()->route('posts.index');
    }

    private function getForm(?Post $post = null): PostForm
    {
        $post = $post ?: new Post();
        return $this->formBuilder->create(PostForm::class, [
            'model' => $post
        ]);
    }

}

Cet objet va nous permettre de représenter le formulaire et devra être envoyé à la vue afin de gérer l'affichage HTML. Le service provider injecte automatiquement au niveau de vos vues une série d'helpers que vous allez pouvoir utiliser pour générer le code HTML de votre formulaire. La méthode form() vous permet de générer l'entièreté du formulaire mais vous disposez d'un ensemble de méthodes qui vont vous permettre de mieux gérer le placement de vos différents champs (ce qui peut s'avérer pratique dans le cas où vous souhaitez disposer votre formulaire d'une manière spécifique avec plusieurs colonnes par exemple).

Un autre aspect intéressant de ce système de FormBuilder, c'est la possibilité de gérer directement au niveau de notre classe Form la gestion de la validation des données. Vous avez la possibilité pour chaque champ de votre formulaire de spécifier à l'aide de l'attribut rules. Cet attribut prend paramètres l'ensemble des règles de validation appliquée au niveau de votre champ. Ces règles sont les mêmes que celles qui sont utilisées par le validateur par défaut de Laravel.

// ...

public function buildForm()
{

    // ...

    $this
        ->add('name', 'text', [
            'label' => 'Titre',
            'rules' => 'required|min:5'
        ])
        ->add('content', 'textarea', [
            'label' => 'Contenu',
            'rules' => 'required|min:5'
        ])
        ->add('tags', 'entity', [
            'class' => App\Tag::class,
            'multiple' => true,
            'property' => 'name'
        ])
        ->add('submit', 'submit', ['label' => $label])

    $this->formOptions = [
        'method' => $method,
        'url' => $url
    ];
}

Vous pourrez ensuite valider les données au niveau de votre controller

    public function store(Request $request)
    {
        $post = new Post();
        $form = $this->getForm();
        $form->redirectIfNotValid();
        $post->fill($request->only(['name', 'content'])->save();
        return redirect()->route('posts.index');
    }