最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to handle the design pattern of nested arrays of DTO's in Yii2barebones PHP? - Stack Overflow

programmeradmin3浏览0评论

I'm trying to use DTOs for my first time.

I am using Yii2 and PHP 7.1 .

For simplicity my use case can be seen as the following DTOs:

use yii\base\Model;
class OrderDto extends Model
{
    /** @var OrderedProductDto[] $orderedProducts */
    protected $orderedProducts;

    /** @var integer $orderTaxAmount */
    protected $orderTaxAmount;

    /** @var integer $orderTotalAmount */
    protected $orderTotalAmount;

    public function rules()
    {
        //my validation rules go here
    }
}

class OrderedProductDto extends Model
{
    /** @var integer $quantity */
    protected $quantity;

    /** @var integer $orderedProductName */
    protected $orderedProductName ;

    public function rules()
    {
        //my validation rules go here
    }
}

Now, in my hydrator which converts from an internal Order object into an OrderDto, I would ideally like to do something like:

class ExternalOrderHydrator
{
   public static function getOrderDtoFromOrder(Order $order)
   {
     /** do stuff to get an $array from $order which looks like
      * ['orderTaxAmount' => 5, 'orderTotalAmount' => 100, 
      *  'orderedProducts' => [
      *             ['quantity' => 5, 'orderedProductName' => 'Product 1'],
      * ],]
      * and then do:
      */
      $orderDto = new OrderDto();
      if (!($orderDto->load($array) and $orderDto->validate())) {
        throw new Exception('Something is wrong with provided data.');
      }
      return $orderDto;
   }
}

The problem with this approach is that I cannot simply pass an array with nested subarrays to $orderDto->load(), because the orderedProducts field will expect an array of OrderedProductDto. But it feels counterproductive to construct such an array manually before passing it to the DTO.

So what I'm asking is, is there a way to just pass an array with simple data in nested subarrays to the highest-level DTO, then let all the lower-level DTOs which appear inside the highest level one do the conversion from array to DTO automatically?

Please bear in mind that I am using Yii2 and PHP 7.1

I'm trying to use DTOs for my first time.

I am using Yii2 and PHP 7.1 .

For simplicity my use case can be seen as the following DTOs:

use yii\base\Model;
class OrderDto extends Model
{
    /** @var OrderedProductDto[] $orderedProducts */
    protected $orderedProducts;

    /** @var integer $orderTaxAmount */
    protected $orderTaxAmount;

    /** @var integer $orderTotalAmount */
    protected $orderTotalAmount;

    public function rules()
    {
        //my validation rules go here
    }
}

class OrderedProductDto extends Model
{
    /** @var integer $quantity */
    protected $quantity;

    /** @var integer $orderedProductName */
    protected $orderedProductName ;

    public function rules()
    {
        //my validation rules go here
    }
}

Now, in my hydrator which converts from an internal Order object into an OrderDto, I would ideally like to do something like:

class ExternalOrderHydrator
{
   public static function getOrderDtoFromOrder(Order $order)
   {
     /** do stuff to get an $array from $order which looks like
      * ['orderTaxAmount' => 5, 'orderTotalAmount' => 100, 
      *  'orderedProducts' => [
      *             ['quantity' => 5, 'orderedProductName' => 'Product 1'],
      * ],]
      * and then do:
      */
      $orderDto = new OrderDto();
      if (!($orderDto->load($array) and $orderDto->validate())) {
        throw new Exception('Something is wrong with provided data.');
      }
      return $orderDto;
   }
}

The problem with this approach is that I cannot simply pass an array with nested subarrays to $orderDto->load(), because the orderedProducts field will expect an array of OrderedProductDto. But it feels counterproductive to construct such an array manually before passing it to the DTO.

So what I'm asking is, is there a way to just pass an array with simple data in nested subarrays to the highest-level DTO, then let all the lower-level DTOs which appear inside the highest level one do the conversion from array to DTO automatically?

Please bear in mind that I am using Yii2 and PHP 7.1

Share Improve this question asked Feb 16 at 19:07 rosecabbagedragonrosecabbagedragon 1706 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

There is no readily available method to automatically convert data passed to load() method. Your options are:

  1. Convert the data in array before you pass them to load() method.
  2. Override load() method in your top level DTO to do the conversion before passing the data to parent::load() call.
  3. Force the access to your OrderDto::$orderedProducts to go through getter/setter and do the conversion in the setter.

Overriding load() method might look like this:

class OrderDto extends Model
{
    public function load($data, $formName = null)
    {
        $scope = $formName === null ? $this->formName() : $formName;
        if ($scope === '' && !empty($data)) {
            $data = $this->transformData($data);
        } elseif (isset($data[$scope])) {
            $data[$scope] = $this-transformData($data[$scope]);
        }
        return parent::load($data, $formName);
    }

    private function transformData($data)
    {
        // ... logic to transform array data to lower level DTOs
    }
    
    //... other OrderDto stuff
}

Forcing access through getters/setters might look like this:

class OrderDto extends Model
{
    private $_orderedProduct;

    public function getOrderedProduct()
    {
        return $this->_orderedProduct;
    }

    public function setOrderedProduct($data)
    {
        // ... logic to convert array data to lower level DTOs
        $this->_orderedProduct = $data;
    }
    
    // ... other OrderDto stuff
}

Making sure that setOrderedProduct() method exists but $orderedProduct property doesn't exist will make sure that setAttribute() method called inside Model::load() will use setter instead of directly assigning value to property.

发布评论

评论列表(0)

  1. 暂无评论