حذف رکورد با Eloquent در لاراول؛ حذف نرم، دائمی و گروهی

یاسین
1404/7/22
24 دقیقه
535 بازدید
حذف رکورد با Eloquent در لاراول؛ حذف نرم، دائمی و گروهی

پاسخ کوتاه: برای حذف یک رکورد $post->delete()، برای چند شناسه Post::destroy([1,2]) و برای حذف گروهی با شرط Post::where('status','draft')->delete(). اگر مدل SoftDeletes دارد، هیچ کدام داده را واقعاً پاک نمی کنند؛ فقط deleted_at را پر می کنند و برای پاک کردن قطعی باید forceDelete() بزنید.

خروجی واقعی: پنج عمل حذف روی لاراول ۱۲

این خروجی از یک پروژهٔ تازهٔ لاراول (نسخهٔ ۱۲٫۷۰٫۲) با جدول posts و تریت SoftDeletes گرفته شده است. پنج رکورد ساخته شد و بعد این دستورها به ترتیب اجرا شدند:

Post::find(1)->delete();
Post::destroy([2, 3]);
Post::where('status', 'draft')->delete();
Post::onlyTrashed()->find(1)->restore();
Post::find(1)->forceDelete();

خروجی چاپ شده در همان اجرا:

تعداد کل: 5
بعد از delete روی مدل: 4 · با حذف شده ها: 5
بعد از destroy گروهی: 2
حذف گروهی با شرط (خروجی عددی): 0
حذف شده های نرم: 3
بعد از بازگردانی: 3
بعد از حذف دائمی: 4

چرا خط چهارم صفر است: بعد از حذف رکوردهای ۲ و ۳، هیچ رکورد draft باقی نمانده بود؛ پس شرط چیزی پیدا نکرد. در اجرای دوم با سه پیش نویس تازه، همان دستور عدد ۳ برگرداند و رکوردهای حذف شده نرم از شمارش معمولی خارج شدند. این تفاوت، همان جایی است که خیلی ها فکر می کنند حذف گروهی کار نکرده است.

متدچه کاری می کندخروجی
delete()حذف یک مدل (نرم اگر SoftDeletes دارد)true/false
destroy([ids])حذف چند مدل با شناسهتعداد حذف شده
where(...)->delete()حذف گروهی با شرطتعداد ردیف ها
forceDelete()حذف قطعی، حتی با SoftDeletestrue/false

در فریم ورک لاراول ، ابزار قدرتمندی به نام Eloquent ORM وجود دارد که کار با پایگاه داده را بسیار ساده می کند. به جای نوشتن کدهای پیچیده SQL، می توان با استفاده از روش های شی گرا داده ها را خواند، ذخیره یا ویرایش کرد. در واقع Eloquent ORM مانند یک مترجم بین جداول پایگاه داده و کدهای PHP عمل می کند. وقتی اولین مدل خود را می سازید، می توانید اطلاعات را به صورت مستقیم و راحت از طریق آن مدیریت کنید.

برای مثال، ساخت یک مدل "User" به شما کمک می کند تا کاربران را از پایگاه داده بخوانید یا کاربر جدیدی ایجاد کنید. این روش باعث می شود کد شما تمیزتر، قابل درک تر و حرفه ای تر باشد. Eloquent ORM پایه ای ترین و درعین حال یکی از کاربردی ترین بخش های لاراول است که هر برنامه نویس باید آن را یاد بگیرد.

Eloquent ORM چیست و چرا باید از آن استفاده کنیم؟

Eloquent ORM یکی از اجزای کلیدی فریم ورک لاراول است که به عنوان یک لایه ارتباطی میان کد و پایگاه داده عمل می کند. این سیستم بر پایه الگوی ActiveRecord طراحی شده و به توسعه دهندگان اجازه می دهد تا با داده ها مانند اشیا کار کنند، نه صرفاً با جداول و کوئری ها. نتیجه آن، ساختاری تمیز، قابل فهم و هماهنگ با اصول برنامه نویسی شی گرا است.

یکی از مهم ترین مزایای Eloquent، سادگی استفاده از آن است. شما بدون نیاز به نوشتن کوئری های SQL پیچیده، می توانید داده ها را بخوانید، ذخیره کنید یا به روزرسانی نمایید. برای مثال، ایجاد یک کاربر جدید تنها با چند خط کد انجام می شود و این درک طبیعی از داده ها، باعث افزایش خوانایی کد و کاهش خطاهای احتمالی می شود.

از دیگر ویژگی های مهم Eloquent ORM، امنیت بالا در برابر حملات رایج مانند SQL Injection است. این ابزار با استفاده از پارامترهای ایمن، داده ها را به صورت خودکار از خطرات احتمالی محافظت می کند. علاوه بر این، امکان تعریف روابط بین جداول (One-to-Many، Many-to-Many و غیره) باعث می شود مدیریت داده های پیچیده نیز ساده و ساخت یافته باشد.

