1
\$\begingroup\$

Let's assume I have 2 objects Product and Volume. 1 Product must have at least 1 Volume which means: Product ----> 1...* Volume.

I want to keep the consistence of Product at its creation, in other words, I want to block the user to create products without any volumes.

I have a ready working code, but nonetheless I want to know your opinions guys.

Here is the running code: https://3v4l.org/t7JqO#v700

Here is my code:

<?php
declare(strict_types = 1);
namespace App
{
 class Product
 {
 private $id;
 private $name;
 private $volumes;
 /**
 * Product constructor.
 * @param int $id
 * @param string $name
 * @param array $volumes
 * @throws \InvalidArgumentException
 */
 public function __construct(int $id, string $name, array $volumes)
 {
 $this->id = $id;
 $this->name = $name;
 if (count($volumes) === 0) {
 throw new \InvalidArgumentException('Your product must have 1 product at least.');
 }
 $this->volumes = $this->prepareVolumes($volumes);
 }
 private function prepareVolumes(array $volumes)
 {
 foreach ($volumes as $volume) {
 $volume->setProduct($this);
 }
 return $volumes;
 }
 }
 class Volume
 {
 protected $id;
 protected $product;
 protected $description;
 public function __construct(string $description)
 {
 $this->description = $description;
 }
 public function setProduct(Product $product)
 {
 $this->product = $product;
 }
 }
 class ProductTest
 {
 public function __construct()
 {
 $volume1 = new Volume('part-1');
 $volume2 = new Volume('part-2');
 $volume3 = new Volume('part-3');
 $product = new Product(1, 'BED', [$volume1, $volume2, $volume3]);
 $invalidProduct = new Product(2, 'Table', []);
 }
 }
 return new ProductTest();
}
asked Jan 28, 2016 at 22:09
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

At first:

Note: Strict typing is only defined for scalar type declarations, and as such, requires PHP 7.0.0 or later, as scalar type declarations were added in that version.

Secondly:
You are passing in an array of volumes $volumes to the __construct function when instantiating an object of class Product. But there is no confidence that each element of $volumes is an object of Volume class. Someone could put into $volumes array an arbitrary value.
I would recommend applying dependency with Volume class and pass in Product constructor only one object of Volume class (following the initial rule: "Product must have at least 1 Volume"). And then, if necessary, you will be able to add some additional 'volumes' to product object using an auxiliary method addVolume().
See the optimized version:

<?php
declare(strict_types = 1);
namespace App
{
 class Product
 {
 private $id;
 private $name;
 private $volumes = [];
 /**
 * Product constructor.
 * @param int $id
 * @param string $name
 * @param array $volumes
 */
 public function __construct(int $id, string $name, Volume $volume)
 {
 $this->id = $id;
 $this->name = $name;
 $volume->setProduct($this); 
 $this->volumes[] = $volume;
 }
 public function addVolume(Volume $volume)
 { 
 $volume->setProduct($this); 
 $this->volumes[] = $volume;
 }
 }
 class Volume
 {
 protected $id;
 protected $product;
 protected $description;
 public function __construct(string $description)
 {
 $this->description = $description;
 }
 public function setProduct(Product $product)
 {
 $this->product = $product;
 }
 }
 class ProductTest
 {
 public function __construct()
 {
 $volume1 = new Volume('part-1');
 $volume2 = new Volume('part-2');
 $volume3 = new Volume('part-3');
 $product = new Product(1, 'BED', $volume1);
 $product->addVolume($volume2);
 $product->addVolume($volume3);
 $invalidProduct = new Product(2, 'Table', []);
 }
 }
 return new ProductTest();
}
answered Jan 29, 2016 at 9:03
\$\endgroup\$
1
  • \$\begingroup\$ Great solution @romanperekhrest. I had already got the point about confidence tip and in my production code I'm using an collection instead of array. Thank you. I owe you a beer. \$\endgroup\$ Commented Jan 29, 2016 at 11:38

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.