この構文を使用して行を削除すると、次のようになります。
$user->delete();
ある種のコールバックを添付して、たとえばこれを自動的に行う方法はありますか?
$this->photo()->delete();
できればモデルクラス内。
この構文を使用して行を削除すると、次のようになります。
$user->delete();
ある種のコールバックを添付して、たとえばこれを自動的に行う方法はありますか?
$this->photo()->delete();
できればモデルクラス内。
これはEloquentイベント(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...
});
}
}
参照整合性を確保するために、おそらくすべてをトランザクション内に配置する必要があります。
移行で実際にこれを設定できます。
$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');
注:この回答はLaravel3用に作成されました。したがって、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();
}
}
それが役に立てば幸い。
ユーザーモデルの関係:
public function photos()
{
return $this->hasMany('Photo');
}
レコードと関連するものを削除します。
$user = User::find($id);
// delete related
$user->photos()->delete();
$user->delete();
これを解決するには、次の3つのアプローチがあります。
1.モデルの起動時にEloquentイベントを使用する(参照: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. Eloquent Event Observersの使用(参照:https ://laravel.com/docs/5.7/eloquent#observers )
AppServiceProviderで、次のようにオブザーバーを登録します。
public function boot()
{
User::observe(UserObserver::class);
}
次に、次のようなObserverクラスを追加します。
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();
});
}
アプリケーション構造を改善するために、クロージャではなく別のクラスにそれらを移動することも考えています。
このためのメソッドをオーバーライドする方が良いですdelete
。delete
このようにして、メソッド自体にDBトランザクションを組み込むことができます。イベント方式を使用する場合は、delete
メソッドを呼び出すたびに、メソッドの呼び出しをDBトランザクションでカバーする必要があります。
あなたのUser
モデルで。
public function delete()
{
\DB::beginTransaction();
$this
->photo()
->delete()
;
$result = parent::delete();
\DB::commit();
return $result;
}
選択した回答を詳しく説明するために、リレーションシップに削除する必要のある子リレーションシップもある場合は、最初にすべての子リレーションシップレコードを取得してから、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();
});
}
}
リレーションシップID列のみをクエリすることで、パフォーマンスを向上させることもできます。
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();
});
}
}
Constrained()
Laravel 7以降、データベースで関係制約を定義するための新しいメソッドforeignId()
とメソッドが利用可能になりました。これらのメソッドでmethodを使用して、関連するレコードを自動的に削除できます。constrained()
OnDelete()
$table->unsignedBigInterer('user_id');
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreignId('user_id')
->constrained()
->onDelete('cascade');
オブジェクト自体を削除する前に、コレクションを繰り返してすべてを切り離します。
次に例を示します。
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);
}
自動ではないことは知っていますが、非常に簡単です。
もう1つの簡単なアプローチは、モデルにメソッドを提供することです。このような:
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();
私の場合、データベーステーブルは削除時にカスケードを使用する外部キーを持つInnoDBであるため、非常に単純でした。
したがって、この場合、写真テーブルにユーザーの外部キー参照が含まれている場合、ホテルを削除するだけで、データベースによってクリーンアップが実行され、データベースはデータからすべての写真レコードを削除します。ベース。
この方法はLaravel8で私のために働きました:
public static function boot() {
parent::boot();
static::deleted(function($item){
$item->deleted_by = \Auth::id(); // to know who delete item, you can delete this row
$item->save(); // to know who delete item, you can delete this row
foreach ($item->photos as $photo){
$photo->delete();
}
});
}
public function photos()
{
return $this->hasMany('App\Models\Photos');
}
注:この構文での削除は$user->photos()->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);
}
デフォルトのlaraveldb接続を使用していない場合は、次のことを行う必要があることに注意してください。
DB::connection('connection_name')->pdo->beginTransaction();
DB::connection('connection_name')->pdo->commit();
DB::connection('connection_name')->pdo->rollBack();
モデルの移行を定義するときは、onDeleteカスケードを使用することをお勧めします。これにより、モデルの関係が削除されます。
例えば
$table->foreign(’user_id’)
->references(’id’)->on(’users’)
->onDelete(’cascade’);
モデルとその関係を3つまたは4つ以上のネストされた関係に削除する方法を考えている場合は、モデルの関係を再定義することを検討する必要があります。
これが完璧な解決策です。
# model
public function order_item_properties()
{
return $this->hasMany(OrderItemProperty::class, 'order_id', 'id');
}
public function order_variations()
{
return $this->hasMany(OrderItemVariation::class, 'order_id', 'id');
}
# controller
$order_item = OrderItem::find($request->order_id);
$order_item->order_item_properties()->delete();
$order_item->order_variations()->delete();
$order_item->delete();
return response()->json([
'message' => 'Deleted',
]);
ええ、しかし@supersanがコメントの上部で述べたように、QueryBuilderでdelete()を実行すると、モデル自体をロードしていないため、モデルイベントは発生しません。次に、そのモデルで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モデルをロードしないため、これはPostでdeleteingイベントを発生させません(次のようなSQLのみを実行するDELETE * from posts where user_id = $user->id
ため、Postモデルもロードされません)
代わりにこの方法を使用できます。
何が起こるかというと、usersテーブルに関連付けられているすべてのテーブルを取得し、ループを使用して関連データを削除します。
$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]);
}