در نهایت، می توان گفت Eloquent ORM نه تنها ابزار کارآمدی برای تعامل با پایگاه داده است، بلکه تجربه ای روان، ایمن و لذت بخش از توسعه را برای برنامه نویسان لاراول به ارمغان می آورد.

Eloquent چگونه کار می کند؟

برای فهمیدن اینکه Eloquent چطور کار می کند، کافی است بدانیم هر جدول در پایگاه داده با یک مدل لاراول در ارتباط است. این مدل لاراول در واقع نماینده همان جدول است و با استفاده از آن می توان داده ها را خواند، ذخیره یا حذف کرد.

وقتی دستوری مثل User::all() را اجرا می کنیم، Eloquent به طور خودکار یک کوئری SQL می سازد، آن را در پایگاه داده اجرا می کند و نتیجه را به صورت مجموعه ای از اشیا PHP برمی گرداند. این یعنی هر رکورد از جدول به یک شیء تبدیل می شود و می توان با آن مثل یک متغیر معمولی کار کرد.

در پشت صحنه، Eloquent با استفاده از اطلاعات موجود در مدل لاراول، نام جدول، کلید اصلی و روابط بین جداول را تشخیص می دهد. به این ترتیب، نیازی به نوشتن کوئری های پیچیده نداریم و همه چیز به شکل خودکار انجام می شود. این روش باعث می شود کار با داده ها در لاراول بسیار راحت تر، تمیزتر و قابل درک تر باشد.

پیش نیازهای شروع کار با Eloquent

قبل از شروع کار با Eloquent، لازم است محیط توسعه شما به درستی آماده سازی شود.

ایجاد یک پروژه جدید لاراول

ایجاد یک پروژه جدید لاراول

برای شروع، باید یک پروژه جدید لاراول ایجاد کنید. ساده ترین روش استفاده از ابزار قدرتمند Composer است که وظیفه مدیریت وابستگی ها را بر عهده دارد. کافی است در ترمینال دستور زیر را وارد کنید:

composer create-project laravel/laravel project-name

این دستور با استفاده از فرمان create-project، جدید ترین نسخه فریم ورک را دانلود کرده و فرآیند نصب پروژه لاراول را به صورت خودکار انجام می دهد. پس از اتمام نصب، پوشه ای با ساختار منظم و آماده برای توسعه ایجاد می شود که می توانید در آن کدنویسی را آغاز کنید.

اتصال به پایگاه داده

برای برقراری ارتباط بین پروژه و پایگاه داده، باید تنظیمات لازم را در فایل .env انجام دهید. این فایل در ریشه پروژه قرار دارد و شامل اطلاعات حساسی است که نحوه اتصال لاراول به دیتابیس را مشخص می کند.

در بخش مربوط به پایگاه داده، مقادیر زیر را مشاهده خواهید کرد:

DB_CONNECTION=mysql  
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_username
DB_PASSWORD=your_password

مقدار DB_CONNECTION نوع پایگاه داده را تعیین می کند (مثلاً mysql یا sqlite). DB_HOST آدرس سرور دیتابیس و DB_PORT شماره پورتی است که ارتباط از طریق آن برقرار می شود. همچنین، نام دیتابیس در DB_DATABASE، نام کاربری در DB_USERNAME و رمز عبور در DB_PASSWORD مشخص می شوند.

با ذخیره این تنظیمات، لاراول به صورت خودکار اتصال ایمن و پایداری با پایگاه داده برقرار کرده و آماده اجرای دستورات Eloquent می شود.

ساخت اولین مدل Eloquent

برای ایجاد اولین مدل در Eloquent، کافی است از ابزار خط فرمان قدرتمند لاراول یعنی Artisan استفاده کنید. این ابزار فرایند تولید فایل ها و ساختارهای اصلی پروژه را بسیار سریع و منظم انجام می دهد. برای ساخت مدل جدید، در ترمینال دستور زیر را وارد کنید:

php artisan make:model Post

با اجرای دستور make:model، لاراول به طور خودکار فایلی به نام Post.php در مسیر app/Models ایجاد می کند. این فایل در واقع نماینده ی جدول posts در پایگاه داده است و نقش اصلی را در تعامل با داده ها ایفا می کند.

درون این فایل، یک کلاس Model تعریف شده که از کلاس پایه Illuminate\Database\Eloquent\Model ارث بری می کند. این کلاس شامل ویژگی ها و متدهایی است که امکان خواندن، ایجاد، ویرایش و حذف داده ها را به ساده ترین شکل فراهم می کند.

