it-swarm.com.de

Hinzufügen von benutzerdefinierten Überprüfungsfehlern zu Laravel bilden

Ich habe ein grundlegendes Formular eingerichtet, das es einem Benutzer ermöglicht, seine E-Mail-Adresse zu ändern, und ich mache die folgende Überprüfung, bevor ich die E-Mail ändere:

// Set up the form validation
$validator = Validator::make(
    Input::all(),
    array(
        'email' => 'email|unique:users',
        'password' => 'required'
    )
);

// If validation fails, redirect to the settings page and send the errors
if ($validator->fails())
{
    return Redirect::route('settings')->withErrors($validator)->withInput();
}

Dies funktioniert gut, aber nach dieser grundlegenden Überprüfung möchte ich prüfen, ob der Benutzer ein korrektes Kennwort eingegeben hat. Um dies zu tun, mache ich Folgendes mit der grundlegenden Authentifizierungsbibliothek von Laravel:

// Find the user and validate their password
$user = Auth::user();

if (!Auth::validate(array('username' => $user->username, 'password' => Input::get('password'))))
{
    die("failed to authenticate");
}

Anstatt die Logik zu verwenden, um dem Benutzer mitzuteilen, dass sein Passwort selbst nicht korrekt ist, füge ich stattdessen einfach einen Formularfehler zur password-Eingabe hinzu, sodass er wie eine normale Formularüberprüfung angezeigt wird. So ähnlich:

if (!Auth::validate(array('username' => $user->username, 'password' => Input::get('password'))))
{
    $validator->addError('password', 'That password is incorrect.');
    return Redirect::route('settings')->withErrors($validator)->withInput();
}

Auf diese Weise wird der falsche Passwortfehler neben meiner Passworteingabe angezeigt und sieht wie eine ordnungsgemäße Formularprüfung aus.

Wie kann ich das machen?

11
John Dorean

Siehe Darren Craig's Antwort.

Eine Möglichkeit, es zu implementieren.

// inside if(Auth::validate)
if(User::where('email', $email)->first())
{
    $validator->getMessageBag()->add('password', 'Password wrong');
}
else
{
    $validator->getMessageBag()->add('email', 'Email not found');
}
26
Bastian Hofmann

