Saat saya menghapus baris menggunakan sintaks ini:
$user->delete();
Apakah ada cara untuk melampirkan semacam callback, sehingga misalnya akan melakukan ini secara otomatis:
$this->photo()->delete();
Lebih disukai di dalam kelas model.
Saat saya menghapus baris menggunakan sintaks ini:
$user->delete();
Apakah ada cara untuk melampirkan semacam callback, sehingga misalnya akan melakukan ini secara otomatis:
$this->photo()->delete();
Lebih disukai di dalam kelas model.
Jawaban:
Saya percaya ini adalah kasus penggunaan yang sempurna untuk acara Eloquent ( http://laravel.com/docs/eloquent#model-events ). Anda dapat menggunakan acara "menghapus" untuk melakukan pembersihan:
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...
});
}
}
Anda mungkin juga harus memasukkan semuanya ke dalam transaksi, untuk memastikan integritas referensial ..
foreach($user->photos as $photo)
, kemudian $photo->delete()
untuk memastikan setiap anak memiliki anak-anak dihapus pada semua tingkatan, bukan hanya satu seperti yang terjadi karena suatu alasan.
Photos
memiliki tags
dan Anda melakukan hal yang sama dalam Photos
model (yaitu pada deleting
metode $photo->tags()->delete();
:) tidak pernah mendapat pemicu. Tetapi jika saya membuatnya for
lingkaran dan melakukan sesuatu seperti for($user->photos as $photo) { $photo->delete(); }
maka tags
juga bisa dihapus! just FYI
Anda sebenarnya dapat mengatur ini di migrasi Anda:
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
Sumber: http://laravel.com/docs/5.1/migrations#foreign-key-constraints
Anda juga dapat menentukan tindakan yang diinginkan untuk properti "saat penghapusan" dan "saat pembaruan" dari kendala:
$table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade');
Catatan : Jawaban ini ditulis untuk Laravel 3 . Dengan demikian mungkin atau mungkin tidak berfungsi dengan baik di versi Laravel yang lebih baru.
Anda dapat menghapus semua foto terkait sebelum benar-benar menghapus pengguna.
<?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();
}
}
Semoga ini bisa membantu.
$this->photos()->delete()
. The photos()
mengembalikan objek query builder.
Hubungan dalam model Pengguna:
public function photos()
{
return $this->hasMany('Photo');
}
Hapus rekaman dan yang terkait:
$user = User::find($id);
// delete related
$user->photos()->delete();
$user->delete();
Ada 3 pendekatan untuk menyelesaikan ini:
1. Menggunakan Eloquent Events Pada Model Boot (ref: 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. Menggunakan Pengamat Acara Eloquent (ref: https://laravel.com/docs/5.7/eloquent#observers )
Di AppServiceProvider Anda, daftarkan pengamat seperti:
public function boot()
{
User::observe(UserObserver::class);
}
Selanjutnya, tambahkan kelas Observer seperti:
class UserObserver
{
public function deleting(User $user)
{
$user->photos()->delete();
}
}
3. Menggunakan Batasan Kunci Asing (ref: https://laravel.com/docs/5.7/migrations#foreign-key-constraints )
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
Pada Laravel 5.2, dokumentasi menyatakan bahwa jenis penangan acara ini harus terdaftar di AppServiceProvider:
<?php
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
User::deleting(function ($user) {
$user->photos()->delete();
});
}
Saya bahkan berpikir untuk memindahkan mereka ke kelas yang terpisah, bukan penutup untuk struktur aplikasi yang lebih baik.
photos()
, Anda juga harus berhati-hati - proses ini tidak akan menghapus cucu karena Anda tidak memuat model. Anda harus mengulang photos
(perhatikan, tidak photos()
) dan jalankan delete()
metode pada mereka sebagai model untuk memecat peristiwa terkait penghapusan.
Lebih baik jika Anda mengganti delete
metode untuk ini. Dengan begitu, Anda bisa memasukkan transaksi DB dalam delete
metode itu sendiri. Jika Anda menggunakan cara acara, Anda harus menutup panggilandelete
metode Anda dengan transaksi DB setiap kali Anda menyebutnya.
Dalam User
model Anda .
public function delete()
{
\DB::beginTransaction();
$this
->photo()
->delete()
;
$result = parent::delete();
\DB::commit();
return $result;
}
Dalam kasus saya itu cukup sederhana karena tabel database saya adalah InnoDB dengan kunci asing dengan Cascade on Delete.
Jadi dalam hal ini jika tabel foto Anda berisi referensi kunci asing untuk pengguna daripada yang harus Anda lakukan adalah menghapus hotel dan pembersihan akan dilakukan oleh Pangkalan Data, basis data akan menghapus semua catatan foto dari data tersebut. mendasarkan.
Saya akan beralih melalui koleksi yang memisahkan semuanya sebelum menghapus objek itu sendiri.
ini sebuah contoh:
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);
}
Saya tahu ini tidak otomatis tetapi sangat sederhana.
Pendekatan sederhana lain adalah menyediakan model dengan metode. Seperti ini:
public function detach(){
try {
if ($this->has('photos')) {
foreach ($this->photos as $photo) {
$this->photos()->detach($photo);
}
}
} catch (Exception $e) {
dd($e);
}
}
Maka Anda cukup memanggil ini di tempat yang Anda butuhkan:
$user->detach();
$user->delete();
Atau Anda dapat melakukan ini jika mau, hanya opsi lain:
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);
}
Catatan jika Anda tidak menggunakan koneksi default laravel db maka Anda perlu melakukan hal berikut:
DB::connection('connection_name')->pdo->beginTransaction();
DB::connection('connection_name')->pdo->commit();
DB::connection('connection_name')->pdo->rollBack();
Untuk menguraikan jawaban yang dipilih, jika hubungan Anda juga memiliki hubungan anak yang harus dihapus, Anda harus mengambil semua catatan hubungan anak terlebih dahulu, kemudian memanggil delete()
metode tersebut sehingga peristiwa penghapusannya juga dipecat dengan benar.
Anda dapat melakukan ini dengan mudah dengan pesan tingkat tinggi .
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();
});
}
}
Anda juga dapat meningkatkan kinerja dengan hanya menanyakan kolom ID hubungan:
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();
});
}
}
ya, tetapi seperti yang dikatakan @supersan di bagian atas dalam komentar, jika Anda menghapus () di QueryBuilder, acara model tidak akan diaktifkan, karena kami tidak memuat model itu sendiri, lalu memanggil delete () pada model itu.
Peristiwa dipecat hanya jika kita menggunakan fungsi hapus pada Instance Model.
Jadi, beeing ini berkata:
if user->hasMany(post)
and if post->hasMany(tags)
untuk menghapus tag posting ketika menghapus pengguna, kita harus mengulang $user->posts
dan menelepon$post->delete()
foreach($user->posts as $post) { $post->delete(); }
-> ini akan memecat acara penghapusan di Posting
VS
$user->posts()->delete()
-> ini tidak akan mem-boot event penghapusan pada postingan karena kita sebenarnya tidak memuat Post Model (kita hanya menjalankan SQL like: DELETE * from posts where user_id = $user->id
dan dengan demikian, model Post bahkan tidak dimuat)
Anda dapat menggunakan metode ini sebagai alternatif.
Apa yang akan terjadi adalah bahwa kami mengambil semua tabel yang terkait dengan tabel pengguna dan menghapus data terkait menggunakan perulangan
$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()
ke dalam query sehingga saya bisa mengakses model-event misalnyaUser::where('id', '=', $id)->first()->delete();
Sumber