ساختار مدل به گونه ای طراحی شده که می توان تنظیماتی مانند نام جدول، کلید اصلی (primaryKey)، نوع داده ها (casts) و روابط بین جداول را در آن مشخص کرد. برای نمونه، می توان رابطه ی hasMany بین مدل User و مدل Post تعریف نمود تا هر کاربر چندین پست داشته باشد.

با ایجاد اولین مدل، پایه ی اصلی کار با Eloquent را بنا می گذارید؛ جایی که داده ها از حالت خام خارج شده و در قالب اشیای قابل مدیریت در اختیار شما قرار می گیرند.

ایجاد Migration برای جدول مدل

برای هر مدل در Eloquent، نیاز است جدولی در پایگاه داده وجود داشته باشد که داده های آن مدل را ذخیره کند. این کار با استفاده از Migration در لاراول انجام می شود. Migration ها در واقع اسکریپت هایی هستند که تغییرات ساختار پایگاه داده را به صورت نسخه بندی شده ثبت می کنند و به شما اجازه می دهند جدول ها را ایجاد، ویرایش یا حذف کنید.

برای ساخت یک Migration جدید، کافی است از دستور زیر در ترمینال استفاده کنید:

php artisan make:migration create_posts_table

این دستور فایلی ایجاد می کند که درون آن ساختار جدول با استفاده از کلاس Schema و متد create table تعریف می شود. به عنوان مثال:

Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});

در این قطعه کد، جدول posts با ستون های id، title، content و زمان بندی خودکار (created_at و updated_at) ساخته می شود. پس از تنظیم ساختار جدول، کافی است دستور زیر را اجرا کنید:

php artisan migrate

با اجرای php artisan migrate، تمامی Migrationهای موجود اعمال می شوند و جدول ها در پایگاه داده ایجاد خواهند شد. این روش باعث می شود تغییرات دیتابیس به صورت منظم، مستند و قابل بازگشت باشند و توسعه پروژه در تیم های بزرگ با نظم و اطمینان بیش تری پیش برود.

سفارشی سازی مدل

در بسیاری از پروژه ها، مدل های Eloquent به صورت پیش فرض نیاز ما را برطرف می کنند، اما در پروژه های واقعی گاهی باید رفتار آن ها را تغییر دهیم. اینجاست که مفهوم سفارشی سازی مدل اهمیت پیدا می کند. لاراول به ما این امکان را می دهد تا با چند property ساده، کنترل دقیق تری بر روی مدل ها و ارتباط آن ها با پایگاه داده داشته باشیم.

یکی از پراپرتی های کلیدی، $table است. به صورت پیش فرض، لاراول نام جدول را از نام مدل استخراج می کند. برای مثال، مدل Post به جدول posts متصل می شود. اما اگر نام جدول متفاوت باشد، می توان آن را به صورت زیر تغییر داد:

protected $table = 'blog_posts';

با این کار، مدل Post به جدول blog_posts در پایگاه داده متصل می شود.

پراپرتی مهم دیگر، $primaryKey است. لاراول به طور پیش فرض ستون id را به عنوان کلید اصلی در نظر می گیرد، اما در صورت استفاده از کلیدی با نام متفاوت (مثلاً post_id)، باید آن را مشخص کرد:

protected $primaryKey = 'post_id';

در بسیاری از پروژه ها ممکن است نیازی به ثبت زمان ایجاد و به روزرسانی رکوردها نباشد. در این حالت می توان با تنظیم مقدار $timestamps به false، این قابلیت را غیرفعال کرد:

public $timestamps = false;

یکی از مهم ترین ویژگی های امنیتی در مدل ها مربوط به $fillable و $guarded است. $fillable مشخص می کند کدام فیلدها مجاز به پر شدن از طریق عملیات create() یا update() هستند:

protected $fillable = ['title', 'content', 'author_id'];

در مقابل، $guarded تعیین می کند کدام فیلدها نباید به صورت مستقیم مقداردهی شوند، مثلاً:

protected $guarded = ['id'];

استفاده درست از این دو پراپرتی نقش مهمی در جلوگیری از حملات تزریق داده (Mass Assignment Vulnerability) دارد و امنیت برنامه را افزایش می دهد.

در نهایت، سفارشی سازی مدل نه تنها باعث سازگاری بیش تر با ساختار پایگاه داده می شود، بلکه کنترل کامل تری بر رفتار داده ها، امنیت و یکپارچگی سیستم ایجاد می کند. در پروژه های حرفه ای لاراول، تسلط بر این تنظیمات، تفاوت میان یک کد معمولی و یک ساختار مهندسی شده را رقم می زند.

کار با مدل های Eloquent

کار با مدل های Eloquent

پس از ایجاد مدل، نوبت آن است که با استفاده از قدرت Eloquent داده ها را مدیریت کنیم. در دنیای توسعه نرم افزار، عملیات اصلی بر روی داده ها با عنوان CRUD شناخته می شود؛ یعنی create (ایجاد)، read (خواندن)، update (به روزرسانی) و delete (حذف). هر یک از این عملیات در لاراول با مجموعه ای از Eloquent methods به سادگی قابل انجام است.

