## Major CodePress CMS Enhancement
### 🚀 New Features - **League CommonMark Integration**: Replaced basic Markdown parser with full CommonMark 2.7 support - **Bootstrap Sass Architecture**: Modern SCSS build system with Bootstrap 5.3.8 - **Enhanced Navigation**: Uses filenames instead of H1 titles for consistency - **Improved Styling**: Transparent navigation backgrounds, no rounded corners ### 🎨 UI/UX Improvements - Navigation items now use formatted filenames (e.g., "kennis-boven-aantallen" → "Kennis Boven Aantallen") - Transparent navigation backgrounds with subtle hover effects - Removed rounded corners from first-level navigation - 50% opacity navigation background using Bootstrap variables ### 🔧 Technical Improvements - **Class Organization**: Extracted CodePressCMS and SimpleTemplate to separate files - **Full PHPDoc Documentation**: Complete documentation for all methods - **Modern Build Process**: npm scripts for SCSS compilation - **Enhanced Markdown Support**: Tables, strikethrough, task lists, autolinks - **Security**: Proper HTML sanitization with CommonMark ### 📦 Dependencies - Added `league/commonmark` for professional Markdown parsing - Added `bootstrap` for SCSS-based styling - Updated `sass` build process ### 🐛 Bug Fixes - Fixed content directory path configuration - Resolved navigation title inconsistencies - Improved Markdown bold/italic formatting - Fixed homepage 404 issues ### 🔄 Migration Notes - Content directory moved from `content/` to `public/content/` - Navigation now displays filenames instead of content H1 titles - CSS now compiled from SCSS source files The CMS now provides a professional, modern experience with robust Markdown support and clean, maintainable code architecture.
This commit is contained in:
53
vendor/nette/schema/src/Schema/Context.php
vendored
Normal file
53
vendor/nette/schema/src/Schema/Context.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
use function count;
|
||||
|
||||
|
||||
final class Context
|
||||
{
|
||||
public bool $skipDefaults = false;
|
||||
|
||||
/** @var string[] */
|
||||
public array $path = [];
|
||||
|
||||
public bool $isKey = false;
|
||||
|
||||
/** @var Message[] */
|
||||
public array $errors = [];
|
||||
|
||||
/** @var Message[] */
|
||||
public array $warnings = [];
|
||||
|
||||
/** @var array[] */
|
||||
public array $dynamics = [];
|
||||
|
||||
|
||||
public function addError(string $message, string $code, array $variables = []): Message
|
||||
{
|
||||
$variables['isKey'] = $this->isKey;
|
||||
return $this->errors[] = new Message($message, $code, $this->path, $variables);
|
||||
}
|
||||
|
||||
|
||||
public function addWarning(string $message, string $code, array $variables = []): Message
|
||||
{
|
||||
return $this->warnings[] = new Message($message, $code, $this->path, $variables);
|
||||
}
|
||||
|
||||
|
||||
/** @return \Closure(): bool */
|
||||
public function createChecker(): \Closure
|
||||
{
|
||||
$count = count($this->errors);
|
||||
return fn(): bool => $count === count($this->errors);
|
||||
}
|
||||
}
|
||||
15
vendor/nette/schema/src/Schema/DynamicParameter.php
vendored
Normal file
15
vendor/nette/schema/src/Schema/DynamicParameter.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
|
||||
interface DynamicParameter
|
||||
{
|
||||
}
|
||||
148
vendor/nette/schema/src/Schema/Elements/AnyOf.php
vendored
Normal file
148
vendor/nette/schema/src/Schema/Elements/AnyOf.php
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema\Elements;
|
||||
|
||||
use Nette;
|
||||
use Nette\Schema\Context;
|
||||
use Nette\Schema\Helpers;
|
||||
use Nette\Schema\Schema;
|
||||
use function array_merge, array_unique, implode, is_array;
|
||||
|
||||
|
||||
final class AnyOf implements Schema
|
||||
{
|
||||
use Base;
|
||||
|
||||
private array $set;
|
||||
|
||||
|
||||
public function __construct(mixed ...$set)
|
||||
{
|
||||
if (!$set) {
|
||||
throw new Nette\InvalidStateException('The enumeration must not be empty.');
|
||||
}
|
||||
|
||||
$this->set = $set;
|
||||
}
|
||||
|
||||
|
||||
public function firstIsDefault(): self
|
||||
{
|
||||
$this->default = $this->set[0];
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function nullable(): self
|
||||
{
|
||||
$this->set[] = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function dynamic(): self
|
||||
{
|
||||
$this->set[] = new Type(Nette\Schema\DynamicParameter::class);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/********************* processing ****************d*g**/
|
||||
|
||||
|
||||
public function normalize(mixed $value, Context $context): mixed
|
||||
{
|
||||
return $this->doNormalize($value, $context);
|
||||
}
|
||||
|
||||
|
||||
public function merge(mixed $value, mixed $base): mixed
|
||||
{
|
||||
if (is_array($value) && isset($value[Helpers::PreventMerging])) {
|
||||
unset($value[Helpers::PreventMerging]);
|
||||
return $value;
|
||||
}
|
||||
|
||||
return Helpers::merge($value, $base);
|
||||
}
|
||||
|
||||
|
||||
public function complete(mixed $value, Context $context): mixed
|
||||
{
|
||||
$isOk = $context->createChecker();
|
||||
$value = $this->findAlternative($value, $context);
|
||||
$isOk() && $value = $this->doTransform($value, $context);
|
||||
return $isOk() ? $value : null;
|
||||
}
|
||||
|
||||
|
||||
private function findAlternative(mixed $value, Context $context): mixed
|
||||
{
|
||||
$expecteds = $innerErrors = [];
|
||||
foreach ($this->set as $item) {
|
||||
if ($item instanceof Schema) {
|
||||
$dolly = new Context;
|
||||
$dolly->path = $context->path;
|
||||
$res = $item->complete($item->normalize($value, $dolly), $dolly);
|
||||
if (!$dolly->errors) {
|
||||
$context->warnings = array_merge($context->warnings, $dolly->warnings);
|
||||
return $res;
|
||||
}
|
||||
|
||||
foreach ($dolly->errors as $error) {
|
||||
if ($error->path !== $context->path || empty($error->variables['expected'])) {
|
||||
$innerErrors[] = $error;
|
||||
} else {
|
||||
$expecteds[] = $error->variables['expected'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($item === $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$expecteds[] = Nette\Schema\Helpers::formatValue($item);
|
||||
}
|
||||
}
|
||||
|
||||
if ($innerErrors) {
|
||||
$context->errors = array_merge($context->errors, $innerErrors);
|
||||
} else {
|
||||
$context->addError(
|
||||
'The %label% %path% expects to be %expected%, %value% given.',
|
||||
Nette\Schema\Message::TypeMismatch,
|
||||
[
|
||||
'value' => $value,
|
||||
'expected' => implode('|', array_unique($expecteds)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function completeDefault(Context $context): mixed
|
||||
{
|
||||
if ($this->required) {
|
||||
$context->addError(
|
||||
'The mandatory item %path% is missing.',
|
||||
Nette\Schema\Message::MissingItem,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->default instanceof Schema) {
|
||||
return $this->default->completeDefault($context);
|
||||
}
|
||||
|
||||
return $this->default;
|
||||
}
|
||||
}
|
||||
163
vendor/nette/schema/src/Schema/Elements/Base.php
vendored
Normal file
163
vendor/nette/schema/src/Schema/Elements/Base.php
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema\Elements;
|
||||
|
||||
use Nette;
|
||||
use Nette\Schema\Context;
|
||||
use Nette\Schema\Helpers;
|
||||
use function count, is_string;
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait Base
|
||||
{
|
||||
private bool $required = false;
|
||||
private mixed $default = null;
|
||||
|
||||
/** @var ?callable */
|
||||
private $before;
|
||||
|
||||
/** @var callable[] */
|
||||
private array $transforms = [];
|
||||
private ?string $deprecated = null;
|
||||
|
||||
|
||||
public function default(mixed $value): self
|
||||
{
|
||||
$this->default = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function required(bool $state = true): self
|
||||
{
|
||||
$this->required = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function before(callable $handler): self
|
||||
{
|
||||
$this->before = $handler;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function castTo(string $type): self
|
||||
{
|
||||
return $this->transform(Helpers::getCastStrategy($type));
|
||||
}
|
||||
|
||||
|
||||
public function transform(callable $handler): self
|
||||
{
|
||||
$this->transforms[] = $handler;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function assert(callable $handler, ?string $description = null): self
|
||||
{
|
||||
$expected = $description ?: (is_string($handler) ? "$handler()" : '#' . count($this->transforms));
|
||||
return $this->transform(function ($value, Context $context) use ($handler, $description, $expected) {
|
||||
if ($handler($value)) {
|
||||
return $value;
|
||||
}
|
||||
$context->addError(
|
||||
'Failed assertion ' . ($description ? "'%assertion%'" : '%assertion%') . ' for %label% %path% with value %value%.',
|
||||
Nette\Schema\Message::FailedAssertion,
|
||||
['value' => $value, 'assertion' => $expected],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/** Marks as deprecated */
|
||||
public function deprecated(string $message = 'The item %path% is deprecated.'): self
|
||||
{
|
||||
$this->deprecated = $message;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function completeDefault(Context $context): mixed
|
||||
{
|
||||
if ($this->required) {
|
||||
$context->addError(
|
||||
'The mandatory item %path% is missing.',
|
||||
Nette\Schema\Message::MissingItem,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
|
||||
public function doNormalize(mixed $value, Context $context): mixed
|
||||
{
|
||||
if ($this->before) {
|
||||
$value = ($this->before)($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
private function doDeprecation(Context $context): void
|
||||
{
|
||||
if ($this->deprecated !== null) {
|
||||
$context->addWarning(
|
||||
$this->deprecated,
|
||||
Nette\Schema\Message::Deprecated,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function doTransform(mixed $value, Context $context): mixed
|
||||
{
|
||||
$isOk = $context->createChecker();
|
||||
foreach ($this->transforms as $handler) {
|
||||
$value = $handler($value, $context);
|
||||
if (!$isOk()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated use Nette\Schema\Validators::validateType() */
|
||||
private function doValidate(mixed $value, string $expected, Context $context): bool
|
||||
{
|
||||
$isOk = $context->createChecker();
|
||||
Helpers::validateType($value, $expected, $context);
|
||||
return $isOk();
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated use Nette\Schema\Validators::validateRange() */
|
||||
private static function doValidateRange(mixed $value, array $range, Context $context, string $types = ''): bool
|
||||
{
|
||||
$isOk = $context->createChecker();
|
||||
Helpers::validateRange($value, $range, $context, $types);
|
||||
return $isOk();
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated use doTransform() */
|
||||
private function doFinalize(mixed $value, Context $context): mixed
|
||||
{
|
||||
return $this->doTransform($value, $context);
|
||||
}
|
||||
}
|
||||
211
vendor/nette/schema/src/Schema/Elements/Structure.php
vendored
Normal file
211
vendor/nette/schema/src/Schema/Elements/Structure.php
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema\Elements;
|
||||
|
||||
use Nette;
|
||||
use Nette\Schema\Context;
|
||||
use Nette\Schema\Helpers;
|
||||
use Nette\Schema\Schema;
|
||||
use function array_diff_key, array_fill_keys, array_key_exists, array_keys, array_map, array_merge, array_pop, array_values, is_array, is_object;
|
||||
|
||||
|
||||
final class Structure implements Schema
|
||||
{
|
||||
use Base;
|
||||
|
||||
/** @var Schema[] */
|
||||
private array $items;
|
||||
|
||||
/** for array|list */
|
||||
private ?Schema $otherItems = null;
|
||||
|
||||
/** @var array{?int, ?int} */
|
||||
private array $range = [null, null];
|
||||
private bool $skipDefaults = false;
|
||||
|
||||
|
||||
/**
|
||||
* @param Schema[] $shape
|
||||
*/
|
||||
public function __construct(array $shape)
|
||||
{
|
||||
(function (Schema ...$items) {})(...array_values($shape));
|
||||
$this->items = $shape;
|
||||
$this->castTo('object');
|
||||
$this->required = true;
|
||||
}
|
||||
|
||||
|
||||
public function default(mixed $value): self
|
||||
{
|
||||
throw new Nette\InvalidStateException('Structure cannot have default value.');
|
||||
}
|
||||
|
||||
|
||||
public function min(?int $min): self
|
||||
{
|
||||
$this->range[0] = $min;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function max(?int $max): self
|
||||
{
|
||||
$this->range[1] = $max;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function otherItems(string|Schema $type = 'mixed'): self
|
||||
{
|
||||
$this->otherItems = $type instanceof Schema ? $type : new Type($type);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function skipDefaults(bool $state = true): self
|
||||
{
|
||||
$this->skipDefaults = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function extend(array|self $shape): self
|
||||
{
|
||||
$shape = $shape instanceof self ? $shape->items : $shape;
|
||||
return new self(array_merge($this->items, $shape));
|
||||
}
|
||||
|
||||
|
||||
public function getShape(): array
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
|
||||
/********************* processing ****************d*g**/
|
||||
|
||||
|
||||
public function normalize(mixed $value, Context $context): mixed
|
||||
{
|
||||
if ($prevent = (is_array($value) && isset($value[Helpers::PreventMerging]))) {
|
||||
unset($value[Helpers::PreventMerging]);
|
||||
}
|
||||
|
||||
$value = $this->doNormalize($value, $context);
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $val) {
|
||||
$itemSchema = $this->items[$key] ?? $this->otherItems;
|
||||
if ($itemSchema) {
|
||||
$context->path[] = $key;
|
||||
$value[$key] = $itemSchema->normalize($val, $context);
|
||||
array_pop($context->path);
|
||||
}
|
||||
}
|
||||
|
||||
if ($prevent) {
|
||||
$value[Helpers::PreventMerging] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
public function merge(mixed $value, mixed $base): mixed
|
||||
{
|
||||
if (is_array($value) && isset($value[Helpers::PreventMerging])) {
|
||||
unset($value[Helpers::PreventMerging]);
|
||||
$base = null;
|
||||
}
|
||||
|
||||
if (is_array($value) && is_array($base)) {
|
||||
$index = $this->otherItems === null ? null : 0;
|
||||
foreach ($value as $key => $val) {
|
||||
if ($key === $index) {
|
||||
$base[] = $val;
|
||||
$index++;
|
||||
} else {
|
||||
$base[$key] = array_key_exists($key, $base) && ($itemSchema = $this->items[$key] ?? $this->otherItems)
|
||||
? $itemSchema->merge($val, $base[$key])
|
||||
: $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
return $value ?? $base;
|
||||
}
|
||||
|
||||
|
||||
public function complete(mixed $value, Context $context): mixed
|
||||
{
|
||||
if ($value === null) {
|
||||
$value = []; // is unable to distinguish null from array in NEON
|
||||
}
|
||||
|
||||
$this->doDeprecation($context);
|
||||
|
||||
$isOk = $context->createChecker();
|
||||
Helpers::validateType($value, 'array', $context);
|
||||
$isOk() && Helpers::validateRange($value, $this->range, $context);
|
||||
$isOk() && $this->validateItems($value, $context);
|
||||
$isOk() && $value = $this->doTransform($value, $context);
|
||||
return $isOk() ? $value : null;
|
||||
}
|
||||
|
||||
|
||||
private function validateItems(array &$value, Context $context): void
|
||||
{
|
||||
$items = $this->items;
|
||||
if ($extraKeys = array_keys(array_diff_key($value, $items))) {
|
||||
if ($this->otherItems) {
|
||||
$items += array_fill_keys($extraKeys, $this->otherItems);
|
||||
} else {
|
||||
$keys = array_map('strval', array_keys($items));
|
||||
foreach ($extraKeys as $key) {
|
||||
$hint = Nette\Utils\Helpers::getSuggestion($keys, (string) $key);
|
||||
$context->addError(
|
||||
'Unexpected item %path%' . ($hint ? ", did you mean '%hint%'?" : '.'),
|
||||
Nette\Schema\Message::UnexpectedItem,
|
||||
['hint' => $hint],
|
||||
)->path[] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($items as $itemKey => $itemVal) {
|
||||
$context->path[] = $itemKey;
|
||||
if (array_key_exists($itemKey, $value)) {
|
||||
$value[$itemKey] = $itemVal->complete($value[$itemKey], $context);
|
||||
} else {
|
||||
$default = $itemVal->completeDefault($context); // checks required item
|
||||
if (!$context->skipDefaults && !$this->skipDefaults) {
|
||||
$value[$itemKey] = $default;
|
||||
}
|
||||
}
|
||||
|
||||
array_pop($context->path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function completeDefault(Context $context): mixed
|
||||
{
|
||||
return $this->required
|
||||
? $this->complete([], $context)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
209
vendor/nette/schema/src/Schema/Elements/Type.php
vendored
Normal file
209
vendor/nette/schema/src/Schema/Elements/Type.php
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema\Elements;
|
||||
|
||||
use Nette\Schema\Context;
|
||||
use Nette\Schema\DynamicParameter;
|
||||
use Nette\Schema\Helpers;
|
||||
use Nette\Schema\Schema;
|
||||
use function array_key_exists, array_pop, implode, is_array, str_replace, strpos;
|
||||
|
||||
|
||||
final class Type implements Schema
|
||||
{
|
||||
use Base;
|
||||
|
||||
private string $type;
|
||||
private ?Schema $itemsValue = null;
|
||||
private ?Schema $itemsKey = null;
|
||||
|
||||
/** @var array{?float, ?float} */
|
||||
private array $range = [null, null];
|
||||
private ?string $pattern = null;
|
||||
private bool $merge = true;
|
||||
|
||||
|
||||
public function __construct(string $type)
|
||||
{
|
||||
$defaults = ['list' => [], 'array' => []];
|
||||
$this->type = $type;
|
||||
$this->default = strpos($type, '[]') ? [] : $defaults[$type] ?? null;
|
||||
}
|
||||
|
||||
|
||||
public function nullable(): self
|
||||
{
|
||||
$this->type = 'null|' . $this->type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function mergeDefaults(bool $state = true): self
|
||||
{
|
||||
$this->merge = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function dynamic(): self
|
||||
{
|
||||
$this->type = DynamicParameter::class . '|' . $this->type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function min(?float $min): self
|
||||
{
|
||||
$this->range[0] = $min;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function max(?float $max): self
|
||||
{
|
||||
$this->range[1] = $max;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal use arrayOf() or listOf()
|
||||
*/
|
||||
public function items(string|Schema $valueType = 'mixed', string|Schema|null $keyType = null): self
|
||||
{
|
||||
$this->itemsValue = $valueType instanceof Schema
|
||||
? $valueType
|
||||
: new self($valueType);
|
||||
$this->itemsKey = $keyType instanceof Schema || $keyType === null
|
||||
? $keyType
|
||||
: new self($keyType);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function pattern(?string $pattern): self
|
||||
{
|
||||
$this->pattern = $pattern;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/********************* processing ****************d*g**/
|
||||
|
||||
|
||||
public function normalize(mixed $value, Context $context): mixed
|
||||
{
|
||||
if ($prevent = (is_array($value) && isset($value[Helpers::PreventMerging]))) {
|
||||
unset($value[Helpers::PreventMerging]);
|
||||
}
|
||||
|
||||
$value = $this->doNormalize($value, $context);
|
||||
if (is_array($value) && $this->itemsValue) {
|
||||
$res = [];
|
||||
foreach ($value as $key => $val) {
|
||||
$context->path[] = $key;
|
||||
$context->isKey = true;
|
||||
$key = $this->itemsKey
|
||||
? $this->itemsKey->normalize($key, $context)
|
||||
: $key;
|
||||
$context->isKey = false;
|
||||
$res[$key] = $this->itemsValue->normalize($val, $context);
|
||||
array_pop($context->path);
|
||||
}
|
||||
|
||||
$value = $res;
|
||||
}
|
||||
|
||||
if ($prevent && is_array($value)) {
|
||||
$value[Helpers::PreventMerging] = true;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
public function merge(mixed $value, mixed $base): mixed
|
||||
{
|
||||
if (is_array($value) && isset($value[Helpers::PreventMerging])) {
|
||||
unset($value[Helpers::PreventMerging]);
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (is_array($value) && is_array($base) && $this->itemsValue) {
|
||||
$index = 0;
|
||||
foreach ($value as $key => $val) {
|
||||
if ($key === $index) {
|
||||
$base[] = $val;
|
||||
$index++;
|
||||
} else {
|
||||
$base[$key] = array_key_exists($key, $base)
|
||||
? $this->itemsValue->merge($val, $base[$key])
|
||||
: $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
return Helpers::merge($value, $base);
|
||||
}
|
||||
|
||||
|
||||
public function complete(mixed $value, Context $context): mixed
|
||||
{
|
||||
$merge = $this->merge;
|
||||
if (is_array($value) && isset($value[Helpers::PreventMerging])) {
|
||||
unset($value[Helpers::PreventMerging]);
|
||||
$merge = false;
|
||||
}
|
||||
|
||||
if ($value === null && is_array($this->default)) {
|
||||
$value = []; // is unable to distinguish null from array in NEON
|
||||
}
|
||||
|
||||
$this->doDeprecation($context);
|
||||
|
||||
$isOk = $context->createChecker();
|
||||
Helpers::validateType($value, $this->type, $context);
|
||||
$isOk() && Helpers::validateRange($value, $this->range, $context, $this->type);
|
||||
$isOk() && $value !== null && $this->pattern !== null && Helpers::validatePattern($value, $this->pattern, $context);
|
||||
$isOk() && is_array($value) && $this->validateItems($value, $context);
|
||||
$isOk() && $merge && $value = Helpers::merge($value, $this->default);
|
||||
$isOk() && $value = $this->doTransform($value, $context);
|
||||
if (!$isOk()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($value instanceof DynamicParameter) {
|
||||
$expected = $this->type . ($this->range === [null, null] ? '' : ':' . implode('..', $this->range));
|
||||
$context->dynamics[] = [$value, str_replace(DynamicParameter::class . '|', '', $expected), $context->path];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
private function validateItems(array &$value, Context $context): void
|
||||
{
|
||||
if (!$this->itemsValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
$res = [];
|
||||
foreach ($value as $key => $val) {
|
||||
$context->path[] = $key;
|
||||
$context->isKey = true;
|
||||
$key = $this->itemsKey ? $this->itemsKey->complete($key, $context) : $key;
|
||||
$context->isKey = false;
|
||||
$res[$key ?? ''] = $this->itemsValue->complete($val, $context);
|
||||
array_pop($context->path);
|
||||
}
|
||||
$value = $res;
|
||||
}
|
||||
}
|
||||
119
vendor/nette/schema/src/Schema/Expect.php
vendored
Normal file
119
vendor/nette/schema/src/Schema/Expect.php
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
use Nette;
|
||||
use Nette\Schema\Elements\AnyOf;
|
||||
use Nette\Schema\Elements\Structure;
|
||||
use Nette\Schema\Elements\Type;
|
||||
use function is_object;
|
||||
|
||||
|
||||
/**
|
||||
* Schema generator.
|
||||
*
|
||||
* @method static Type scalar($default = null)
|
||||
* @method static Type string($default = null)
|
||||
* @method static Type int($default = null)
|
||||
* @method static Type float($default = null)
|
||||
* @method static Type bool($default = null)
|
||||
* @method static Type null()
|
||||
* @method static Type list($default = [])
|
||||
* @method static Type mixed($default = null)
|
||||
* @method static Type email($default = null)
|
||||
* @method static Type unicode($default = null)
|
||||
*/
|
||||
final class Expect
|
||||
{
|
||||
public static function __callStatic(string $name, array $args): Type
|
||||
{
|
||||
$type = new Type($name);
|
||||
if ($args) {
|
||||
$type->default($args[0]);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
|
||||
public static function type(string $type): Type
|
||||
{
|
||||
return new Type($type);
|
||||
}
|
||||
|
||||
|
||||
public static function anyOf(mixed ...$set): AnyOf
|
||||
{
|
||||
return new AnyOf(...$set);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Schema[] $shape
|
||||
*/
|
||||
public static function structure(array $shape): Structure
|
||||
{
|
||||
return new Structure($shape);
|
||||
}
|
||||
|
||||
|
||||
public static function from(object $object, array $items = []): Structure
|
||||
{
|
||||
$ro = new \ReflectionObject($object);
|
||||
$props = $ro->hasMethod('__construct')
|
||||
? $ro->getMethod('__construct')->getParameters()
|
||||
: $ro->getProperties();
|
||||
|
||||
foreach ($props as $prop) {
|
||||
$item = &$items[$prop->getName()];
|
||||
if (!$item) {
|
||||
$type = Helpers::getPropertyType($prop) ?? 'mixed';
|
||||
$item = new Type($type);
|
||||
if ($prop instanceof \ReflectionProperty ? $prop->isInitialized($object) : $prop->isOptional()) {
|
||||
$def = ($prop instanceof \ReflectionProperty ? $prop->getValue($object) : $prop->getDefaultValue());
|
||||
if (is_object($def)) {
|
||||
$item = static::from($def);
|
||||
} elseif ($def === null && !Nette\Utils\Validators::is(null, $type)) {
|
||||
$item->required();
|
||||
} else {
|
||||
$item->default($def);
|
||||
}
|
||||
} else {
|
||||
$item->required();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (new Structure($items))->castTo($ro->getName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed[] $shape
|
||||
*/
|
||||
public static function array(?array $shape = []): Structure|Type
|
||||
{
|
||||
return Nette\Utils\Arrays::first($shape ?? []) instanceof Schema
|
||||
? (new Structure($shape))->castTo('array')
|
||||
: (new Type('array'))->default($shape);
|
||||
}
|
||||
|
||||
|
||||
public static function arrayOf(string|Schema $valueType, string|Schema|null $keyType = null): Type
|
||||
{
|
||||
return (new Type('array'))->items($valueType, $keyType);
|
||||
}
|
||||
|
||||
|
||||
public static function listOf(string|Schema $type): Type
|
||||
{
|
||||
return (new Type('list'))->items($type);
|
||||
}
|
||||
}
|
||||
184
vendor/nette/schema/src/Schema/Helpers.php
vendored
Normal file
184
vendor/nette/schema/src/Schema/Helpers.php
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
use Nette;
|
||||
use Nette\Utils\Reflection;
|
||||
use function count, explode, get_debug_type, implode, in_array, is_array, is_float, is_int, is_object, is_scalar, is_string, method_exists, preg_match, preg_quote, preg_replace, preg_replace_callback, settype, str_replace, strlen, trim, var_export;
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Helpers
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
public const PreventMerging = '_prevent_merging';
|
||||
|
||||
|
||||
/**
|
||||
* Merges dataset. Left has higher priority than right one.
|
||||
*/
|
||||
public static function merge(mixed $value, mixed $base): mixed
|
||||
{
|
||||
if (is_array($value) && isset($value[self::PreventMerging])) {
|
||||
unset($value[self::PreventMerging]);
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (is_array($value) && is_array($base)) {
|
||||
$index = 0;
|
||||
foreach ($value as $key => $val) {
|
||||
if ($key === $index) {
|
||||
$base[] = $val;
|
||||
$index++;
|
||||
} else {
|
||||
$base[$key] = static::merge($val, $base[$key] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
return $base;
|
||||
|
||||
} elseif ($value === null && is_array($base)) {
|
||||
return $base;
|
||||
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function getPropertyType(\ReflectionProperty|\ReflectionParameter $prop): ?string
|
||||
{
|
||||
if ($type = Nette\Utils\Type::fromReflection($prop)) {
|
||||
return (string) $type;
|
||||
} elseif (
|
||||
($prop instanceof \ReflectionProperty)
|
||||
&& ($type = preg_replace('#\s.*#', '', (string) self::parseAnnotation($prop, 'var')))
|
||||
) {
|
||||
$class = Reflection::getPropertyDeclaringClass($prop);
|
||||
return preg_replace_callback('#[\w\\\]+#', fn($m) => Reflection::expandClassName($m[0], $class), $type);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an annotation value.
|
||||
* @param \ReflectionProperty $ref
|
||||
*/
|
||||
public static function parseAnnotation(\Reflector $ref, string $name): ?string
|
||||
{
|
||||
if (!Reflection::areCommentsAvailable()) {
|
||||
throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
|
||||
}
|
||||
|
||||
$re = '#[\s*]@' . preg_quote($name, '#') . '(?=\s|$)(?:[ \t]+([^@\s]\S*))?#';
|
||||
if ($ref->getDocComment() && preg_match($re, trim($ref->getDocComment(), '/*'), $m)) {
|
||||
return $m[1] ?? '';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static function formatValue(mixed $value): string
|
||||
{
|
||||
if ($value instanceof DynamicParameter) {
|
||||
return 'dynamic';
|
||||
} elseif (is_object($value)) {
|
||||
return 'object ' . $value::class;
|
||||
} elseif (is_string($value)) {
|
||||
return "'" . Nette\Utils\Strings::truncate($value, 15, '...') . "'";
|
||||
} elseif (is_scalar($value)) {
|
||||
return var_export($value, return: true);
|
||||
} else {
|
||||
return get_debug_type($value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function validateType(mixed $value, string $expected, Context $context): void
|
||||
{
|
||||
if (!Nette\Utils\Validators::is($value, $expected)) {
|
||||
$expected = str_replace(DynamicParameter::class . '|', '', $expected);
|
||||
$expected = str_replace(['|', ':'], [' or ', ' in range '], $expected);
|
||||
$context->addError(
|
||||
'The %label% %path% expects to be %expected%, %value% given.',
|
||||
Message::TypeMismatch,
|
||||
['value' => $value, 'expected' => $expected],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function validateRange(mixed $value, array $range, Context $context, string $types = ''): void
|
||||
{
|
||||
if (is_array($value) || is_string($value)) {
|
||||
[$length, $label] = is_array($value)
|
||||
? [count($value), 'items']
|
||||
: (in_array('unicode', explode('|', $types), true)
|
||||
? [Nette\Utils\Strings::length($value), 'characters']
|
||||
: [strlen($value), 'bytes']);
|
||||
|
||||
if (!self::isInRange($length, $range)) {
|
||||
$context->addError(
|
||||
"The length of %label% %path% expects to be in range %expected%, %length% $label given.",
|
||||
Message::LengthOutOfRange,
|
||||
['value' => $value, 'length' => $length, 'expected' => implode('..', $range)],
|
||||
);
|
||||
}
|
||||
} elseif ((is_int($value) || is_float($value)) && !self::isInRange($value, $range)) {
|
||||
$context->addError(
|
||||
'The %label% %path% expects to be in range %expected%, %value% given.',
|
||||
Message::ValueOutOfRange,
|
||||
['value' => $value, 'expected' => implode('..', $range)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function isInRange(mixed $value, array $range): bool
|
||||
{
|
||||
return ($range[0] === null || $value >= $range[0])
|
||||
&& ($range[1] === null || $value <= $range[1]);
|
||||
}
|
||||
|
||||
|
||||
public static function validatePattern(string $value, string $pattern, Context $context): void
|
||||
{
|
||||
if (!preg_match("\x01^(?:$pattern)$\x01Du", $value)) {
|
||||
$context->addError(
|
||||
"The %label% %path% expects to match pattern '%pattern%', %value% given.",
|
||||
Message::PatternMismatch,
|
||||
['value' => $value, 'pattern' => $pattern],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function getCastStrategy(string $type): \Closure
|
||||
{
|
||||
if (Nette\Utils\Validators::isBuiltinType($type)) {
|
||||
return static function ($value) use ($type) {
|
||||
settype($value, $type);
|
||||
return $value;
|
||||
};
|
||||
} elseif (method_exists($type, '__construct')) {
|
||||
return static fn($value) => is_array($value) || $value instanceof \stdClass
|
||||
? new $type(...(array) $value)
|
||||
: new $type($value);
|
||||
} else {
|
||||
return static fn($value) => Nette\Utils\Arrays::toObject((array) $value, new $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
vendor/nette/schema/src/Schema/Message.php
vendored
Normal file
99
vendor/nette/schema/src/Schema/Message.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
use Nette;
|
||||
use function implode, preg_last_error_msg, preg_replace_callback;
|
||||
|
||||
|
||||
final class Message
|
||||
{
|
||||
/** variables: {value: mixed, expected: string} */
|
||||
public const TypeMismatch = 'schema.typeMismatch';
|
||||
|
||||
/** variables: {value: mixed, expected: string} */
|
||||
public const ValueOutOfRange = 'schema.valueOutOfRange';
|
||||
|
||||
/** variables: {value: mixed, length: int, expected: string} */
|
||||
public const LengthOutOfRange = 'schema.lengthOutOfRange';
|
||||
|
||||
/** variables: {value: string, pattern: string} */
|
||||
public const PatternMismatch = 'schema.patternMismatch';
|
||||
|
||||
/** variables: {value: mixed, assertion: string} */
|
||||
public const FailedAssertion = 'schema.failedAssertion';
|
||||
|
||||
/** no variables */
|
||||
public const MissingItem = 'schema.missingItem';
|
||||
|
||||
/** variables: {hint: string} */
|
||||
public const UnexpectedItem = 'schema.unexpectedItem';
|
||||
|
||||
/** no variables */
|
||||
public const Deprecated = 'schema.deprecated';
|
||||
|
||||
/** @deprecated use Message::TypeMismatch */
|
||||
public const TYPE_MISMATCH = self::TypeMismatch;
|
||||
|
||||
/** @deprecated use Message::ValueOutOfRange */
|
||||
public const VALUE_OUT_OF_RANGE = self::ValueOutOfRange;
|
||||
|
||||
/** @deprecated use Message::LengthOutOfRange */
|
||||
public const LENGTH_OUT_OF_RANGE = self::LengthOutOfRange;
|
||||
|
||||
/** @deprecated use Message::PatternMismatch */
|
||||
public const PATTERN_MISMATCH = self::PatternMismatch;
|
||||
|
||||
/** @deprecated use Message::FailedAssertion */
|
||||
public const FAILED_ASSERTION = self::FailedAssertion;
|
||||
|
||||
/** @deprecated use Message::MissingItem */
|
||||
public const MISSING_ITEM = self::MissingItem;
|
||||
|
||||
/** @deprecated use Message::UnexpectedItem */
|
||||
public const UNEXPECTED_ITEM = self::UnexpectedItem;
|
||||
|
||||
/** @deprecated use Message::Deprecated */
|
||||
public const DEPRECATED = self::Deprecated;
|
||||
|
||||
public string $message;
|
||||
public string $code;
|
||||
|
||||
/** @var string[] */
|
||||
public array $path;
|
||||
|
||||
/** @var string[] */
|
||||
public array $variables;
|
||||
|
||||
|
||||
public function __construct(string $message, string $code, array $path, array $variables = [])
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->code = $code;
|
||||
$this->path = $path;
|
||||
$this->variables = $variables;
|
||||
}
|
||||
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
$vars = $this->variables;
|
||||
$vars['label'] = empty($vars['isKey']) ? 'item' : 'key of item';
|
||||
$vars['path'] = $this->path
|
||||
? "'" . implode("\u{a0}›\u{a0}", $this->path) . "'"
|
||||
: null;
|
||||
$vars['value'] = Helpers::formatValue($vars['value'] ?? null);
|
||||
|
||||
return preg_replace_callback('~( ?)%(\w+)%~', function ($m) use ($vars) {
|
||||
[, $space, $key] = $m;
|
||||
return $vars[$key] === null ? '' : $space . $vars[$key];
|
||||
}, $this->message) ?? throw new Nette\InvalidStateException(preg_last_error_msg());
|
||||
}
|
||||
}
|
||||
96
vendor/nette/schema/src/Schema/Processor.php
vendored
Normal file
96
vendor/nette/schema/src/Schema/Processor.php
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Schema validator.
|
||||
*/
|
||||
final class Processor
|
||||
{
|
||||
public array $onNewContext = [];
|
||||
private Context $context;
|
||||
private bool $skipDefaults = false;
|
||||
|
||||
|
||||
public function skipDefaults(bool $value = true): void
|
||||
{
|
||||
$this->skipDefaults = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes and validates data. Result is a clean completed data.
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function process(Schema $schema, mixed $data): mixed
|
||||
{
|
||||
$this->createContext();
|
||||
$data = $schema->normalize($data, $this->context);
|
||||
$this->throwsErrors();
|
||||
$data = $schema->complete($data, $this->context);
|
||||
$this->throwsErrors();
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes and validates and merges multiple data. Result is a clean completed data.
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function processMultiple(Schema $schema, array $dataset): mixed
|
||||
{
|
||||
$this->createContext();
|
||||
$flatten = null;
|
||||
$first = true;
|
||||
foreach ($dataset as $data) {
|
||||
$data = $schema->normalize($data, $this->context);
|
||||
$this->throwsErrors();
|
||||
$flatten = $first ? $data : $schema->merge($data, $flatten);
|
||||
$first = false;
|
||||
}
|
||||
|
||||
$data = $schema->complete($flatten, $this->context);
|
||||
$this->throwsErrors();
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getWarnings(): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($this->context->warnings as $message) {
|
||||
$res[] = $message->toString();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
private function throwsErrors(): void
|
||||
{
|
||||
if ($this->context->errors) {
|
||||
throw new ValidationException(null, $this->context->errors);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function createContext(): void
|
||||
{
|
||||
$this->context = new Context;
|
||||
$this->context->skipDefaults = $this->skipDefaults;
|
||||
Nette\Utils\Arrays::invoke($this->onNewContext, $this->context);
|
||||
}
|
||||
}
|
||||
37
vendor/nette/schema/src/Schema/Schema.php
vendored
Normal file
37
vendor/nette/schema/src/Schema/Schema.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
|
||||
interface Schema
|
||||
{
|
||||
/**
|
||||
* Normalization.
|
||||
* @return mixed
|
||||
*/
|
||||
function normalize(mixed $value, Context $context);
|
||||
|
||||
/**
|
||||
* Merging.
|
||||
* @return mixed
|
||||
*/
|
||||
function merge(mixed $value, mixed $base);
|
||||
|
||||
/**
|
||||
* Validation and finalization.
|
||||
* @return mixed
|
||||
*/
|
||||
function complete(mixed $value, Context $context);
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
function completeDefault(Context $context);
|
||||
}
|
||||
55
vendor/nette/schema/src/Schema/ValidationException.php
vendored
Normal file
55
vendor/nette/schema/src/Schema/ValidationException.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Schema;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Validation error.
|
||||
*/
|
||||
class ValidationException extends Nette\InvalidStateException
|
||||
{
|
||||
/** @var Message[] */
|
||||
private array $messages;
|
||||
|
||||
|
||||
/**
|
||||
* @param Message[] $messages
|
||||
*/
|
||||
public function __construct(?string $message, array $messages = [])
|
||||
{
|
||||
parent::__construct($message ?: $messages[0]->toString());
|
||||
$this->messages = $messages;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getMessages(): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($this->messages as $message) {
|
||||
$res[] = $message->toString();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Message[]
|
||||
*/
|
||||
public function getMessageObjects(): array
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user