Skip to content

Commit

Permalink
ValueObject support added which does not include id attribute
Browse files Browse the repository at this point in the history
This can also be used for form validation or etc…
  • Loading branch information
mkorkmaz committed Nov 27, 2018
1 parent 4c41950 commit 873e1c2
Show file tree
Hide file tree
Showing 7 changed files with 344 additions and 106 deletions.
104 changes: 10 additions & 94 deletions src/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,121 +3,37 @@

namespace Selami\Entity;

use JsonSerializable;
use stdClass;
use Opis\JsonSchema\Validator;
use Selami\Entity\Exception\InvalidArgumentException;
use Selami\Entity\Exception\UnexpectedValueException;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use JsonSerializable;
use Selami\Entity\Exception\UnexpectedValueException;

final class Entity implements JsonSerializable
{
/**
* @var Model
*/
private $model;
/*
* @var stdClass
*/
private $data;
use ObjectTrait;

public function __construct(Model $model, ?stdClass $data = null)
public function __construct(Model $model, UuidInterface $id, ?stdClass $data = null)
{
$this->model = $model;
$this->data = $data;
if ($data === null) {
$this->data = new stdClass();
}
$this->checkAndSetId();
}

private function checkAndSetId() : void
{
if (!isset($this->data->id)) {
$this->data->id = Uuid::uuid4()->toString();
}
}

public function __get($name)
{
return $this->data->{$name};
}

public function __set($name, $value) : void
{
$this->data->{$name} = $value;
}

public function __isset($name) : bool
{
return property_exists($this->data, $name);
}

public function __unset($name)
{
unset($this->data->{$name});
}

public function validate() : bool
{
return $this->validateData($this->data, $this->model->getSchema());
}

public function validatePartially(array $requiredFields) : bool
{
$model = $this->model->getModel();
$model->required = $requiredFields;
$schema = $this->model->getSchema($model);
return $this->validateData($this->data, $schema);
}

private function validateData($data, $schema) : bool
{
$validation = (new Validator())->schemaValidation($data, $schema);
if (!$validation->isValid()) {
$errors = $validation->getErrors();
$message = 'Data validation failed.' . PHP_EOL;
foreach ($errors as $error) {
$message .= sprintf(
'ERROR: %s. %s',
$error->keyword(),
json_encode($error->keywordArgs(), JSON_PRETTY_PRINT)
) . PHP_EOL;
}
throw new InvalidArgumentException(
$message
);
}
return true;
}


public function equals($rightHandedObject) : bool
{
return (string) $this === (string) $rightHandedObject;
}

public function jsonSerialize() : string
{
return (string) json_encode($this->data);
}

public function __toString()
{
return $this->jsonSerialize();
$this->data->id = $id->toString();
}

public static function createFromJsonFile($filePath) : Entity
public static function createFromJsonFile($filePath, UuidInterface $id) : Entity
{
if (!file_exists($filePath)) {
throw new UnexpectedValueException(sprintf('Model definition file (%s) does not exist!', $filePath));
}
$json = file_get_contents($filePath);
return self::createFromJson($json);
return static::createFromJson($json, $id);
}

public static function createFromJson($json) : Entity
public static function createFromJson($json, UuidInterface $id) : Entity
{
return new self(new Model($json));
return new static(new Model($json), $id);
}
}
1 change: 1 addition & 0 deletions src/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function getModel() : \stdClass
{
return $this->model;
}

public function getRequiredFields() : array
{
return $this->requiredFields;
Expand Down
89 changes: 89 additions & 0 deletions src/ObjectTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php
declare(strict_types=1);

namespace Selami\Entity;

use stdClass;
use Opis\JsonSchema\Validator;
use Selami\Entity\Exception\InvalidArgumentException;

trait ObjectTrait
{
/**
* @var Model
*/
private $model;

/*
* @var stdClass
*/
private $data;

public function __get($name)
{
return $this->data->{$name};
}

public function __set($name, $value) : void
{
$this->data->{$name} = $value;
}

public function __isset($name) : bool
{
return property_exists($this->data, $name);
}

public function __unset($name)
{
unset($this->data->{$name});
}

public function validate() : bool
{
return $this->validateData($this->data, $this->model->getSchema());
}

public function validatePartially(array $requiredFields) : bool
{
$model = $this->model->getModel();
$model->required = $requiredFields;
$schema = $this->model->getSchema($model);
return $this->validateData($this->data, $schema);
}

private function validateData($data, $schema) : bool
{
$validation = (new Validator())->schemaValidation($data, $schema);
if (!$validation->isValid()) {
$errors = $validation->getErrors();
$message = 'Data validation failed.' . PHP_EOL;
foreach ($errors as $error) {
$message .= sprintf(
'ERROR: %s. %s',
$error->keyword(),
json_encode($error->keywordArgs(), JSON_PRETTY_PRINT)
) . PHP_EOL;
}
throw new InvalidArgumentException(
$message
);
}
return true;
}

public function equals($rightHandedObject) : bool
{
return (string) $this === (string) $rightHandedObject;
}

public function jsonSerialize() : stdClass
{
return $this->data;
}

public function __toString() : string
{
return (string) json_encode($this);
}
}
35 changes: 35 additions & 0 deletions src/ValueObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);

namespace Selami\Entity;

use stdClass;
use JsonSerializable;
use Selami\Entity\Exception\UnexpectedValueException;

final class ValueObject implements JsonSerializable
{
use ObjectTrait;

public function __construct(Model $model, ?stdClass $data = null)
{
$this->model = $model;
$this->data = $data;
if ($data === null) {
$this->data = new stdClass();
}
}

public static function createFromJsonFile($filePath) : ValueObject
{
if (!file_exists($filePath)) {
throw new UnexpectedValueException(sprintf('Model definition file (%s) does not exist!', $filePath));
}
$json = file_get_contents($filePath);
return static::createFromJson($json);
}
public static function createFromJson($json) : ValueObject
{
return new static(new Model($json));
}
}
81 changes: 81 additions & 0 deletions tests/resources/test-schema-value-object.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://api.example.com/profile.json#",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"pattern": "^[a-zA-Z0-9\\-]+(\\s[a-zA-Z0-9\\-]+)*$"
},
"age": {
"type": "integer",
"minimum": 18,
"maximum": 100
},
"email": {
"type": "string",
"maxLength": 128,
"format": "email"
},
"website": {
"type": ["string", "null"],
"maxLength": 128,
"format": "hostname"
},
"location": {
"type": "object",
"properties": {
"country": {
"enum": ["US", "CA", "GB"]
},
"address": {
"type": "string",
"maxLength": 128
}
},
"required": ["country", "address"],
"additionalProperties": false
},
"available_for_hire": {
"type": "boolean"
},
"interests": {
"type": "array",
"minItems": 3,
"maxItems": 100,
"uniqueItems": true,
"items": {
"type": "string",
"maxLength": 120
}
},
"skills": {
"type": "array",
"maxItems": 100,
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLenght": 1,
"maxLength": 64
},
"value": {
"type": "number",
"minimum": 0,
"maximum": 100,
"multipleOf": 0.25
}
},
"required": ["name", "value"],
"additionalProperties": false
}
}
},
"required": ["name", "age", "email", "location",
"available_for_hire", "interests", "skills"],
"additionalProperties": false
}
Loading

0 comments on commit 873e1c2

Please sign in to comment.