خواندن اطلاعات از پایگاه داده

خواندن داده ها از پایگاه داده، از اصلی ترین وظایف Eloquent در لاراول است. این فرایند با استفاده از متدهای قدرتمند و ساده انجام می شود که امکان بازیابی رکوردها را به صورت کاملاً شی گرا فراهم می کنند.

ساده ترین روش برای واکشی تمام داده ها از یک جدول، استفاده از متد all() است. این متد تمامی رکوردهای جدول مرتبط با مدل را به صورت مجموعه ای از اشیا برمی گرداند:

$posts = Post::all();

در صورتی که بخواهیم رکورد خاصی را بر اساس شناسه (ID) واکشی کنیم، متد find() کاربرد دارد:

$post = Post::find(1);

اما گاهی نیاز به فیلتر کردن داده ها داریم. در این حالت، متد where() وارد عمل می شود تا شرایط خاصی را برای جست وجو اعمال کند:

$posts = Post::where('status', 'published')->get();

در این مثال، فقط پست هایی که وضعیت آن ها “published” است بازگردانده می شوند. متد get() در انتهای عبارت، نتایج را از پایگاه داده واکشی کرده و در قالب مجموعه ای از مدل ها برمی گرداند.

برای زمانی که تنها به یک رکورد نیاز داریم، می توان از متد first() استفاده کرد. این متد اولین نتیجه ای را که با شرایط تعیین شده مطابقت دارد، بازمی گرداند:

$post = Post::where('id', 5)->first();

ترکیب هوشمندانه متدهای all()، find()، where()، first() و get() به شما این امکان را می دهد تا هر نوع داده ای را با کم ترین کد و بالاترین خوانایی واکشی کنید. این متدها قلب فرایند بازیابی رکوردها در Eloquent هستند و درک عمیق آن ها، گامی اساسی در تسلط بر کار با پایگاه داده در لاراول محسوب می شود.

ذخیره و به روزرسانی اطلاعات

در Eloquent، مدیریت داده ها تنها به خواندن محدود نمی شود؛ بلکه بخش مهم تری از کار، ذخیره اطلاعات جدید و به روزرسانی داده های موجود است. این فرآیند با استفاده از متدهای قدرتمند و ساده ای مانند save()، update() و create() انجام می شود.

برای ذخیره رکورد جدید، می توان ابتدا یک نمونه از مدل ایجاد کرد و سپس داده ها را در آن قرار داد:

$post = new Post();
$post->title = 'پست جدید';
$post->content = 'محتوای آموزشی لاراول';
$post->save();

در اینجا متد save() داده های واردشده را در پایگاه داده ذخیره می کند. این روش زمانی مفید است که بخواهید کنترل بیش تری روی مقداردهی فیلدها داشته باشید یا عملیات خاصی را قبل از ذخیره انجام دهید.

اگر بخواهید داده ای را مستقیماً و با یک خط کد وارد کنید، می توانید از متد create() استفاده نمایید:

Post::create(['title' => 'پست نمونه', 'content' => 'متن تستی']);

این متد به کمک ویژگی $fillable فقط فیلدهای مجاز را ذخیره می کند و از تزریق داده های ناامن جلوگیری می نماید.

برای به روزرسانی داده ها نیز می توان ابتدا رکورد را واکشی کرده و سپس مقادیر جدید را در آن اعمال کرد:

$post = Post::find(1);
$post->title = 'عنوان جدید';
$post->update();

همچنین متد update() قابلیت به روزرسانی گروهی را دارد و می توان با ترکیب آن با شرط where() چندین رکورد را به طور همزمان تغییر داد:

Post::where('status', 'draft')->update(['status' => 'published']);

این متدها باعث می شوند عملیات ذخیره اطلاعات و بروزرسانی در لاراول بسیار سریع، خوانا و امن انجام شود. Eloquent با این امکانات، ارتباط با پایگاه داده را از سطح کوئری های پیچیده SQL به یک تجربه شی گرای ساده و قدرتمند تبدیل می کند.

تصمیم درست پیش از حذف رکورد؛ چهار روش حذف در Eloquent و تفاوت واقعی شان
تصمیم درست پیش از حذف رکورد؛ چهار روش حذف در Eloquent و تفاوت واقعی شان

پیش از کار روزمره با این واسطه، دانستن این که زیر آن چه خبر است کمک می کند: «دیتابیس چیست» را ببینید.

حذف رکورد با Eloquent؛ حذف نرم، حذف دائمی و حذف گروهی

