gmarche/src/Framework/Validator.php

272 lines
6.9 KiB
PHP

<?php
namespace Framework;
use Framework\Database\Table;
use Framework\Validator\ValidationError;
use Psr\Http\Message\UploadedFileInterface;
class Validator
{
private const MIME_TYPES = [
'jpg' => 'image/jpeg',
'png' => 'image/png',
'pdf' => 'application/pdf'
];
/**
* @var array
*/
private $params;
/**
* @var string[]
*/
private $errors = [];
public function __construct(array $params)
{
$this->params = $params;
}
/**
* Vérifie que les champs soient présents dans le tableau
*
* @param string[] ...$keys
* @return Validator
*/
public function required(string ...$keys): self
{
foreach ($keys as $key) {
$value = $this->getValue($key);
if (is_null($value)) {
$this->addError($key, 'required');
}
}
return $this;
}
/**
* Vérifie que le champ n'est pas vide
*
* @param string[] ...$keys
* @return Validator
*/
public function notEmpty(string ...$keys): self
{
foreach ($keys as $key) {
$value = $this->getValue($key);
if (is_null($value) || empty($value)) {
$this->addError($key, 'empty');
}
}
return $this;
}
public function length(string $key, ?int $min, ?int $max = null): self
{
$value = $this->getValue($key);
$length = mb_strlen($value);
if (!is_null($min) &&
!is_null($max) &&
($length < $min || $length > $max)
) {
$this->addError($key, 'betweenLength', [$min, $max]);
return $this;
}
if (!is_null($min) &&
$length < $min
) {
$this->addError($key, 'minLength', [$min]);
return $this;
}
if (!is_null($max) &&
$length > $max
) {
$this->addError($key, 'maxLength', [$max]);
}
return $this;
}
/**
* Vérifie que l'élément est un slug
*
* @param string $key
* @return Validator
*/
public function slug(string $key): self
{
$value = $this->getValue($key);
$pattern = '/^[a-z0-9]+(-[a-z0-9]+)*$/';
if (!is_null($value) && !preg_match($pattern, $value)) {
$this->addError($key, 'slug');
}
return $this;
}
/**
* Vérifie qu'une date correspond au format demandé
*
* @param string $key
* @param string $format
* @return Validator
*/
public function dateTime(string $key, string $format = "Y-m-d H:i:s"): self
{
$value = $this->getValue($key);
$date = \DateTime::createFromFormat($format, $value);
$errors = \DateTime::getLastErrors();
if ($errors['error_count'] > 0 || $errors['warning_count'] > 0 || $date === false) {
$this->addError($key, 'datetime', [$format]);
}
return $this;
}
/**
* Vérifie que la clef existe dans la table donnée
*
* @param string $key
* @param string $table
* @param \PDO $pdo
* @return Validator
*/
public function exists(string $key, string $table, \PDO $pdo): self
{
$value = $this->getValue($key);
$statement = $pdo->prepare("SELECT id FROM $table WHERE id = ?");
$statement->execute([$value]);
if ($statement->fetchColumn() === false) {
$this->addError($key, 'exists', [$table]);
}
return $this;
}
/**
* Vérifie que la clef est unique dans la base de données
*
* @param string $key
* @param string|Table $table
* @param \PDO $pdo
* @param int|null $exclude
* @return Validator
*/
public function unique(string $key, $table, ?\PDO $pdo = null, ?int $exclude = null): self
{
if ($table instanceof Table) {
$pdo = $table->getPdo();
$table = $table->getTable();
}
$value = $this->getValue($key);
$query = "SELECT id FROM $table WHERE $key = ?";
$params = [$value];
if ($exclude !== null) {
$query .= " AND id != ?";
$params[] = $exclude;
}
$statement = $pdo->prepare($query);
$statement->execute($params);
if ($statement->fetchColumn() !== false) {
$this->addError($key, 'unique', [$value]);
}
return $this;
}
/**
* Vérifie si le fichier a bien été uploadé
* @param string $key
* @return Validator
*/
public function uploaded(string $key): self
{
$file = $this->getValue($key);
if ($file === null || $file->getError() !== UPLOAD_ERR_OK) {
$this->addError($key, 'uploaded');
}
return $this;
}
/**
* Vérifie si l'email est valide
* @param string $key
* @return Validator
*/
public function email(string $key): self
{
$value = $this->getValue($key);
if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
$this->addError($key, 'email');
}
return $this;
}
public function confirm(string $key): self
{
$value = $this->getValue($key);
$valueConfirm = $this->getValue($key . '_confirm');
if ($valueConfirm !== $value) {
$this->addError($key, 'confirm');
}
return $this;
}
/**
* Vérifie le format de fichier
* @param string $key
* @param array $extensions
* @return Validator
*/
public function extension(string $key, array $extensions): self
{
/** @var UploadedFileInterface $file */
$file = $this->getValue($key);
if ($file !== null && $file->getError() === UPLOAD_ERR_OK) {
$type = $file->getClientMediaType();
$extension = mb_strtolower(pathinfo($file->getClientFilename(), PATHINFO_EXTENSION));
$expectedType = self::MIME_TYPES[$extension] ?? null;
if (!in_array($extension, $extensions) || $expectedType !== $type) {
$this->addError($key, 'filetype', [join(',', $extensions)]);
}
}
return $this;
}
/**
* @return bool
*/
public function isValid(): bool
{
return empty($this->errors);
}
/**
* Récupère les erreurs
* @return ValidationError[]
*/
public function getErrors(): array
{
return $this->errors;
}
/**
* Ajoute une erreur
*
* @param string $key
* @param string $rule
* @param array $attributes
*/
private function addError(string $key, string $rule, array $attributes = []): void
{
$this->errors[$key] = new ValidationError($key, $rule, $attributes);
}
private function getValue(string $key)
{
if (array_key_exists($key, $this->params)) {
return $this->params[$key];
}
return null;
}
}