diff --git a/.idea/php.xml b/.idea/php.xml index 31b8a3a..97a38d7 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/prop-relations/Brand.php b/prop-relations/Brand.php new file mode 100644 index 0000000..7a3b030 --- /dev/null +++ b/prop-relations/Brand.php @@ -0,0 +1,10 @@ + + */ +class Collection implements Iterator +{ + private int $position = 0; + private ?array $array; + + public function __construct ( + /** @var T[] */ + ?array $items = null, + ) { + $this->array = $items; + } + + public function rewind (): void + { + $this->isInitializedOrFail(); + $this->position = 0; + } + + public function current () + { + $this->isInitializedOrFail(); + return $this->array[$this->position]; + } + + public function key () + { + $this->isInitializedOrFail(); + return $this->position; + } + + public function next (): void + { + $this->isInitializedOrFail(); + ++$this->position; + } + + public function valid (): bool + { + $this->isInitializedOrFail(); + return isset($this->array[$this->position]); + } + + /** + * @return T[] + */ + public function getItems (): array + { + $this->isInitializedOrFail(); + return $this->array; + } + + protected function isInitializedOrFail (): void + { + if ($this->array === null) { + throw new CollectionNotInitializedException(); + } + } +} diff --git a/prop-relations/CollectionNotInitializedException.php b/prop-relations/CollectionNotInitializedException.php new file mode 100644 index 0000000..7d9b682 --- /dev/null +++ b/prop-relations/CollectionNotInitializedException.php @@ -0,0 +1,6 @@ + */ + public readonly Collection $categories, + // Option: add ID + public readonly ?int $brandId = null, + // Option: add Model + public readonly ?Brand $brand = null, + // Option: schrodinger cat + public readonly ?Relation $brand_ = null, + ) + { + } +} diff --git a/prop-relations/Relation.php b/prop-relations/Relation.php new file mode 100644 index 0000000..bbbd5de --- /dev/null +++ b/prop-relations/Relation.php @@ -0,0 +1,29 @@ + + */ +class Relation +{ + public function __construct ( + /** @var T */ + protected readonly ?object $value = null, + ) { + } + + /** + * @return T + */ + public function getValue (): object + { + $this->isInitializedOrFail(); + return $this->value; + } + + protected function isInitializedOrFail (): void + { + if ($this->value === null) { + throw new CollectionNotInitializedException(); + } + } +} diff --git a/prop-relations/index.php b/prop-relations/index.php new file mode 100644 index 0000000..e2b7761 --- /dev/null +++ b/prop-relations/index.php @@ -0,0 +1,68 @@ +categories->getItems(); + +// GetProductQuery +$productWithoutCategories = new Product( + 1, + 'product a', + new Collection(), +); + +// Throw Exception +$productCategories = $productWithoutCategories->categories->getItems(); + +// ------------------------------------------------------- + +// how to differentiate if Brand was filled or is null + +// Oriol suggestion +$productWithBrand = new Product( + id: 2, + name: 'product b', + categories: new Collection(), + brandId: 1, + brand: null, //new Brand(1, 'brand a'), +); + +// Miguel Angel suggestion +$productWithoutBrand = new Product( + id: 2, + name: 'product b', + categories: new Collection(), + brand: null, //new Brand(1, 'brand a'), +); + +// Àlex Suggestion +// GetProductWithBrandQuery +$productWithOptionalBrand = new Product( + id: 2, + name: 'product b', + categories: new Collection(), + brand_: new Relation(new Brand(1, 'brand a')), +); + +// Works +$productBrand = $productWithOptionalBrand->brand_->getValue(); + +// GetProductQuery +$productWithoutOptionalBrand = new Product( + id: 2, + name: 'product b', + categories: new Collection(), + brand_: new Relation(), +); + +// Throw Exception +$productBrand = $productWithoutOptionalBrand->brand_->getValue();