From 4e5c568c3d0516f0739691ff4c9b0dd90b1492ff Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Sun, 23 Jul 2017 22:08:42 +0100 Subject: [PATCH 01/19] Clean up and improve json decode check --- src/CollectionJson/BaseEntity.php | 18 +++++++++++++++--- src/CollectionJson/DataAware.php | 2 +- src/CollectionJson/DataContainer.php | 2 +- src/CollectionJson/Entity/Data.php | 2 ++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/CollectionJson/BaseEntity.php b/src/CollectionJson/BaseEntity.php index ce35daa..0325279 100644 --- a/src/CollectionJson/BaseEntity.php +++ b/src/CollectionJson/BaseEntity.php @@ -49,7 +49,13 @@ public static function fromArray(array $data) } elseif (method_exists($object, $wither)) { $object = $object->$wither($value); } else { - throw new \DomainException(sprintf('Could not inject the entry "%s"', $key)); + throw new \DomainException( + sprintf( + 'Invalid schema! Could not inject entry "%s" into entity "%s"', + $key, + get_class($object) + ) + ); } } } @@ -67,6 +73,11 @@ public static function fromJson($json) $data = json_decode($json, true); $type = static::getObjectType(); + if (!$data || json_last_error() !== JSON_ERROR_NONE) { + throw new \LogicException(sprintf('Invalid JSON: %s', json_last_error_msg())); + } + + // unwrapping if (array_key_exists($type, $data)) { $data = $data[$type]; } @@ -95,18 +106,19 @@ public function jsonSerialize(): array public function toArray(): array { $data = $this->getObjectData(); - $data = $this->recursiveToArray($data); $data = $this->addWrapper($data); - return $data; + return $this->recursiveToArray($data); } /** + * @TODO this method should return a new entity * @return self */ final public function wrap(): self { $this->wrapper = static::getObjectType(); + return $this; } diff --git a/src/CollectionJson/DataAware.php b/src/CollectionJson/DataAware.php index ba19a95..33ed6b4 100644 --- a/src/CollectionJson/DataAware.php +++ b/src/CollectionJson/DataAware.php @@ -34,7 +34,7 @@ public function withData($data); public function withDataSet(array $set); /** - * @return array + * @return Entity\Data[] */ public function getDataSet(): array; diff --git a/src/CollectionJson/DataContainer.php b/src/CollectionJson/DataContainer.php index f8db56e..c237601 100644 --- a/src/CollectionJson/DataContainer.php +++ b/src/CollectionJson/DataContainer.php @@ -67,7 +67,7 @@ public function withDataSet(array $set) } /** - * @return array + * @return Data[] */ public function getDataSet(): array { diff --git a/src/CollectionJson/Entity/Data.php b/src/CollectionJson/Entity/Data.php index 2de19cf..570b6be 100644 --- a/src/CollectionJson/Entity/Data.php +++ b/src/CollectionJson/Entity/Data.php @@ -62,6 +62,8 @@ public function __construct(string $name = null, $value = null, string $prompt = $this->prompt = $prompt; } + // @TODO add a __toString method + /** * @param string $name * From b2ca51d0255826b23c4fffe4d055912fc1d47624 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Mon, 24 Jul 2017 19:34:42 +0100 Subject: [PATCH 02/19] Add Dataset validator --- composer.json | 3 + src/CollectionJson/Validator/Dataset.php | 97 ++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 src/CollectionJson/Validator/Dataset.php diff --git a/composer.json b/composer.json index ece4ba9..3e018fa 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,9 @@ "satooshi/php-coveralls": "^1.0", "leanphp/phpspec-code-coverage": "^3.1" }, + "suggest": { + "symfony/validator": "Adds DataSet validation support" + }, "config": { "bin-dir": "bin" }, diff --git a/src/CollectionJson/Validator/Dataset.php b/src/CollectionJson/Validator/Dataset.php new file mode 100644 index 0000000..62cae8a --- /dev/null +++ b/src/CollectionJson/Validator/Dataset.php @@ -0,0 +1,97 @@ + [ + * new Constraints\NotBlank(), + * ], + * 'url' => [ + * new Constraints\NotBlank(), + * new Constraints\Url(), + * ], + * 'email' => [ + * new Constraints\NotBlank(), + * new Constraints\Email(), + * ], + * ]; + * + * $template = (new Template()) + * ->withData(new Data('id', '123')) + * ->withData(new Data('url', 'http://example.co')) + * ->withData(new Data('email', 'test@example.co')); + * + * $errors = (new Validator()) + * ->validate($template->getDataSet(), $constraints); + * + * @param array $dataSet + * @param array $constraints + * + * @return array + */ + public function validate(array $dataSet, array $constraints): array + { + $errors = []; + $data = self::flatten($dataSet); + $validator = Validation::createValidator(); + + foreach ($constraints as $name => $constraint) { + $value = $data[$name] ?? null; + $violations = $validator->validate($value, $constraint); + + foreach ($violations as $violation) { + /** @var ConstraintViolationInterface $violation */ + $errors[] = [ + 'code' => $violation->getCode(), + 'message' => $violation->getMessage(), + 'property' => $violation->getPropertyPath(), + 'value' => $violation->getInvalidValue(), + ]; + } + } + + return $errors; + } + + /** + * @param Data[] $dataSet + * + * @return array + */ + public static function flatten(array $dataSet): array + { + return array_reduce($dataSet, function($carry, Data $item) { + $carry[$item->getName()] = $item->getValue(); + return $carry; + }, []); + } +} From e219cff85e765fc3150ba2830a54d476b81f0d32 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Mon, 24 Jul 2017 22:50:29 +0100 Subject: [PATCH 03/19] Code style fix --- src/CollectionJson/Validator/Dataset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CollectionJson/Validator/Dataset.php b/src/CollectionJson/Validator/Dataset.php index 62cae8a..26ff807 100644 --- a/src/CollectionJson/Validator/Dataset.php +++ b/src/CollectionJson/Validator/Dataset.php @@ -89,7 +89,7 @@ public function validate(array $dataSet, array $constraints): array */ public static function flatten(array $dataSet): array { - return array_reduce($dataSet, function($carry, Data $item) { + return array_reduce($dataSet, function ($carry, Data $item) { $carry[$item->getName()] = $item->getValue(); return $carry; }, []); From bef64e3ee978104dac30de3dc9f4017c195a2c5c Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 25 Jul 2017 21:48:24 +0100 Subject: [PATCH 04/19] Update README --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index 0660bf9..916d4be 100644 --- a/README.md +++ b/README.md @@ -274,3 +274,36 @@ $item = (new Item()) $data2 ]); ``` + +### Validation + +it is now possible to validate the data entering your API by using the Symfony validator. + +```php +use CollectionJson\Validator\Dataset as DatasetValidator; +use Symfony\Component\Validator\Constraints; + +$constraints = [ + 'id' => [ + new Constraints\NotBlank(), + ], + 'url' => [ + new Constraints\NotBlank(), + new Constraints\Url(), + ], + 'email' => [ + new Constraints\NotBlank(), + new Constraints\Email(), + ], +]; + +$template = (new Template()) + ->withData(new Data('id', '123')) + ->withData(new Data('url', 'http://example.co')) + ->withData(new Data('email', 'test@example.co')); + +$errors = (new DatasetValidator()) + ->validate($template->getDataSet(), $constraints); +``` + +It will return the list of errors. From 2ef83b9c570976313a8475acc538deaa348baf37 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 25 Jul 2017 21:51:23 +0100 Subject: [PATCH 05/19] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 916d4be..d939f8f 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ $item = (new Item()) ### Validation -it is now possible to validate the data entering your API by using the Symfony validator. +it is now possible to validate the data entering your API by using the [Symfony validator](https://symfony.com/doc/current/components/validator.html). ```php use CollectionJson\Validator\Dataset as DatasetValidator; From edf47ba578d140bdf96e735a687ba8b98b916bee Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Fri, 4 Aug 2017 12:21:26 +0100 Subject: [PATCH 06/19] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d939f8f..f216de7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Collection Json [![Build Status](https://travis-ci.org/mickaelvieira/CollectionJson.svg?branch=master)](https://travis-ci.org/mickaelvieira/CollectionJson) -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/mickaelvieira/CollectionJson/blob/master/LICENSE) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/mickaelvieira/CollectionJson/blob/master/LICENSE.md) [![Coverage Status](https://coveralls.io/repos/github/mickaelvieira/CollectionJson/badge.svg?branch=master)](https://coveralls.io/github/mickaelvieira/CollectionJson?branch=master) PHP implementation of the Collection+JSON Media Type @@ -34,7 +34,7 @@ Please see [CONTRIBUTING](https://github.com/mickaelvieira/CollectionJson/tree/m ## License -The MIT License (MIT). Please see [License File](https://github.com/mickaelvieira/CollectionJson/tree/master/LICENSE) for more information. +The MIT License (MIT). Please see [License File](https://github.com/mickaelvieira/CollectionJson/tree/master/LICENSE.md) for more information. ## Documentation From cbc2dabbbd0fb57e311a5a0aac7ac60d296b5d16 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Fri, 4 Aug 2017 14:36:54 +0100 Subject: [PATCH 07/19] Composer branch alias --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3e018fa..53c7769 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.x-dev" } } } From 1a01bdad128c4dd5b1b44cfa58814dfd0d50cb99 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Fri, 4 Aug 2017 15:14:33 +0100 Subject: [PATCH 08/19] Add packagist badge --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f216de7..e220bda 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # Collection Json +[![Software License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/mickaelvieira/CollectionJson/blob/master/LICENSE.md) +[![Latest Stable Version](https://img.shields.io/packagist/v/mvieira/collection-json.svg)](https://packagist.org/packages/mvieira/collection-json) [![Build Status](https://travis-ci.org/mickaelvieira/CollectionJson.svg?branch=master)](https://travis-ci.org/mickaelvieira/CollectionJson) -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/mickaelvieira/CollectionJson/blob/master/LICENSE.md) [![Coverage Status](https://coveralls.io/repos/github/mickaelvieira/CollectionJson/badge.svg?branch=master)](https://coveralls.io/github/mickaelvieira/CollectionJson?branch=master) PHP implementation of the Collection+JSON Media Type -Specification: +Specification: - [http://amundsen.com/media-types/collection/](http://amundsen.com/media-types/collection/) ## Installation From ac8190e6dda4b6c060cfa534fa3e5313d4115b53 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Sun, 6 Aug 2017 18:15:11 +0100 Subject: [PATCH 09/19] Update README --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d939f8f..f4d3767 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # Collection Json +[![Software License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/mickaelvieira/CollectionJson/blob/master/LICENSE.md) +[![Latest Stable Version](https://img.shields.io/packagist/v/mvieira/collection-json.svg)](https://packagist.org/packages/mvieira/collection-json) [![Build Status](https://travis-ci.org/mickaelvieira/CollectionJson.svg?branch=master)](https://travis-ci.org/mickaelvieira/CollectionJson) -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/mickaelvieira/CollectionJson/blob/master/LICENSE) [![Coverage Status](https://coveralls.io/repos/github/mickaelvieira/CollectionJson/badge.svg?branch=master)](https://coveralls.io/github/mickaelvieira/CollectionJson?branch=master) PHP implementation of the Collection+JSON Media Type -Specification: +Specification: - [http://amundsen.com/media-types/collection/](http://amundsen.com/media-types/collection/) ## Installation @@ -243,7 +244,7 @@ $item = (new Item()) 'value' => 'email value' ]); -// ...is similar to +// ...is similar to $data = Data::fromArray([ 'name' => 'email', 'value' => 'email value' @@ -259,7 +260,7 @@ $item = (new Item()) new Data('tel', '0000000000') ]); -// ...is similar to +// ...is similar to $data1 = Data::fromArray([ 'name' => 'email', 'value' => 'hello@example.co' @@ -277,7 +278,7 @@ $item = (new Item()) ### Validation -it is now possible to validate the data entering your API by using the [Symfony validator](https://symfony.com/doc/current/components/validator.html). +It is now possible to validate the data entering your API by using the [Symfony validator](https://symfony.com/doc/current/components/validator.html). ```php use CollectionJson\Validator\Dataset as DatasetValidator; From b82b8f9dc93e2509f230eb83aed0fe985143acf1 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Mon, 11 Sep 2017 14:22:34 +0100 Subject: [PATCH 10/19] Add Makefile --- .travis.yml | 11 +++++++---- CONTRIBUTING.md | 14 ++++++++++---- Makefile | 32 ++++++++++++++++++++++++++++++++ README.md | 2 +- 4 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 Makefile diff --git a/.travis.yml b/.travis.yml index a4137af..2b3da2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ sudo: false # use container-based-infrastructure +env: + global: + - MAKEFLAGS="-j 2" + language: php php: [7.0, 7.1] @@ -10,9 +14,9 @@ install: script: - mkdir -p build/logs - - php bin/phpcs --standard=PSR2 ./src/ --report=full - - php bin/phpspec run --format=pretty -v - - php bin/test-examples + - make lint + - make test + - make examples after_success: - travis_retry php bin/coveralls -v @@ -20,4 +24,3 @@ after_success: cache: directories: - $HOME/.composer/cache - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 33f7fe7..50fa857 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ```sh $ git clone git@github.com:mickaelvieira/CollectionJson.git $ cd CollectionJson -$ composer install +$ make ``` ## Run the test @@ -11,7 +11,7 @@ $ composer install The test suite has been written with [PHPSpec](http://phpspec.net/) ```sh -$ ./bin/phpspec run --format=pretty +$ make test ``` ## PHP Code Sniffer @@ -19,11 +19,17 @@ $ ./bin/phpspec run --format=pretty This project follows the coding style guide [PSR1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) and [PSR2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) ```sh -$ ./bin/phpcs --standard=PSR2 ./src/ +$ make lint +``` + +To fix PHP Code Sniffer issues + +```sh +$ make fmt ``` ## Run the examples (see `./examples`) ```sh -$ ./bin/test-examples +$ make examples ``` diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d51a234 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +OS := $(shell uname -s) +PATH := bin:$(PATH) +SHELL := /bin/bash +SOURCE_DIR := src + +.PHONY: all clean install lint fmt test examples branch release + +all: clean install + +clean: + rm -rf vendor/* + +install: composer.json composer.lock + composer install + +lint: + phpcs --standard=PSR2 --report=full $(SOURCE_DIR) + +fmt: + phpcbf --standard=PSR2 $(SOURCE_DIR) + +test: + phpspec run --format=pretty -vvv + +examples: + test-examples + +branch: + create-branch + +release: + create-release diff --git a/README.md b/README.md index b1c9940..316247a 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ echo json_encode($template); Examples are available in the directory ```./examples/```, you can execute them on the command line by running: ```sh -$ ./bin/test-example +$ make examples ``` Or separately From 216630a29f5c6e1a17506061f000feaa8cf8cd90 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 13:15:20 +0100 Subject: [PATCH 11/19] DataContainer and LinkContainer These containers no longer return null when trying to access the first or the last element in the set. Their existence must be tested beforehands with hasLinks and hasData --- spec/CollectionJson/Entity/CollectionSpec.php | 12 ---------- spec/CollectionJson/Entity/ItemSpec.php | 24 ------------------- spec/CollectionJson/Entity/QuerySpec.php | 12 ---------- spec/CollectionJson/Entity/TemplateSpec.php | 12 ---------- src/CollectionJson/DataAware.php | 8 +++---- src/CollectionJson/DataContainer.php | 8 +++---- src/CollectionJson/LinkAware.php | 8 +++---- src/CollectionJson/LinkContainer.php | 8 +++---- 8 files changed, 16 insertions(+), 76 deletions(-) diff --git a/spec/CollectionJson/Entity/CollectionSpec.php b/spec/CollectionJson/Entity/CollectionSpec.php index 6a37fda..d9ee314 100644 --- a/spec/CollectionJson/Entity/CollectionSpec.php +++ b/spec/CollectionJson/Entity/CollectionSpec.php @@ -647,15 +647,9 @@ function it_should_return_the_first_link_in_the_set() $collection = $this->withLinksSet([$link1, $link2, $link3]); - $this->getFirstLink()->shouldBeNull(); $collection->getFirstLink()->shouldBeLike($link1); } - function it_should_return_null_when_the_first_link_in_not_the_set() - { - $this->getFirstLink()->shouldBeNull(); - } - function it_should_return_the_last_link_in_the_set() { $link1 = Link::fromArray(['rel' => 'rel1', 'href' => 'http://example.com']); @@ -664,15 +658,9 @@ function it_should_return_the_last_link_in_the_set() $collection = $this->withLinksSet([$link1, $link2, $link3]); - $this->getLastLink()->shouldBeNull(); $collection->getLastLink()->shouldBeLike($link3); } - function it_should_return_null_when_the_last_link_in_not_the_set() - { - $this->getLastLink()->shouldBeNull(); - } - function it_should_know_if_it_has_links() { $link = new Link(); diff --git a/spec/CollectionJson/Entity/ItemSpec.php b/spec/CollectionJson/Entity/ItemSpec.php index 12b72a9..b13ae00 100644 --- a/spec/CollectionJson/Entity/ItemSpec.php +++ b/spec/CollectionJson/Entity/ItemSpec.php @@ -286,15 +286,9 @@ function it_should_return_the_first_link_in_the_set() $item = $this->withLinksSet([$link1, $link2, $link3]); - $this->getFirstLink()->shouldBeNull(); $item->getFirstLink()->shouldBeLike($link1); } - function it_should_return_null_when_the_first_link_in_not_the_set() - { - $this->getFirstLink()->shouldBeNull(); - } - function it_should_return_the_last_link_in_the_set() { $link1 = Link::fromArray(['rel' => 'rel1', 'href' => 'http://example.com']); @@ -303,15 +297,9 @@ function it_should_return_the_last_link_in_the_set() $item = $this->withLinksSet([$link1, $link2, $link3]); - $this->getLastLink()->shouldBeNull(); $item->getLastLink()->shouldBeLike($link3); } - function it_should_return_null_when_the_last_link_in_not_the_set() - { - $this->getLastLink()->shouldBeNull(); - } - function it_should_know_if_it_has_links() { $link = new Link(); @@ -334,15 +322,9 @@ function it_should_return_the_first_data_in_the_set() $item = $this->withDataSet([$data1, $data2, $data3]); - $this->getFirstData()->shouldBeNull(); $item->getFirstData()->shouldBeLike($data1); } - function it_should_return_null_when_the_first_data_in_not_the_set() - { - $this->getFirstData()->shouldBeNull(); - } - function it_should_return_the_last_data_in_the_set() { $data1 = Data::fromArray(['value' => 'value1']); @@ -351,15 +333,9 @@ function it_should_return_the_last_data_in_the_set() $item = $this->withDataSet([$data1, $data2, $data3]); - $this->getLastData()->shouldBeNull(); $item->getLastData()->shouldReturn($data3); } - function it_should_return_null_when_the_last_data_in_not_the_set() - { - $this->getLastData()->shouldBeNull(); - } - function it_should_know_if_it_has_data() { $data = new Data(); diff --git a/spec/CollectionJson/Entity/QuerySpec.php b/spec/CollectionJson/Entity/QuerySpec.php index 5307e98..e1581c0 100644 --- a/spec/CollectionJson/Entity/QuerySpec.php +++ b/spec/CollectionJson/Entity/QuerySpec.php @@ -280,15 +280,9 @@ function it_should_return_the_first_data_in_the_set() $query = $this->withDataSet([$data1, $data2, $data3]); - $this->getFirstData()->shouldBeNull(); $query->getFirstData()->shouldBeLike($data1); } - function it_should_return_null_when_the_first_data_in_not_the_set() - { - $this->getFirstData()->shouldBeNull(); - } - function it_should_return_the_last_data_in_the_set() { $data1 = Data::fromArray(['value' => 'value1']); @@ -297,15 +291,9 @@ function it_should_return_the_last_data_in_the_set() $query = $this->withDataSet([$data1, $data2, $data3]); - $this->getLastData()->shouldBeNull(); $query->getLastData()->shouldBeLike($data3); } - function it_should_return_null_when_the_last_data_in_not_the_set() - { - $this->getLastData()->shouldBeNull(); - } - function it_should_know_if_it_has_data() { $data = new Data(); diff --git a/spec/CollectionJson/Entity/TemplateSpec.php b/spec/CollectionJson/Entity/TemplateSpec.php index 71a0022..1d9c6be 100644 --- a/spec/CollectionJson/Entity/TemplateSpec.php +++ b/spec/CollectionJson/Entity/TemplateSpec.php @@ -237,15 +237,9 @@ function it_should_return_the_first_data_in_the_set() $template = $this->withDataSet([$data1, $data2, $data3]); - $this->getFirstData()->shouldBeNull(); $template->getFirstData()->shouldBeLike($data1); } - function it_should_return_null_when_the_first_data_in_not_the_set() - { - $this->getFirstData()->shouldBeNull(); - } - function it_should_return_the_last_data_in_the_set() { $data1 = Data::fromArray(['value' => 'value1']); @@ -254,15 +248,9 @@ function it_should_return_the_last_data_in_the_set() $template = $this->withDataSet([$data1, $data2, $data3]); - $this->getLastData()->shouldBeNull(); $template->getLastData()->shouldBeLike($data3); } - function it_should_return_null_when_the_last_data_in_not_the_set() - { - $this->getLastData()->shouldBeNull(); - } - function it_should_know_if_it_has_data() { $data = new Data(); diff --git a/src/CollectionJson/DataAware.php b/src/CollectionJson/DataAware.php index 33ed6b4..bf6ae1f 100644 --- a/src/CollectionJson/DataAware.php +++ b/src/CollectionJson/DataAware.php @@ -46,14 +46,14 @@ public function getDataSet(): array; public function getDataByName($name); /** - * @return Entity\Data|null + * @return Entity\Data */ - public function getFirstData(); + public function getFirstData(): Entity\Data; /** - * @return Entity\Data|null + * @return Entity\Data */ - public function getLastData(); + public function getLastData(): Entity\Data; /** * @return bool diff --git a/src/CollectionJson/DataContainer.php b/src/CollectionJson/DataContainer.php index c237601..944d1bb 100644 --- a/src/CollectionJson/DataContainer.php +++ b/src/CollectionJson/DataContainer.php @@ -89,17 +89,17 @@ public function getDataByName($name) } /** - * @return Data|null + * @return Data */ - public function getFirstData() + public function getFirstData(): Data { return $this->data->first(); } /** - * @return Data|null + * @return Data */ - public function getLastData() + public function getLastData(): Data { return $this->data->last(); } diff --git a/src/CollectionJson/LinkAware.php b/src/CollectionJson/LinkAware.php index 9166459..6fcc77c 100644 --- a/src/CollectionJson/LinkAware.php +++ b/src/CollectionJson/LinkAware.php @@ -29,14 +29,14 @@ interface LinkAware extends LinkProviderInterface, EvolvableLinkProviderInterfac public function withLinksSet(array $set); /** - * @return Entity\Link|null + * @return Entity\Link */ - public function getFirstLink(); + public function getFirstLink(): Entity\Link; /** - * @return Entity\Link|null + * @return Entity\Link */ - public function getLastLink(); + public function getLastLink(): Entity\Link; /** * @return bool diff --git a/src/CollectionJson/LinkContainer.php b/src/CollectionJson/LinkContainer.php index 5f819dd..b2ffc38 100644 --- a/src/CollectionJson/LinkContainer.php +++ b/src/CollectionJson/LinkContainer.php @@ -82,17 +82,17 @@ public function getLinksByRel($rel): array } /** - * @return Link|null + * @return Entity\Link */ - public function getFirstLink() + public function getFirstLink(): Entity\Link { return $this->links->first(); } /** - * @return Link|null + * @return Entity\Link */ - public function getLastLink() + public function getLastLink(): Entity\Link { return $this->links->last(); } From 944c597642923fc18f98e7cc629d0f85ceb07a09 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 13:36:58 +0100 Subject: [PATCH 12/19] Collection The collection entity no longer return null when trying to access the first or the last item or query in the set. Their existence must be tested beforehand with hasLinks and hasData --- spec/CollectionJson/Entity/CollectionSpec.php | 42 +++++-------------- src/CollectionJson/Entity/Collection.php | 40 +++++++++++------- src/CollectionJson/Entity/Item.php | 4 +- 3 files changed, 37 insertions(+), 49 deletions(-) diff --git a/spec/CollectionJson/Entity/CollectionSpec.php b/spec/CollectionJson/Entity/CollectionSpec.php index d9ee314..cd0e7be 100644 --- a/spec/CollectionJson/Entity/CollectionSpec.php +++ b/spec/CollectionJson/Entity/CollectionSpec.php @@ -347,7 +347,7 @@ function it_should_throw_an_exception_when_setting_the_href_field_with_an_invali function it_should_set_the_href_value() { $link = $this->withHref("htp://google.com"); - $this->getHref()->shouldBeNull(); + $this->hasHref()->shouldReturn(false); $link->getHref()->shouldBeEqualTo("htp://google.com"); } @@ -432,15 +432,10 @@ function it_should_return_the_first_item_in_the_set() $item3 = new Item(); $collection = $this->withItemsSet([$item1, $item2, $item3]); - $this->getFirstItem()->shouldBeNull(); + $this->shouldNotHaveItems(); $collection->getFirstItem()->shouldBeLike($item1); } - function it_should_return_null_when_the_first_item_in_not_the_set() - { - $this->getFirstItem()->shouldBeNull(); - } - function it_should_return_the_last_item_in_the_set() { $item1 = new Item(); @@ -448,15 +443,10 @@ function it_should_return_the_last_item_in_the_set() $item3 = new Item(); $collection = $this->withItemsSet([$item1, $item2, $item3]); - $this->getLastItem()->shouldBeNull(); + $this->shouldNotHaveItems(); $collection->getLastItem()->shouldBeLike($item3); } - function it_should_return_null_when_the_last_item_in_not_the_set() - { - $this->getLastItem()->shouldBeNull(); - } - function it_should_know_if_it_has_items() { $item1 = new Item(); @@ -534,15 +524,10 @@ function it_should_return_the_first_query_in_the_set() $query3 = new Query(); $collection = $this->withQueriesSet([$query1, $query2, $query3]); - $this->getFirstQuery()->shouldBeNull(); + $this->shouldNotHaveQueries(); $collection->getFirstQuery()->shouldBeLike($query1); } - function it_should_return_null_when_the_first_data_in_not_the_set() - { - $this->getFirstQuery()->shouldBeNull(); - } - function it_should_return_the_last_data_in_the_set() { $query1 = new Query(); @@ -550,15 +535,10 @@ function it_should_return_the_last_data_in_the_set() $query3 = new Query(); $collection = $this->withQueriesSet([$query1, $query2, $query3]); - $this->getLastQuery()->shouldBeNull(); + $this->shouldNotHaveQueries(); $collection->getLastQuery()->shouldBeLike($query3); } - function it_should_return_null_when_the_last_data_in_not_the_set() - { - $this->getLastQuery()->shouldBeNull(); - } - function it_should_know_if_it_has_queries() { $query = new Query(); @@ -681,7 +661,7 @@ function it_should_set_the_error() ->withCode('error code'); $collection = $this->withError($error); - $this->getError()->shouldBeNull(); + $this->shouldNotHaveError(); $collection->getError()->shouldBeAnInstanceOf(Error::class); $collection->getError()->getCode()->shouldBeEqualTo('error code'); } @@ -695,7 +675,7 @@ function it_should_remove_the_error() $collection->getError()->shouldBeAnInstanceOf(Error::class); $collection = $collection->withoutError(); - $collection->getError()->shouldBeNull(); + $collection->shouldNotHaveError(); } function it_should_set_the_error_when_passing_an_array() @@ -705,7 +685,7 @@ function it_should_set_the_error_when_passing_an_array() 'title' => 'title code', 'code' => 'error code', ]); - $this->getError()->shouldBeNull(); + $this->shouldNotHaveError(); $collection->getError()->shouldBeAnInstanceOf(Error::class); $collection->getError()->getMessage()->shouldBeEqualTo('message code'); $collection->getError()->getTitle()->shouldBeEqualTo('title code'); @@ -738,7 +718,7 @@ function it_should_set_the_template() $template = new Template(); $collection = $this->withTemplate($template); - $this->getTemplate()->shouldBeNull(); + $this->shouldNotHaveTemplate(); $collection->getTemplate()->shouldBeAnInstanceOf(Template::class); } @@ -750,7 +730,7 @@ function it_should_remove_the_template() $collection->getTemplate()->shouldBeAnInstanceOf(Template::class); $collection = $collection->withoutTemplate(); - $collection->getTemplate()->shouldBeNull(); + $collection->shouldNotHaveTemplate(); } function it_should_set_the_template_when_passing_an_array() @@ -763,7 +743,7 @@ function it_should_set_the_template_when_passing_an_array() ] ] ]); - $this->getTemplate()->shouldBeNull(); + $this->shouldNotHaveTemplate(); $collection->getTemplate()->shouldBeAnInstanceOf(Template::class); $collection->getTemplate()->getDataSet()->shouldHaveCount(1); } diff --git a/src/CollectionJson/Entity/Collection.php b/src/CollectionJson/Entity/Collection.php index 689fa51..6fa506f 100644 --- a/src/CollectionJson/Entity/Collection.php +++ b/src/CollectionJson/Entity/Collection.php @@ -88,7 +88,7 @@ public function __construct(string $href = null) } /** - * @param string $href + * @param string|Object $href * * @return Collection * @@ -107,13 +107,21 @@ public function withHref($href): Collection } /** - * @return string|null + * @return string */ - public function getHref() + public function getHref(): string { return $this->href; } + /** + * @return bool + */ + public function hasHref(): bool + { + return is_string($this->href); + } + /** * @param $item * @@ -132,7 +140,7 @@ public function withItem($item): Collection * * @return Collection */ - public function withoutItem($item) + public function withoutItem($item): Collection { $copy = clone $this; $copy->items = $this->items->without($item); @@ -162,17 +170,17 @@ public function getItemsSet(): array } /** - * @return Item|null + * @return Item */ - public function getFirstItem() + public function getFirstItem(): Item { return $this->items->first(); } /** - * @return Item|null + * @return Item */ - public function getLastItem() + public function getLastItem(): Item { return $this->items->last(); } @@ -233,17 +241,17 @@ public function getQueriesSet(): array } /** - * @return Query|null + * @return Query */ - public function getFirstQuery() + public function getFirstQuery(): Query { return $this->queries->first(); } /** - * @return Query|null + * @return Query */ - public function getLastQuery() + public function getLastQuery(): Query { return $this->queries->last(); } @@ -291,9 +299,9 @@ public function withoutError(): Collection } /** - * @return Error|null + * @return Error */ - public function getError() + public function getError(): Error { return $this->error; } @@ -341,9 +349,9 @@ public function withoutTemplate(): Collection } /** - * @return Template|null + * @return Template */ - public function getTemplate() + public function getTemplate(): Template { return $this->template; } diff --git a/src/CollectionJson/Entity/Item.php b/src/CollectionJson/Entity/Item.php index 31d3277..feb93e1 100644 --- a/src/CollectionJson/Entity/Item.php +++ b/src/CollectionJson/Entity/Item.php @@ -70,14 +70,14 @@ public function __construct(string $href = null) * * @throws \DomainException */ - public function withHref($href): Item + public function withHref(string $href): Item { if (!Uri::isValid($href)) { throw InvalidParameter::fromTemplate(self::getObjectType(), 'href', Uri::allowed()); } $copy = clone $this; - $copy->href = (string)$href; + $copy->href = $href; return $copy; From 74f7521154f782dc906b4fa7c88c10cde666c653 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 14:26:05 +0100 Subject: [PATCH 13/19] Add Dataset validator specs --- spec/CollectionJson/Validator/DatasetSpec.php | 79 +++++++++++++++++++ src/CollectionJson/Validator/Dataset.php | 4 +- 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 spec/CollectionJson/Validator/DatasetSpec.php diff --git a/spec/CollectionJson/Validator/DatasetSpec.php b/spec/CollectionJson/Validator/DatasetSpec.php new file mode 100644 index 0000000..21eb080 --- /dev/null +++ b/spec/CollectionJson/Validator/DatasetSpec.php @@ -0,0 +1,79 @@ +shouldHaveType(Dataset::class); + } + + function it_validates_a_data_set_when_it_does_not_contain_errors() + { + $constraints = [ + 'id' => [ + new Constraints\NotBlank(), + ], + 'url' => [ + new Constraints\NotBlank(), + new Constraints\Url(), + ], + 'email' => [ + new Constraints\NotBlank(), + new Constraints\Email(), + ], + ]; + + $template = (new Template()) + ->withData(new Data('id', '123')) + ->withData(new Data('url', 'http://example.co')) + ->withData(new Data('email', 'test@example.co')); + + $this->validate($template->getDataSet(), $constraints)->shouldReturn([]); + } + + function it_does_not_validate_a_data_set_when_it_contains_errors() + { + $constraints = [ + 'id' => [ + new Constraints\NotBlank(), + ], + 'url' => [ + new Constraints\NotBlank(), + new Constraints\Url(), + ], + 'email' => [ + new Constraints\NotBlank(), + new Constraints\Email(), + ] + ]; + + $template = (new Template()) + ->withData(new Data('url', 'example.co')) + ->withData(new Data('email', 'testexample.co')); + + $this->validate($template->getDataSet(), $constraints)->shouldReturn([ + 'id' => [ + 'message' => 'This value should not be blank.', + 'value' => null, + ], + 'url' => [ + 'message' => 'This value is not a valid URL.', + 'value' => 'example.co', + ], + 'email' => [ + 'message' => 'This value is not a valid email address.', + 'value' => 'testexample.co', + ], + ]); + } +} diff --git a/src/CollectionJson/Validator/Dataset.php b/src/CollectionJson/Validator/Dataset.php index 26ff807..b76dc4e 100644 --- a/src/CollectionJson/Validator/Dataset.php +++ b/src/CollectionJson/Validator/Dataset.php @@ -70,10 +70,8 @@ public function validate(array $dataSet, array $constraints): array foreach ($violations as $violation) { /** @var ConstraintViolationInterface $violation */ - $errors[] = [ - 'code' => $violation->getCode(), + $errors[$name] = [ 'message' => $violation->getMessage(), - 'property' => $violation->getPropertyPath(), 'value' => $violation->getInvalidValue(), ]; } From 7faa908ac1d5b955a0df6295b57e606d4fe4f4a7 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 14:39:04 +0100 Subject: [PATCH 14/19] Add symfony validator as a dev dependency --- composer.json | 3 ++- src/CollectionJson/ArrayConvertible.php | 2 +- src/CollectionJson/Bag.php | 2 +- src/CollectionJson/BaseEntity.php | 2 +- src/CollectionJson/DataAware.php | 2 +- src/CollectionJson/DataContainer.php | 2 +- src/CollectionJson/Entity/Collection.php | 2 +- src/CollectionJson/Entity/Data.php | 2 +- src/CollectionJson/Entity/Error.php | 2 +- src/CollectionJson/Entity/Item.php | 2 +- src/CollectionJson/Entity/Link.php | 2 +- src/CollectionJson/Entity/Query.php | 2 +- src/CollectionJson/Entity/Template.php | 2 +- src/CollectionJson/Exception/InvalidParameter.php | 2 +- src/CollectionJson/Exception/InvalidType.php | 2 +- src/CollectionJson/Exception/MissingProperty.php | 2 +- src/CollectionJson/LinkAware.php | 2 +- src/CollectionJson/LinkContainer.php | 2 +- src/CollectionJson/Type/Relation.php | 2 +- src/CollectionJson/Type/Render.php | 2 +- src/CollectionJson/Validator/DataValue.php | 2 +- src/CollectionJson/Validator/Dataset.php | 11 ++++++++++- src/CollectionJson/Validator/Render.php | 2 +- src/CollectionJson/Validator/Uri.php | 2 +- 24 files changed, 34 insertions(+), 24 deletions(-) diff --git a/composer.json b/composer.json index 53c7769..26a5f9b 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "phpspec/phpspec": "^3.0", "squizlabs/php_codesniffer": "^3.0", "satooshi/php-coveralls": "^1.0", - "leanphp/phpspec-code-coverage": "^3.1" + "leanphp/phpspec-code-coverage": "^3.1", + "symfony/validator": "^3.3" }, "suggest": { "symfony/validator": "Adds DataSet validation support" diff --git a/src/CollectionJson/ArrayConvertible.php b/src/CollectionJson/ArrayConvertible.php index 3ebe077..c7c0e29 100644 --- a/src/CollectionJson/ArrayConvertible.php +++ b/src/CollectionJson/ArrayConvertible.php @@ -1,5 +1,5 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace CollectionJson\Validator; use CollectionJson\Entity\Data; use Symfony\Component\Validator\Validation; -use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\ConstraintViolationInterface; /** diff --git a/src/CollectionJson/Validator/Render.php b/src/CollectionJson/Validator/Render.php index 6df319e..752e7d0 100644 --- a/src/CollectionJson/Validator/Render.php +++ b/src/CollectionJson/Validator/Render.php @@ -1,5 +1,5 @@ Date: Tue, 17 Oct 2017 19:45:12 +0100 Subject: [PATCH 15/19] Required properties must be now provided to the constructor --- spec/CollectionJson/BagSpec.php | 34 +++---- spec/CollectionJson/Entity/CollectionSpec.php | 72 +++++++-------- spec/CollectionJson/Entity/DataSpec.php | 32 +++---- spec/CollectionJson/Entity/ItemSpec.php | 77 ++++++++++------ spec/CollectionJson/Entity/LinkSpec.php | 54 +++++------ spec/CollectionJson/Entity/QuerySpec.php | 89 +++++++++---------- spec/CollectionJson/Entity/TemplateSpec.php | 26 +++--- .../Exception/InvalidParameterSpec.php | 2 + .../Exception/InvalidTypeSpec.php | 4 +- .../Exception/MissingPropertySpec.php | 26 ------ src/CollectionJson/BaseEntity.php | 49 ++++++++-- src/CollectionJson/Entity/Collection.php | 3 +- src/CollectionJson/Entity/Data.php | 16 ++-- src/CollectionJson/Entity/Error.php | 7 +- src/CollectionJson/Entity/Item.php | 10 +-- src/CollectionJson/Entity/Link.php | 24 +++-- src/CollectionJson/Entity/Query.php | 16 ++-- .../Exception/CollectionJsonException.php | 22 +++++ .../Exception/InvalidParameter.php | 2 +- src/CollectionJson/Exception/InvalidType.php | 2 +- .../Exception/MissingProperty.php | 35 -------- 21 files changed, 292 insertions(+), 310 deletions(-) delete mode 100644 spec/CollectionJson/Exception/MissingPropertySpec.php create mode 100644 src/CollectionJson/Exception/CollectionJsonException.php delete mode 100644 src/CollectionJson/Exception/MissingProperty.php diff --git a/spec/CollectionJson/BagSpec.php b/spec/CollectionJson/BagSpec.php index 1e2c25f..0d5348e 100644 --- a/spec/CollectionJson/BagSpec.php +++ b/spec/CollectionJson/BagSpec.php @@ -31,14 +31,14 @@ function it_should_empty_by_default() function it_should_add_an_item_to_the_bag_link_set() { - $bag = $this->with(new Item()); + $bag = $this->with(new Item('http://example.com')); $this->shouldHaveCount(0); $bag->shouldHaveCount(1); } function it_should_remove_an_item_from_the_bag_link_set() { - $item = new Item(); + $item = new Item('http://example.com'); $bag = $this->with($item); $this->shouldHaveCount(0); $bag->shouldHaveCount(1); @@ -52,8 +52,8 @@ function it_should_remove_an_item_from_the_bag_link_set() function it_should_not_blow_up_when_removing_an_unexisting_item_from_the_bag_link_set() { - $item1 = new Item(); - $item2 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); $bag = $this->with($item1); $this->shouldHaveCount(0); $bag->shouldHaveCount(1); @@ -67,8 +67,8 @@ function it_should_not_blow_up_when_removing_an_unexisting_item_from_the_bag_lin function it_is_clonable() { - $item1 = new Item(); - $item2 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); $copy = $this->with($item1)->with($item2); @@ -83,8 +83,8 @@ function it_is_clonable() function it_should_throw_an_exception_when_item_is_of_the_wrong_type() { $this->shouldThrow( - new \BadMethodCallException('Property [item] must be of type [CollectionJson\Entity\Item]') - )->during('with', [new Query()]); + new \DomainException('Property [item] must be of type [CollectionJson\Entity\Item]') + )->during('with', [new Query('http://example.com', 'item')]); } function it_should_build_an_item_from_an_array() @@ -98,15 +98,15 @@ function it_should_build_an_item_from_an_array() function it_should_add_multiple_items_to_the_bag() { - $bag = $this->withSet([new Item(), ['href' => 'http://example.com']]); + $bag = $this->withSet([new Item('http://example.com'), ['href' => 'http://example.com']]); $this->shouldHaveCount(0); $bag->shouldHaveCount(2); } function it_should_return_the_set() { - $item1 = new Item(); - $item2 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); $bag = $this->with($item1); $bag = $bag->with($item2); @@ -115,9 +115,9 @@ function it_should_return_the_set() function it_should_return_the_first_element_in_the_set() { - $item1 = new Item(); - $item2 = new Item(); - $item3 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); + $item3 = new Item('http://example.com'); $bag = $this->withSet([$item1, $item2, $item3]); @@ -132,9 +132,9 @@ function it_should_return_null_when_the_first_element_in_not_the_set() function it_should_return_the_last_element_in_the_set() { - $item1 = new Item(); - $item2 = new Item(); - $item3 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); + $item3 = new Item('http://example.com'); $bag = $this->withSet([$item1, $item2, $item3]); diff --git a/spec/CollectionJson/Entity/CollectionSpec.php b/spec/CollectionJson/Entity/CollectionSpec.php index cd0e7be..6ed1d82 100644 --- a/spec/CollectionJson/Entity/CollectionSpec.php +++ b/spec/CollectionJson/Entity/CollectionSpec.php @@ -353,9 +353,9 @@ function it_should_set_the_href_value() function it_should_be_chainable() { - $link = new Link(); - $item = new Item(); - $query = new Query(); + $link = new Link('http://example.com', 'item'); + $item = new Item('http://example.com'); + $query = new Query('http://example.com', 'item'); $error = new Error(); $template = new Template(); @@ -381,7 +381,7 @@ function it_should_not_extract_null_and_empty_array_fields() function it_should_add_an_item() { - $item = new Item(); + $item = new Item('http://example.com'); $collection = $this->withItem($item); $this->getItemsSet()->shouldHaveCount(0); @@ -390,7 +390,7 @@ function it_should_add_an_item() function it_should_remove_an_item() { - $item = new Item(); + $item = new Item('http://example.com'); $collection = $this->withItem($item); $collection->getItemsSet()->shouldHaveCount(1); @@ -402,7 +402,7 @@ function it_should_remove_an_item() function it_should_throw_an_exception_when_item_has_the_wrong_type() { $this->shouldThrow( - new \BadMethodCallException('Property [item] must be of type [CollectionJson\Entity\Item]') + new \DomainException('Property [item] must be of type [CollectionJson\Entity\Item]') )->during('withItem', [new Template()]); } @@ -417,8 +417,8 @@ function it_should_add_a_item_when_passing_array() function it_should_add_multiple_items() { - $item1 = new Item(); - $item2 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); $collection = $this->withItemsSet([$item1, $item2]); $this->getItemsSet()->shouldHaveCount(0); @@ -427,9 +427,9 @@ function it_should_add_multiple_items() function it_should_return_the_first_item_in_the_set() { - $item1 = new Item(); - $item2 = new Item(); - $item3 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); + $item3 = new Item('http://example.com'); $collection = $this->withItemsSet([$item1, $item2, $item3]); $this->shouldNotHaveItems(); @@ -438,9 +438,9 @@ function it_should_return_the_first_item_in_the_set() function it_should_return_the_last_item_in_the_set() { - $item1 = new Item(); - $item2 = new Item(); - $item3 = new Item(); + $item1 = new Item('http://example.com'); + $item2 = new Item('http://example.com'); + $item3 = new Item('http://example.com'); $collection = $this->withItemsSet([$item1, $item2, $item3]); $this->shouldNotHaveItems(); @@ -449,7 +449,7 @@ function it_should_return_the_last_item_in_the_set() function it_should_know_if_it_has_items() { - $item1 = new Item(); + $item1 = new Item('http://example.com'); $collection = $this->withItem($item1); $this->shouldNotHaveItems(); @@ -463,7 +463,7 @@ function it_should_know_if_it_has_no_items() function it_should_add_a_query() { - $query = new Query(); + $query = new Query('http://example.com', 'item'); $collection = $this->withQuery($query); $this->getQueriesSet()->shouldHaveCount(0); $collection->getQueriesSet()->shouldHaveCount(1); @@ -471,8 +471,8 @@ function it_should_add_a_query() function it_should_remove_a_query() { - $query1 = new Query(); - $query2 = new Query(); + $query1 = new Query('http://example.com', 'item'); + $query2 = new Query('http://example.com', 'item'); $collection = $this->withQuery($query1)->withQuery($query2); $collection->getQueriesSet()->shouldHaveCount(2); @@ -485,7 +485,7 @@ function it_should_remove_a_query() function it_should_throw_an_exception_when_query_has_the_wrong_type() { $this->shouldThrow( - new \BadMethodCallException('Property [query] must be of type [CollectionJson\Entity\Query]') + new \DomainException('Property [query] must be of type [CollectionJson\Entity\Query]') )->during('withQuery', [new Template()]); } @@ -509,8 +509,8 @@ function it_should_add_a_query_when_passing_an_array() function it_should_add_multiple_queries() { - $query1 = new Query(); - $query2 = new Query(); + $query1 = new Query('http://example.com', 'item'); + $query2 = new Query('http://example.com', 'item'); $collection = $this->withQueriesSet([$query1, $query2]); $this->getQueriesSet()->shouldHaveCount(0); @@ -519,9 +519,9 @@ function it_should_add_multiple_queries() function it_should_return_the_first_query_in_the_set() { - $query1 = new Query(); - $query2 = new Query(); - $query3 = new Query(); + $query1 = new Query('http://example.com', 'item'); + $query2 = new Query('http://example.com', 'item'); + $query3 = new Query('http://example.com', 'item'); $collection = $this->withQueriesSet([$query1, $query2, $query3]); $this->shouldNotHaveQueries(); @@ -530,9 +530,9 @@ function it_should_return_the_first_query_in_the_set() function it_should_return_the_last_data_in_the_set() { - $query1 = new Query(); - $query2 = new Query(); - $query3 = new Query(); + $query1 = new Query('http://example.com', 'item'); + $query2 = new Query('http://example.com', 'item'); + $query3 = new Query('http://example.com', 'item'); $collection = $this->withQueriesSet([$query1, $query2, $query3]); $this->shouldNotHaveQueries(); @@ -541,7 +541,7 @@ function it_should_return_the_last_data_in_the_set() function it_should_know_if_it_has_queries() { - $query = new Query(); + $query = new Query('http://example.com', 'item'); $collection = $this->withQuery($query); $this->shouldNotHaveQueries(); @@ -555,7 +555,7 @@ function it_should_know_if_it_has_no_queries() function it_should_add_a_link() { - $link = new Link(); + $link = new Link('http://example.com', 'item'); $collection = $this->withLink($link); $this->getLinks()->shouldHaveCount(0); @@ -564,7 +564,7 @@ function it_should_add_a_link() function it_should_remove_a_link() { - $link = new Link(); + $link = new Link('http://example.com', 'item'); $collection = $this->withLink($link); $collection->getLinks()->shouldHaveCount(1); @@ -605,7 +605,7 @@ function it_should_add_a_link_when_passing_an_array() function it_should_add_a_link_set() { - $link1 = new Link(); + $link1 = new Link('http://example.com', 'item'); $collection = $this->withLinksSet([ $link1, @@ -643,7 +643,7 @@ function it_should_return_the_last_link_in_the_set() function it_should_know_if_it_has_links() { - $link = new Link(); + $link = new Link('http://example.com', 'item'); $collection = $this->withLink($link); @@ -695,8 +695,8 @@ function it_should_set_the_error_when_passing_an_array() function it_should_throw_an_exception_when_error_has_the_wrong_type() { $this->shouldThrow( - new \BadMethodCallException('Property [error] must be of type [CollectionJson\Entity\Error]') - )->during('withError', [new Query()]); + new \DomainException('Property [error] must be of type [CollectionJson\Entity\Error]') + )->during('withError', [new Query('http://example.com', 'item')]); } function it_should_know_if_it_has_an_error() @@ -766,7 +766,7 @@ function it_should_know_if_it_has_not_an_template() function it_should_throw_an_exception_when_template_has_the_wrong_type() { $this->shouldThrow( - new \BadMethodCallException('Property [template] must be of type [CollectionJson\Entity\Template]') - )->during('withTemplate', [new Query()]); + new \DomainException('Property [template] must be of type [CollectionJson\Entity\Template]') + )->during('withTemplate', [new Query('http://example.com', 'item')]); } } diff --git a/spec/CollectionJson/Entity/DataSpec.php b/spec/CollectionJson/Entity/DataSpec.php index 0a1ced7..14a3d23 100644 --- a/spec/CollectionJson/Entity/DataSpec.php +++ b/spec/CollectionJson/Entity/DataSpec.php @@ -11,6 +11,7 @@ class DataSpec extends ObjectBehavior { function it_is_initializable() { + $this->beConstructedWith('Data Name'); $this->shouldHaveType(Data::class); $this->shouldImplement(ArrayConvertible::class); $this->shouldImplement(\JsonSerializable::class); @@ -18,6 +19,7 @@ function it_is_initializable() function it_should_return_the_object_type() { + $this->beConstructedWith('Data Name'); $this::getObjectType()->shouldBeEqualTo('data'); } @@ -47,6 +49,7 @@ function it_is_clonable() function it_should_be_chainable() { + $this->beConstructedWith('Data Name'); $this->withName('value')->shouldHaveType(Data::class); $this->withPrompt('value')->shouldHaveType(Data::class); $this->withValue('value')->shouldHaveType(Data::class); @@ -67,13 +70,15 @@ function it_may_be_construct_with_an_array_representation_of_the_data() function it_should_convert_the_name_value_to_a_string() { + $this->beConstructedWith('Data Name'); $data = $this->withName(true); - $this->getName()->shouldBeNull(); + $this->getName()->shouldBeEqualTo('Data Name'); $data->getName()->shouldBeEqualTo('1'); } function it_should_not_set_the_prompt_if_it_is_not_string() { + $this->beConstructedWith('Data Name'); $data = $this->withPrompt(true); $this->getPrompt()->shouldBeNull(); $data->getPrompt()->shouldBeEqualTo('1'); @@ -81,6 +86,7 @@ function it_should_not_set_the_prompt_if_it_is_not_string() function it_should_set_the_value_if_it_is_a_boolean() { + $this->beConstructedWith('Data Name'); $data = $this->withValue(false); $this->getValue()->shouldBeNull(); $data->getValue()->shouldBeEqualTo(false); @@ -88,6 +94,7 @@ function it_should_set_the_value_if_it_is_a_boolean() function it_should_set_the_value_if_it_is_a_string() { + $this->beConstructedWith('Data Name'); $data = $this->withValue('string value'); $this->getValue()->shouldBeNull(); $data->getValue()->shouldBeEqualTo('string value'); @@ -95,6 +102,7 @@ function it_should_set_the_value_if_it_is_a_string() function it_should_set_the_value_if_it_is_a_number() { + $this->beConstructedWith('Data Name'); $data = $this->withValue(42); $this->getValue()->shouldBeNull(); $data->getValue()->shouldBeEqualTo(42); @@ -102,6 +110,7 @@ function it_should_set_the_value_if_it_is_a_number() function it_should_set_the_value_if_it_is_a_float() { + $this->beConstructedWith('Data Name'); $data = $this->withValue(42.10); $this->getValue()->shouldBeNull(); $data->getValue()->shouldBeEqualTo(42.10); @@ -109,6 +118,7 @@ function it_should_set_the_value_if_it_is_a_float() function it_should_set_the_value_if_it_is_a_null() { + $this->beConstructedWith('Data Name'); $data = $this->withValue(null); $this->getValue()->shouldBeNull(); $data->getValue()->shouldBeEqualTo(null); @@ -116,6 +126,7 @@ function it_should_set_the_value_if_it_is_a_null() function it_should_not_set_the_value_if_it_is_an_array() { + $this->beConstructedWith('Data Name'); $this->shouldThrow( new \DomainException( 'Property [value] of entity [data] can only have one of the following values [scalar,NULL]' @@ -125,6 +136,7 @@ function it_should_not_set_the_value_if_it_is_an_array() function it_should_not_set_the_value_if_it_is_an_object() { + $this->beConstructedWith('Data Name'); $this->shouldThrow( new \DomainException( 'Property [value] of entity [data] can only have one of the following values [scalar,NULL]' @@ -134,6 +146,7 @@ function it_should_not_set_the_value_if_it_is_an_object() function it_should_not_set_the_value_if_it_is_a_resource() { + $this->beConstructedWith('Data Name'); $this->shouldThrow( new \DomainException( "Property [value] of entity [data] can only have one of the following values [scalar,NULL]" @@ -145,6 +158,7 @@ function it_should_not_set_the_value_if_it_is_a_callable() { $fn = function() {}; + $this->beConstructedWith('Data Name'); $this->shouldThrow( new \DomainException( "Property [value] of entity [data] can only have one of the following values [scalar,NULL]" @@ -152,22 +166,10 @@ function it_should_not_set_the_value_if_it_is_a_callable() )->during('withValue', [$fn]); } - function it_should_throw_an_exception_during_array_conversion_when_the_field_name_is_null() - { - $this->shouldThrow(new \DomainException('Property [name] of entity [data] is required'))->during('toArray'); - } - - function it_should_throw_an_exception_during_json_conversion_when_the_field_name_is_null() - { - $this->shouldThrow( - new \DomainException('Property [name] of entity [data] is required') - )->during('jsonSerialize'); - } - function it_should_not_return_empty_arrays_and_null_properties_apart_from_the_value_field() { - $data = $this->withName('Name'); - $data->toArray()->shouldBeEqualTo([ + $this->beConstructedWith('Name'); + $this->toArray()->shouldBeEqualTo([ 'name' => 'Name', 'value' => null ]); diff --git a/spec/CollectionJson/Entity/ItemSpec.php b/spec/CollectionJson/Entity/ItemSpec.php index b13ae00..274aa21 100644 --- a/spec/CollectionJson/Entity/ItemSpec.php +++ b/spec/CollectionJson/Entity/ItemSpec.php @@ -17,6 +17,7 @@ class ItemSpec extends ObjectBehavior { function it_is_initializable() { + $this->beConstructedWith('http://example.com'); $this->shouldHaveType(Item::class); $this->shouldImplement(DataAware::class); $this->shouldImplement(LinkAware::class); @@ -26,6 +27,7 @@ function it_is_initializable() function it_should_return_the_object_type() { + $this->beConstructedWith('http://example.com'); $this::getObjectType()->shouldBeEqualTo('item'); } @@ -85,10 +87,11 @@ function it_is_clonable() function it_should_be_chainable() { + $this->beConstructedWith('http://example.com'); $this->withHref('http://example.com')->shouldHaveType(Item::class); - $this->withLink(new Link())->shouldHaveType(Item::class); + $this->withLink(new Link('http://example.com', 'item'))->shouldHaveType(Item::class); $this->withLinksSet([])->shouldHaveType(Item::class); - $this->withData([])->shouldHaveType(Item::class); + $this->withData(['name' => 'my name'])->shouldHaveType(Item::class); $this->withDataSet([])->shouldHaveType(Item::class); } @@ -118,6 +121,7 @@ function it_may_be_construct_with_an_array_representation_of_the_item() function it_should_throw_an_exception_when_setting_the_href_field_with_an_invalid_url() { + $this->beConstructedWith('http://example.com'); $this->shouldThrow( new \DomainException("Property [href] of entity [item] can only have one of the following values [URI]") )->during('withHref', ['uri']); @@ -125,23 +129,12 @@ function it_should_throw_an_exception_when_setting_the_href_field_with_an_invali function it_should_set_the_href_value() { + $this->beConstructedWith('http://example.com'); $link = $this->withHref("htp://google.com"); - $this->getHref()->shouldBeNull(); + $this->getHref()->shouldBeEqualTo('http://example.com'); $link->getHref()->shouldBeEqualTo("htp://google.com"); } - function it_should_throw_an_exception_during_array_conversion_when_the_field_href_is_null() - { - $this->shouldThrow(new \DomainException('Property [href] of entity [item] is required'))->during('toArray'); - } - - function it_should_throw_an_exception_during_json_conversion_when_the_field_href_is_null() - { - $this->shouldThrow( - new \DomainException('Property [href] of entity [item] is required') - )->during('jsonSerialize'); - } - function it_should_not_return_empty_array() { $data = (new Prophet())->prophesize(Data::class); @@ -150,6 +143,7 @@ function it_should_not_return_empty_array() 'value' => null ]); + $this->beConstructedWith('http://example.com'); $collection = $this->withHref('http://example.com'); $collection = $collection->withData($data); $collection->toArray()->shouldBeEqualTo([ @@ -165,7 +159,9 @@ function it_should_not_return_empty_array() function it_should_add_data_when_it_is_passed_as_an_object() { - $data = new Data(); + $data = new Data('Name'); + + $this->beConstructedWith('http://example.com'); $item = $this->withData($data); $this->getDataSet()->shouldHaveCount(0); $item->getDataSet()->shouldHaveCount(1); @@ -173,8 +169,9 @@ function it_should_add_data_when_it_is_passed_as_an_object() function it_should_remove_data() { - $data = new Data(); + $data = new Data('Name'); + $this->beConstructedWith('http://example.com'); $template = $this->withData($data); $template->getDataSet()->shouldHaveCount(1); @@ -184,14 +181,16 @@ function it_should_remove_data() function it_should_throw_an_exception_when_data_has_the_wrong_type() { + $this->beConstructedWith('http://example.com'); $this->shouldThrow( - new \BadMethodCallException('Property [data] must be of type [CollectionJson\Entity\Data]') + new \DomainException('Property [data] must be of type [CollectionJson\Entity\Data]') )->during('withData', [new Template()]); } function it_should_add_data_when_it_is_passed_as_an_array() { - $item = $this->withData(['value' => 'value 1']); + $this->beConstructedWith('http://example.com'); + $item = $this->withData(['name' => 'name 1', 'value' => 'value 1']); $this->getDataSet()->shouldHaveCount(0); $item->getDataSet()->shouldHaveCount(1); } @@ -199,7 +198,9 @@ function it_should_add_data_when_it_is_passed_as_an_array() function it_should_add_a_data_set() { $data = (new Prophet())->prophesize(Data::class); - $item = $this->withDataSet([$data, ['value' => 'value 2']]); + + $this->beConstructedWith('http://example.com'); + $item = $this->withDataSet([$data, ['name' => 'name 2', 'value' => 'value 2']]); $this->getDataSet()->shouldHaveCount(0); $item->getDataSet()->shouldHaveCount(2); } @@ -212,9 +213,9 @@ function it_should_retrieve_the_data_by_name() $data1->getName()->willReturn('name1'); $data2->getName()->willReturn('name2'); + $this->beConstructedWith('http://example.com'); $item = $this->withDataSet([$data1, $data2]); - $this->getDataByName('name1')->shouldBeNull(); $this->getDataByName('name2')->shouldBeNull(); @@ -227,6 +228,7 @@ function it_should_retrieve_the_link_by_relation() $link1 = Link::fromArray(['rel' => 'rel1', 'href' => 'http://example.com']); $link2 = Link::fromArray(['rel' => 'rel2', 'href' => 'http://example2.com']); + $this->beConstructedWith('http://example.com'); $item = $this->withLinksSet([$link1, $link2]); $this->getLinksByRel('rel1')->shouldHaveCount(0); @@ -238,23 +240,28 @@ function it_should_retrieve_the_link_by_relation() function it_should_return_null_when_data_is_not_in_the_set() { + $this->beConstructedWith('http://example.com'); $this->getDataByName('name1')->shouldBeNull(); } function it_should_return_null_when_link_is_not_in_the_set() { + $this->beConstructedWith('http://example.com'); $this->getLinksByRel('rel1')->shouldReturn([]); } function it_should_add_a_link_when_it_is_passed_as_an_object() { $link = (new Prophet())->prophesize(Link::class); + + $this->beConstructedWith('http://example.com'); $item = $this->withLink($link); $item->getLinks()->shouldHaveCount(1); } function it_should_add_a_link_when_it_is_passed_as_an_array() { + $this->beConstructedWith('http://example.com'); $item = $this->withLink(Link::fromArray([ 'href' => 'http://example.com', 'rel' => 'Rel value', @@ -266,6 +273,8 @@ function it_should_add_a_link_when_it_is_passed_as_an_array() function it_should_add_a_link_set() { $link1 = (new Prophet())->prophesize(Link::class); + + $this->beConstructedWith('http://example.com'); $item = $this->withLinksSet([ $link1, [ @@ -284,6 +293,7 @@ function it_should_return_the_first_link_in_the_set() $link2 = Link::fromArray(['rel' => 'rel2', 'href' => 'http://example2.com']); $link3 = Link::fromArray(['rel' => 'rel3', 'href' => 'http://example3.com']); + $this->beConstructedWith('http://example.com'); $item = $this->withLinksSet([$link1, $link2, $link3]); $item->getFirstLink()->shouldBeLike($link1); @@ -295,6 +305,7 @@ function it_should_return_the_last_link_in_the_set() $link2 = Link::fromArray(['rel' => 'rel2', 'href' => 'http://example2.com']); $link3 = Link::fromArray(['rel' => 'rel3', 'href' => 'http://example3.com']); + $this->beConstructedWith('http://example.com'); $item = $this->withLinksSet([$link1, $link2, $link3]); $item->getLastLink()->shouldBeLike($link3); @@ -302,8 +313,9 @@ function it_should_return_the_last_link_in_the_set() function it_should_know_if_it_has_links() { - $link = new Link(); + $link = new Link('http://example.com', 'item'); + $this->beConstructedWith('http://example.com'); $item = $this->withLink($link); $item->shouldHaveLinks(); @@ -311,14 +323,17 @@ function it_should_know_if_it_has_links() function it_should_know_if_it_has_no_links() { + $this->beConstructedWith('http://example.com'); $this->shouldNotHaveLinks(); } function it_should_return_the_first_data_in_the_set() { - $data1 = Data::fromArray(['value' => 'value1']); - $data2 = Data::fromArray(['value' => 'value2']); - $data3 = Data::fromArray(['value' => 'value3']); + $this->beConstructedWith('http://example.com'); + + $data1 = Data::fromArray(['name' => 'name 1', 'value' => 'value1']); + $data2 = Data::fromArray(['name' => 'name 2', 'value' => 'value2']); + $data3 = Data::fromArray(['name' => 'name 3', 'value' => 'value3']); $item = $this->withDataSet([$data1, $data2, $data3]); @@ -327,9 +342,11 @@ function it_should_return_the_first_data_in_the_set() function it_should_return_the_last_data_in_the_set() { - $data1 = Data::fromArray(['value' => 'value1']); - $data2 = Data::fromArray(['value' => 'value2']); - $data3 = Data::fromArray(['value' => 'value3']); + $this->beConstructedWith('http://example.com'); + + $data1 = Data::fromArray(['name' => 'name 1', 'value' => 'value1']); + $data2 = Data::fromArray(['name' => 'name 2', 'value' => 'value2']); + $data3 = Data::fromArray(['name' => 'name 3', 'value' => 'value3']); $item = $this->withDataSet([$data1, $data2, $data3]); @@ -338,8 +355,9 @@ function it_should_return_the_last_data_in_the_set() function it_should_know_if_it_has_data() { - $data = new Data(); + $data = new Data('Name'); + $this->beConstructedWith('http://example.com'); $item = $this->withData($data); $this->shouldNotHaveData(); $item->shouldHaveData(); @@ -347,6 +365,7 @@ function it_should_know_if_it_has_data() function it_should_know_if_it_has_no_data() { + $this->beConstructedWith('http://example.com'); $this->shouldNotHaveData(); } } diff --git a/spec/CollectionJson/Entity/LinkSpec.php b/spec/CollectionJson/Entity/LinkSpec.php index 24cf854..ed18286 100644 --- a/spec/CollectionJson/Entity/LinkSpec.php +++ b/spec/CollectionJson/Entity/LinkSpec.php @@ -12,6 +12,7 @@ class LinkSpec extends ObjectBehavior { function it_is_initializable() { + $this->beConstructedWith('http://example.com', 'item'); $this->shouldHaveType(Link::class); $this->shouldImplement(ArrayConvertible::class); $this->shouldImplement(\JsonSerializable::class); @@ -20,11 +21,13 @@ function it_is_initializable() function it_s_not_templated() { + $this->beConstructedWith('http://example.com', 'item'); $this->shouldNotBeTemplated(); } function it_should_return_the_object_type() { + $this->beConstructedWith('http://example.com', 'item'); $this::getObjectType()->shouldBeEqualTo('link'); } @@ -58,6 +61,7 @@ function it_is_clonable() function it_should_be_chainable() { + $this->beConstructedWith('http://example.com', 'item'); $this->withHref('http://example.com')->shouldHaveType(Link::class); $this->withRel('value')->shouldHaveType(Link::class); $this->withName('value')->shouldHaveType(Link::class); @@ -84,20 +88,23 @@ function it_may_be_construct_with_an_array_representation_of_the_link() function it_should_convert_the_rel_value_to_a_string() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withRel(true); - $this->getRels()->shouldHaveCount(0); - $link->getRels()->shouldBeEqualTo(['1']); + $this->getRels()->shouldBeEqualTo(['item']); + $link->getRels()->shouldBeEqualTo(['item', '1']); } function it_should_return_a_new_link_with_the_added_relation_type() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withRel('stylesheet'); - $this->getRels()->shouldBeEqualTo([]); - $link->getRels()->shouldBeEqualTo(['stylesheet']); + $this->getRels()->shouldBeEqualTo(['item']); + $link->getRels()->shouldBeEqualTo(['item', 'stylesheet']); } function it_knows_when_it_has_a_relation_type() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withRel('stylesheet'); $link->shouldHaveRel('stylesheet'); $link->shouldNotHaveRel('canonical'); @@ -106,6 +113,7 @@ function it_knows_when_it_has_a_relation_type() function it_should_return_a_new_link_without_the_removed_relation_type() { $this->beConstructedThrough('fromArray', [[ + 'href' => 'http://example.com', 'rel' => 'stylesheet' ]]); @@ -116,12 +124,14 @@ function it_should_return_a_new_link_without_the_removed_relation_type() function it_should_return_a_list_of_relations() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withRel('stylesheet'); - $link->getRels()->shouldBeEqualTo(['stylesheet']); + $link->getRels()->shouldBeEqualTo(['item', 'stylesheet']); } function it_should_set_render_type() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withRender(Render::IMAGE); $this->getRender()->shouldBeEqualTo(Render::LINK); $link->getRender()->shouldBeEqualTo(Render::IMAGE); @@ -129,11 +139,13 @@ function it_should_set_render_type() function it_should_return_the_default_render_value() { + $this->beConstructedWith('http://example.com', 'item'); $this->getRender()->shouldBeEqualTo('link'); } function it_should_throw_an_exception_when_setting_an_incorrect_render_type() { + $this->beConstructedWith('http://example.com', 'item'); $this->shouldThrow(new \DomainException( "Property [render] of entity [link] can only have one of the following values [link,image]" ))->during('withRender', ["Render this"]); @@ -142,45 +154,19 @@ function it_should_throw_an_exception_when_setting_an_incorrect_render_type() function it_should_convert_the_prompt_value_to_a_string() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withPrompt(true); $link->getPrompt()->shouldBeEqualTo('1'); } - function it_should_throw_an_exception_during_array_conversion_when_the_field_href_is_null() - { - $link = $this->withRel('Rel value'); - $link->shouldThrow(new \DomainException('Property [href] of entity [link] is required'))->during('toArray'); - } - - function it_should_throw_an_exception_during_json_conversion_when_the_field_href_is_null() - { - $link = $this->withRel('Rel value'); - $link->shouldThrow( - new \DomainException('Property [href] of entity [link] is required') - )->during('jsonSerialize'); - } - - function it_should_throw_an_exception_during_array_conversion_when_the_field_rel_is_null() - { - $link = $this->withHref('http://example.com'); - $link->shouldThrow(new \DomainException('Property [rel] of entity [link] is required'))->during('toArray'); - } - - function it_should_throw_an_exception_during_json_conversion_when_the_field_rel_is_null() - { - $link = $this->withHref('http://example.com'); - $link->shouldThrow( - new \DomainException('Property [rel] of entity [link] is required') - )->during('jsonSerialize'); - } - function it_should_not_return_null_values() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withRel('Rel value'); $link = $link->withHref('http://example.com'); $link->toArray()->shouldBeEqualTo([ 'href' => 'http://example.com', - 'rel' => 'Rel value', + 'rel' => 'item,Rel value', 'render' => 'link' ]); } diff --git a/spec/CollectionJson/Entity/QuerySpec.php b/spec/CollectionJson/Entity/QuerySpec.php index e1581c0..4731f4a 100644 --- a/spec/CollectionJson/Entity/QuerySpec.php +++ b/spec/CollectionJson/Entity/QuerySpec.php @@ -15,6 +15,7 @@ class QuerySpec extends ObjectBehavior { function it_is_initializable() { + $this->beConstructedWith('http://example.com', 'item'); $this->shouldHaveType(Query::class); $this->shouldImplement(DataAware::class); $this->shouldImplement(ArrayConvertible::class); @@ -23,6 +24,7 @@ function it_is_initializable() function it_should_return_the_object_type() { + $this->beConstructedWith('http://example.com', 'item'); $this::getObjectType()->shouldBeEqualTo('query'); } @@ -73,11 +75,12 @@ function it_is_clonable() function it_should_be_chainable() { + $this->beConstructedWith('http://example.com', 'item'); $this->withHref('http://example.com')->shouldHaveType(Query::class); $this->withRel('value')->shouldHaveType(Query::class); $this->withName('value')->shouldHaveType(Query::class); $this->withPrompt('value')->shouldHaveType(Query::class); - $this->withData([])->shouldHaveType(Query::class); + $this->withData(['name' => 'my name'])->shouldHaveType(Query::class); $this->withDataSet([])->shouldHaveType(Query::class); } @@ -115,6 +118,7 @@ function it_may_be_construct_with_an_array_representation_of_the_query() function it_should_throw_an_exception_when_setting_the_href_field_with_an_invalid_url() { + $this->beConstructedWith('http://example.com', 'item'); $this->shouldThrow( new \DomainException("Property [href] of entity [query] can only have one of the following values [URI]") )->during('withHref', ['uri']); @@ -122,20 +126,23 @@ function it_should_throw_an_exception_when_setting_the_href_field_with_an_invali function it_should_set_the_href_value() { + $this->beConstructedWith('http://example.com', 'item'); $link = $this->withHref("htp://google.com"); - $this->getHref()->shouldBeNull(); + $this->getHref()->shouldBeEqualTo('http://example.com'); $link->getHref()->shouldBeEqualTo("htp://google.com"); } function it_should_convert_the_rel_value_to_a_string() { + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withRel(true); - $this->getRel()->shouldBeNull(); + $this->getRel()->shouldBeEqualTo('item'); $query->getRel()->shouldBeEqualTo('1'); } function it_should_convert_the_name_value_to_a_string() { + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withName(true); $this->getName()->shouldBeNull(); $query->getName()->shouldBeEqualTo('1'); @@ -143,41 +150,15 @@ function it_should_convert_the_name_value_to_a_string() function it_should_convert_the_prompt_value_to_a_string() { + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withPrompt(true); $this->getPrompt()->shouldBeNull(); $query->getPrompt()->shouldBeEqualTo('1'); } - function it_should_throw_an_exception_during_array_conversion_when_the_field_href_is_null() - { - $query = $this->withRel('Rel value'); - $query->shouldThrow(new \DomainException('Property [href] of entity [query] is required'))->during('toArray'); - } - - function it_should_throw_an_exception_during_json_conversion_when_the_field_href_is_null() - { - $query = $this->withRel('Rel value'); - $query->shouldThrow( - new \DomainException('Property [href] of entity [query] is required') - )->during('jsonSerialize'); - } - - function it_should_throw_an_exception_during_array_conversion_when_the_field_rel_is_null() - { - $query = $this->withHref('http://example.com'); - $query->shouldThrow(new \DomainException('Property [rel] of entity [query] is required'))->during('toArray'); - } - - function it_should_throw_an_exception_during_json_conversion_when_the_field_rel_is_null() - { - $query = $this->withHref('http://example.com'); - $query->shouldThrow( - new \DomainException('Property [rel] of entity [query] is required') - )->during('jsonSerialize'); - } - function it_should_not_return_null_values_and_empty_arrays() { + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withRel('Rel value'); $query = $query->withHref('http://example.com'); $query->toArray()->shouldBeEqualTo([ @@ -188,7 +169,9 @@ function it_should_not_return_null_values_and_empty_arrays() function it_should_add_data_when_it_is_passed_as_an_object() { - $data = new Data(); + $data = new Data('Name'); + + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withData($data); $this->getDataSet()->shouldHaveCount(0); $query->getDataSet()->shouldHaveCount(1); @@ -196,8 +179,9 @@ function it_should_add_data_when_it_is_passed_as_an_object() function it_should_remove_data() { - $data = new Data(); + $data = new Data('Name'); + $this->beConstructedWith('http://example.com', 'item'); $template = $this->withData($data); $template->getDataSet()->shouldHaveCount(1); @@ -207,14 +191,16 @@ function it_should_remove_data() function it_should_throw_an_exception_when_data_has_the_wrong_type() { + $this->beConstructedWith('http://example.com', 'item'); $this->shouldThrow( - new \BadMethodCallException('Property [data] must be of type [CollectionJson\Entity\Data]') + new \DomainException('Property [data] must be of type [CollectionJson\Entity\Data]') )->during('withData', [new Template()]); } function it_should_add_data_when_it_is_passed_as_an_array() { - $query = $this->withData(['value' => 'value 1']); + $this->beConstructedWith('http://example.com', 'item'); + $query = $this->withData(['name' => 'name 1', 'value' => 'value 1']); $this->getDataSet()->shouldHaveCount(0); $query->getDataSet()->shouldHaveCount(1); } @@ -222,7 +208,9 @@ function it_should_add_data_when_it_is_passed_as_an_array() function it_should_add_a_data_set() { $data = (new Prophet())->prophesize(Data::class); - $query = $this->withDataSet([$data, ['value' => 'value 2']]); + + $this->beConstructedWith('http://example.com', 'item'); + $query = $this->withDataSet([$data, ['name' => 'name 2', 'value' => 'value 2']]); $this->getDataSet()->shouldHaveCount(0); $query->getDataSet()->shouldHaveCount(2); } @@ -232,17 +220,18 @@ function it_should_return_an_array_with_the_data_list() $data1 = (new Prophet())->prophesize(Data::class); $data2 = (new Prophet())->prophesize(Data::class); - $data1->toArray()->willReturn(['value' => 'value 1']); - $data2->toArray()->willReturn(['value' => 'value 2']); + $data1->toArray()->willReturn(['name' => 'name 1', 'value' => 'value 1']); + $data2->toArray()->willReturn(['name' => 'name 2', 'value' => 'value 2']); + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withData($data1); $query = $query->withData($data2); $query = $query->withRel('Rel value'); $query = $query->withHref('http://example.com'); $query->toArray()->shouldBeEqualTo([ 'data' => [ - ['value' => 'value 1'], - ['value' => 'value 2'], + ['name' => 'name 1', 'value' => 'value 1'], + ['name' => 'name 2', 'value' => 'value 2'], ], 'href' => 'http://example.com', 'rel' => 'Rel value' @@ -258,6 +247,7 @@ function it_should_retrieve_the_data_by_name() $data1->getName()->willReturn('name1'); $data2->getName()->willReturn('name2'); + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withDataSet([$data1, $data2]); $this->getDataByName('name1')->shouldBeNull(); @@ -269,15 +259,17 @@ function it_should_retrieve_the_data_by_name() function it_should_return_null_when_data_is_not_in_the_set() { + $this->beConstructedWith('http://example.com', 'item'); $this->getDataByName('name1')->shouldBeNull(); } function it_should_return_the_first_data_in_the_set() { - $data1 = Data::fromArray(['value' => 'value1']); - $data2 = Data::fromArray(['value' => 'value2']); - $data3 = Data::fromArray(['value' => 'value3']); + $data1 = Data::fromArray(['name' => 'name 1', 'value' => 'value1']); + $data2 = Data::fromArray(['name' => 'name 2', 'value' => 'value2']); + $data3 = Data::fromArray(['name' => 'name 3', 'value' => 'value3']); + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withDataSet([$data1, $data2, $data3]); $query->getFirstData()->shouldBeLike($data1); @@ -285,10 +277,11 @@ function it_should_return_the_first_data_in_the_set() function it_should_return_the_last_data_in_the_set() { - $data1 = Data::fromArray(['value' => 'value1']); - $data2 = Data::fromArray(['value' => 'value2']); - $data3 = Data::fromArray(['value' => 'value3']); + $data1 = Data::fromArray(['name' => 'name 1', 'value' => 'value1']); + $data2 = Data::fromArray(['name' => 'name 2', 'value' => 'value2']); + $data3 = Data::fromArray(['name' => 'name 3', 'value' => 'value3']); + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withDataSet([$data1, $data2, $data3]); $query->getLastData()->shouldBeLike($data3); @@ -296,8 +289,9 @@ function it_should_return_the_last_data_in_the_set() function it_should_know_if_it_has_data() { - $data = new Data(); + $data = new Data('Name'); + $this->beConstructedWith('http://example.com', 'item'); $query = $this->withData($data); $this->shouldNotHaveData(); $query->shouldHaveData(); @@ -305,6 +299,7 @@ function it_should_know_if_it_has_data() function it_should_know_if_it_has_no_data() { + $this->beConstructedWith('http://example.com', 'item'); $this->shouldNotHaveData(); } } diff --git a/spec/CollectionJson/Entity/TemplateSpec.php b/spec/CollectionJson/Entity/TemplateSpec.php index 1d9c6be..a55dd64 100644 --- a/spec/CollectionJson/Entity/TemplateSpec.php +++ b/spec/CollectionJson/Entity/TemplateSpec.php @@ -116,7 +116,7 @@ function it_may_be_construct_from_a_json_representation_of_the_collection() function it_should_be_chainable() { - $this->withData([])->shouldHaveType(Template::class); + $this->withData(['name' => 'my name'])->shouldHaveType(Template::class); $this->withDataSet([])->shouldHaveType(Template::class); } @@ -127,7 +127,7 @@ function it_should_not_return_null_values_and_empty_arrays() function it_should_add_data_when_it_is_passed_as_an_object() { - $data = new Data(); + $data = new Data('Name'); $template = $this->withData($data); $this->getDataSet()->shouldHaveCount(0); @@ -136,7 +136,7 @@ function it_should_add_data_when_it_is_passed_as_an_object() function it_should_remove_data() { - $data = new Data(); + $data = new Data('Name'); $template = $this->withData($data); $template->getDataSet()->shouldHaveCount(1); @@ -148,13 +148,13 @@ function it_should_remove_data() function it_should_throw_an_exception_when_data_has_the_wrong_type() { $this->shouldThrow( - new \BadMethodCallException('Property [data] must be of type [CollectionJson\Entity\Data]') + new \DomainException('Property [data] must be of type [CollectionJson\Entity\Data]') )->during('withData', [new Template()]); } function it_should_add_data_when_it_is_passed_as_an_array() { - $template = $this->withData(['value' => 'value 1']); + $template = $this->withData(['name' => 'name 1', 'value' => 'value 1']); $this->getDataSet()->shouldHaveCount(0); $template->getDataSet()->shouldHaveCount(1); } @@ -163,7 +163,7 @@ function it_should_add_a_data_set() { $data = (new Prophet())->prophesize(Data::class); - $template = $this->withDataSet([$data, ['value' => 'value 2']]); + $template = $this->withDataSet([$data, ['name' => 'name 2', 'value' => 'value 2']]); $this->getDataSet()->shouldHaveCount(0); $template->getDataSet()->shouldHaveCount(2); } @@ -231,9 +231,9 @@ function it_should_return_null_when_data_is_not_in_the_set() function it_should_return_the_first_data_in_the_set() { - $data1 = Data::fromArray(['value' => 'value1']); - $data2 = Data::fromArray(['value' => 'value2']); - $data3 = Data::fromArray(['value' => 'value3']); + $data1 = Data::fromArray(['name' => 'name 1', 'value' => 'value1']); + $data2 = Data::fromArray(['name' => 'name 2', 'value' => 'value2']); + $data3 = Data::fromArray(['name' => 'name 3', 'value' => 'value3']); $template = $this->withDataSet([$data1, $data2, $data3]); @@ -242,9 +242,9 @@ function it_should_return_the_first_data_in_the_set() function it_should_return_the_last_data_in_the_set() { - $data1 = Data::fromArray(['value' => 'value1']); - $data2 = Data::fromArray(['value' => 'value2']); - $data3 = Data::fromArray(['value' => 'value3']); + $data1 = Data::fromArray(['name' => 'name 1', 'value' => 'value1']); + $data2 = Data::fromArray(['name' => 'name 2', 'value' => 'value2']); + $data3 = Data::fromArray(['name' => 'name 3', 'value' => 'value3']); $template = $this->withDataSet([$data1, $data2, $data3]); @@ -253,7 +253,7 @@ function it_should_return_the_last_data_in_the_set() function it_should_know_if_it_has_data() { - $data = new Data(); + $data = new Data('Name'); $template = $this->withData($data); $this->shouldNotHaveData(); diff --git a/spec/CollectionJson/Exception/InvalidParameterSpec.php b/spec/CollectionJson/Exception/InvalidParameterSpec.php index 07c94bb..2430c6d 100644 --- a/spec/CollectionJson/Exception/InvalidParameterSpec.php +++ b/spec/CollectionJson/Exception/InvalidParameterSpec.php @@ -2,6 +2,7 @@ namespace spec\CollectionJson\Exception; +use CollectionJson\Exception\CollectionJsonException; use PhpSpec\ObjectBehavior; use Prophecy\Argument; use CollectionJson\Exception\InvalidParameter; @@ -11,6 +12,7 @@ class InvalidParameterSpec extends ObjectBehavior function it_is_initializable() { $this->shouldHaveType(InvalidParameter::class); + $this->shouldHaveType(CollectionJsonException::class); } function it_should_build_a_domain_exception() diff --git a/spec/CollectionJson/Exception/InvalidTypeSpec.php b/spec/CollectionJson/Exception/InvalidTypeSpec.php index d4824b7..8c9a02e 100644 --- a/spec/CollectionJson/Exception/InvalidTypeSpec.php +++ b/spec/CollectionJson/Exception/InvalidTypeSpec.php @@ -5,17 +5,19 @@ use PhpSpec\ObjectBehavior; use Prophecy\Argument; use CollectionJson\Exception\InvalidType; +use CollectionJson\Exception\CollectionJsonException; class InvalidTypeSpec extends ObjectBehavior { function it_is_initializable() { $this->shouldHaveType(InvalidType::class); + $this->shouldHaveType(CollectionJsonException::class); } function it_should_build_a_domain_exception() { - $this::fromTemplate('property', 'type')->shouldHaveType(\BadMethodCallException::class); + $this::fromTemplate('property', 'type')->shouldHaveType(\DomainException::class); } function it_should_format_the_exception_message() diff --git a/spec/CollectionJson/Exception/MissingPropertySpec.php b/spec/CollectionJson/Exception/MissingPropertySpec.php deleted file mode 100644 index e7de336..0000000 --- a/spec/CollectionJson/Exception/MissingPropertySpec.php +++ /dev/null @@ -1,26 +0,0 @@ -shouldHaveType(MissingProperty::class); - } - - function it_should_build_a_domain_exception() - { - $this::fromTemplate('entity', 'property')->shouldHaveType(\DomainException::class); - } - - function it_should_format_the_exception_message() - { - $exception = $this::fromTemplate('my entity', 'its property'); - $exception->getMessage()->shouldReturn('Property [its property] of entity [my entity] is required'); - } -} diff --git a/src/CollectionJson/BaseEntity.php b/src/CollectionJson/BaseEntity.php index d8fc483..213fa5a 100644 --- a/src/CollectionJson/BaseEntity.php +++ b/src/CollectionJson/BaseEntity.php @@ -13,8 +13,9 @@ namespace CollectionJson; +use CollectionJson\Exception\CollectionJsonException; + use JsonSerializable; -use CollectionJson\Exception\MissingProperty; /** * Class BaseEntity @@ -34,7 +35,11 @@ abstract class BaseEntity implements JsonSerializable, ArrayConvertible */ public static function fromArray(array $data) { - $object = new static(); + [$props, $data] = self::getRequiredParameters($data); + + $object = count($props) > 0 + ? new static(...$props) + : new static(); foreach ($data as $key => $value) { // version is a constant @@ -49,7 +54,7 @@ public static function fromArray(array $data) } elseif (method_exists($object, $wither)) { $object = $object->$wither($value); } else { - throw new \DomainException( + throw new CollectionJsonException( sprintf( 'Invalid schema! Could not inject entry "%s" into entity "%s"', $key, @@ -86,9 +91,40 @@ public static function fromJson($json) } /** - * @return array + * @param array $data * - * @throws MissingProperty + * @return array + */ + private static function getRequiredParameters(array $data): array + { + $method = new \ReflectionMethod(static::class, '__construct'); + $params = $method->getParameters(); + + $required = array_filter($params, function (\ReflectionParameter $param) { + return !$param->isDefaultValueAvailable(); + }); + + $props = []; + foreach ($required as $item) { + $name = $item->getName(); + $prop = $name === 'rels' ? 'rel' : $name; + + if (!array_key_exists($prop, $data)) { + throw new CollectionJsonException( + sprintf('Property "%s" is missing to build "%s', $name, static::class) + ); + } + + $props[] = $data[$prop]; + + unset($data[$prop]); + } + + return [$props, $data]; + } + + /** + * @return array */ public function jsonSerialize(): array { @@ -100,8 +136,6 @@ public function jsonSerialize(): array /** * @return array - * - * @throws MissingProperty */ public function toArray(): array { @@ -171,7 +205,6 @@ final public function __set($name, $value) } /** - * @throws MissingProperty * @return array */ abstract protected function getObjectData(): array; diff --git a/src/CollectionJson/Entity/Collection.php b/src/CollectionJson/Entity/Collection.php index 730aa80..9a3ab7d 100644 --- a/src/CollectionJson/Entity/Collection.php +++ b/src/CollectionJson/Entity/Collection.php @@ -20,6 +20,7 @@ use CollectionJson\Validator\Uri; use CollectionJson\Exception\InvalidType; use CollectionJson\Exception\InvalidParameter; +use CollectionJson\Exception\CollectionJsonException; /** * Class Collection @@ -92,7 +93,7 @@ public function __construct(string $href = null) * * @return Collection * - * @throws \DomainException + * @throws CollectionJsonException */ public function withHref($href): Collection { diff --git a/src/CollectionJson/Entity/Data.php b/src/CollectionJson/Entity/Data.php index 7088184..77f19e1 100644 --- a/src/CollectionJson/Entity/Data.php +++ b/src/CollectionJson/Entity/Data.php @@ -16,7 +16,7 @@ use CollectionJson\BaseEntity; use CollectionJson\Validator\DataValue; use CollectionJson\Exception\InvalidParameter; -use CollectionJson\Exception\MissingProperty; +use CollectionJson\Exception\CollectionJsonException; /** * Class Data @@ -51,7 +51,7 @@ class Data extends BaseEntity * @param string|int|float|bool|null $value * @param string|null $prompt */ - public function __construct(string $name = null, $value = null, string $prompt = null) + public function __construct(string $name, $value = null, string $prompt = null) { if (!is_null($value) && !DataValue::isValid($value)) { throw InvalidParameter::fromTemplate(self::getObjectType(), 'value', DataValue::allowed()); @@ -62,14 +62,12 @@ public function __construct(string $name = null, $value = null, string $prompt = $this->prompt = $prompt; } - // @TODO add a __toString method - /** * @param string $name * * @return Data * - * @throws \DomainException + * @throws CollectionJsonException */ public function withName(string $name): Data { @@ -92,7 +90,7 @@ public function getName() * * @return Data * - * @throws \DomainException + * @throws CollectionJsonException */ public function withPrompt(string $prompt): Data { @@ -115,7 +113,7 @@ public function getPrompt() * * @return Data * - * @throws \DomainException + * @throws CollectionJsonException */ public function withValue($value): Data { @@ -142,10 +140,6 @@ public function getValue() */ protected function getObjectData(): array { - if (is_null($this->name)) { - throw MissingProperty::fromTemplate(self::getObjectType(), 'name'); - } - $data = [ 'name' => $this->name, 'prompt' => $this->prompt, diff --git a/src/CollectionJson/Entity/Error.php b/src/CollectionJson/Entity/Error.php index 7a50b84..0451e27 100644 --- a/src/CollectionJson/Entity/Error.php +++ b/src/CollectionJson/Entity/Error.php @@ -14,6 +14,7 @@ namespace CollectionJson\Entity; use CollectionJson\BaseEntity; +use CollectionJson\Exception\CollectionJsonException; /** * Class Error @@ -60,7 +61,7 @@ public function __construct(string $code = null, string $message = null, string * * @return Error * - * @throws \DomainException + * @throws CollectionJsonException */ public function withCode(string $code): Error { @@ -83,7 +84,7 @@ public function getCode() * * @return Error * - * @throws \DomainException + * @throws CollectionJsonException */ public function withMessage(string $message): Error { @@ -106,7 +107,7 @@ public function getMessage() * * @return Error * - * @throws \DomainException + * @throws CollectionJsonException */ public function withTitle(string $title): Error { diff --git a/src/CollectionJson/Entity/Item.php b/src/CollectionJson/Entity/Item.php index 98b8bae..90b6b88 100644 --- a/src/CollectionJson/Entity/Item.php +++ b/src/CollectionJson/Entity/Item.php @@ -21,7 +21,7 @@ use CollectionJson\DataContainer; use CollectionJson\Validator\Uri; use CollectionJson\Exception\InvalidParameter; -use CollectionJson\Exception\MissingProperty; +use CollectionJson\Exception\CollectionJsonException; /** * Class Item @@ -52,7 +52,7 @@ class Item extends BaseEntity implements LinkAware, DataAware * * @param string|null $href */ - public function __construct(string $href = null) + public function __construct(string $href) { if (is_string($href) && !Uri::isValid($href)) { throw InvalidParameter::fromTemplate(self::getObjectType(), 'href', Uri::allowed()); @@ -68,7 +68,7 @@ public function __construct(string $href = null) * * @return Item * - * @throws \DomainException + * @throws CollectionJsonException */ public function withHref(string $href): Item { @@ -96,10 +96,6 @@ public function getHref() */ protected function getObjectData(): array { - if (is_null($this->href)) { - throw MissingProperty::fromTemplate(self::getObjectType(), 'href'); - } - $data = [ 'data' => $this->getDataSet(), 'href' => $this->href, diff --git a/src/CollectionJson/Entity/Link.php b/src/CollectionJson/Entity/Link.php index e956d5a..2d48346 100644 --- a/src/CollectionJson/Entity/Link.php +++ b/src/CollectionJson/Entity/Link.php @@ -17,10 +17,10 @@ use Psr\Link\EvolvableLinkInterface; use CollectionJson\BaseEntity; -use CollectionJson\Type\Render as RenderType; use CollectionJson\Validator\Render; +use CollectionJson\Type\Render as RenderType; use CollectionJson\Exception\InvalidParameter; -use CollectionJson\Exception\MissingProperty; +use CollectionJson\Exception\CollectionJsonException; /** * Class Link @@ -67,8 +67,12 @@ class Link extends BaseEntity implements LinkInterface, EvolvableLinkInterface * @param string|array|null $rels * @param string|null $name */ - public function __construct(string $href = null, $rels = [], string $name = null) + public function __construct(string $href, $rels, string $name = null) { + if (!is_string($rels) && !is_array($rels)) { + throw new InvalidParameter('rels property must be of type string or array'); + } + if (is_string($rels)) { $rels = [ $rels @@ -153,7 +157,7 @@ public function hasRel($rel): bool * * @return Link * - * @throws \DomainException + * @throws CollectionJsonException */ public function withName(string $name): Link { @@ -176,7 +180,7 @@ public function getName() * * @return Link * - * @throws \DomainException + * @throws CollectionJsonException */ public function withPrompt(string $prompt): Link { @@ -199,7 +203,7 @@ public function getPrompt() * * @return Link * - * @throws \DomainException + * @throws CollectionJsonException */ public function withRender(string $render): Link { @@ -260,14 +264,6 @@ public function isTemplated(): bool */ protected function getObjectData(): array { - if (is_null($this->href)) { - throw MissingProperty::fromTemplate(self::getObjectType(), 'href'); - } - - if (empty($this->rels)) { - throw MissingProperty::fromTemplate(self::getObjectType(), 'rel'); - } - $data = [ 'href' => $this->href, 'name' => $this->name, diff --git a/src/CollectionJson/Entity/Query.php b/src/CollectionJson/Entity/Query.php index 5f872d9..e6ab28f 100644 --- a/src/CollectionJson/Entity/Query.php +++ b/src/CollectionJson/Entity/Query.php @@ -19,7 +19,7 @@ use CollectionJson\Validator\Uri; use CollectionJson\DataContainer; use CollectionJson\Exception\InvalidParameter; -use CollectionJson\Exception\MissingProperty; +use CollectionJson\Exception\CollectionJsonException; /** * Class Query @@ -66,7 +66,7 @@ class Query extends BaseEntity implements DataAware * @param string|null $name * @param string|null $prompt */ - public function __construct(string $href = null, string $rel = null, string $name = null, string $prompt = null) + public function __construct(string $href, string $rel, string $name = null, string $prompt = null) { if (is_string($href) && !Uri::isValid($href)) { throw InvalidParameter::fromTemplate(self::getObjectType(), 'href', Uri::allowed()); @@ -111,7 +111,7 @@ public function getHref() * * @return Query * - * @throws \DomainException + * @throws CollectionJsonException */ public function withName(string $name): Query { @@ -134,7 +134,7 @@ public function getName() * * @return Query * - * @throws \DomainException + * @throws CollectionJsonException */ public function withPrompt(string $prompt): Query { @@ -157,7 +157,7 @@ public function getPrompt() * * @return Query * - * @throws \DomainException + * @throws CollectionJsonException */ public function withRel(string $rel): Query { @@ -180,12 +180,6 @@ public function getRel() */ protected function getObjectData(): array { - foreach (['href', 'rel'] as $property) { - if (is_null($this->$property)) { - throw MissingProperty::fromTemplate(self::getObjectType(), $property); - } - } - $data = [ 'data' => $this->getDataSet(), 'href' => $this->href, diff --git a/src/CollectionJson/Exception/CollectionJsonException.php b/src/CollectionJson/Exception/CollectionJsonException.php new file mode 100644 index 0000000..902727a --- /dev/null +++ b/src/CollectionJson/Exception/CollectionJsonException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CollectionJson\Exception; + +/** + * Class CollectionJsonException + * @package CollectionJson\Exception + */ +class CollectionJsonException extends \DomainException +{ +} diff --git a/src/CollectionJson/Exception/InvalidParameter.php b/src/CollectionJson/Exception/InvalidParameter.php index f1df83f..5526392 100644 --- a/src/CollectionJson/Exception/InvalidParameter.php +++ b/src/CollectionJson/Exception/InvalidParameter.php @@ -17,7 +17,7 @@ * Class WrongParameter * @package CollectionJson\Exception */ -final class InvalidParameter extends \DomainException +final class InvalidParameter extends CollectionJsonException { const TEMPLATE = 'Property [%s] of entity [%s] can only have one of the following values [%s]'; diff --git a/src/CollectionJson/Exception/InvalidType.php b/src/CollectionJson/Exception/InvalidType.php index d9501f2..8e105a8 100644 --- a/src/CollectionJson/Exception/InvalidType.php +++ b/src/CollectionJson/Exception/InvalidType.php @@ -17,7 +17,7 @@ * Class WrongType * @package CollectionJson\Exception */ -final class InvalidType extends \BadMethodCallException +final class InvalidType extends CollectionJsonException { const TEMPLATE = 'Property [%s] must be of type [%s]'; diff --git a/src/CollectionJson/Exception/MissingProperty.php b/src/CollectionJson/Exception/MissingProperty.php deleted file mode 100644 index fd141ec..0000000 --- a/src/CollectionJson/Exception/MissingProperty.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace CollectionJson\Exception; - -/** - * Class MissingProperty - * @package CollectionJson\Exception - */ -final class MissingProperty extends \DomainException -{ - const TEMPLATE = 'Property [%s] of entity [%s] is required'; - - /** - * @param string $entity - * @param string $property - * - * @return MissingProperty - */ - public static function fromTemplate(string $entity, string $property): MissingProperty - { - $message = sprintf(self::TEMPLATE, $property, $entity); - return new self($message); - } -} From 2985c20417e572dbafbae7b8bb61713acc65a8f4 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 19:52:31 +0100 Subject: [PATCH 16/19] Fix PHP7 backward compatibility issue --- src/CollectionJson/BaseEntity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CollectionJson/BaseEntity.php b/src/CollectionJson/BaseEntity.php index 213fa5a..ae0637e 100644 --- a/src/CollectionJson/BaseEntity.php +++ b/src/CollectionJson/BaseEntity.php @@ -35,7 +35,7 @@ abstract class BaseEntity implements JsonSerializable, ArrayConvertible */ public static function fromArray(array $data) { - [$props, $data] = self::getRequiredParameters($data); + list($props, $data) = self::getRequiredParameters($data); $object = count($props) > 0 ? new static(...$props) From 32e4ced149916e52ee8300d3a252c521d214c953 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 19:57:26 +0100 Subject: [PATCH 17/19] Fix examples --- examples/create-data.php | 3 +-- examples/create-item.php | 3 +-- examples/create-link.php | 4 +--- examples/create-query.php | 4 +--- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/examples/create-data.php b/examples/create-data.php index 0d7f0b3..cfd961a 100644 --- a/examples/create-data.php +++ b/examples/create-data.php @@ -5,8 +5,7 @@ use CollectionJson\Entity\Data; -$data = (new Data()) - ->withName('data name') +$data = (new Data('data name')) ->withPrompt('data prompt') ->withValue('data value'); diff --git a/examples/create-item.php b/examples/create-item.php index e4aba9d..d0c8595 100644 --- a/examples/create-item.php +++ b/examples/create-item.php @@ -8,8 +8,7 @@ use CollectionJson\Entity\Link; use CollectionJson\Type\Relation; -$item = (new Item()) - ->withHref('https://example.co/item/1') +$item = (new Item('https://example.co/item/1')) ->withDataSet([ new Data('data 1'), new Data('data 2', 'value 2') diff --git a/examples/create-link.php b/examples/create-link.php index 27ba4b5..bd615d1 100644 --- a/examples/create-link.php +++ b/examples/create-link.php @@ -6,11 +6,9 @@ use CollectionJson\Entity\Link; use CollectionJson\Type; -$link = (new Link()) +$link = (new Link('https://example.co', Type\Relation::ITEM)) ->withName('link name') - ->withHref('https://example.co') ->withPrompt('prompt value') - ->withRel(Type\Relation::ITEM) ->withRender(Type\Render::IMAGE); // default Render::LINK echo json_encode($link, JSON_PRETTY_PRINT); diff --git a/examples/create-query.php b/examples/create-query.php index 7ec7d75..7f8765b 100644 --- a/examples/create-query.php +++ b/examples/create-query.php @@ -7,9 +7,7 @@ use CollectionJson\Entity\Data; use CollectionJson\Type\Relation; -$query = (new Query()) - ->withHref('https://example.co') - ->withRel(Relation::SEARCH) +$query = (new Query('https://example.co', Relation::SEARCH)) ->withName('value') ->withPrompt('value') ->withData(new Data('data 1', true)) From 3fed77fe5895a1de15096b3c7cc270adea699393 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 20:03:09 +0100 Subject: [PATCH 18/19] Update README --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 316247a..e99e94a 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,7 @@ The MIT License (MIT). Please see [License File](https://github.com/mickaelvieir ```php $collection = (new Collection()) - ->withItem((new Item()) - ->withHref('https://example.co/item/1') + ->withItem((new Item('https://example.co/item/1')) ->withDataSet([ new Data('data 1'), new Data('data 2', 'value 2') @@ -101,8 +100,7 @@ $data = Data::fromArray([ ...or by using the accessors (Note that entities are immutable) ```php -$data = (new Data()) - ->withName('email') +$data = (new Data('email')) ->withValue('hello@example.co'); ``` @@ -238,7 +236,7 @@ They allows you to add the corresponding entities to objects that implement them ```php // this... -$item = (new Item()) +$item = (new Item('https://example.co/item/1')) ->withData([ 'name' => 'email', 'value' => 'email value' @@ -250,11 +248,11 @@ $data = Data::fromArray([ 'value' => 'email value' ]); -$item = (new Item()) +$item = (new Item('https://example.co/item/1')) ->withData($data); // and that... -$item = (new Item()) +$item = (new Item('https://example.co/item/1')) ->withDataSet([ new Data('email', 'hello@example.co'), new Data('tel', '0000000000') @@ -269,7 +267,7 @@ $data2 = Data::fromArray([ 'name' => 'tel', 'value' => '0000000000' ]); -$item = (new Item()) +$item = (new Item('https://example.co/item/1')) ->withDataSet([ $data1, $data2 From c3187282f3e90fb185237468c2f1af0085ce88b1 Mon Sep 17 00:00:00 2001 From: Mickael Vieira Date: Tue, 17 Oct 2017 20:14:07 +0100 Subject: [PATCH 19/19] Rename an exception --- src/CollectionJson/BaseEntity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CollectionJson/BaseEntity.php b/src/CollectionJson/BaseEntity.php index ae0637e..9e18e95 100644 --- a/src/CollectionJson/BaseEntity.php +++ b/src/CollectionJson/BaseEntity.php @@ -79,7 +79,7 @@ public static function fromJson($json) $type = static::getObjectType(); if (!$data || json_last_error() !== JSON_ERROR_NONE) { - throw new \LogicException(sprintf('Invalid JSON: %s', json_last_error_msg())); + throw new CollectionJsonException(sprintf('Invalid JSON: %s', json_last_error_msg())); } // unwrapping