简体   繁体   中英

Pimple and dynamic constructor injection

I have a question regarding Pimple and dynamic constructor injection.

Say I have an MVC framework and I want to do something like image uploading. The semi-DI way of doing it would be like this:

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');
    }
}

Basically Image is a simple container for the properties of the image I want to create and save. JPEGImageSaver makes use of imagecreatefromjpeg() , imagecopyresized() , and imagejpeg() and the properties of the Image object as well as the properties from the uploaded temp image to save a new safe version of the uploaded image. ImageUploader interfaces with the JPEGImageSaver to safely store the uploaded image.

The problem is I have three tightly coupled classes with the controller, and the way I've attempted to avoid that is by using Pimple, and then passing Pimple into the controller.

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');
    }
}

But as you can see, using Pimple to inject dependencies into my controller has made using them MORE complicated than before. The main issue is that I don't see a way in Pimple to set constructor values for objects during request, thus needing a bunch of setters for the Image object.

Is there a common solution to this problem? I've thought about wrapping Pimple in a resolving container that lets me pass in constructor arguments, but the problem with that is my IDE won't indicate how the various objects should be constructed through intellisensing. I'm also a bit dubious about how much more testable $this->app['something'] has even made my controller.

Do controllers even need to be testable? If so, can I consider the Image object to be a value object?

Any thoughts?

Pimple is a container to store values or services. The application asks Pimple to retrieve a service such as session object.

If the image class is used throughout your application with exact definition,

<?php

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

then you can ask Pimple to store this definition.

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

If you have different image sizes in your application, you can do something like:

<?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');
};

You can go even further and store the parameters of Image class and re-use them.

<?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'
    );
};

Currently in Pimple you can't pass parameters while retrieving a service:

<?php

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

You will need to extend Pimple to implement this feature.

However, you can create a factory method in your controller class that will modify the image parameters stored in Pimple, then call the image service to create the image object with your specific parameters, and then revert the stored parameters to the original values.

<?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');

  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM