जब मैं इस सिंटैक्स का उपयोग करके एक पंक्ति हटाता हूं:
$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 के लिए लिखा गया था । इस प्रकार लारवेल के अधिक हाल के संस्करण में अच्छी तरह से काम कर सकता है या नहीं।
उपयोगकर्ता को हटाने से पहले आप सभी संबंधित फ़ोटो हटा सकते हैं।
<?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. एलोकेंट इवेंट ऑब्जर्वर का उपयोग करना (Ref: 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');
लारावेल 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 में भी उपलब्ध है और इसका उपयोग ऐपस्वाइसप्रोविडर से किया जा सकता है।
photos()
, आप भी सावधान रहने की आवश्यकता होगी - इस प्रक्रिया को होगा नहीं हटाने पोते क्योंकि आप मॉडल लोड नहीं कर रहे हैं। आपको डिलीट से संबंधित घटनाओं को आग लगाने के लिए मॉडल के रूप में लूप photos
(नोट, नहीं photos()
) और delete()
उन पर विधि को आग लगाने की आवश्यकता होगी।
इसके लिए delete
विधि को ओवरराइड करें तो बेहतर है । इस तरह, आप डीबी लेनदेन को delete
विधि के भीतर ही शामिल कर सकते हैं । यदि आप ईवेंट तरीके का उपयोग करते हैं, तो आपको delete
हर बार कॉल करने के दौरान डीबी लेनदेन के साथ अपने कॉल ऑफ मेथड को कवर करना होगा।
अपने User
मॉडल में।
public function delete()
{
\DB::beginTransaction();
$this
->photo()
->delete()
;
$result = parent::delete();
\DB::commit();
return $result;
}
मेरे मामले में यह बहुत आसान था क्योंकि मेरे डेटाबेस टेबल इनकोडी हैं जो कैस्केड के साथ विदेशी कुंजी के साथ डिलीट हैं।
तो इस मामले में यदि आपकी फ़ोटो तालिका में उपयोगकर्ता के लिए एक विदेशी कुंजी संदर्भ है, जो आपको करना है, तो होटल को हटाना है और डेटा बेस द्वारा क्लीनअप किया जाएगा, डेटा बेस डेटा से सभी फ़ोटो रिकॉर्ड हटा देगा आधार।
मैं इस संग्रह के माध्यम से वस्तु को हटाने से पहले सब कुछ अलग करना होगा।
यहाँ एक उदाहरण है:
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::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 पर हटाते हैं (), तो मॉडल ईवेंट को निकाल नहीं दिया जाएगा, क्योंकि हम मॉडल को स्वयं लोड नहीं कर रहे हैं, फिर उस मॉडल पर कॉल हटाएं ()।
यदि हम किसी मॉडल इंस्टेंस पर डिलीट फंक्शन का उपयोग करते हैं, तो ईवेंट केवल निकाल दिए जाते हैं।
तो, इस मधुमक्खी ने कहा:
if user->hasMany(post)
and if post->hasMany(tags)
उपयोगकर्ता को हटाते समय पोस्ट टैग को हटाने के लिए, हमें $user->posts
कॉल और कॉल करना होगा$post->delete()
foreach($user->posts as $post) { $post->delete(); }
-> यह पोस्ट पर डिलीट करने की घटना को आग देगा
वी.एस.
$user->posts()->delete()
-> यह पोस्ट पर डिलीट करने वाले ईवेंट को आग नहीं देगा क्योंकि हम वास्तव में पोस्ट मॉडल को लोड नहीं करते हैं (हम केवल एक SQL चलाते हैं: DELETE * from posts where user_id = $user->id
और इस प्रकार, पोस्ट मॉडल भी लोड नहीं होता है)
आप इस विधि का विकल्प के रूप में उपयोग कर सकते हैं।
क्या होगा यह है कि हम उपयोगकर्ता तालिका से जुड़े सभी तालिकाओं को लेते हैं और लूपिंग का उपयोग करके संबंधित डेटा को हटाते हैं
$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();