Столкнулся со следующими проблемами:
Yii Version: 2.0.48.1
PHP 8.2.8
Есть AR модель Product (для простоты поля guid (первичный ключ), file_guid, lock)
Есть вторая модель File, в которой хранятся данные файла (поля guid (первичный ключ), name...)
Есть собственный behavior для файлов:
Код: Выделить всё
<?php
namespace app\modules\file\behaviors;
use app\modules\file\models\File;
use yii\base\Behavior;
use yii\base\Event;
use yii\db\ActiveRecord;
use yii\db\AfterSaveEvent;
use yii\db\BaseActiveRecord;
use yii\web\UploadedFile;
/**
* Class FileBehavior
* @property ActiveRecord $owner
* @package app\modules\file\behaviors
*/
class FileBehavior extends Behavior
{
/**
* eg:
* [
* 'attribute' => [
* 'formName' => 'Model', // instance by name
* 'formField' => 'field', // instance by name
* 'group' => 'fileGroup',
* ]
* ]
* @var array
*/
public array $fields = [];
public function init(): void
{
parent::init();
$fields = [];
foreach ($this->fields as $attribute => $field) {
$f = array_merge([
'formField' => $attribute,
'group' => '',
], $field);
$fields[$attribute] = $f;
}
$this->fields = $fields;
}
public function events(): array
{
return [
BaseActiveRecord::EVENT_AFTER_INSERT => 'afterSave',
BaseActiveRecord::EVENT_AFTER_UPDATE => 'afterSave',
BaseActiveRecord::EVENT_AFTER_DELETE => 'afterDelete',
];
}
/**
* @param AfterSaveEvent $event
*/
public function afterSave(AfterSaveEvent $event): void
{
foreach ($this->fields as $attribute => $field) {
$file = UploadedFile::getInstanceByName($field['formField']);
if ($file && $file->error === UPLOAD_ERR_OK) {
$file = File::upload($file, '', $field['group'], true);
if ($file) {
if ($this->owner->$attribute) {
$this->owner->$attribute->delete();
}
$this->owner->link($attribute, $file);
}
}
}
}
public function afterDelete(Event $event): void
{
foreach ($this->fields as $attribute => $field) {
if (!empty($event->sender->$attribute)) {
$event->sender->$attribute->delete();
}
}
}
}
Код: Выделить всё
Product extends \yii\db\ActiveRecord{
public function behaviors(): array
{
return [
'files' => [
'class' => FileBehavior::class,
'fields' => [
'file' => [
'formField' => 'Product[fileImage]',
]
]
]
];
}
public function getImage(): ActiveQuery
{
return $this->hasOne(File::class, ['guid' => 'file_guid']);
}
}
Проблема №1:
метод link($attribute, $file); вызывает событие EVENT_AFTER_UPDATE, который, соответственно повторно вызывает afterSave у Product.
Хотя в документации прописано:
Картинка с ошибкой, где видно, что вызывается 2 раза:The relationship is established by setting the foreign key value(s) in one model to be the corresponding primary key value(s) in the other model. The model with the foreign key will be saved into database without performing validation and without events/behaviors.
https://von-hamster.ru/uploads/ext/%D0% ... %D0%B8.png
Вопрос в том - это я что-то не так использую, или это бага?
Проблема №2:
Связана с 1 - при использовании link и OptimisticLockBehavior - вторая выдает ошибку:
https://von-hamster.ru/uploads/ext/%D0% ... -10-00.pngThe object being updated is outdated.