Skip to content

Commit

Permalink
feat: new ErrorBag class for manipulate validation errors
Browse files Browse the repository at this point in the history
  • Loading branch information
chipslays committed Feb 16, 2023
1 parent db184cf commit 3b7794f
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 10 deletions.
11 changes: 9 additions & 2 deletions examples/basic-events/events/hello-to.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@
'username' => ['stringType', ['length', [4, 18]]],
];

protected array $messages = [
'username' => [
'stringType' => 'Property %prop% must be a string.',
'length' => 'Length of %prop% must be 4-18 chars.',
],
];

public function handle(Connection $connection, Payload $payload, Server $server)
{
if (!$this->validate()) {
return $this->reply('bad request', ['errors' => $this->errors]);
}
return $this->reply('errors', $this->errorBag()->all());
};

$username = $this->payload->data['username'];
$this->reply(data: ['message' => "Hello, {$username}!"]);
Expand Down
7 changes: 5 additions & 2 deletions examples/simple-chat/chat.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<script src="https://cdn.tailwindcss.com"></script>

<title>Chat</title>
<title>Simple Chat</title>
</head>

<body class="bg-gray-50">
Expand All @@ -18,7 +18,6 @@
Users: <span id="usersCount">0</span>
</div>
<div id="chat" class="flex flex-col divide-y border rounded-md h-96 overflow-y-auto"></div>

<div class="mt-4">
<input id="message" class="focus:outline-none outline-none px-3 py-2 rounded-lg focus:shadow-sm bg-gray-50 focus:bg-transparent border text-sm w-full" type="text" placeholder="Text message (Enter)">
</div>
Expand Down Expand Up @@ -57,6 +56,10 @@
document.getElementById('usersCount').innerHTML = payload.data.count;
});

client.on('errors', payload => {
console.log('errors:', payload.data);
});

client.listen();
</script>
</body>
Expand Down
11 changes: 10 additions & 1 deletion examples/simple-chat/events/chat-message.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@
'message' => ['stringType', ['length', [1, 256]]],
];

protected array $messages = [
'message' => [
'stringType' => 'Property %prop% must be a string.',
'length' => 'Length of %prop% must be 1-256 chars.',
],
];

public function handle(Connection $connection, Payload $payload, Server $server)
{
if (!$this->validate()) return;
if (!$this->validate()) {
return $this->reply('errors', [$this->errorBag()->first('message')]);
};

$this->broadcast($payload->type, data: [
'nickname' => $connection->nickname,
Expand Down
36 changes: 31 additions & 5 deletions src/Events/AbstractEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,18 @@ abstract class AbstractEvent
protected array $rules = [];

/**
* Array of validate errors.
* Array of validation custom messages.
*
* @var array
*/
public array $errors = [];
protected array $messages = [];

/**
* Errors bag for validation.
*
* @var ErrorBag
*/
public ErrorBag $errorBag;

/**
* Short cut for payload data (as &link).
Expand All @@ -84,6 +91,7 @@ public function boot(Connection $connection, Payload $payload): self
$this->payload = $payload;
$this->server = Server::getInstance();
$this->data = &$this->payload->data;
$this->errorBag = new ErrorBag;

$this->setMagicalVariables();

Expand Down Expand Up @@ -200,28 +208,46 @@ public function validator(): Validator
* @param array $rules Pass custom rules. Default use $rules class attribute.
* @return bool Returns False if has errors.
*/
protected function validate(array $rules = null): bool
public function validate(array $rules = null): bool
{
foreach ($rules ?? $this->rules as $property => $rules) {
foreach ($rules as $rule) {
if (!$this->payload->is($rule, $property)) {
// get a rule name
$rule = ((array) $rule)[0];
$this->errors[$property][$rule] = "{$property} failed validation: {$rule}";

// get a message
$message = @$this->messages[$property][$rule]
? str_replace(['%prop%', '%property%'], $property, $this->messages[$property][$rule])
: "Property {$property} failed validation {$rule} rule.";

// add error to errors bag
$this->errorBag()->add($property, $rule, $message);
}
}
}

return !$this->hasErrors();
}

/**
* Get a errors bag.
*
* @return ErrorBag
*/
public function errorBag(): ErrorBag
{
return $this->errorBag;
}

/**
* Returns `true` if has errors on validate payload data.
*
* @return bool
*/
public function hasErrors(): bool
{
return count($this->errors) > 0;
return $this->errorBag()->any();
}

/**
Expand Down
137 changes: 137 additions & 0 deletions src/Events/ErrorBag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

namespace Porter\Events;

use Porter\Support\Collection;

/**
* A class for store and manipulate validation errors.
*/
class ErrorBag
{
/**
* Contain errors by property.
*
* @var Collection
*/
protected Collection $errors;

/**
* Constructor.
*
* @param array $errors
*/
public function __construct(array $errors = [])
{
$this->errors = new Collection($errors);
}

/**
* Get a errors by property.
*
* @param string $property
* @return array|null
*/
public function get(string $property): ?array
{
return $this->errors->get($property);
}

/**
* Property has any errors.
*
* @param string $property
* @return boolean
*/
public function has(string $property): bool
{
return $this->errors->has($property);
}

/**
* Remove property from errors bag.
*
* @param string $property
* @return self
*/
public function remove(string $property): self
{
$this->errors->remove($property);

return $this;
}

/**
* Get a first error message of property.
*
* @param string $property
* @return string|null
*/
public function first(string $property): ?string
{
$messages = $this->get($property);

if (is_array($messages) && count($messages) > 0) {
return array_values($messages)[0];
}

return null;
}

/**
* Add new error to errors bag.
*
* @param string $property
* @param string $rule
* @param string $message
* @return self
*/
public function add(string $property, string $rule, string $message): self
{
$this->errors->set("{$property}.{$rule}", $message);

return $this;
}

/**
* Get all errors as array.
*
* @return array
*/
public function all(): array
{
return $this->errors->all();
}

/**
* Get count of errors.
*
* @return integer
*/
public function count(): int
{
return $this->errors->count();
}

/**
* Has any erorrs.
*
* @return boolean
*/
public function any(): bool
{
return $this->errors->count() > 0;
}

/**
* Clear errors bag.
*
* @return self
*/
public function clear(): self
{
$this->errors = new Collection;

return $this;
}
}

0 comments on commit 3b7794f

Please sign in to comment.