Коли я видаляю рядок за допомогою цього синтаксису:
$user->delete();
Чи є спосіб приєднати такий тип зворотного виклику, щоб, наприклад, це зробити автоматично:
$this->photo()->delete();
Переважно всередині модельного класу.
Коли я видаляю рядок за допомогою цього синтаксису:
$user->delete();
Чи є спосіб приєднати такий тип зворотного виклику, щоб, наприклад, це зробити автоматично:
$this->photo()->delete();
Переважно всередині модельного класу.
Відповіді:
Я вважаю, що це ідеальний варіант використання для красномовних подій ( http://laravel.com/docs/eloquent#model-events ). Ви можете скористатися подією "видалення", щоб зробити очищення:
class User extends Eloquent
{
public function photos()
{
return $this->has_many('Photo');
}
// this is a recommended way to declare event handlers
public static function boot() {
parent::boot();
static::deleting(function($user) { // before delete() method call this
$user->photos()->delete();
// do the rest of the cleanup...
});
}
}
Ви, ймовірно, також повинні помістити всю річ всередину транзакції, щоб забезпечити цілісність референції.
foreach($user->photos as $photo)
, $photo->delete()
щоб переконатися, що кожна дитина видалила своїх дітей на всіх рівнях, а не лише одного, як це відбувалося з якихось причин.
Photos
є tags
і ви робите те ж саме в Photos
моделі (тобто за deleting
методом $photo->tags()->delete();
:), він ніколи не отримує тригер. Але якщо я зроблю це for
цикл і роблю щось подібне, for($user->photos as $photo) { $photo->delete(); }
то tags
також видаляю! просто FYI
Ви можете фактично налаштувати це під час міграцій:
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
Джерело: http://laravel.com/docs/5.1/migrations#foreign-key-constraints
Ви також можете вказати бажану дію для властивостей обмеження "при видаленні" та "оновлення":
$table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade');
Примітка . Ця відповідь була написана для Laravel 3 . Таким чином, це може чи не може спрацювати добре в більш новій версії Laravel.
Ви можете видалити всі пов’язані фотографії, перш ніж фактично видалити користувача.
<?php
class User extends Eloquent
{
public function photos()
{
return $this->has_many('Photo');
}
public function delete()
{
// delete all related photos
$this->photos()->delete();
// as suggested by Dirk in comment,
// it's an uglier alternative, but faster
// Photo::where("user_id", $this->id)->delete()
// delete the user
return parent::delete();
}
}
Сподіваюся, це допомагає.
$this->photos()->delete()
. photos()
Повертає об'єкт конструктор запитів.
Відношення в моделі користувача:
public function photos()
{
return $this->hasMany('Photo');
}
Видалити запис і пов’язане з ним:
$user = User::find($id);
// delete related
$user->photos()->delete();
$user->delete();
Існує 3 підходи до вирішення цього питання:
1. Використання красномовних подій у завантаженні моделі (посилання: https://laravel.com/docs/5.7/eloquent#events )
class User extends Eloquent
{
public static function boot() {
parent::boot();
static::deleting(function($user) {
$user->photos()->delete();
});
}
}
2. Використання красномовних спостерігачів подій (посилання: https://laravel.com/docs/5.7/eloquent#observers )
У своєму AppServiceProvider зареєструйте спостерігача так:
public function boot()
{
User::observe(UserObserver::class);
}
Далі додайте клас спостерігача так:
class UserObserver
{
public function deleting(User $user)
{
$user->photos()->delete();
}
}
3. Використання зовнішніх ключових обмежень (див. Https://laravel.com/docs/5.7/migrations#foreign-key-constraints )
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
Станом на Laravel 5.2, у документації зазначено, що такі види обробників подій повинні бути зареєстровані в AppServiceProvider:
<?php
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
User::deleting(function ($user) {
$user->photos()->delete();
});
}
Я навіть припускаю перемістити їх у окремі класи замість закриття для кращої структури додатків.
Eloquent::observe()
метод доступний і в 5.2, і його можна використовувати з AppServiceProvider.
photos()
, вам також потрібно бути обережними - цей процес не видалить онуків, оскільки ви не завантажуєте моделі. Вам потрібно буде переосмислити photos
(зверніть увагу, не photos()
) та запустити delete()
метод на них як моделі, щоб запустити події, пов’язані з видаленням.
Краще, якщо ви перекриєте delete
метод для цього. Таким чином, ви можете включати транзакції з БД у сам delete
метод. Якщо ви використовуєте спосіб події, вам доведеться покривати свій виклик delete
методу транзакцією DB кожного разу, коли ви його викликаєте.
У вашій User
моделі.
public function delete()
{
\DB::beginTransaction();
$this
->photo()
->delete()
;
$result = parent::delete();
\DB::commit();
return $result;
}
У моєму випадку це було досить просто, тому що в моїх базах даних є InnoDB із зовнішніми ключами із Cascade on Delete.
Тож у такому випадку, якщо таблиця ваших фотографій містить користувальницьку довідкову інформацію, ніж все, що вам потрібно зробити, це видалити готель, а очищення буде здійснено за допомогою Бази даних, база даних видалить усі записи фотографій із даних база.
Я хотів би повторити колекцію, де деталізується все, перш ніж видаляти сам об'єкт.
ось приклад:
try {
$user = user::findOrFail($id);
if ($user->has('photos')) {
foreach ($user->photos as $photo) {
$user->photos()->detach($photo);
}
}
$user->delete();
return 'User deleted';
} catch (Exception $e) {
dd($e);
}
Я знаю, що це не автоматично, але це дуже просто.
Іншим простим підходом було б надання моделі методом. Подобається це:
public function detach(){
try {
if ($this->has('photos')) {
foreach ($this->photos as $photo) {
$this->photos()->detach($photo);
}
}
} catch (Exception $e) {
dd($e);
}
}
Тоді ви можете просто зателефонувати цьому, де вам потрібно:
$user->detach();
$user->delete();
Або ви можете зробити це, якщо хочете, просто інший варіант:
try {
DB::connection()->pdo->beginTransaction();
$photos = Photo::where('user_id', '=', $user_id)->delete(); // Delete all photos for user
$user = Geofence::where('id', '=', $user_id)->delete(); // Delete users
DB::connection()->pdo->commit();
}catch(\Laravel\Database\Exception $e) {
DB::connection()->pdo->rollBack();
Log::exception($e);
}
Зверніть увагу, якщо ви не використовуєте підключення db за замовчуванням, тоді вам потрібно зробити наступне:
DB::connection('connection_name')->pdo->beginTransaction();
DB::connection('connection_name')->pdo->commit();
DB::connection('connection_name')->pdo->rollBack();
Щоб уточнити обрану відповідь, якщо у ваших стосунках також є стосунки з дітьми, які потрібно видалити, спочатку потрібно отримати всі записи про стосунки з дітьми, а потім зателефонувати за delete()
методом, щоб і їх події видалення також були належними.
Це можна легко зробити з повідомленнями вищого порядку .
class User extends Eloquent
{
/**
* The "booting" method of the model.
*
* @return void
*/
public static function boot() {
parent::boot();
static::deleting(function($user) {
$user->photos()->get()->each->delete();
});
}
}
Ви також можете покращити ефективність, запитуючи лише стовпчик ідентифікаторів відносин:
class User extends Eloquent
{
/**
* The "booting" method of the model.
*
* @return void
*/
public static function boot() {
parent::boot();
static::deleting(function($user) {
$user->photos()->get(['id'])->each->delete();
});
}
}
так, але, як @supersan зазначив верх у коментарі, якщо ви видалите () на QueryBuilder, подія моделі не буде запущено, оскільки ми не завантажуємо саму модель, а потім викликаємо delete () на цій моделі.
Події запускаються, лише якщо ми використовуємо функцію видалення на екземплярі моделі.
Отже, цей бджіл сказав:
if user->hasMany(post)
and if post->hasMany(tags)
щоб видалити теги допису під час видалення користувача, нам доведеться повторити $user->posts
та дзвонити$post->delete()
foreach($user->posts as $post) { $post->delete(); }
-> це призведе до запуску події видалення в Пості
VS
$user->posts()->delete()
-> це не призведе до запуску події видалення на посаді, оскільки ми фактично не завантажуємо модель Post (ми запускаємо лише SQL типу: DELETE * from posts where user_id = $user->id
і, таким чином, модель Post навіть не завантажується)
Ви можете використовувати цей метод як альтернативу.
Що станеться, ми беремо всі таблиці, пов’язані з таблицею користувачів, і видаляємо пов’язані дані за допомогою циклу
$tables = DB::select("
SELECT
TABLE_NAME,
COLUMN_NAME,
CONSTRAINT_NAME,
REFERENCED_TABLE_NAME,
REFERENCED_COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_NAME = 'users'
");
foreach($tables as $table){
$table_name = $table->TABLE_NAME;
$column_name = $table->COLUMN_NAME;
DB::delete("delete from $table_name where $column_name = ?", [$id]);
}
first()
запит, щоб я міг отримати доступ до події моделі, наприкладUser::where('id', '=', $id)->first()->delete();
Джерело