Код: Выделить всё
[
'class' => ...
'imageAttr' => 'avatar', // аттрибут ар в котором будет лежать FileUploaded
'additionalImages' => [ //дополнительные изображение
'small' => ['resize' => [300,400]], //дополнительное изображение 1, постфикс small, применяем модификатор Resize 300x400
'medium-rotate' => ['resize' => [500,700], 'rotate' => [40]], //по аналогии выше
],
'postfix' => 'avatar', //постфикс для оригинального изображения
'saveDirectory' => static::IMG_DIR, //папка для сохрания
],
Код: Выделить всё
public function beforeUpdate($event)
{
if ($this->owner->validate()) {
$this->initBehavior();
$this->imageList->save($this->saveDirectory);
}
}
public function initBehavior(){
if ($this->owner->{$this->imageAttr} instanceof \yii\web\UploadedFile) {
$this->uploadImage = $this->owner->{$this->imageAttr};
} else {
throw new Exception('file object must be instance of UploadFile');
}
$fileName = $this->uploadImage->tempName;
$imageFactory = new helpers\ImageFactory(); //фабрика изображений
$this->imageList = new helpers\ImageList(); //контейнер изображений
$this->imageList->add(
$imageFactory->getImage($fileName, $this->postfix, []) // добавляем в контейнер оригинальное изображение
);
foreach ($this->additionalImages as $imagePostfix=>$imageOptions){
$this->imageList->add(
$imageFactory->getImage($fileName, $imagePostfix, $imageOptions) //добавляем в контейнер модифицированные изображения
);
}
}
Код: Выделить всё
class ImageFactory
{
/**
* @param $fileName
* @param $postfix
* @return ImageInterface
*/
private function getOriginalImage($fileName, $postfix)
{
return new ImageFile($fileName, $postfix);
}
/**
* @param string $prefix decorator class prefix
* @param ImageInterface $object
* @param array $params
* @return ImageInterface
* @throws \yii\base\InvalidConfigException
*/
private function addDecorator($prefix, $object, $params)
{
$className = $this->decorators[ucfirst($prefix)] ;
return \Yii::createObject($className, [$object, $params]);
}
/**
* @param string $fileName full path to file
* @param string $postfix
* @param array $imageOptions
* @return ImageInterface
*/
public function getImage($fileName, $postfix, array $imageOptions)
{
$image = $this->getOriginalImage($fileName, $postfix);
foreach ($imageOptions as $option => $value) {
$image = $this->addDecorator($option, $image, $value);
}
return $image;
}
public function __construct()
{
$this->decorators = [
'Resize' => decorators\ResizeDecorator::className(),
'Rotate' => decorators\RotateDecorator::className()
];
}
private $decorators;
}
Код: Выделить всё
class ImageFile implements ImageInterface{
/**
* @property mixed $image
* @property string $postfix
*/
private $image;
private $postfix;
public function __construct($filePath, $postfix){
$driver = new ImageDriver;
$driver->driver = 'GD';
$this->image = $driver->load($filePath);
$this->postfix = $postfix;
}
/**
* @inheritdoc
*/
public function save($path)
{
$fileName = $path . ??? . $this->postfix;
$this->image->save($fileName, $quality = 90);
}
/**
* @return mixed
*/
public function getSource(){
return $this->image;
}
}
Код: Выделить всё
class RotateDecorator extends Object implements ImageInterface
{
/**
* @property ImageInterface
*/
private $imageFile;
/**
* @property int $degrees
*/
private $degrees;
/**
* @param ImageInterface $imageFile
* @param integer[] $config
*/
public function __construct(ImageInterface $imageFile, array $config)
{
$this->imageFile = $imageFile;
$this->degrees = $config[0];
}
/**
* @inheritdoc
*/
public function save($path)
{
$this->imageFile->getSource()->rotate($this->degrees);
$this->imageFile->save($path);
}
/**
* @return mixed
*/
public function getSource()
{
return $this->imageFile->getSource();
}
}
1) Должен ли behavior предоставлять get методы для каждой из сохраненных картинок, единственный вариант реализации __get ?
2) в какой момент лучше сохранять изображения beforeU, AfterU имеет ли вообще смысл проверка if ($this->owner->validate()) в событии beforeUpdate или это событие генерятся когда валидация уже прошла?
2) Как удобнее всего генерировать имя картинки? Использовать time-stamp или id записи или..?
3) Попробовал использовать timestamp, очевидно получилось что у каждого сохраненного изображения полностью оригинальное название и понять что является модифицированной копией какого не возможно. Если использовать id то придется параметризировать save дополнительным параметром и тащить этот параметр через все декораторы. Возможно стоит добавить объект который бы решал вопрос генерации имен, но как он должен выглядеть и куда инкапсулироваться?
Буду рад помощи, если у кого то найдется время все это читать