web-dev-qa-db-fra.com

Laravel 5 Pré-manipulation des données de formulaire

Je traite un formulaire où un utilisateur peut mettre à jour sa date de naissance. Le formulaire donne à l'utilisateur 3 champs séparés pour day, month et year. Côté serveur, bien sûr, je veux traiter ces 3 champs séparés comme une seule valeur, c'est-à-dire yyyy-mm-dd.

Donc, avant de valider et de mettre à jour ma base de données, je souhaite modifier la demande de formulaire pour créer un date_of_birth champ en concaténant year, month et day avec - caractères pour créer le format de date dont j'ai besoin (et éventuellement désactiver les 3 champs d'origine).

Réaliser cela manuellement avec mon contrôleur n'est pas un problème. Je peux simplement saisir l'entrée, joindre les champs ensemble séparés par - caractères et les désactiver. Je peux ensuite valider manuellement avant de passer à une commande pour gérer le traitement.

Cependant, je préférerais utiliser un FormRequest pour gérer la validation et l'injecter dans ma méthode de contrôleur. J'ai donc besoin d'un moyen de modifier réellement la demande de formulaire avant que la validation ne soit exécutée.

J'ai trouvé la question suivante qui est similaire: Laravel 5 Request - modification des données

Il suggère de remplacer la méthode all sur la demande de formulaire pour contenir la logique de manipulation des données avant la validation.

<?php namespace App\Http\Requests;

class UpdateSettingsRequest extends Request {

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [];
    }

    public function all()
    {
        $data = parent::all();
        $data['date_of_birth'] = 'test';
        return $data;
    }

C'est très bien pour la validation, mais remplacer la méthode all ne modifie pas réellement les données sur l'objet de demande de formulaire. Ainsi, lorsqu'il s'agit d'exécuter la commande, la demande de formulaire contient les données d'origine non modifiées. À moins que j'utilise la méthode all désormais surchargée pour extraire les données.

Je cherche un moyen plus concret de modifier les données dans ma demande de formulaire qui ne nécessite pas l'appel d'une méthode spécifique.

À votre santé

26
Jonathon

dans laravel 5.1 vous pouvez le faire

<?php namespace App\Http\Requests;

class UpdateSettingsRequest extends Request {

public function authorize()
{
    return true;
}

public function rules()
{
    return [];
}

protected function getValidatorInstance()
{
    $data = $this->all();
    $data['date_of_birth'] = 'test';
    $this->getInputSource()->replace($data);

    /*modify data before send to validator*/

    return parent::getValidatorInstance();
}
35
Julia Shestakova

Après quelques brouhaha autour de moi, j'ai trouvé ce qui suit:

app/Http/Requests/Request.php

<?php namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

abstract class Request extends FormRequest {

    /**
    * Override the initialize method called from the constructor to give subclasses
    * an opportunity to modify the input before anything happens.
    *
    * @param array $query
    * @param array $request
    * @param array $attributes
    * @param array $cookies
    * @param array $files
    * @param array $server
    * @param null $content
    */
    public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
    {
        parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content);

        // Grab the input
        $data = $this->getInputSource()->all();
        // Pass it off to modifyInput function
        $data = $this->modifyInput($data);
        // Replace modified data back into input.
        $this->getInputSource()->replace($data);
    }


    /**
    * Function that can be overridden to manipulate the input data before anything
    * happens with it.
    *
    * @param array $data The original data.
    * @return array The new modified data.
    */
    public function modifyInput(array $data)
    {
        return $data;
    }

}

Ensuite, lors de l'extension des classes, vous pouvez simplement remplacer la méthode modifyInput comme ceci:

app/Http/Requests/TestRequest.php

<?php namespace App\Http\Requests;

class TestRequest extends Request {

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [];
    }

    /**
     * Modify the input.
     */
    public function modifyInput(array $data)
    {
        $data['date_of_birth'] = 'something';

        // Make sure to return it.
        return $data;
    }

}

Cela semble fonctionner pour mes besoins. Je ne suis pas sûr des inconvénients de le faire de cette façon, donc je salue tous les commentaires/critiques.

La réponse donnée par The Shift Exchange ci-dessus fonctionnera également très bien.

9
Jonathon

Depuis Laravel 5.4, vous pouvez utiliser la méthode prepareForValidation sur les classes FormRequest.

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title' => 'required|max:200',
            'body' => 'required',
            'tags' => 'required|array|max:10',
            'is_published' => 'required|boolean',
            'author_name' => 'required',
        ];
    }

    /**
     * Prepare the data for validation.
     *
     * @return void
     */
    protected function prepareForValidation()
    {
        $this->merge([
            'title' => fix_typos($this->title),
            'body' => filter_malicious_content($this->body),
            'tags' => convert_comma_separated_values_to_array($this->tags),
            'is_published' => (bool) $this->is_published,
        ]);
    }
}

Il y a un article plus détaillé ici: https://sampo.co.uk/blog/manipulating-request-data-before-performing-validation-in-laravel

7
BenSampo

Je pense que c'est la meilleure approche pour le faire: Laravel 5.1 Modifier l'entrée avant la validation de la demande de formulaire

Dans Laravel 5.4+ il y a une méthode dédiée pour des trucs comme ça alors utilisez-la: prepareForValidation

3
Thomas Venturini

J'ai adopté une approche similaire à Julia Logvina mais je pense que cette façon est un moyen légèrement plus élégant d'ajouter/modifier des champs avant la validation (Laravel 5.1)

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class UpdateSettingsRequest extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {        
        return [];
    }


    /** 
     * Extend the default getValidatorInstance method
     * so fields can be modified or added before validation
     *
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function getValidatorInstance()
    {

        // Add new data field before it gets sent to the validator
        $this->merge(array('date_of_birth' => 'test'));

        // OR: Replace ALL data fields before they're sent to the validator
        // $this->replace(array('date_of_birth' => 'test'));

        // Fire the parent getValidatorInstance method
        return parent::getValidatorInstance();

    }

}

Cela étendra la valeur par défaut getValidatorInstance afin que nous puissions modifier les valeurs d'entrée dans la demande avant qu'elle ne parvienne au validateur (l'empêchant d'utiliser les données d'origine non modifiées). Une fois les données modifiées, elles déclenchent le getValidatorInstance d'origine, puis tout se poursuit normalement.

Vous pouvez utiliser $this->replace(array()) ou $this->merge(array()) vos nouveaux champs dans votre demande. J'ai inclus un exemple de la façon de faire les deux dans l'extrait ci-dessus.

replace() remplacera tous les champs par le tableau que vous fournissez.

merge() ajoutera un nouveau champ à votre demande.

3
bmagg

Vous remplacez toujours la méthode all() - mais essayez comme ceci

public function all()
{
    $input = $this->all();
    $input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
    $this->replace($input);
    return $this->all();
}

Ensuite, vous n'avez pas réellement appelez la méthode vous-même - elle sera appelée par le validateur lui-même lors de l'élaboration des règles.

2
Laurence

Moi aussi, j'avais besoin d'un moyen rapide et sale pour y parvenir. Je voulais utiliser la solution Shift Exchanges mais cela n'a pas fonctionné à cause des appels à $this qui crée une boucle récursive infinie. Un changement rapide pour référencer la méthode parent à la place résoudra le problème:

public function all()
{
    $input = parent::all();
    $input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
    $this->replace($input);
    return parent::all();
}

HTH autres dans le besoin.

0
snstoller