Инъекция прыщей и динамических конструкторов
У меня вопрос по поводу 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
объект, а также свойства из загруженного временного изображения, чтобы сохранить новую безопасную версию загруженного изображения. ImageUploader
интерфейсы с JPEGImageSaver
безопасно хранить загруженное изображение.
Проблема в том, что у меня есть три тесно связанных класса с контроллером, и я попытался избежать этого, используя 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
объект.
Есть ли общее решение этой проблемы? Я думал об обертывании Pimple в разрешающий контейнер, который позволяет передавать аргументы конструктора, но проблема в том, что моя среда IDE не будет указывать, как различные объекты должны создаваться с помощью intellisensing. Я также немного сомневаюсь, насколько более тестируемым $this->app['something']
даже сделал мой контроллер.
Контроллеры вообще должны быть тестируемыми? Если да, могу ли я рассмотреть Image
объект быть объектом значения?
Какие-нибудь мысли?
1 ответ
Прыщ - это контейнер для хранения ценностей или услуг. Приложение запрашивает 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');
}
}