Es gibt ein Problem mit der akzeptierten Antwort (und meiner Meinung nach generell mit Laravel's Validator) - der Validierungsprozess selbst und die Validierung des Validierungsstatus werden in einer Methode zusammengefasst. 

Wenn Sie blind alle Validierungsnachrichten aus der Tasche rendern, ist das keine große Sache. Wenn Sie jedoch über eine zusätzliche Logik verfügen, die feststellt, ob der Prüfer fehlgeschlagen ist oder nicht, und zusätzliche Aktionen ausführt (z. B. internationale Textnachrichten für aktuell validierte Formularfelder eingeben), liegt ein Problem vor. 

Demonstration:

    // let's create an empty validator, assuming that we have no any errors yet
    $v = Validator::make([], []);

    // add an error
    $v->errors()->add('some_field', 'some_translated_error_key');
    $fails = $v->fails(); // false!!! why???
    $failedMessages = $v->failed(); // 0 failed messages!!! why???

Ebenfalls, 

    $v->getMessageBag()->add('some_field', 'some_translated_error_key');

liefert die gleichen Ergebnisse. Warum? Wenn Sie sich den Validator-Code von Laravel ansehen, werden Sie Folgendes finden:

public function fails()
{
    return ! $this->passes();
}

public function passes()
{
    $this->messages = new MessageBag;

Wie Sie sehen, löscht die fails()-Methode im Wesentlichen den Beutel, der alle von Ihnen angehängten Nachrichten verliert, und lässt den Prüfer davon ausgehen, dass keine Fehler vorliegen. 

Es gibt keine Möglichkeit, Fehler an den vorhandenen Prüfer anzuhängen und ihn zum Scheitern zu bringen. Sie können einen neuen Prüfer nur mit benutzerdefinierten Fehlern wie folgt erstellen:

    $v = Validator::make(['some_field' => null],
            ['some_field' => 'Required:some_translated_error_key']);
    $fails = $v->fails(); // true
    $failedMessages = $v->failed(); // has error for `required` rule

Wenn Sie die required-Überprüfungsregel für benutzerdefinierte angefügte Fehler nicht missbrauchen möchten, können Sie Laravel Validator immer um benutzerdefinierte Regeln erweitern. Ich habe eine generische failkey-Regel hinzugefügt und dies auf folgende Weise verbindlich gemacht:

    // in custom Validator constructor: our enforced failure validator
    array_Push($this->implicitRules, "Failkey");

    ...


/**
 * Allows to fail every passed field with custom key left as a message
 * which should later be picked up by controller
 * and resolved with correct message namespaces in validate or failValidation methods
 *
 * @param $attribute
 * @param $value
 * @param $parameters
 *
 * @return bool
 */
public function validateFailkey($attribute, $value, $parameters)
{
    return false; // always fails
}

protected function replaceFailkey($message, $attribute, $rule, $parameters)
{
    $errMsgKey = $parameters[0];

    // $parameters[0] is the message key of the failure
    if(array_key_exists($errMsgKey, $this->customMessages)){
        $msg = $this->customMessages[$parameters[0]];
    }       
    // fallback to default, if exists
    elseif(array_key_exists($errMsgKey, $this->fallbackMessages)){
        return $this->fallbackMessages[$parameters[0]];
    }
    else {
        $msg = $this->translator->trans("validation.{$errMsgKey}");
    }

    // do the replacement again, if possible
    $msg = str_replace(':attribute', "`" . $this->getAttribute($attribute) 
            . "`", $msg);

    return $msg;
}

Und ich kann es so verwenden:

    $v = Validator::make(['some_field' => null],
            ['some_field' => 'failkey:some_translated_error_key']);
    $fails = $v->fails(); // true
    $failedMessages = $v->failed(); // has error for `Failkey` rule

Natürlich ist das immer noch eine harte Art, das Problem zu umgehen. 

Idealerweise würde ich den Validator so umgestalten, dass seine Validierungsphase klar von der Statuserkennung getrennt wird (getrennte Methoden für validate() und passes() oder besser isValid()) und außerdem bequeme Methoden hinzugefügt werden, um ein bestimmtes Feld mit bestimmten Regeln manuell auszufallen. Dies kann zwar auch als hackig betrachtet werden, aber wir haben keine andere Wahl, wenn wir den Laravel-Validator nicht nur mit den eigenen Validierungsregeln von Laravel verwenden möchten, sondern auch mit unseren benutzerdefinierten Geschäftslogikregeln.

8
JustAMartin

Alternative Syntax:

$validator->errors()
          ->add('photos', 'At least one photo is required for a new listing.');
3
zeros-and-ones

Darüber hinaus kann es hilfreich sein, die folgende Redirect::back()-Funktion hinzuzufügen:

$validator->getMessageBag()->add('password', 'Password wrong');    
return Redirect::back()->withErrors($validator)->withInput();

Gemäß 

Das Alpha

( http://heera.it/laravel-manually-invalidate-validation#.VVt7Wfl_NBc )

2
Pathros

Ich habe ein ähnliches Problem mit der Validierung und benutzerdefinierten Validierung gelöst. In meinem Fall muss ich sicherstellen, dass die hochgeladene Datei mit dem Formular ein gültiges Bild und auch die Nachbearbeitungsdaten ist. Daher muss ich einen Validierungstest für die Datei und die Überprüfungstests für die Nachbearbeitungsdaten durchführen. Ich war ein Problem, als ich versuchte, meine benutzerdefinierten Validierungsdaten zurückzugeben. Nur Laravel-Validierungsfehler waren vorhanden. Laut dem @JustAMartin-Beitrag wurde eine Lösung codiert, die alle Fehler anzeigt. 

    //Creem una instància del validador. Açò ens permet manipular-lo
    $validator = Validator::make($request->all(), [
        'nomCompanyia' => 'required',
        'urlCompanyia' => 'url'
    ]);

    $imageError = false;
    $imgOriginal = null;
    $imgMitjana = null;
    $imgXicoteta = null;
    $fallaValidacio = !$validator->passes(); //-> Retorna true si cap error, false en cas contrari.

    if($request->hasFile('logoCompanyia') && !$fallaValidacio)
    {
        $imatge = $request->file('logoCompanyia');

        if($imatge->isValid() && $this->verificaExtensionsImatges($imatge->getClientOriginalExtension(), $imatge->guessExtension()))
        {
            $sPath = $imatge->store('images/companyies/', 'public');
            $fullPathOriginal = public_path() . "/storage/" . $sPath;
            $fpInfo = pathinfo($fullPathOriginal);
            $imgOriginal = sprintf("%s.%s", $fpInfo['filename'], $fpInfo['extension']);

            //Crear les miniatures
            $mitjana = Image::make($fullPathOriginal)->widen(300, function ($constraint) {
                $constraint->upsize();
            });

            $imgMitjana = sprintf("%s_300.%s", $fpInfo['filename'], $fpInfo['extension']);
            $mitjana->save($fpInfo['dirname'] . '/' . $imgMitjana);

            $xicoteta = Image::make($fullPathOriginal)->widen(100, function ($constraint) {
                $constraint->upsize();
            });

            $imgXicoteta = sprintf("%s_100.%s", $fpInfo['filename'], $fpInfo['extension']);
            $xicoteta->save($fpInfo['dirname'] . '/' . $imgXicoteta);
        }
        else
        {
            $imageError = true;
            $validator->getMessageBag()->add('logoCompanyia', "Sembla que el fitxer d'imatge no és vàlid o està corrupte. Només s'accepten els formats: .jpg, .jpeg, .png, .gif");
        }
    }
    else
    {
        $imageError = true;
        $validator->getMessageBag()->add('logoCompanyia', "Sembla que el fitxer d'imatge no és vàlid o ha sigut rebutjat per el servidor si és massa gran.");
    }

    if($fallaValidacio || $imageError)
    {
        $data['mode'] = "nou";
        $data['urlFormulari'] = "administracio/companyies/afegir";
        $data['nomCompanyia'] = $request->nomCompanyia;
        $data['idCompanyia'] = 0;
        $data['urlCompanyia'] = $request->urlCompanyia;
        $data['logoCompanyia'] = $request->logoCompanyia;
        $data['errors'] = (object) $validator->errors();

        return view($this->formulariTemplate, $data);
    }

    $companyia = new Companyies();
    $companyia->nom = $request->nomCompanyia;
    $companyia->url = $request->urlCompanyia;
    $companyia->logo_original = $imgOriginal;
    $companyia->logo_300 = $imgMitjana;
    $companyia->logo_100 = $imgXicoteta;

    $companyia->save();

Wie Sie sehen, rufe ich nur $ validator-> pass () auf und speichere das Ergebnis in einer Variablen. Wenn ich diese Methode aufrufe, werden alle Laravel Tests durchgeführt. Wenn sie übergeben werden oder nicht, wird das Ergebnis in der Variablen gespeichert, sodass Sie Ihre Variable später testen können. Dadurch können die Tests der Datei durchgeführt werden, um schließlich zu bestimmen, ob alle Daten in Ordnung sind oder nicht. 

Wenn es Fehler gibt, leite ich mit dem view () - Helper zurück und füge alle Daten hinzu: Eingabe und Fehler. Wenn keine Fehler vorhanden sind, wird das normale Verhalten für die Methode fortgesetzt. 

0
 $validator -> errors() -> add('attribute', 'value');
 return redirect($request -> url())
                    -> withErrors($validator)
                    -> withInput();

In "Wert" können Sie alles übergeben.

0
Lipa

Wenn Sie ajax-Aufrufe verwenden, vergessen Sie nicht, eine ValidationException zu werfen.

if ($subscribed) {
    $validator->errors()->add('email', __('Your email is already subscribed.'));
    throw new ValidationException($validator);
}
0
Toni Almeida

Ich verstehe, warum Sie dies möchten, es ist jedoch aus Sicherheitsgründen eine schlechte Praxis, eine Nachricht zurückzugeben, die angibt, ob der Benutzername und/oder das Passwort falsch sind. Dies würde einem Hacker ermöglichen, zu verstehen, ob er den Benutzernamen oder das Kennwort richtig eingegeben hat.

Es ist besser, eine allgemeine Nachricht wie "Ihre Anmeldeinformationen sind falsch" zurückzugeben, die Sie sowieso nicht neben Ihren Feldern anzeigen möchten.

0
Darren Craig

benutzer Matt K sagte in einem Kommentar, dass laravel hat seitdem Validierungs-Hooks implementiert , was genau das macht, was wir wollen:

$validator = Validator::make(...);

$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add('field', 'Something is wrong with this field!');
    }
});

if ($validator->fails()) {
    // this actually runs! even if the original validator succeeded!
}
0
TKoL