حذف رکورد با Eloquent سه رفتار متفاوت است، نه یک متد: انتخاب اشتباه بین آن ها یا داده ای را برمی گرداند که فکر می کردید پاک شده، یا چیزی را برای همیشه نابود می کند. این بخش هر سه حالت را با کد قابل اجرا می بیند: حذف یک رکورد با delete()، حذف گروهی، حذف نرم با SoftDeletes، پاک سازی دائمی با forceDelete() و در پایان حذف رکوردهای وابسته که به روابط Eloquent در همین مقاله گره می خورد.

پاسخ کوتاه: حذف رکورد دیتابیس در Eloquent با متد delete() روی یک مدل انجام می شود و اگر مدل SoftDeletes داشته باشد همین متد رکورد را به سطل زباله می برد، نه بیرون از جدول. انتخاب درست بین چهار روش به یک پرسش بستگی دارد: بعد از حذف به آن داده نیاز دارید یا نه.

حذف رکورد دیتابیس در Eloquent؛ کدام روش برای کدام کار

پیش از نوشتن کد، روش را انتخاب کنید. جدول زیر چهار روش پرکاربرد را با تفاوت واقعی شان می آورد؛ ستون سوم مهم ترین ستون است: هر جا رویداد مدل اجرا نشود، پاک سازی فایل یا حافظه ای که داخل رویداد نوشته اید هم اجرا نمی شود.

روشچه کاری می کندرویداد مدل اجرا می شود؟برگشت پذیریجای مناسب
delete()همان رکورد را حذف می کندبلهبا SoftDeletes بلهحذف یک رکورد مشخص
destroy([شناسه])هر شناسه را جدا می خواند و حذف می کندبلهبا SoftDeletes بلهچند شناسه از فرم یا فهرست
where(...)->delete()یک دستور SQL روی همهٔ ردیف های منطبقخیرخیرپاک سازی انبوه
forceDelete()رکورد را واقعاً از جدول برمی داردبلهخیرپایان کار یا درخواست واقعی کاربر

خطرناک ترین خطای این بخش، حذف بدون شرط است: اگر روی یک مدل، بدون where، دستور حذف بزنید همهٔ ردیف های جدول پاک می شوند و راهی برنمی گردد. سه قانون جلوی این حادثه را می گیرد: پیش از حذف انبوه شمارش بگیرید، حذف چند مرحله ای را داخل تراکنش بگذارید و برای رکورد هایی که بازگشتشان محتمل است حذف نرم را انتخاب کنید.

کد زیر را در ترمینال لاراول در همان مدل Post اجرا کنید: اول تعداد ردیف های منطبق را می شمارد، بعد داخل تراکنش حذف می کند و در پایان دوباره می شمارد تا عدد قبل و بعد را با هم ببینید.

// روی مدل Post: شمارش قبل و بعد از حذف
$before = Post::where('status', 'draft')->count();

DB::transaction(function () {
    Post::where('status', 'draft')->delete();
});

$after = Post::where('status', 'draft')->count();
echo "before={$before} after={$after}";

حذف یک رکورد با delete()

use App\Models\Post;

// رکورد را می گیریم و بعد حذف می کنیم
$post = Post::find(1);
$post->delete();   // true اگر حذف شد، false اگر نشد

// اگر رکورد نبود، خطای ۴۰۴ بدهد نه null
Post::findOrFail(1)->delete();

// داخل تراکنش: اگر وسط کار خطایی رخ دهد، حذف برمی گردد
Post::findOrFail(1)->deleteOrFail();

نبود رکورد دام رایجی است: find() روی شناسه ای که وجود ندارد null برمی گرداند و null->delete() خطای مرگبار می دهد؛ findOrFail() همان حالت را به یک خطای ۴۰۴ قابل مدیریت تبدیل می کند.

حذف گروهی با destroy() در برابر where()->delete()

// چند شناسه را یک جا حذف کن؛ برای هر مدل رویداد deleting/deleted اجرا می شود
Post::destroy([12, 13, 14]);
Post::destroy(15);
$count = Post::destroy([16, 17]);   // تعداد رکوردهای حذف شده

// همهٔ رکوردهایی که با شرط می خورند، با یک کوئری
$count = Post::where('status', 'draft')
    ->where('created_at', '<', now()->subYear())
    ->delete();

تفاوت این دو در رویدادهاست، نه در نتیجه: destroy() هر مدل را جداگانه می خواند و delete() را روی آن صدا می زند، پس رویدادهای deleting و deleted و آبزرورها اجرا می شوند. حذف انبوه با where(...)->delete() یک دستور SQL می فرستد و هیچ رویدادی اجرا نمی کند؛ سریع است، اما اگر پاک سازی فایل یا حافظه را داخل رویداد deleted نوشته باشید، آن جا اجرا نمی شود.

