From cc19ce609a62a5292c9b2945b91dba903546ef67 Mon Sep 17 00:00:00 2001 From: Dimitri Sitchet Tomkeu Date: Mon, 18 Sep 2023 12:01:01 +0200 Subject: [PATCH 1/3] fix: validation --- src/Container/Services.php | 5 +- src/Exceptions/ValidationException.php | 12 +++++ src/Http/Redirection.php | 6 +-- src/Validation/ErrorBag.php | 71 ++++++++++++++++++++++++++ src/View/View.php | 10 ++-- 5 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/Container/Services.php b/src/Container/Services.php index 13ab295e..6c62521a 100644 --- a/src/Container/Services.php +++ b/src/Container/Services.php @@ -24,12 +24,13 @@ use BlitzPHP\Filesystem\Filesystem; use BlitzPHP\Filesystem\FilesystemManager; use BlitzPHP\Http\Negotiator; -use BlitzPHP\HTTP\Redirection; +use BlitzPHP\Http\Redirection; use BlitzPHP\Http\Request; use BlitzPHP\Http\Response; use BlitzPHP\Http\ResponseEmitter; use BlitzPHP\Http\ServerRequest; use BlitzPHP\Http\Uri; +use BlitzPHP\Http\UrlGenerator; use BlitzPHP\Mail\Mail; use BlitzPHP\Router\RouteCollection; use BlitzPHP\Router\Router; @@ -282,7 +283,7 @@ public static function redirection(bool $shared = true): Redirection return static::$instances[Redirection::class]; } - return static::$instances[Redirection::class] = static::factory(Redirection::class); + return static::$instances[Redirection::class] = new Redirection(static::factory(UrlGenerator::class)); } /** diff --git a/src/Exceptions/ValidationException.php b/src/Exceptions/ValidationException.php index 37abdf16..4625ecd7 100644 --- a/src/Exceptions/ValidationException.php +++ b/src/Exceptions/ValidationException.php @@ -12,7 +12,9 @@ namespace BlitzPHP\Exceptions; use BlitzPHP\Contracts\Http\StatusCode; +use BlitzPHP\Validation\ErrorBag; use Dimtrovich\Validation\Exceptions\ValidationException as BaseValidationException; +use Rakit\Validation\ErrorBag as RakitErrorBag; class ValidationException extends BaseValidationException { @@ -22,4 +24,14 @@ class ValidationException extends BaseValidationException * @var int */ protected $code = StatusCode::BAD_REQUEST; + + /** + * Set errors + */ + public function setErrors(?RakitErrorBag $errors): self + { + $this->errors = new ErrorBag($errors->toArray()); + + return $this; + } } diff --git a/src/Http/Redirection.php b/src/Http/Redirection.php index a1d39bca..69255670 100644 --- a/src/Http/Redirection.php +++ b/src/Http/Redirection.php @@ -173,13 +173,11 @@ public function withErrors(array|ErrorBag|string $errors, string $key = 'default if ($errors instanceof ErrorBag) { $errors = $errors->toArray(); } elseif (is_string($errors)) { - $errors = [$errors]; + $errors = [$key => $errors]; } if (! empty($errors)) { - $this->session->flashErrors($errors, $key); - - Services::viewer()->share('errors', new ErrorBag($errors)); + Services::viewer()->share('errors', new ErrorBag($this->session->flashErrors($errors, $key))); } return $this; diff --git a/src/Validation/ErrorBag.php b/src/Validation/ErrorBag.php index 155ce1df..bb64af12 100644 --- a/src/Validation/ErrorBag.php +++ b/src/Validation/ErrorBag.php @@ -26,4 +26,75 @@ public function line(string $key, string $separator = ', ', string $format = ':m return join($separator, $errors); } + + /** + * Get messages from given key, can be use custom format + * + */ + public function get(string $key, string $format = ':message'): array + { + list($key, $ruleName) = $this->parsekey($key); + $results = []; + if ($this->isWildcardKey($key)) { + $messages = $this->filterMessagesForWildcardKey($key, $ruleName); + foreach ($messages as $explicitKey => $keyMessages) { + foreach ($keyMessages as $rule => $message) { + $results[$explicitKey][$rule] = $this->formatMessage($message, $format); + } + } + } else { + $keyMessages = isset($this->messages[$key])? $this->messages[$key] : []; + foreach ((array) $keyMessages as $rule => $message) { + if ($ruleName and $ruleName != $rule) { + continue; + } + $results[$rule] = $this->formatMessage($message, $format); + } + } + + return $results; + } + + /** + * Get all messages + */ + public function all(string $format = ':message'): array + { + $messages = $this->messages; + + $results = []; + foreach ($messages as $key => $keyMessages) { + foreach ((array) $keyMessages as $message) { + $results[] = $this->formatMessage($message, $format); + } + } + return $results; + } + + /** + * Filter messages with wildcard key + */ + protected function filterMessagesForWildcardKey(string $key, $ruleName = null): array + { + $messages = $this->messages; + $pattern = preg_quote($key, '#'); + $pattern = str_replace('\*', '.*', $pattern); + + $filteredMessages = []; + + foreach ($messages as $k => $keyMessages) { + if ((bool) preg_match('#^'.$pattern.'\z#u', $k) === false) { + continue; + } + + foreach ((array) $keyMessages as $rule => $message) { + if ($ruleName and $rule != $ruleName) { + continue; + } + $filteredMessages[$k][$rule] = $message; + } + } + + return $filteredMessages; + } } diff --git a/src/View/View.php b/src/View/View.php index b91b9c39..9622f878 100644 --- a/src/View/View.php +++ b/src/View/View.php @@ -290,20 +290,24 @@ private function setValidationErrors() { $errors = []; - if (null !== $e = session('errors')) { + if (null !== $e = session()->getFlashdata('errors')) { if (is_array($e)) { $errors = array_merge($errors, $e); } else { $errors['error'] = $e; } - } - if (null !== $e = session('error')) { + session()->unmarkFlashdata('errors'); + } + + if (null !== $e = session()->getFlashdata('error')) { if (is_array($e)) { $errors = array_merge($errors, $e); } else { $errors['error'] = $e; } + + session()->unmarkFlashdata('error'); } $this->adapter->addData(['errors' => new ErrorBag($errors)]); From e07bbf24727528d799b289e9aabc8d9fe023e8b9 Mon Sep 17 00:00:00 2001 From: Dimitri Sitchet Tomkeu Date: Mon, 18 Sep 2023 12:01:38 +0200 Subject: [PATCH 2/3] patch: update RouteBuilder::form --- src/Router/RouteBuilder.php | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Router/RouteBuilder.php b/src/Router/RouteBuilder.php index 605a27f3..2316794d 100644 --- a/src/Router/RouteBuilder.php +++ b/src/Router/RouteBuilder.php @@ -14,6 +14,7 @@ use BadMethodCallException; use BlitzPHP\Container\Services; use BlitzPHP\Utilities\Iterable\Arr; +use BlitzPHP\Utilities\String\Text; use Closure; use InvalidArgumentException; @@ -149,7 +150,48 @@ public function environment(string $env, Closure $callback): void public function form(string $from, $to, array $options = []): void { - $this->match(['get', 'post'], $from, $to, $options); + $options = $options + $this->attributes; + $this->attributes = []; + + if (isset($options['unique'])) { + $this->match(['get', 'post'], $from, $to, $options); + return; + } + + $toGet = $toPost = $to; + + if (is_string($to)) { + $parts = explode('::', $to); + } else if(is_array($to)) { + $parts = $to; + } else { + $parts = []; + } + + if (count($parts) == 2) { // Si on a defini le controleur et la methode + $controller = $parts[0]; + $method = $parts[1]; + } else if (count($parts) == 1) { + // Si on est ici, ca veut dire 2 choses. + // - Soit c'est la methode qui est definie (utilisateur d'un string) + // - Soit c'est le controleur qui est defini (utilisateur d'un array) + + if (is_array($to)) { + $controller = $parts[0]; + $method = $this->collection->getDefaultMethod(); + } else { + $controller = ''; + $method = $parts[0]; + } + } + + if (isset($controller) && isset($method)) { + $toGet = implode('::', array_filter([$controller, Text::camel('form_' . $method)])); + $toPost = implode('::', array_filter([$controller, Text::camel('process_' . $method)])); + } + + $this->collection->get($from, $toGet, $options); + $this->collection->post($from, $toPost, $options); } /** From b49c3d58a615ef923b5e2131f880988e439aeced Mon Sep 17 00:00:00 2001 From: Dimitri Sitchet Tomkeu Date: Mon, 18 Sep 2023 12:02:02 +0200 Subject: [PATCH 3/3] feat: validation Exists --- src/Validation/Rule.php | 1 + src/Validation/Rules/Exists.php | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/Validation/Rules/Exists.php diff --git a/src/Validation/Rule.php b/src/Validation/Rule.php index 98de0781..d8d10012 100644 --- a/src/Validation/Rule.php +++ b/src/Validation/Rule.php @@ -17,6 +17,7 @@ /** * {@inheritDoc} * + * @method static \BlitzPHP\Validation\Rules\Exists exists(string $table, ?string $column = null) * @method static \BlitzPHP\Validation\Rules\Unique unique(string $table, ?string $column = null, mixed $ignore = null) */ abstract class Rule extends DimtrovichRule diff --git a/src/Validation/Rules/Exists.php b/src/Validation/Rules/Exists.php new file mode 100644 index 00000000..7fc59ef4 --- /dev/null +++ b/src/Validation/Rules/Exists.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace BlitzPHP\Validation\Rules; + +use BlitzPHP\Contracts\Database\ConnectionInterface; + +class Exists extends AbstractRule +{ + protected $message = ':attribute :value do not exist'; + protected $fillableParams = ['table', 'column']; + + + public function __construct(protected ConnectionInterface $db) + { + } + + public function check($value): bool + { + $this->requireParameters(['table']); + + $table = $this->parameter('table'); + $column = $this->parameter('column'); + $column = $column ?: $this->getAttribute()->getKey(); + + $builder = $this->db->table($table)->where($column, $value); + + return $builder->count() > 0; + } +}