- Created Articles.php for rendering article views including full articles, miniature lists, and news sections. - Added Banners.php for handling banner displays. - Introduced Languages.php for rendering language options. - Implemented Menu.php for dynamic menu rendering. - Developed Newsletter.php for newsletter view rendering. - Created Scontainers.php for rendering specific containers. - Added ShopCategory.php for category descriptions and product listings. - Introduced ShopClient.php for managing client-related views such as address editing and order history. - Implemented ShopPaymentMethod.php for displaying payment methods in the basket. - Created ShopProduct.php for generating product URLs. - Added ShopSearch.php for rendering a simple search form. - Added .htaccess file to enhance security by restricting access to sensitive files and directories.
197 lines
5.9 KiB
PHP
197 lines
5.9 KiB
PHP
<?php
|
|
namespace admin\Validation;
|
|
|
|
use admin\ViewModels\Forms\FormField;
|
|
use admin\ViewModels\Forms\FormFieldType;
|
|
|
|
/**
|
|
* Walidator formularzy
|
|
*/
|
|
class FormValidator
|
|
{
|
|
private array $errors = [];
|
|
|
|
/**
|
|
* Waliduje dane na podstawie definicji pól
|
|
*
|
|
* @param array $data Dane z POST
|
|
* @param array $fields Definicje pól (FormField[])
|
|
* @param array|null $languages Języki (dla walidacji pól językowych)
|
|
* @return array Tablica błędów (pusta jeśli OK)
|
|
*/
|
|
public function validate(array $data, array $fields, ?array $languages = null): array
|
|
{
|
|
$this->errors = [];
|
|
|
|
foreach ($fields as $field) {
|
|
if ($field->type === FormFieldType::LANG_SECTION) {
|
|
$this->validateLangSection($data, $field, $languages ?? []);
|
|
} else {
|
|
$this->validateField($data, $field);
|
|
}
|
|
}
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Waliduje pojedyncze pole
|
|
*/
|
|
private function validateField(array $data, FormField $field): void
|
|
{
|
|
$value = $data[$field->name] ?? null;
|
|
|
|
// Walidacja wymagalności
|
|
if ($field->required && $this->isEmpty($value)) {
|
|
$this->errors[$field->name] = "Pole \"{$field->label}\" jest wymagane.";
|
|
return;
|
|
}
|
|
|
|
// Jeśli pole puste i nie jest wymagane - pomijamy dalszą walidację
|
|
if ($this->isEmpty($value)) {
|
|
return;
|
|
}
|
|
|
|
// Walidacja typu
|
|
switch ($field->type) {
|
|
case FormFieldType::EMAIL:
|
|
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
|
$this->errors[$field->name] = "Pole \"{$field->label}\" musi być poprawnym adresem e-mail.";
|
|
}
|
|
break;
|
|
|
|
case FormFieldType::NUMBER:
|
|
if (!is_numeric($value)) {
|
|
$this->errors[$field->name] = "Pole \"{$field->label}\" musi być liczbą.";
|
|
}
|
|
break;
|
|
|
|
case FormFieldType::DATE:
|
|
if (!$this->isValidDate($value)) {
|
|
$this->errors[$field->name] = "Pole \"{$field->label}\" musi być poprawną datą (YYYY-MM-DD).";
|
|
}
|
|
break;
|
|
|
|
case FormFieldType::DATETIME:
|
|
if (!$this->isValidDateTime($value)) {
|
|
$this->errors[$field->name] = "Pole \"{$field->label}\" musi być poprawną datą i czasem.";
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Walidacja customowa (callback)
|
|
if (isset($field->attributes['validate_callback']) && is_callable($field->attributes['validate_callback'])) {
|
|
$result = call_user_func($field->attributes['validate_callback'], $value, $data);
|
|
if ($result !== true) {
|
|
$this->errors[$field->name] = is_string($result) ? $result : "Pole \"{$field->label}\" zawiera nieprawidłową wartość.";
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Waliduje sekcję językową
|
|
*/
|
|
private function validateLangSection(array $data, FormField $section, array $languages): void
|
|
{
|
|
if ($section->langFields === null) {
|
|
return;
|
|
}
|
|
|
|
foreach ($languages as $language) {
|
|
if (!($language['status'] ?? false)) {
|
|
continue;
|
|
}
|
|
|
|
$langId = $language['id'];
|
|
|
|
foreach ($section->langFields as $field) {
|
|
$fieldName = $field->name;
|
|
$value = $data[$fieldName][$langId] ?? null;
|
|
|
|
// Walidacja wymagalności
|
|
if ($field->required && $this->isEmpty($value)) {
|
|
$errorKey = "{$section->name}_{$fieldName}";
|
|
$this->errors[$errorKey][$langId] = "Pole \"{$field->label}\" ({$language['name']}) jest wymagane.";
|
|
continue;
|
|
}
|
|
|
|
// Walidacja typu dla pól językowych
|
|
if (!$this->isEmpty($value)) {
|
|
switch ($field->type) {
|
|
case FormFieldType::EMAIL:
|
|
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
|
$errorKey = "{$section->name}_{$fieldName}";
|
|
$this->errors[$errorKey][$langId] = "Pole \"{$field->label}\" ({$language['name']}) musi być poprawnym e-mailem.";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sprawdza czy wartość jest pusta
|
|
*/
|
|
private function isEmpty($value): bool
|
|
{
|
|
return $value === null || $value === '' || (is_array($value) && empty($value));
|
|
}
|
|
|
|
/**
|
|
* Sprawdza czy data jest poprawna (YYYY-MM-DD)
|
|
*/
|
|
private function isValidDate(string $date): bool
|
|
{
|
|
$d = \DateTime::createFromFormat('Y-m-d', $date);
|
|
return $d && $d->format('Y-m-d') === $date;
|
|
}
|
|
|
|
/**
|
|
* Sprawdza czy data i czas są poprawne
|
|
*/
|
|
private function isValidDateTime(string $datetime): bool
|
|
{
|
|
$d = \DateTime::createFromFormat('Y-m-d H:i:s', $datetime);
|
|
if ($d && $d->format('Y-m-d H:i:s') === $datetime) {
|
|
return true;
|
|
}
|
|
|
|
// Spróbuj bez sekund
|
|
$d = \DateTime::createFromFormat('Y-m-d H:i', $datetime);
|
|
return $d && $d->format('Y-m-d H:i') === $datetime;
|
|
}
|
|
|
|
/**
|
|
* Sprawdza czy walidacja zakończyła się sukcesem
|
|
*/
|
|
public function isValid(): bool
|
|
{
|
|
return empty($this->errors);
|
|
}
|
|
|
|
/**
|
|
* Zwraca wszystkie błędy
|
|
*/
|
|
public function getErrors(): array
|
|
{
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Zwraca pierwszy błąd
|
|
*/
|
|
public function getFirstError(): ?string
|
|
{
|
|
if (empty($this->errors)) {
|
|
return null;
|
|
}
|
|
|
|
$first = reset($this->errors);
|
|
if (is_array($first)) {
|
|
return reset($first);
|
|
}
|
|
return $first;
|
|
}
|
|
}
|