حذف نرم (Soft Delete) با SoftDeletes

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use SoftDeletes;
}
// در فایل migration: ستون تاریخ حذف را به جدول اضافه می کند
Schema::table('posts', function (Blueprint $table) {
    $table->softDeletes();   // ستون deleted_at
});
$post->delete();          // فقط deleted_at پر می شود؛ رکورد سر جایش می ماند

Post::withTrashed()->find(1);   // رکوردهای حذف شده را هم بیاور
Post::onlyTrashed()->get();     // فقط رکوردهای حذف شده
$post->trashed();               // true اگر نرم حذف شده باشد
$post->restore();               // برگرداندن یک رکورد
Post::onlyTrashed()->where('user_id', 3)->restore();   // برگرداندن گروهی

حذف نرم در پنل مدیریت معنا پیدا می کند: دکمهٔ «حذف» رکورد را به سطل زباله می برد و کاربر فرصت دارد آن را برگرداند. یک نکته را حساب کنید: رکورد حذف نرم شده هنوز در جدول است، پس قید یکتایی روی ایمیل یا اسلاگ باید با حذف نرم هماهنگ باشد، وگرنه بعد از حذف نمی توانید همان مقدار را دوباره بسازید.

حذف دائمی با forceDelete()

// فقط برای مدلی که SoftDeletes دارد و باید از سطل زباله پاک شود
$post->forceDelete();

// رکوردهای مرتبط را هم برای همیشه پاک کن
$post->comments()->forceDelete();

forceDelete() رکورد را واقعاً از جدول برمی دارد و بعد از آن راه برگشتی نیست. جای درستش دو حالت است: پاک سازی داده های قدیمی در یک Job زمان بندی شده، و درخواست واقعی کاربر برای حذف حساب. پیش از اجرا پشتیبان بگیرید یا رکورد را در جدول آرشیو نگه دارید.

حذف رکوردهای وابسته (کلید خارجی و روابط)

// در فایل migration: با حذف پست، نظراتش هم در سطح دیتابیس پاک می شوند
Schema::create('comments', function (Blueprint $table) {
    $table->id();
    $table->foreignId('post_id')->constrained()->cascadeOnDelete();
    $table->text('body');
    $table->timestamps();
});
// اگر کلید خارجی cascade ندارد، خودت حذف کن
$post = Post::with('comments')->findOrFail(1);
$post->comments()->delete();   // اول رکوردهای مرتبط
$post->delete();               // بعد خود رکورد

// یا یک بار برای همیشه، در رویداد مدل
protected static function booted(): void
{
    static::deleting(function (Post $post) {
        $post->comments()->delete();
    });
}
// رابطه چند به چند: ردیف های جدول واسط را جدا کن
$user->roles()->detach();          // همه
$user->roles()->detach($roleId);   // فقط یکی
$user->roles()->sync([]);          // همه، با جایگزینی لیست تازه

اینجا همان جایی است که یک حذف ساده ناقص می ماند: پست پاک می شود و نظراتش بی صاحب در دیتابیس می مانند و در صفحه خطا می دهند. دو راه دارد و ترتیب مهم است — اگر cascadeOnDelete روی کلید خارجی گذاشته اید، دیتابیس خودش کار را تمام می کند؛ در غیر این صورت اول رکوردهای وابسته و بعد خود رکورد را حذف کنید. حذف نرم والد هم فرزندان را نرم حذف نمی کند و باید جداگانه برای آن ها تصمیم بگیرید.

حذف زمان بندی شده و تکه تکه برای جدول های بزرگ

اگر این پاک سازی هر شب یا هر هفته تکرار می شود، آن را به یک فرمان Artisan بسپارید تا هر بار دستی اجرا نشود. فرمان را با دستور زیر بسازید و کد زیر را داخل همان فایل بنویسید و اجرا کنید.

// php artisan make:command PruneDraftPosts
namespace App\Console\Commands;

use App\Models\Post;
use Illuminate\Console\Command;

class PruneDraftPosts extends Command
{
    protected $signature = 'posts:prune-drafts';
    protected $description = 'حذف پیش نویس های قدیمی';

    public function handle(): int
    {
        $count = Post::where('status', 'draft')
            ->where('created_at', '<', now()->subYear())
            ->delete();

        $this->info("حذف شد: {$count}");
        return self::SUCCESS;
    }
}

برای اجرای خودکار همین فرمان را در زمان بند لاراول ثبت کنید. اگر حجم پاک سازی سنگین است و روی پاسخ کاربران اثر می گذارد، اجرای کار های سنگین در صف را انتخاب کنید تا کندی به کاربر منتقل نشود.

حذف چند صد هزار ردیف در یک دستور، جدول را قفل و سایت را کند می کند. برای جدول های بزرگ، کد زیر را در همان فرمان بنویسید تا به جای یک حذف سنگین، در هر دور فقط هزار ردیف پاک شود.

