Files
Jacek Pyziak 3ecbe628dc Add view classes for articles, banners, languages, menu, newsletter, containers, shop categories, clients, payment methods, products, and search
- 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.
2026-02-21 23:00:15 +01:00

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;
}
}