疙瘩和动态构造函数注入

时间:2013-12-01 07:23:55

标签: php dependency-injection pimple

我有关于Pimple和动态构造函数注入的问题。

假设我有一个MVC框架,我想做一些像图像上传的事情。半DI方式就是这样:

class ImageUploadController
{
    public function upload()
    {
         $targetImage = new Image(1920, 1080, 75, 'jpg', 'save/path');
         $imageSaver = new JPEGImageSaver($targetImage);
         $imageUploader = new ImageUploader($imageSaver);
         $imageUploader->upload('myUploadfield');
    }
}

基本上Image是我想要创建和保存的图像属性的简单容器。 JPEGImageSaver使用imagecreatefromjpeg()imagecopyresized()imagejpeg()以及Image对象的属性以及上传的临时图像中的属性来保存上传图片的新安全版本。 ImageUploaderJPEGImageSaver接口以安全存储上传的图片。

问题是我有三个与控制器紧密耦合的类,我尝试避免这种情况的方法是使用Pimple,然后将Pimple传递给控制器​​。

class ImageUploadController
{
    public function upload()
    {
         $targetImage = $this->app['Image'];
         $targetImage->setWidth(1920);
         $targetImage->setHeight(1080);
         $targetImage->setQuality(75);
         $targetImage->setExtension('jpg');
         $targetImage->setSavePath('save/path');


         $imageSaver = $this->app['JPEGImageSaver'];
         $imageSaver->setTargetImage($targetImage);

         $imageUploader = $this->app['ImageUploader'];
         $imageUploader->setImageSaver($imageSaver);
         $imageUploader->upload('myUploadField');
    }
}

但正如您所看到的,使用Pimple将依赖项注入我的控制器使得使用它们比以前更加复杂。主要问题是我没有在Pimple中看到在请求期间为对象设置构造函数值的方法,因此需要为Image对象提供一堆setter。

这个问题有一个共同的解决方案吗?我想过将Pimple包装在一个解析容器中,让我传入构造函数参数,但问题是我的IDE不会指示如何通过智能感知来构造各种对象。我也有点怀疑有多少可测试$this->app['something']甚至让我的控制器。

控制器甚至需要可测试吗?如果是这样,我可以将Image对象视为值对象吗?

有什么想法?

1 个答案:

答案 0 :(得分:1)

Pimple是一个存储价值观或服务的容器。应用程序要求Pimple检索诸如会话对象之类的服务。

如果图像类在整个应用程序中使用并具有精确定义,

<?php

$targetImage = new Image(1920, 1080, 75, 'jpg', 'save/path');

然后你可以问Pimple存储这个定义。

<?php
// define image service
$container['image'] = function ($c) {
    return new Image(1920, 1080, 75, 'jpg', 'save/path');
};

如果您的应用程序中有不同的图像大小,则可以执行以下操作:

<?php
// define image service
$container['bigImage'] = function ($c) {
    return new Image(1920, 1080, 75, 'jpg', 'save/path');
};

$container['smallImage'] = function ($c) {
    return new Image(200, 200, 75, 'jpg', 'save/path');
};

您可以更进一步,存储Image类的参数并重新使用它们。

<?php

$container['imageParams'] = [
   'width' => 1920,
   'height' => 1080,
   'type' => 'jpg',
   'quality' => 75
];

// define image service
$container['image'] = function ($c) {
    $image = $c['imageParams'];
    return new Image($image['width'],
                     $image['height'],
                     $image['quality'],
                     $image['type'],
                     'save/path'
    );
};

目前在Pimple中,您无法在检索服务时传递参数:

<?php

$this->app['image'](1920, 1080, 75, 'jpg', 'save/path');

您需要扩展Pimple才能实现此功能。

但是,您可以在控制器类中创建一个工厂方法,该方法将修改存储在Pimple中的图像参数,然后调用图像服务以使用您的特定参数创建图像对象,然后将存储的参数恢复为原始值

<?php

class ImageUploadController {

  protected function imageFactory($width, $height, $type, $quality) {
     // Store original parameters
     $origin = $this->app['imageParams'];

     // Override the original parameters
     $this->app['imageParams']['width'] = $width;
     $this->app['imageParams']['height'] = $height;
     $this->app['imageParams']['quality'] = $quality;
     $this->app['imageParams']['type'] = $type;

     // Get image class
     $image = $this->app['image'];

     // Rest image parameters
     $this->app['imageParams'] = $origin;

     return $image;
  }

  public function upload()
  {
     $targetImage = $this->imageFactory(1920, 1080, 75, 'jpg');

  }
}