// حذف تکه تکه؛ در هر دور ۱۰۰۰ ردیف
Post::where('status', 'draft')
    ->chunkById(1000, function ($rows) {
        Post::whereIn('id', $rows->pluck('id'))->delete();
    });

پیش از حذف و بعد از آن چه چیزی را بررسی کنیم؟

حذف برگشت ناپذیر است، پس چند بررسی کوتاه پیش و پس از اجرا وقت کمی می گیرد و خطر را کم می کند.

  1. شمار ردیف های منطبق را با count() بگیرید و همان عدد را در تیکت کار یا لاگ بنویسید.
  2. روی محیط آزمایشی اجرا کنید و اثرش را روی رکورد های وابسته ببینید.
  3. پیش از forceDelete() پشتیبان بگیرید یا رکورد را به جدول آرشیو منتقل کنید.
  4. پس از حذف با withTrashed() بررسی کنید که رکورد واقعاً رفته و وابسته هایش هم پاک شده اند.

نکتهٔ پایانی دربارهٔ نشانی صفحه: رکوردی که نرم حذف شده یا کاملاً پاک شده، در نمایش عمومی به خطای ۴۰۴ تبدیل می شود؛ اگر می خواهید مرورگر بداند این نشانی برای همیشه رفته است، راهنمای همان خطا تفاوت ۴۰۴ و ۴۱۰ را توضیح می دهد.

خلاصهٔ عملی همین چند خط است: برای یک رکورد delete()، برای چند شناسه destroy()، برای پاک سازی انبوه where(...)->delete()، برای بازگشت پذیری SoftDeletes و برای پایان دادن forceDelete(). هرچه انتخاب سخت گیرانه تر، مسئولیت بیش تر؛ پیش از forceDelete() مطمئن شوید رکوردهای وابسته هم درست حذف می شوند.

قدرت واقعی Eloquent: کار با روابط (Relationships)

کار با روابط الکونت

قدرت اصلی Eloquent در توانایی آن برای مدیریت روابط لاراول نهفته است. این سیستم به شما اجازه می دهد ارتباط میان جداول مختلف را به صورت طبیعی و خوانا تعریف کنید. روابطی مانند hasOne، hasMany، belongsTo و manyToMany ساختار داده ها را منظم و قابل درک می سازند.

برای مثال، یک کاربر می تواند چندین پست داشته باشد و هر پست به یک کاربر تعلق بگیرد. تعریف این روابط در مدل ها باعث می شود واکشی داده ها، ویرایش و حتی فیلتر آن ها به شکلی روان و قدرتمند انجام شود. روابط لاراول در حقیقت قلب تعاملات هوشمند میان داده ها هستند.

رابطه یک به یک (One to One)

در سیستم Eloquent، زمانی که دو جدول دارای ارتباط مستقیم و یکتا با یکدیگر هستند، از رابطه یک به یک یا One to One Relationship استفاده می شود. این نوع ارتباط زمانی کاربرد دارد که هر رکورد در یک جدول دقیقاً با یک رکورد در جدول دیگر مرتبط است؛ مانند ارتباط میان کاربران و پروفایل ها، جایی که هر کاربر فقط یک پروفایل دارد و هر پروفایل متعلق به یک کاربر است.

برای تعریف این رابطه در مدل اصلی (مثلاً User)، از متد hasOne استفاده می شود:

public function profile()
{
return $this->hasOne(Profile::class);
}

در اینجا، متد hasOne مشخص می کند که هر کاربر، تنها یک رکورد در جدول profiles دارد. لاراول به صورت پیش فرض انتظار دارد کلید خارجی (user_id) در جدول profiles وجود داشته باشد تا بتواند ارتباط را برقرار کند.

در سمت دیگر رابطه، یعنی در مدل Profile، باید متد belongsTo تعریف شود تا مشخص شود هر پروفایل به کدام کاربر تعلق دارد:

public function user()
{
return $this->belongsTo(User::class);
}

متد belongsTo بیانگر این است که مدل فعلی (Profile) به مدل دیگر (User) وابسته است.

این ساختار ساده اما قدرتمند، خوانایی و هماهنگی بالایی میان داده ها ایجاد می کند. با استفاده از آن می توان به راحتی داده ها را واکشی کرد، مثلاً:

$user = User::find(1);
$profile = $user->profile;

رابطه یک به یک پایه ای ترین نوع روابط در Eloquent است که به کمک متدهای hasOne و belongsTo، اتصال داده ها را به شکل شفاف و کارآمد ممکن می سازد.

رابطه یک به چند (One to Many)

در معماری داده ها، یکی از پرکاربردترین روابط در Eloquent، رابطه یک به چند یا (One to Many Relationship) است. این نوع رابطه زمانی به کار می رود که یک موجودیت بتواند چندین رکورد وابسته در جدول دیگر داشته باشد. برای مثال، هر پست (Post) ممکن است دارای چندین نظر (Comment) باشد، اما هر نظر فقط به یک پست تعلق دارد.

