Skip to content

Instantly share code, notes, and snippets.

@wesrice
Last active August 4, 2021 22:02
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wesrice/74740b70c34a373fd451 to your computer and use it in GitHub Desktop.
Save wesrice/74740b70c34a373fd451 to your computer and use it in GitHub Desktop.
Self Validating Value Objects and Entities (Laravel Implementation)
<?php
abstract class AbstractEntity extends AbstractValueObject
{
/**
* Offset Set
*
* @param mixed $offset
* @param mixed $value
*
* @return void
*/
public function offsetSet($offset, $value)
{
$this->input[$offset] = $value;
if ($this->validate) {
$this->validate();
}
}
/**
* Offset Unset
*
* @param mixed $offset
*
* @return void
*/
public function offsetUnset($offset)
{
unset($this->input[$offset]);
if ($this->validate) {
$this->validate();
}
}
}
<?php
use ArrayAccess;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
use JsonSerializable;
use ValidatorInvalidArgumentException;
abstract class AbstractValueObject implements ArrayAccess, Arrayable, Jsonable, JsonSerializable
{
/**
* Input
*
* @var array
*/
protected $input;
/**
* Validate
*
* @var bool
*/
protected $validate;
/**
* Rules
*
* @var array
*/
public $rules = [];
/**
* Messages
*
* @var array
*/
public $messages = [];
/**
* Validator
*
* @var Illuminate\Validation\Factory
*/
protected $validator;
/**
* Constructor
*
* @param array $input Input
*/
public function __construct(array $input, $validate = true)
{
$this->validator = app()->make('validator');
$this->input = $input;
$this->validate = $validate;
if ($this->validate) {
$this->validate();
}
}
/**
* Get Input
*
* @return array Input
*/
public function getInput()
{
return $this->input();
}
/**
* Validate
*
* @return null|Dingo\Api\Exception\ValidationHttpException
*/
public function validate()
{
$validator = $this->validator->make($this->input, $this->rules, $this->messages);
if ($validator->fails()) {
$exception = new ValidatorInvalidArgumentException();
$exception
->setMessage('This is invalid')
->setErrors($validator->errors())
->setInput($this->input);
throw $exception;
}
}
/**
* Offset Exists
*
* @param mixed $offset
*
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->input[$offset]);
}
/**
* Offset Get
*
* @param mixed $offset
*
* @return mixed
*/
public function offsetGet($offset)
{
return $this->input[$offset];
}
/**
* Offset Set
*
* @param mixed $offset
* @param mixed $value
*
* @return void
*/
public function offsetSet($offset, $value)
{
return;
}
/**
* Offset Unset
*
* @param mixed $offset
*
* @return void
*/
public function offsetUnset($offset)
{
return;
}
/**
* To Array
*
* @return array Array of validated inputs
*/
public function toArray()
{
return array_only($this->input, array_keys($this->rules));
}
/**
* Json Serialize
*
* @return array Convert the object into something JSON serializable.
*/
public function jsonSerialize()
{
return $this->toArray();
}
/**
* To Json
*
* @return string Json string of validated inputs
*/
public function toJson($options = 0)
{
return json_encode($this->jsonSerialize(), $options);
}
}
<?php
use ValidatorInvalidArgumentException;
class AuthController extends ApiController
{
/**
* Auth Service
*
* @var AuthService
*/
protected $auth_service;
/**
* Constructor
*
* @param AuthService $auth_service Auth Service
*/
public function __construct(AuthService $auth_service)
{
$this->auth_service = $auth_service;
}
/**
* Authenticate
*
* @param Request $request Request
*
* @return Response Response
*/
public function authenticate(Request $request)
{
$credentials = new CredentialsEntity($request->only('email', 'password'));
try {
$token = $this->auth_service->authenticate($credentials);
} catch (ValidatorInvalidArgumentException $exception) {
return [
'message' => $exception->getMessage(),
'errors' => $exception->getErrors(),
'input' => $exception->getInput(),
];
}
return [
'token' => $token
];
}
}
<?php
class AuthService
{
/**
* Authenticate
*
* @param CredentialsEntity $credentials Credentials
*
* @return string Token
*/
public function authenticate(CredentialsEntity $credentials)
{
$token = ''; // Do something with valid $credentials here
return $token;
}
}
<?php
class CredentialsEntity extends AbstractEntity
{
/**
* Rules
*
* @var array
*/
public $rules = [
'email' => 'required|email',
'password' => 'required',
];
}
<?php
class CredentialsValueObject extends AbstractValueObject
{
/**
* Rules
*
* @var array
*/
public $rules = [
'email' => 'required|email',
'password' => 'required',
];
}
<?php
// Value Objects are immutable.
$credentials = new CredentialsValueObject(['email' => 'foo@bar.com', 'password' => 'baz']);
print $credentials['email'];
// Prints email.
print isset($credentials['email']);
// Prints `true`.
print_r($credentials->toArray());
// Prints array of input.
print $credentials->toJson();
// Prints input in json format.
$credentials['something'] = 'else';
print $credentials['something'];
// The key will not exist.
// Entities are mutable.
$credentials = new CredentialsEntity(['email' => 'foo@bar.com', 'password' => 'baz']);
unset($credentials['email']);
// Removes `email` key from input property in object and then revalidates. Validation fails.
$credentials['something'] = 'else';
print $credentials['something'];
// Prints `else`.
<?php
use InvalidArgumentException;
use Illuminate\Support\MessageBag;
class ValidatorInvalidArgumentException extends InvalidArgumentException
{
/**
* Errors
*
* @var Illuminate\Support\MessageBag
*/
protected $errors = [];
/**
* Input
*
* @var array
*/
protected $input = [];
/**
* Constructor
*
* @param string $message Message
* @param integer $code Code
* @param Exception|null $previous Previous
*/
public function __construct($message = '', $code = 0, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->errors = new MessageBag;
}
/**
* Set Message
*
* @param string $message Message
*
* @return ValidatorInvalidArgumentException
*/
public function setMessage($message = '')
{
$this->message = $message;
return $this;
}
/**
* Set Errors
*
* @param MessageBag $errors Errors
*/
public function setErrors(MessageBag $errors)
{
$this->errors = $errors;
return $this;
}
/**
* Get Errors
*
* @return MessageBag Errors
*/
public function getErrors()
{
return $this->errors;
}
/**
* Set Input
*
* @param array $input Input
*/
public function setInput(array $input)
{
$this->input = $input;
return $this;
}
/**
* Get Input
*
* @return array Input
*/
public function getInput()
{
return $this->input;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment