Neben Bedenken hinsichtlich der Leistung der REST-API und der Microservices bin ich sehr besorgt über die Lesbarkeit des Codes, den wir täglich eingeben, um Arbeitsprobleme einschließlich der Datenvalidierung zu lösen.
Ich möchte Codeteile aus meinen eigenen Benchmarks anzeigen, damit Sie die Breite der Lösungsansätze für dasselbe Problem einschätzen können. Stellen wir uns vor, der folgende Datensatz ist bei uns angekommen:
$form = [
'name' => 'Elon Mask',
'name_wrong' => 'Mask',
'login' => 'mask',
'login_wrong' => 'm@sk',
'email' => 'elon@tesla.com',
'email_wrong' => 'elon@tesla_com',
'password' => '1q!~|w2o<z',
'password_wrong' => '123456',
'date' => '2020-06-05 15:52:00',
'date_wrong' => '2020:06:05 15-52-00',
'ipv4' => '192.168.1.1',
'ipv4_wrong' => '402.28.6.12',
'uuid' => '70fcf623-6c4e-453b-826d-072c4862d133',
'uuid_wrong' => 'abcd-xyz-6c4e-453b-826d-072c4862d133',
'extra' => 'that field out of scope of validation',
'empty' => ''
];
Unser Ziel ist es, dieses Array durch eine Reihe von Validierungsregeln zu führen, was zu einer Liste aller Felder mit Fehlern und Standardnachrichten führt, die dem Benutzer demonstriert werden sollen.
Industriestandard und Symbol für reines OOP - Symfony natürlich
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Translation\MessageSelector;
$validator = Validation::createValidator();
$constraint = new Assert\Collection([
'name' => new Assert\Regex('/^[A-Za-z]+\s[A-Za-z]+$/u'),
'login' => new Assert\Regex('/^[a-zA-Z0-9]-_+$/'),
'email' => new Assert\Email(),
'password' => [
new Assert\NotBlank(),
new Assert\Length(['max' => 64]),
new Assert\Type(['type' => 'string'])
],
'agreed' => new Assert\Type(['type' => 'boolean'])
]);
$violations = $validator->validate($form, $constraint);
$errors = [];
if (0 !== count($violations)) {
foreach ($violations as $violation) {
$errors[] = $violation->getPropertyPath() . ' : ' . $violation->getMessage();
}
}
return $errors;
Rasiermesser-Code in reinem PHP
$errors = [];
if (!preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $form['name']))
$errors['name'] = 'should consist of two words!';
if (!preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $form['name_wrong']))
$errors['name_wrong'] = 'should consist of two words!';
if (!preg_match('/^[a-zA-Z0-9-_]+$/', $form['login']))
$errors['login'] = 'should contain only alphanumeric!';
if (!preg_match('/^[a-zA-Z0-9]-_+$/', $form['login_wrong']))
$errors['login_wrong'] = 'should contain only alphanumeric!';
if (filter_var($form['email'], FILTER_VALIDATE_EMAIL) != $form['email'])
$errors['email'] = 'provide correct email!';
if (filter_var($form['email_wrong'], FILTER_VALIDATE_EMAIL) != $form['email_wrong'])
$errors['email_wrong'] = 'provide correct email!';
if (!is_string($form['password']) ||
$form['password'] == '' ||
strlen($form['password']) < 8 ||
strlen($form['password']) > 64
)
$errors['password'] = 'provide correct password!';
if (!is_string($form['password_wrong']) ||
$form['password_wrong'] == '' ||
strlen($form['password_wrong']) < 8 ||
strlen($form['password_wrong']) > 64
)
$errors['password_wrong'] = 'provide correct password!';
if (!preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', $form['date']))
$errors['date'] = 'provide correct date!';
if (!preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', $form['date_wrong']))
$errors['date_wrong'] = 'provide correct date!';
if (filter_var($form['ipv4'], FILTER_VALIDATE_IP) != $form['ipv4'])
$errors['ipv4'] = 'provide correct ip4!';
if (filter_var($form['ipv4_wrong'], FILTER_VALIDATE_IP) != $form['ipv4_wrong'])
$errors['ipv4_wrong'] = 'provide correct ip4!';
if (!preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $form['uuid']))
$errors['uuid'] = 'provide correct uuid!';
if (!preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $form['uuid_wrong']))
$errors['uuid_wrong'] = 'provide correct uuid!';
if (!isset($form['agreed']) || !is_bool($form['agreed']) || $form['agreed'] != true)
$errors['agreed'] = 'you should agree with terms!';
return $errors;
Lösung basierend auf einer der beliebtesten Respect Validation-Bibliotheken
use Respect\Validation\Validator as v;
use Respect\Validation\Factory;
Factory::setDefaultInstance(
(new Factory())
->withRuleNamespace('Validation')
->withExceptionNamespace('Validation')
);
$messages = [];
try {
v::attribute('name', v::RespectRule())
->attribute('name_wrong', v::RespectRule())
->attribute('login', v::alnum('-_'))
->attribute('login_wrong', v::alnum('-_'))
->attribute('email', v::email())
->attribute('email_wrong', v::email())
->attribute('password', v::notEmpty()->stringType()->length(null, 64))
->attribute('password_wrong', v::notEmpty()->stringType()->length(null, 64))
->attribute('date', v::date())
->attribute('date_wrong', v::date())
->attribute('ipv4', v::ipv4())
->attribute('ipv4_wrong', v::ipv4())
->attribute('uuid', v::uuid())
->attribute('uuid_wrong', v::uuid())
->attribute('agreed', v::trueVal())
->assert((object) $form);
} catch (\Exception $ex) {
$messages = $ex->getMessages();
}
return $messages;
Auch bekannter Name: Valitron
use Valitron\Validator;
Validator::addRule('uuid', function($field, $value) {
return (bool) preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $value);
}, 'UUID should confirm RFC style!');
$rules = [
'required' => [ 'login', 'agreed' ],
'regex' => [ ['name', '/^[A-Za-z]+\s[A-Za-z]+$/'] ],
'lengthMin' => [ [ 'password', '8'], [ 'password_wrong', '8'] ],
'lengthMax' => [ [ 'password', '64'], [ 'password_wrong', '64'] ],
'slug' => [ 'login', 'login_wrong' ],
'email' => [ 'email', 'email_wrong' ],
'date' => [ 'date', 'date_wrong' ],
'ipv4' => [ 'ipv4', 'ipv4_wrong' ],
'uuid' => [ 'uuid', 'uuid_wrong' ],
'accepted' => 'agreed'
];
$validator = new Validator($form);
$validator->rules($rules);
$validator->rule('accepted', 'agreed')->message('You should set {field} value!');
$validator->validate();
return $validator->errors());
Schöner Sirius
$validator = new \Sirius\Validation\Validator;
$validator
->add('name', 'required | \Validation\SiriusRule')
->add('login', 'required | alphanumhyphen', null, 'Only latin chars, underscores and dashes please.')
->add('email', 'required | email', null, 'Give correct email please.')
->add('password', 'required | maxlength(64)', null, 'Wrong password.')
->add('agreed', 'required | equal(true)', null, 'Where is your agreement?');
$validator->validate($form);
$errors = [];
foreach ($validator->getMessages() as $attribute => $messages) {
foreach ($messages as $message) {
$errors[] = $attribute . ' : '. $message->getTemplate();
}
}
return $errors;
Und so validieren sie in Laravel
use Illuminate\Validation\Factory as ValidatorFactory;
use Illuminate\Translation\Translator;
use Illuminate\Translation\ArrayLoader;
use Symfony\Component\Translation\MessageSelector;
use Illuminate\Support\Facades\Validator as FacadeValidator;
$rules = array(
'name' => ['regex:/^[A-Za-z]+\s[A-Za-z]+$/u'],
'name_wrong' => ['regex:/^[A-Za-z]+\s[A-Za-z]+$/u'],
'login' => ['required', 'alpha_num'],
'login_wrong' => ['required', 'alpha_num'],
'email' => ['email'],
'email_wrong' => ['email'],
'password' => ['required', 'min:8', 'max:64'],
'password_wrong' => ['required', 'min:8', 'max:64'],
'date' => ['date'],
'date_wrong' => ['date'],
'ipv4' => ['ipv4'],
'ipv4_wrong' => ['ipv4'],
'uuid' => ['uuid'],
'uuid_wrong' => ['uuid'],
'agreed' => ['required', 'boolean']
);
$messages = [
'name_wrong.regex' => 'Username is required.',
'password_wrong.required' => 'Password is required.',
'password_wrong.max' => 'Password must be no more than :max characters.',
'email_wrong.email' => 'Email is required.',
'login_wrong.required' => 'Login is required.',
'login_wrong.alpha_num' => 'Login must consist of alfa numeric chars.',
'agreed.required' => 'Confirm radio box required.',
);
$loader = new ArrayLoader();
$translator = new Translator($loader, 'en');
$validatorFactory = new ValidatorFactory($translator);
$validator = $validatorFactory->make($form, $rules, $messages);
return $validator->messages();
Rakit Validation Unerwarteter Diamant
$validator = new \Rakit\Validation\Validator;
$validator->addValidator('uuid', new \Validation\RakitRule);
$validation = $validator->make($form, [
'name' => 'regex:/^[A-Za-z]+\s[A-Za-z]+$/u',
'name_wrong' => 'regex:/^[A-Za-z]+\s[A-Za-z]+$/u',
'email' => 'email',
'email_wrong' => 'email',
'password' => 'required|min:8|max:64',
'password_wrong' => 'required|min:8|max:64',
'login' => 'alpha_dash',
'login_wrong' => 'alpha_dash',
'date' => 'date:Y-m-d H:i:s',
'date_wrong' => 'date:Y-m-d H:i:s',
'ipv4' => 'ipv4',
'ipv4_wrong' => 'ipv4',
'uuid' => 'uuid',
'uuid_wrong' => 'uuid',
'agreed' => 'required|accepted'
]);
$validation->setMessages([
'uuid' => 'UUID should confirm RFC rules!',
'required' => ':attribute is required!',
// etc
]);
$validation->validate();
return $validation->errors()->toArray();
Na und? Welches Codebeispiel ist das aussagekräftigste, idiomatischste, korrekteste und allgemein „korrekteste“? Meine persönliche Wahl ist an den Docks auf Comet: github.com/gotzmann/comet Zum Schluss
noch eine kleine Umfrage für die Nachwelt.