در مدل Post، برای تعریف این ارتباط از متد hasMany استفاده می شود:

public function comments()
{
return $this->hasMany(Comment::class);
}

متد hasMany مشخص می کند که هر پست می تواند چندین نظر مرتبط داشته باشد. لاراول به صورت خودکار فرض می کند که جدول comments دارای ستونی به نام post_id است که به شناسه جدول posts اشاره دارد. این ساختار باعث می شود بتوان به سادگی تمامی نظرات یک پست را دریافت کرد:

$post = Post::find(1);
$comments = $post->comments;

در سمت دیگر رابطه، در مدل Comment، متد belongsTo تعریف می شود تا نشان دهد هر نظر به یک پست خاص تعلق دارد:

public function post()
{
return $this->belongsTo(Post::class);
}

این متد belongsTo مسیر معکوس رابطه را مشخص می کند و اجازه می دهد از طریق هر نظر، پست مرتبط با آن را فراخوانی کنیم.

رابطه یک به چند از پرکاربردترین الگوها در طراحی دیتابیس است و با ترکیب متدهای hasMany و belongsTo، کار با داده ها را در Eloquent طبیعی و ساده می سازد. این الگو زیربنای بسیاری از ساختارهای پیچیده تر مانند دسته بندی محصولات، مقالات و دیدگاه ها در فریم ورک لاراول است.

رابطه چند به چند (Many to Many)

در Eloquent، زمانی که دو موجودیت بتوانند هر دو به چندین رکورد از یکدیگر مرتبط باشند، از رابطه چند به چند یا (Many to Many Relationship) استفاده می شود. این نوع رابطه در مواردی مانند ارتباط بین کاربران و نقش ها کاربرد دارد؛ جایی که هر کاربر می تواند چندین نقش داشته باشد و هر نقش نیز می تواند به چند کاربر اختصاص یابد.

برای پیاده سازی این ساختار، از متد belongsToMany در هر دو مدل استفاده می شود. به عنوان مثال، در مدل User می نویسیم:

public function roles()
{
return $this->belongsToMany(Role::class);
}

و در مدل Role نیز:

public function users()
{
return $this->belongsToMany(User::class);
}

در این نوع رابطه، یک جدول واسط یا همان pivot table نقش اصلی را ایفا می کند. این جدول معمولاً شامل دو ستون است که کلیدهای خارجی از هر دو جدول اصلی را در خود ذخیره می کند. در مثال بالا، نام جدول واسط معمولاً role_user است و شامل ستون های user_id و role_id خواهد بود. لاراول به صورت خودکار این نام را تشخیص می دهد، اما در صورت نیاز می توان نام دلخواهی را نیز تعیین کرد.

با استفاده از این ساختار می توان به سادگی نقش های هر کاربر را دریافت کرد:

$user = User::find(1);
$roles = $user->roles;

همچنین می توان از متدهایی مانند attach()، detach() و sync() برای مدیریت داده های جدول واسط استفاده کرد.

رابطه چند به چند با کمک متد belongsToMany و جدول pivot table یکی از قدرتمندترین قابلیت های Eloquent است که امکان ایجاد ارتباطات پیچیده و پویا بین داده ها را فراهم می کند و در طراحی سیستم های کاربرمحور، مدیریت دسترسی ها و دسته بندی های پیشرفته نقشی حیاتی دارد. همین مدل سازی داده، هسته سامانه های کاربرمحور است؛ برای سفارش ساخت سامانه اختصاصی کد یاس را ببینید.

جمع بندی

اگر با معماری mvc در لاراول آشنا باشید میدانید که یکی از مهم ترین بخش ها مودل میباشد. در نهایت، Eloquent ORM قلب تعامل لاراول با پایگاه داده است؛ ابزاری که سادگی، سرعت و امنیت را در کنار هم فراهم می کند. با استفاده از مدل ها و روابط، می توان داده ها را به صورت شی گرا و خوانا مدیریت کرد. تسلط بر Eloquent، گامی اساسی برای ساخت پروژه های تمیز، قابل نگهداری و حرفه ای در دنیای لاراول است. اگر ترجیح می دهید همین بخش را تیم پیاده کند، خدمات طراحی سایت در شیراز کد یاس را ببینید.

اشتراک‌گذاری مقاله:

سوالات متداول

نظرات کاربران

ارسال نظر جدید

حداقل ۱۰ و حداکثر ۱۰۰۰ کاراکتر

هنوز نظری ثبت نشده است

اولین نفری باشید که دیدگاه خود را می‌نویسد!

مقالات مرتبط با این موضوع

مجموعه کاملی از مطالب تخصصی در این حوزه