Событие replicating
Событие replicating вызывается в момент, когда модель Eloquent
клонируется с помощью метода replicate. Это событие позволяет
модифицировать данные перед созданием копии, например, очищать
определённые поля или устанавливать новые значения. Событие
срабатывает до того, как будет создан новый экземпляр модели.
Оно даёт возможность контролировать процесс копирования и
изменять атрибуты будущей копии.
Синтаксис
<?php
Model::replicating(function($model) {
// Логика перед копированием
});
?>
Событие регистрируется в модели с помощью свойства
$dispatchesEvents или через метод booted.
Коллбэк получает текущий экземпляр модели и может
изменять его атрибуты перед созданием копии.
Пример через свойство $dispatchesEvents
Давайте создадим модель Post и настроим событие
replicating, которое будет очищать поле slug
перед копированием:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Events\ReplicatingPost;
class Post extends Model
{
protected $dispatchesEvents = [
'replicating' => ReplicatingPost::class,
];
}
?>
Теперь создадим обработчик события, который будет
очищать поле slug и устанавливать новый заголовок:
<?php
namespace App\Events;
use App\Models\Post;
class ReplicatingPost
{
public function handle(Post $post)
{
$post->slug = null;
$post->title = $post->title . ' (Copy)';
}
}
?>
Теперь при копировании записи поле slug будет пустым,
а в заголовок добавится суффикс:
<?php
use App\Models\Post;
$post = Post::first();
$copy = $post->replicate();
echo $copy->slug;
echo $copy->title;
?>
Результат выполнения кода:
""
"Original title (Copy)"
Пример через метод booted
Рассмотрим вариант регистрации события через метод
booted внутри модели. Это удобно, когда нужно
написать логику прямо в модели без создания отдельного
класса-обработчика:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected static function booted()
{
static::replicating(function($model) {
$model->sku = null;
$model->stock = 0;
});
}
}
?>
Теперь при копировании товара поля sku и stock
будут сброшены, чтобы новый товар имел уникальный артикул
и нулевой остаток:
<?php
use App\Models\Product;
$product = Product::where('sku', 'ABC-123')->first();
$copy = $product->replicate();
echo $copy->sku;
echo $copy->stock;
echo $copy->name;
?>
Результат выполнения кода:
""
"0"
"Original product name"
Пример с обработкой связей
Событие replicating также позволяет управлять
копированием связанных данных. Давайте настроим модель
Category, которая имеет связь с товарами,
и при копировании категории будем очищать поле
parent_id:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected static function booted()
{
static::replicating(function($category) {
$category->parent_id = null;
$category->slug = $category->slug . '-copy';
});
}
public function products()
{
return $this->hasMany(Product::class);
}
}
?>
Теперь при копировании категории поле parent_id
будет сброшено, а в slug добавится суффикс:
<?php
use App\Models\Category;
$category = Category::where('slug', 'electronics')->first();
$copy = $category->replicate();
echo $copy->parent_id;
echo $copy->slug;
echo $copy->name;
?>
Результат выполнения кода:
""
"electronics-copy"
"Electronics"
Пример с условной логикой
В обработчике события можно использовать условную логику, чтобы по-разному обрабатывать копирование в зависимости от состояния модели. Например, для архивных записей мы можем сбрасывать больше полей:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected static function booted()
{
static::replicating(function($article) {
$article->slug = null;
if ($article->status === 'archived') {
$article->status = 'draft';
$article->views = 0;
}
});
}
}
?>
Теперь при копировании архивной статьи статус будет меняться на черновик, а счётчик просмотров обнуляться:
<?php
use App\Models\Article;
$article = Article::where('status', 'archived')->first();
$copy = $article->replicate();
echo $copy->status;
echo $copy->views;
echo $copy->title;
?>
Результат выполнения кода:
"draft"
"0"
"Archived article title"