-
-
Save basherr/4f5d5fef9213587120a96988162d29bb to your computer and use it in GitHub Desktop.
/// PRODUCT Data type | |
<?php | |
namespace App\DataTypes; | |
/** | |
* class Product | |
* | |
* Represent the Product type for the shopbot | |
* | |
* @package App\DataTypes | |
*/ | |
class Product extends PropertyAccessor | |
{ | |
/** | |
* @var string | |
*/ | |
protected $sku; | |
/** | |
* @var string | |
*/ | |
protected $title; | |
/** | |
* @var string | |
*/ | |
protected $image; | |
/** | |
* @var string | |
*/ | |
protected $link; | |
} | |
/// Default Property Accessor class | |
namespace App\DataTypes; | |
/** | |
* class PropertyAccessor | |
* | |
* Retrieve/changes any property of the class dynmically without the need for | |
* setters & getters | |
* | |
* To set `foo` property for a class, just call `setFoo` method on object instance | |
* where `Foo` first character will be converted to lowercase | |
* | |
* @package App\DataTypes | |
*/ | |
abstract class PropertyAccessor | |
{ | |
/** | |
* Set any property for the class dynamically | |
* | |
* @param string $name | |
* @param mixed $value | |
* @return $this | |
*/ | |
public function __call(string $name, $value) | |
{ | |
if (substr($name, 0, 3) === 'set') { | |
return $this->setProperty($name, $value); | |
} else if (substr($name, 0, 3) === 'get') { | |
return $this->getProperty($name); | |
} | |
} | |
/** | |
* Set any property for the class | |
* | |
* @param string $name | |
* @param mixed $value | |
* @return $this | |
* @throws \App\Exception\InvalidSetterException | |
*/ | |
protected function setProperty(string $name, $value) | |
{ | |
$property = lcfirst(str_replace('set', '', $name)); | |
if (property_exists($this, $property)) { | |
$this->$property = array_shift($value); | |
return $this; | |
} | |
throw new \Exception('Invalid Property Setter'); | |
} | |
/** | |
* Retrieve any property for the class dynamically | |
* | |
* @param string $name | |
* @return mixed | |
* @throws \App\Exception\InvalidGetterException | |
*/ | |
public function getProperty(string $name) | |
{ | |
$property = lcfirst(str_replace('get', '', $key)); | |
if (property_exists($this, $property)) { | |
return $this->$property; | |
} | |
throw new \Exception('Invalid Property Getter'); | |
} | |
} | |
@brentkelly Why Product
should be abstract? How we will instantiate an abstract class Product
? What I believe it should implement a contract to hydrate
or extend
a base abstract class that contains hydrate
method as abstract
.
Because Zest
isn't going to be the only Connector
we have long term. It should be App\ApiModels\AbstractProduct
which defines 90% of the class, but then there needs to be a connector implementation for Zest which tells it how to hydrate from a API result.
So \App\Connectors\Zest\ApiModels\Product
extends App\ApiModels\AbstractProduct
& probably has 1 method:
hydrate($productData)
- this receives a raw API product data & hydrates the properties defined inAbstractProduct
.
Then in future when we want to connect to e.g. Shopify
, we will have a \App\Connectors\Shopify\Product
which will extend AbstractProduct
, and its hydrate
method will take a Shopify product API result & translate it to hydrate the AbstractProduct
properties.
@brentkelly Perfect, thanks.
This is fine in principle:
PropertyAccessor
should be a trait rather than a base class. Something like\App\Traits\CanAccessProperties
.Product
should beabstract
& have anabstract public function hydrate($incoming): self
.ApiModelTestCase
for the ApiModel tests to inherit from and then add a method something like:Now your tests can just say:
Add the following tests for your trait testing too & make them pass: