-
المساهمات
3552 -
تاريخ الانضمام
-
تاريخ آخر زيارة
-
عدد الأيام التي تصدر بها
34
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو سمير عبود
-
يُمكن أن تأخذ الإجراءات بعض الوقت لذلك لا تقلق سيتم إعلامك مباشرة بعد الموافقة، إنتظر قليلاً لمدة أقصاها 24 ساعة و إن لم يتم التواصل معك حينها يُمكنك مراسلة الدعم الفني كما أخبرتك.
-
مرحباً @Ahmed Ali51 إذا كنت قد إشتركت في إحدى الدورات فإنه سيتم إرسال بريد إلكتروني لك للعنوان الذي اشتركت به يحتوي على كافة الإرشادات و الخطوات اللازمة للإلتحاق بالدورة التي اشتركت فيها. إذا لم يصلك أي بريد تأكد إن كنت لا تستطيع الوصول للدورة التي التحقت به من خلال القائمة العلوية: ثم الضغط على دوراتي، إذا لم يظهر لك ذلك يُمكنك مراسلة الدعم الفني من خلال: مركز المساعدة ثم فتح تذكرة و شرح المُشكلة لهم و سيتواصلون معك في أقرب وقت.
-
هناك طريقتين للتعامل مع قاعدة البيانات إما عن طريق ال eloquent orm و هي نفس الطريقة التي قد إستخدمناها في الدورات او عن طريق ال query builder. ال orm هو رابط الكائنات بالعلاقات و يعتمد بشكل أساسي على نماذج و الربط بينها عن طريق العلاقات وكل نموذج يتم ربطه مع جدول في قاعدة البيانات أما ال query builder او مُنشئ الإستعلامات و هي نفس الطريقة التي ذكرتها و نستخدم فيها ال DB facade و هي عبارة عن واجهة تسهل التعامل مع قاعدة البيانات بشكل سلس. كلا الطريقتين تؤديان نفس الغرض، و إن كانت طريقة مُنشئ الإستعلامات أسرع بنسبة صغيرة و افضل من ناحية الأداء من رابط الكائنات بالعلاقات في بعض الأحيان إلا أن مُعظم مُطوري لارافيل يستخدمون eloquent لكون الشيفرات التي يتم كتابتها به مقروءة بشكل كبير، إن كان المُطور سيعتمد بشكل كلي على query builder و لا يستعمل النماذج (models) نهائياً فإستعماله للإطار و لمفهوم MVC خاطئ خصوصا إن كان المشروع كبير و العلاقات الموجوة بين الجداول كثيرة، فإستعمال الquery builder لا يعني بالضرورة الإستغناء عن النماذج (models). و إستعمال الquery builder لا يعني بالضرورة أيضاً عدم إستخدام eloquent و العكس صحيح. شخصياً استخدم eloquent و أحياناً عندما يكون الإستعلام مُعقد قليلاً و كمية البيانات التي يتم معالجتها كبير جداً في عمليات البحث و الفلترة او جلب تقارير من بيانات ضخمة في هذه الحالة الأفضل إستخدام Query Builder.
- 3 اجابة
-
- 1
-
من بين المشاريع التي يُمكنك التدرب و تطبيق الأساسيات عليها هي مشروع بناء منتدى بسيط حيث يُمكن مبدئياً العمل على هذه الخصائص: في المنتدى مجموعة من الأعضاء يُمكنهم تسجيل الدخول و الخروج و الإشتراك إتاحة إنشاء مُساهمات داخل المُنتدى للأعضاء الردود على المُساهمات تصنيفات المُساهمات فلترة المُساهمات حسب التصنيفات فلترة المُساهمات حسب الأكثر شعبية و التي لم يتم الإجابة عنها. فلترة المُساهمات حسب المستخدمين إمكانية الإعجاب بالردود الحساب الشخصي لكل عضو عرض نشاط المستخدم في المنتدى إمكانية الإشتراك بمُساهمة بحيث عندما يتم إضافة رد عليها يتم إشعار المُشتركين بذلك و العديد من الخصائص التي بإمكانك إضافتها مع الوقت
- 3 اجابة
-
- 1
-
قد تحدث المُشكلة بسبب أحد النقاط التالية: أنك تقوم بتصفح الرابط بشكل خاطئ أي أن المسار الذي تُحاول الوصول إليه فعلاً غير موجود. فيجب التأكد من هذه النُقطة أولاً أن المسار الذي تحاول الوصول إليه مُتضارب مع مسار آخر موجود فوقه في الترتيب فإن كان لديك مسار آخر بالشكل التالي: Route::get('/threads/{thread}', [ThreadController::class, 'show']); Route::get('/threads/create', [ThreadController::class, 'create']); و كنت تُحاول الوصول إلى الرابط threads/create/ فلن يتم أخذ المسار الثاني بعين الإعتبار بل سيتم في هذه الحالة تنفيذ المسار الأول و تمرير الكلمة create كمُعامل للتابع show. لذلك إن أردت أن يكون المسار الخاص بالتابع create له اولوية ضعه فوق المسار الذي به مُعامل بهذا الشكل: Route::get('/threads/create', [ThreadController::class, 'create']); Route::get('/threads/{thread}', [ThreadController::class, 'show']); أن التطبيق الخاص بك يعمل بالcache أي أن المسارات مُخزنة في الcache فأي مسار جديد تقوم بإضافته لا يتم الإنتباه له و في هذه الحالة يجب عليك عمل clear لل cache الخاص بالمسارات بتنفيذ أحد هذه الأوامر: php artisan route:clear // او php artisan optimize:clear حيث أن الأمر الأخير يقوم بعمل clear لعدة أشياء ليس المسارات فحسب بل صفحات العرض و الإعدادات وما إلى ذلك.
- 2 اجابة
-
- 1
-
Mass Assignment او التعيين الجماعي هو عندما تقوم بإرسال مصفوفة بمفاتيح و قيم مُتنوعة للعملية إنشاء كائن ما سواء عن طريق الباني أو عن طريق دوال eloquent مثل create او update: <?php $model = new Model([ 'key1' => 'value1', 'key2' => 'value2', . . . ]); // او $model = Model::create([ 'key1' => 'value1', 'key2' => 'value2', . . . ]); // او $model->update([ 'key1' => 'value1', 'key2' => 'value2', . . . ]); في هذه الحالة لارافيل ستُحاول حمايتك تلقائياً من بعض الثغرات التي تُسببها هذه العملية. قد يظهر لك الأمر عادي لكن هذه العملية تحميك كثيرا مثلاً إذا كان لديك جدول للمُستخدمين و به عمود is_admin إذا كانت قيمته 1 فإن المُستخدم سيكون مُشرف في التطبيق، قد يستغل اي شخص ذلك و يُرسل حقل مخفي is_admin مع الطلب قيمته 1 و بالتالي سيُصبح مشرف بدل أن يكون مستخدم عادي. توفر laravel طريقة للحماية من هذا الأمر فيُمكنك مثلا إستخدام الطريقة العادية في إنشاء كائن جديد بتعيين الخصائص بشكل منفصل: <?php $model = new Model(); $model->prop1 = "value1"; $model->prop2 = "value2"; . . . $model->save(); لكن إن أردت إستخدام التعيين الجماعي يُمكنك إستخدام أحد المصفوفات fillable او guarded الموجودتان ضمن النموذج حيث في المصفوفة fillable تضع كافة الخصائص التي تريد أن تُعين جماعياً: protected $fillable = ['prop1', 'prop2']; أما المصفوفة guarded فتُستخدم لحماية بعض الخاصيات التي لا تريد أن تُعين جماعياً على سبيل المثال: protected $guarded = ['is_admin']; بطبيعة الحال يُمكنك فقط إستخدام أحد المصفوفتين فهما يعملان عكس بعضهما، ف fillable تعني القائمة البيضاء و guarded تعني القائمة السوداء أما بخصوص: غالباً ما يحدث هذا الخطأ بسبب csrf token تقوم لارافيل بحقنه في الجلسة و إرساله مع كل نموذج لذلك إن كان لديك نموذج form يجب عليك إضافة الحقل المخفي csrf سواء عن طريق: <form action="" method="post"> @csrf ... او عن طريق <form action="" method="post"> {{ csrf_field() }} ... أحيانا يكون هذا الحقل مُضمن في النموذج و يحدث الخطأ و ذلك راجع غالباً لإنتهاء الجلسة او أن الجلسة لم يتم حفظها بشكل جيد، إفتراضياً يتم حفظ الجلسات على شكل ملفات في المُجلد storage. قد لا تكون الصلاحيات المُطبقة على هذا المُجلد مناسبة مما لا يسمح بحفظ الملفات عليه.
- 2 اجابة
-
- 3
-
يُمكنك إنشاء أمر artisan خاص يقوم بعمل النُسخة التي تريدها عند تنفيذه و لإنشاء ذلك الأمر نقوم بدايةً بتنفيذ الأمر التالي: php artisan make:command DatabaseBackUp سيُنشئ لك الأمر صنف بالإسم DatabaseBackUp في المسار: app/Console/Commands/DatabaseBackUp تقوم بالتعديل عليه ليُصبح بالشكل التالي: <?php namespace App\Console\Commands; use Carbon\Carbon; use Illuminate\Console\Command; class DatabaseBackUp extends Command { protected $signature = 'database:backup'; protected $description = 'create database backup'; public function __construct() { parent::__construct(); } public function handle() { $filename = "backup-" . Carbon::now()->format('Y-m-d') . ".gz"; $command = "mysqldump --user=" . env('DB_USERNAME') ." --password=" . env('DB_PASSWORD') . " --host=" . env('DB_HOST') . " " . env('DB_DATABASE') . " | gzip > " . storage_path() . "/app/backup/" . $filename; $returnVar = NULL; $output = NULL; exec($command, $output, $returnVar); } } بعد ذلك تقوم بإنشاء مُجلد backup في المسار: storage/app/backup و عندما تريد إنشاء نُسخة من قاعدة البيانات فقط تقوم بتنفيذ الأمر: php artisan database:backup و هذا الأمر سيقوم بإنشاء نُسخة من قاعدة البيانات بنفس تاريخ تنفيذ الأمر. في المُجلد الذي أنشأناه.
- 2 اجابة
-
- 2
-
إسم الصنف هو about-me لكن عند تطبيقك للصنف في العنصر كتبت about me <!--start about me--> <div class="about me"> <div class="container"> <div class="image"> <img src="../image/300px.png" alt="test"> </div> <div class="info"> info test </div> </div> </div> <!--end about me--> هذا يعني أنك تُطبق صنفي تنسيقات على العُنصر أحدهما about و الثاني me لأنك فصلت الإثنين بمسافة. إذا كنت تريد تطبيق الصنف about-me عليك أن تكتبه بشكل صحيح: <div class="about-me"> </div>
-
يُمكن ذلك بإضافة حقل جديد لجدول المُستخدم banned_until و إستخدام middleware تعمل على منع المُستخدم من تسجيل الدخول إذا كان في فترة توقيف حسابه إضافة الحقل banned_until إلى جدول المستخدمين: php artisan make:migration add_banned_until_to_users_table هذا الأمر سيُنشئ ملف تهجير يُمكننا من إضافة حقل جديد لجدول المستخدمين. class AddBannedUntilToUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { $table->timestamp('banned_until')->nullable(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('banned_until'); }); } } بعد ذلك نقوم بتنفيذ أمر التهجير: php artisan migrate هذا يعني أن المُستخدم إن كانت banned_until فارغة أي null فإن الحساب نشيط، اما إن كان بالحقل تاريخ مُستقبلي فإن الحساب قد تم إيقافه. نضيف الحقل إلى مصفوفة fillable و مصفوفة dates في النموذج User و ذلك حتى نستطيع مُعاملة الحقل على أنه تاريخ: class User extends Authenticatable { protected $fillable = [ 'name', 'email', 'password', 'banned_until' ]; protected $dates = [ 'banned_until' ]; } نقوم بإنشاء middleware نُسميها CheckBanned بهذا الأمر: php artisan make:middleware CheckBanned سيتم إنشاء الmiddleware في المسار التالي app/Http/Middleware نقوم بفتح الملف و نُعدل على الدالة handle بالشكل التالي: <?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Str; class CheckBanned { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle(Request $request, Closure $next) { if (auth()->check() && auth()->user()->banned_until && now()->lessThan(auth()->user()->banned_until)) { $banned_days = now()->diffInDays(auth()->user()->banned_until); auth()->logout(); $message = 'Your account has been suspended for '.$banned_days.' '.Str::plural('day', $banned_days).'. Please contact administrator.'; return redirect()->route('login')->withMessage($message); } return $next($request); } } تعمل الmiddleware على التحقق من أن المُصادقة تمت أي أن المستخدم أدخل بيانات صحيحة، و أن الحقل banned_until لهذا المُستخدم ليس فارغ و أن الحقل به تاريخ مُستقبلي: إذا تحققت هذه الشروط تقوم بحساب فارق الأيام بين التاريخ الحالي و تاريخ الإيقاف و تقوم بتسجيل خروج للمُستخدم و إعادة توجيهه إلى صفحة تسجيل الخروج مع تمرير الرسالة. يُمكن تمرير رسالة مُختلفة بحسب عدد الأيام كأن نتحقق إن كان عدد الأيام أقل من 20 نعرض عدد الأيام و إذا كان عدد الأيام اكبر لا نعرض عدد الأيام. فقط نقول أن الحساب تم إيقافه و لا نذكر المدة. الأمر راجع لك في هذه النقطة. يتبقى تسجيل هذه الmiddleware و يتم ذلك على مستوى الملف app/Http/Kernel.php في المصفوفة middlewareGroups داخل المصفوفة ذات المفتاح web: protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, // ... other middleware classes \App\Http\Middleware\CheckBanned::class, ], الآن نقوم بعرض الرسالة في حالة كانت موجودة على مستوى صفحة العرض login.blade.php: <div class="card-body"> @if (session('message')) <div class="alert alert-danger">{{ session('message') }}</div> @endif <form method="POST" action="{{ route('login') }}"> ... و هذه النتيجة:
- 2 اجابة
-
- 2
-
بإمكانك إستخدام أمر إنشاء ملف تهجير فملفات التهجير ليست مُخصصة فقط لإنشاء الجداول و إنما تُمكنك أيضاً من إضافة عمود جديد لجدول بيانات أيضاً. لنفترض أننا نريد إضافة عمود age للجدول users فيتم ذلك عن طريق الأمر التالي: php artisan make:migration add_age_to_users_table هذا الأمر سيُنشئ لنا ملف migration جديد و سيحتوي على الصنف التالي: class AddAgeToUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { }); } } الآن نقوم بإضافة العمود في الدالة up و من خلال الدالة down نقوم بحذفه كما هو موضح أدناه: <?php public function up() { Schema::table('users', function (Blueprint $table) { $table->unsignedTinyInteger('age')->nullable()->after('username'); }); } و هذا يعني أننا نريد إضافة العمود age على أنه unsignedTinyInteger إضافة الى أنه سيكون فارغ إفتراضياً و سيُضاف بعد العمود username. أما الدالة down ستكون بهذا الشكل: <?php public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('age'); }); } و بالتالي كل ما عليك الآن هو تنفيذ امر التهجير: php artisan migrate هذا الأمر سيُنفذ الدالة up و يُضيف العمود الجديد. أما الدالة down يتم تنفيذها عند تنفيذ أمر rollback الذي سيحذف العمود age.
- 1 جواب
-
- 2
-
NullPointerException هو عبارة عن إستثناء يتم رميه عندما تقوم بتعريف متغير ولكنك لم تقم بإنشاء كائن وتعيينه إلى هذا المتغير أي أنه يكون يشير إلى Null ثم تستدعي أحد الدوال عليه. في الحالات العادية عند إنشائك لمُتغير و لا تقوم بإسناد أي قيمة له ثم تحاول إستخدام هذا المُتغير سينتبه مُترجم اللغة مثلا إن قمت بالتالي: Employee e; System.out.println(e); سيُعطيك المُترجم الخطأ التالي: variable e might not have been initialized لكن أحياناً أخرى قد تكتب كود لا يقوم بإنشاء الكائن مُباشرة بل يتم إنشاؤه بشكل غير مُباشر مثلاً: لدينا صنف الموظف التالي: class Employee{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return name.toUpperCase(); } } ثم نقوم بإنشاء كائن من الصنف Employee بهذا الشكل: Employee e = new Employee(); إلى الآن لا توجد أي مُشكلة، لكن في هذه اللحظة عند إنشائنا لكائن من النوع Employee فإن الخاصية name تُشير إلى null و بالتالي إذا ما قمنا بطباعة المُتغير e بهذا الشكل: System.out.println(e); فإنه سيتم إستدعاء الدالة toString وهذه الدالة تقوم بإرجاع الإسم بحروف كبيرة أي تستدعي الدالة toUpperCase على الخاصية name لكن كما تعلم فنحن لم نُسند للخاصية name اي قيمة فهي تُشير إلى null و هنا سيتم رمي الإستثناء NullPointerException. طرق مُعالجة الأمر كثيرة فمثلاً يُمكنك إستخدام try catch و يتم ذلك بوضع الكود الذي نشك أن فيه خلل و أنه سيُسبب في رمي الإستثناء في البلوك try و في البلوك catch نقوم بالمعالجة try { Employee e = new Employee(); System.out.println(e); } catch (NullPointerException ex) { System.out.println(ex.getMessage()); } . او نقوم بالتحقق من المُتغير إذا كان لا يُساوي null نقوم بالعملية التي نريد بهذا الشكل في مثالنا: @Override public String toString() { if (name != null) return name.toUpperCase(); return "Employee name property == null"; }
-
لا أدري ماذا يوجد في الملف a.txt لديك لكن كما أخبرتك سابقاً يُمكن إستخدام مُتغير من نوع string تُخزن فيه مُحتوى الملف a.txt ثم تكتب ما خزنته بإستعمال الدالة fputs في الملف الذي تريد بهذا الشكل: #include <stdio.h> #include <string> using namespace std; int main () { FILE *fp; string content = "content of source file"; fp = fopen("file.txt", "w"); fputs(content.c_str(), fp); fclose(fp); return(0); }
-
لم أفهم ماذا تريد بالضبط في هذه النقطة: الإنسان حتى ينقل محتوى ملف يقرأ من الملف الأول ثم يُخزن ما قرأ في ذاكرته و بعد ذلك يكتب ماهو موجود في ذاكرته، نفس الشيء تقريباً هنا يجب فتح الملف الأول للقراءة و الثاني للكتابة ثم كل حرف تقرأه من الملف الأول تكتبه في الملف الثاني حتى نصل للنهاية.
-
يوجد لديك خطأ في إستعمال الدالة fputs هذه الدالة تستقبل سلسلة نصية على شكل مصفوفة محارف كمُعامل أول و مؤشر على File كمُعامل ثاني بهذا الشكل مثلاً: #include <stdio.h> int main () { FILE *fp; fp = fopen("file.txt", "w+"); fputs("This is c programming.", fp); fclose(fp); return(0); } أنت لم تقرأ شيء من الملف الذي تريد نقل مُحتواه فللكتابة في الملف الثاني يجب قراءة مُحتوى الملف الأول ثم نقله للملف الثاني بهذا الشكل مثلاً: #include <iostream> #include <stdio.h> using namespace std; int main() { FILE* pFile; // المصدر FILE* pofg; // الخرج char ch; // مُتغير سنستخدمه للقراءة pFile = fopen("a.txt", "r"); // فتح المصدر للقراءة pofg = fopen("abc.txt", "w"); // فتح الخرج للكتابة if (pFile != NULL) // إذا كان المصدر لا يُساوي null { ch = fgetc(pFile); // قراءة المحرف الأول من المصدر while(ch != EOF) // بما اننا لم نصل إلى نهاية الملف { fputc(ch, pofg); // أكتب في الخرج ما قمت بقرائته ch = fgetc(pFile); // واصل القراءة } cout<<"\nFile copied successfully."; // تم نقل المحتوى fclose(pFile); // غلق المصدر fclose(pofg); // غلق الخرج } return 0; }
- 6 اجابة
-
- 1
-
لنفترض أنه لديك حقل username في جدول المُستخدمين بهذا الشكل: $table->string('username')->unique(); الآن يجب أن تُعدل على نموذج تسجيل الدخول و بالضبط في حقل البريد ليُصبح بهذا الشكل: <div class="form-group row"> <label for="login" class="col-md-4 col-form-label text-md-right">{{ __('Username or Email') }}</label> <div class="col-md-6"> <input id="login" type="text" class="form-control{{ $errors->has('username') || $errors->has('email') ? ' is-invalid' : '' }}" name="login" value="{{ old('username') ?: old('email') }}" required autofocus> @if ($errors->has('username') || $errors->has('email')) <span class="invalid-feedback"> <strong>{{ $errors->first('username') ?: $errors->first('email') }}</strong> </span> @endif </div> </div> في ملف login.blade.php، و هذا حتى يقبل الحقل إدخال نص و عرض رسائل الخطأ. الآن يجب التعديل على المُتحكم LoginController سنُجري عليه بعض التعديلات حتى يُلائم الوضعية: نضيف الخاصية التالية للمُتحكم: protected $username; ثم من خلال الباني نقوم بتهيئة هذه الخاصية: public function __construct() { $this->middleware('guest')->except('logout'); $this->username = $this->findUsername(); } لاحظ أنها تأخذ قيمتها من خلال ما يُرجعه التابع findUsername لذلك نقوم بإنشائه في المتحكم أيضاً: <?php public function findUsername() { $login = request()->input('login'); // جلب قيمة النص الذي أدخله المُستخدم في الحقل $fieldType = filter_var($login, FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; // بإستخدام القيمة يُمكننا معرفة إن كان المُدخل بريد او نص و على اساسها نضع نوع الحقل request()->merge([$fieldType => $login]); // وضع حقل جديد في الطلب return $fieldType; // email or username } كل ما يفعله التابع أنه يجلب لنا email او username على حسب القيمة المُدخلة و يضيف ذلك لمصفوفة الطلب: إذا كان المُدخل بريداً: 'email' => 'قيمة الحقل' إذا لم يكن بريد إلكتروني: 'username' => 'قيمة الحقل' الآن نقوم بإعادة تعريف كل من التابع username و التابع login اللذان يستخدمها المُتحكم LoginController إعتمادًا على الTrait AuthenticatesUsers لن نُغير على التابع login كثيراً سنأخذه كما هو و نضيف بعض الأشياء فقط: التابع username: <?php public function username() { return $this->username; } التابع login: <?php public function login(Request $request) { //نُغير التحقق $this->validate($request, [ 'login' => 'required|string', 'password' => 'required|string', ]); // نجلب نوع التسجيل $login_type = filter_var($request->input('login'), FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; // نضيفه لمصفوفة الطلب $request->merge([ $login_type => $request->input('login') ]); // بقية الأشياء موجودة من الإطار نفسه و لن نغير فيها // If the class is using the ThrottlesLogins trait, we can automatically throttle // the login attempts for this application. We'll key this by the username and // the IP address of the client making these requests into this application. if (method_exists($this, 'hasTooManyLoginAttempts') && $this->hasTooManyLoginAttempts($request)) { $this->fireLockoutEvent($request); return $this->sendLockoutResponse($request); } if ($this->attemptLogin($request)) { return $this->sendLoginResponse($request); } // If the login attempt was unsuccessful we will increment the number of attempts // to login and redirect the user back to the login form. Of course, when this // user surpasses their maximum number of attempts they will get locked out. $this->incrementLoginAttempts($request); return $this->sendFailedLoginResponse($request); } لا تنسى إستدعاء الكلاسات المُستخدم في المُتحكم. هذا مُحتوى المُتحكم LoginController بعد التعديلات المُضافة: <?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Providers\RouteServiceProvider; use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Http\Request; class LoginController extends Controller { /* |-------------------------------------------------------------------------- | Login Controller |-------------------------------------------------------------------------- | | This controller handles authenticating users for the application and | redirecting them to your home screen. The controller uses a trait | to conveniently provide its functionality to your applications. | */ use AuthenticatesUsers; /** * Where to redirect users after login. * * @var string */ protected $redirectTo = RouteServiceProvider::HOME; protected $username; /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('guest')->except('logout'); $this->username = $this->findUsername(); } public function findUsername() { $login = request()->input('login'); $fieldType = filter_var($login, FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; request()->merge([$fieldType => $login]); return $fieldType; } public function username() { return $this->username; } public function login(Request $request) { $this->validate($request, [ 'login' => 'required|string', 'password' => 'required|string', ]); $login_type = filter_var($request->input('login'), FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; $request->merge([ $login_type => $request->input('login') ]); // If the class is using the ThrottlesLogins trait, we can automatically throttle // the login attempts for this application. We'll key this by the username and // the IP address of the client making these requests into this application. if (method_exists($this, 'hasTooManyLoginAttempts') && $this->hasTooManyLoginAttempts($request)) { $this->fireLockoutEvent($request); return $this->sendLockoutResponse($request); } if ($this->attemptLogin($request)) { return $this->sendLoginResponse($request); } // If the login attempt was unsuccessful we will increment the number of attempts // to login and redirect the user back to the login form. Of course, when this // user surpasses their maximum number of attempts they will get locked out. $this->incrementLoginAttempts($request); return $this->sendFailedLoginResponse($request); } } ملاحظة: هذه الطريقة مُستخدمة على إصدار 8 من لارافيل، بإستعمال الحزمة Laravel/ui
- 2 اجابة
-
- 1
-
هناك عدة حزم مُعظم المُطورون يستخدمون إحداها لعمل هذه الجزئية في مشروعهم و من هذه الحزم أذكر: Laravel-permission التي تم تطويرها من طرف spatie و هم معروفين بتطوير عدة حزم مشهورة و مُستخدمة و يُطورون عليها بإستمرار. bouncer من تطوير Joseph Silber Laratrust هذه الحزم أكثر إستخداماً في هذا الموضوع و هي تُحدث بإستمرار حتى تدعم الإصدارات الجديدة من إطار laravel. إن كنت تريد إنجاز هذا الأمر فستتعب قليلاً و هذه الخطوات يُمكنك تطبيقها للوصول إلى ما تريد: إنشاء مودل لكل من Role و Permission و ملف تهجير لكل منهما: php artisan make:model Permission -m php artisan make:model Role -m كما تعلم فتمرير -m يعني أننا نريد إنشاء ملف تهجير أيضاً. تعديل ملفات التهجير: ملف تهجير الصلاحيات: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreatePermissionsTable extends Migration { public function up() { Schema::create('permissions', function (Blueprint $table) { $table->id(); $table->string('name'); // edit posts $table->string('slug'); //edit-posts $table->timestamps(); }); } public function down() { Schema::dropIfExists('permissions'); } } ملف تهجير الأدوار: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateRolesTable extends Migration { public function up() { Schema::create('roles', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('slug'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('roles'); } } إنشاء ملفات تهجير الجداول الإضافية لربط الصلاحيات بالمستخدمين و ربط الصلاحيات بالأدوار و ربط الأدوار بالمُستخدمين: php artisan make:migration create_users_permissions_table --create=users_permissions php artisan make:migration create_users_roles_table --create=users_roles php artisan make:migration create_roles_permissions_table --create=roles_permissions و في ما يلي مُحتوى ملفات التهجير التي أنشأناها: جدول users_permissions: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersPermissionsTable extends Migration { public function up() { Schema::create('users_permissions', function (Blueprint $table) { $table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('permission_id'); //FOREIGN KEY CONSTRAINTS $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade'); //SETTING THE PRIMARY KEYS $table->primary(['user_id','permission_id']); }); } public function down() { Schema::dropIfExists('users_permissions'); } } جدول users_roles: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersRolesTable extends Migration { public function up() { Schema::create('users_roles', function (Blueprint $table) { $table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('role_id'); //FOREIGN KEY CONSTRAINTS $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade'); //SETTING THE PRIMARY KEYS $table->primary(['user_id','role_id']); }); } public function down() { Schema::dropIfExists('users_roles'); } } جدول roles_permissions: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateRolesPermissionsTable extends Migration { public function up() { Schema::create('roles_permissions', function (Blueprint $table) { $table->unsignedBigInteger('role_id'); $table->unsignedBigInteger('permission_id'); //FOREIGN KEY CONSTRAINTS $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade'); $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade'); //SETTING THE PRIMARY KEYS $table->primary(['role_id','permission_id']); }); } public function down() { Schema::dropIfExists('roles_permissions'); } } نقوم بعملية التهجير: php artisan migrate إنشاء العلاقات بين النماذج علاقات النموذج Role: public function permissions() { return $this->belongsToMany(Permission::class,'roles_permissions'); } public function users() { return $this->belongsToMany(User::class,'users_roles'); } علاقات النموذج Permission: public function roles() { return $this->belongsToMany(Role::class,'roles_permissions'); } public function users() { return $this->belongsToMany(User::class,'users_permissions'); } إنشاء Trait لإستخدامه في النموذج User، في مٌجلد app نقوم بإنشاء مُجلد Permissions و نضع بداخله ملف HasPermissionsTrait.php ثم نقوم بتضمينه داخل النموذج User: <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use App\Permissions\HasPermissionsTrait; class User extends Authenticatable { use HasFactory, Notifiable, HasPermissionsTrait; } يكون مُحتوى الملف HasPermissionsTrait بالشكل التالي: <?php namespace App\Permissions; use App\Models\Permission; use App\Models\Role; trait HasPermissionsTrait { public function givePermissionsTo(... $permissions) { $permissions = $this->getAllPermissions($permissions); if($permissions === null) { return $this; } $this->permissions()->saveMany($permissions); return $this; } public function withdrawPermissionsTo( ... $permissions ) { $permissions = $this->getAllPermissions($permissions); $this->permissions()->detach($permissions); return $this; } public function refreshPermissions( ... $permissions ) { $this->permissions()->detach(); return $this->givePermissionsTo($permissions); } public function hasPermissionTo($permission) { return $this->hasPermissionThroughRole($permission) || $this->hasPermission($permission); } public function hasPermissionThroughRole($permission) { foreach ($permission->roles as $role){ if($this->roles->contains($role)) { return true; } } return false; } public function hasRole( ... $roles ) { foreach ($roles as $role) { if ($this->roles->contains('slug', $role)) { return true; } } return false; } public function roles() { return $this->belongsToMany(Role::class,'users_roles'); } public function permissions() { return $this->belongsToMany(Permission::class,'users_permissions'); } protected function hasPermission($permission) { return (bool) $this->permissions->where('slug', $permission->slug)->count(); } protected function getAllPermissions(array $permissions) { return Permission::whereIn('slug',$permissions)->get(); } } إنشاء مُزود خدمة PermissionsServiceProvider: php artisan make:provider PermissionsServiceProvider نقوم بإضافة blade directive فيه و تعريف بوابة Gate من أجل كل صلاحية في الدالة boot: <?php namespace App\Providers; use App\Models\Permission; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Gate; use Illuminate\Support\ServiceProvider; class PermissionsServiceProvider extends ServiceProvider { public function register() { // } public function boot() { try { Permission::get()->map(function ($permission) { Gate::define($permission->slug, function ($user) use ($permission) { return $user->hasPermissionTo($permission); }); }); } catch (\Exception $e) { report($e); return false; } //Blade directives Blade::directive('role', function ($role) { return "if(auth()->check() && auth()->user()->hasRole({$role})) :"; //return this if statement inside php tag }); Blade::directive('endrole', function ($role) { return "endif;"; //return this endif statement inside php tag }); } } بعد ذلك نقوم بتسجيل مُزود الخدمة في مصفوفة providers في الملف config\app.php: 'providers' => [ App\Providers\PermissionsServiceProvider::class, ], الآن تحتاج إلا إضافة بعض البيانات الإختبارية ملف بذر لكل من الصلاحيات و الأدوار و تضع فيه كل صلاحيات الموقع و بعض الأدوار التي تريد أن تكون ضمن تطبيقك و تربط الصلاحيات بالأدوار ثم تربط الأدوار بالمُستخدمين. <?php $admin_permission = Permission::where('slug','create-users')->first(); $manager_permission = Permission::where('slug', 'edit-users')->first(); //RoleTableSeeder.php $admin_role = new Role(); $admin_role->slug = 'admin'; $admin_role->name = 'Admin Role'; $admin_role->save(); $admin_role->permissions()->attach($admin_permission); $manager_role = new Role(); $manager_role->slug = 'manager'; $manager_role->name = 'Assistant Manager'; $manager_role->save(); $manager_role->permissions()->attach($manager_permission); $admin_role = Role::where('slug','admin')->first(); $manager_role = Role::where('slug', 'manager')->first(); $createUsers = new Permission(); $createUsers->slug = 'create-users'; $createUsers->name = 'Create Users'; $createUsers->save(); $createUsers->roles()->attach($admin_role); $editUsers = new Permission(); $editUsers->slug = 'edit-users'; $editUsers->name = 'Edit Users'; $editUsers->save(); $editUsers->roles()->attach($manager_role); $admin_role = Role::where('slug','admin')->first(); $manager_role = Role::where('slug', 'manager')->first(); $admin_perm = Permission::where('slug','create-users')->first(); $manager_perm = Permission::where('slug','edit-users')->first(); $admin = new User(); $admin->name = 'Samir Abboud'; $admin->email = 'samir@gmail.com'; $admin->password = bcrypt('password'); $admin->save(); $admin->roles()->attach($admin_role); $admin->permissions()->attach($admin_perm); $manager = new User(); $manager->name = 'Kamel Mahmoudi'; $manager->email = 'kamel@gmail.com'; $manager->password = bcrypt('password'); $manager->save(); $manager->roles()->attach($manager_role); $manager->permissions()->attach($manager_perm); يُمكنك إستخدام tinker لعمل test: $admin = User::where('email', 'samir@gmail.com')->first(); $admin->hasRole('admin'); // لفحص إن كان المُستخدم يملك الدور مدير $admin->givePermissionsTo('edit-users') // إعطاء المُستخدم صلاحية تعديل مُستخدمين $admin->can('create-users') // فحص المُستخدم إذا كان لديه صلاحية إنشاء مُستخدم في صفحات العرض يُمكن إستخدام التوجيه الذي أنشأناه: @role('admin') مرحبا مدير @endrole الخطوة الأخيرة هي إنشاء middleware لعدم السماح للمُستخدم الوصول إلى مسار مُحدد إذا لم يكن يملك الصلاحية: php artisan make:middleware RoleMiddleware php artisan make:middleware PermissionMiddleware <?php namespace App\Http\Middleware; use Closure; class RoleMiddleware { public function handle($request, Closure $next, $role) { if (!auth()->check()) { return redirect()->route('login'); } if(!auth()->user()->hasRole($role)) { abort(403); } return $next($request); } } <?php namespace App\Http\Middleware; use Closure; class PermissionMiddleware { public function handle($request, Closure $next, $permission) { if (!auth()->check()) { return redirect()->route('login'); } if(!auth()->user()->can($permission)) { abort(403); } return $next($request); } } بعد ذلك تقوم بتسجيل هاتين الmiddleware ضمن App\Http\Kernel.php في مصفوفة routeMiddleware: <?php protected $routeMiddleware = [ . . 'role' => \App\Http\Middleware\RoleMiddleware::class, 'permission' => \App\Http\Middleware\PermissionMiddleware::class, ]; الآن يتبقى فقط الإستخدام في ملف المسارات: <?php Route::group(['middleware' => 'role:admin'], function() { // مسارات المُستخدم الذي يملك الدور مدير }); أو من خلال باني المُتحكم: public function __construct() { $this->middleware('permission:create-users')->only(['create', 'store']); } إن كنت ستستخدم حزمة جاهزة فستجد كل هذه الخصائص موجودة فيها و ستجدها قد تم إختبارها بإستعمال الإختبارات الأحادية أيضاً.
- 3 اجابة
-
- 2
-
يُمكن إستخدام eloquent لحذف السجلات بشكل ناعم، عند الحذف الناعم للسجل، لن تُحذف السجلات فعليًّا، وإنما ستُعيّن الخاصية deleted_at على السجل وتُحفظ في قاعدة البيانات. في حال كان السجل يملك قيمة deleted_at غير فارغة non-null، هذا يعني أنه قد حُذف. لتمكين الحذف الناعم لسجل ما نضيف ال trait SoftDeletes للمودل الذي نريد أن يُطبق الحذف الناعم: <?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class User extends Model { use SoftDeletes; } و نضيف العمود deleted_at لملف التهجير الخاص بالمودل: <?php Schema::table('users', function ($table) { // other fields $table->softDeletes(); }); بهذا الشكل عند إستخدام التابع delete على أي كائن من الصنف User: <?php $user = User::find(1); $user->delete(); لن يتم حذفه فعلياً بل سيتم تعديل السجل بتعديل قيمة deleted_at إلى التاريخ الذي تم حذف السجل فيه. و سيبقى في قاعدة البيانات، و عند الإستعلام على المُستخدمين: <?php $users = User::all(); لن تظهر السجلات المحذوفة بشكل ناعم مع السجلات الكلية. هناك عدة توابع أخرى يُمكن إستخدامها لمعرفة ما إذا كان سجل ما محذوف بشكل ناعم، او جلب السجلات المحذوفة ناعماً بالإضافة إلى عملية إسترجاع هذه السجلات يُمكنك الإطلاع عليها من خلال توثيق موسوعة حسوب: الحذف الناعم (Soft Deleting)
- 3 اجابة
-
- 1
-
يبدو أن الأمور مُختلطة عليك قليلاً، في المُتحكم كل تابع يُؤدي مهمة مُعينة مثلاً إن قمنا بإنشاء مُتحكم PostController فالتابع index مسؤول عن إرجاع صفحة عرض واحدة و تمرير المقالات لها مثلا بهذا الشكل: <?php public function index() { $posts = Post::latest()->get(); return view("posts.index", compact('posts')); } إذا أضفنا أي كود بعد التعليمة return هذا الكود يُسمى dead code و لن يتم تنفيذه، أي ما تُحاولين القيام به غير مُمكن. بما أنك تريدين القيام بجزء لوحة التحكم و جزء الواجهة فيُنصح بفصل الجزئين عن بعضهما و هذا ما أفعله: إنشاء مُجلد خاص لمُتحكمات لوحة التحكم و ليكن Dashboard داخل مُجلد Controllers و أي مُتحكم أحتاجه في لوحة التحكم أضعه فيه. أحيانا قد يكون المشروع كبير فالأحسن إنشاء ملف مسارات خاص بلوحة التحكم أيضاً مثلاً admin.php و نضع فيه كافة مسارات لوحة التحكم سيكون بهذا الشكل مثلاً: <?php use Illuminate\Support\Facades\Route; Route::prefix('dashboard') ->name('dashboard.') ->group(function () { // هنا نضع أي مسار خاص بلوحة التحكم و أي مسار يكون مسبوق تلقائياً ب dashboard في الرابط }); الآن يجب أن نُخبر laravel أن هناك ملف مسارات جديد يجب أن تأخذه بعين الإعتبار و يتم ذلك على مُستوى مزود الخدمة RouteServiceProvider: اولاً نُضيف مجال الأسماء لمُتحكمات لوحة التحكم في مُتغير: <?php protected $dashboard_namespace = 'App\Http\Controllers\Dashboard'; حيث كافة المتحكمات الموجودة في المُجلد Dashboard الذي أنشأناه سابقاً يجب أن تكون تابعة لهذا المجال. ثانياً في التابع map نضيف سطر جديد لعمل map لمسارات ملف admin.php بهذا الشكل: <?php public function map() { $this->mapApiRoutes(); // هذا السطر يكون موجود $this->mapWebRoutes(); // هذا السطر يكون موجود ايضاً $this->mapDashboardRoutes(); // هذا ما نضيفه // } ثالثاً بعدما استدعينا التابع mapDashboardRoutes نقوم بإنشائه لأنه لن يكون موجوداً ضمن نفس مزود الخدمة: <?php protected function mapDashboardRoutes() { Route::middleware('web') ->namespace($this->dashboard_namespace) // هذا السطر لتحديد مجال الأسماء ->group(base_path('routes/admin.php')); // و هنا حددنا ملف المسارات } الآن بعدما أعددنا كل شيء نحتاج فقط لإضافة المسار الذي نُريده و المتحكم الذي نريده مثلاً نريد عرض المقالات في لوحة التحكم فنُنشئ المسار على شكل resource لأنه سيضم مُختلف العمليات في ملف مسارات لوحة التحكم admin.php: <?php use Illuminate\Support\Facades\Route; Route::prefix('dashboard') ->name('dashboard.') ->group(function () { // admins routes Route::resource('posts', 'PostController'); }); بعدما أعددنا المسار نحتاج إنشاء مُتحكم للمقالات PostController في المُجلد Dashboard الذي أنشأناه سابقاً: <?php namespace App\Http\Controllers\Dashboard; use App\Http\Controllers\Controller; use App\Post; class PostController extends Controller { public function index() { $posts = Post::latest()->get(); return view('dashboard.posts.index', compact('posts')); } } هذا يعني أننا سنُضيف مُجلد dashboard داخل مُجلد views و فيه نضع كافة صفحات العرض الخاصة بلوحة التحكم، و بما أننا نعمل على المقالات فسنضع مُجلد إسمه posts و فيه نضع كافة صفحات العرض الخاصة بالمقالات: views |_ dashboard |__|___ posts |__|____|__ index.blade.php |__|____|__ create.blade.php |__|____|__ edit.blade.php |__|____|__ show.blade.php |__|___ categories |__|____|__ index.blade.php |__|____|__ create.blade.php |__|____|__ edit.blade.php |__|____|__ show.blade.php |... هذا فيما يخص جزء لوحة التحكم، فيما يخص جزء الواجهة فسيبقى كما كان، المسارات الخاصة به سيتم وضعها في ملف web.php و المُتحكمات الخاصة به ستكون في مُجلد Controllers مُباشرة، يُمكنك التنظيم أيضاً فبما أننا وضعنا مُجلد يضم كافة صفحات العرض الخاصة بلوحة التحكم يُمكنك وضع مُجلد يضم كافة صفحات العرض الخاصة بالواجهة، الأمر يعود لك بهذا الخصوص. الآن إذا اردنا الذهاب إلى صفحة المقالات الموجودة في لوحة التحكم سنستعرض الرابط التالي: /dashboard/posts أما صفحة المقالات الخاصة بالواجهة: /posts بالتوفيق.
- 10 اجابة
-
- 2
-
يُمكن ذلك عن طريق: Model::latest()->get() بهذا الشكل سيتم ترتيب السجل على حسب تاريخ إنشائها أي حسب العمود created_at من الأحدث تنازلياً إلى الأقدم. إذا أردت الترتيب عن طريق عمود آخر بشكل تنازلي: Model::orderByDesc('column_name')->get(); // او Model::orderBy('column_name', "desc")->get(); أما: Model::orderBy('column_name')->get(); // او Model::orderBy('column_name', 'asc')->get(); فهما نفس الشيء و سيتم الترتيب تصاعدياً.
-
قد تلاحظين أن في laravel هناك عدة طرق للوصول إلى ما نريد، لذلك في هذه الحالة لا يوجد فرق، whereIn تُستخدم لإنشاء الإستعلام الذي نريده و get هي التي تقوم بتطبيق الإستعلام و إرجاع النتائج، بعكس find التي تقوم بالإثنين معاً، أحياناً قد لا نريد جلب السجلات بل نريد حذفها مثلاً او إجراء عملية أخرى و في هذه الحالة لن تُساعدنا find، يُمكن إستخدامها لكن سنقوم في هذه الحالة بإجراء إستعلامات زائدة لا داعي لها. فإذا كنا نريد الحذف لماذا نجلب البيانات ما دُمنا نستطيع حذفها مُباشرة: Model::whereIn('id', [1, 2])->delete();
- 23 اجابة
-
- 1
-
لجلب سجلات مُحددة عن طريق id النموذج مثلاً 1، 4، و 9 نقوم بإستعمال التابع find على الmodel و تمرير مصفوفة تضم المُعرفات التي نريد جلب سجلاتها: Model::find([1, 4, 9]); أي أننا إن أردنا جلب المُستخدم الأول و الثاني يُمكننا إستخدام: User::find([1, 2]); أما إن كنا نريد جلب سجلين عشوائيين يُمكن إستخدام هذه الطريق: Model::inRandomOrder()->limit(2)->get(); الفرق بين first و get أن first يجلب أول سجل يُطابق الإستعلام، أما get تجلب كل السجلات التي تُطابق الإستعلام على شكل collection، مجموعة سجلات
- 23 اجابة
-
- 1
-
إذا كنت تريد وضع خاصية الإتصال بقاعدة البيانات في الصنف Teacher فطريقة فهمك للبرمجة الكائنية خاطئة، إسأل نفسك هل الأستاذ لديه خاصية إسمها إتصال بقاعدة بيانات لا فهذا غير منطقي، يُمكن أن يكون للأستاذ إسم و لقب يُمكن أن يكون له سنوات خبرة كم، راتبه هذه الأشياء المُتعلقة بالأستاذ يُمكن وضعها في الصنف الخاص به، أما ما تُحاول القيام به فهو غير منطقي، الصواب هو أن تقوم ببناء كلاس يتعلق بقاعدة البيانات و تضع الأشياء المُتعلقة بقاعدة البيانات فيه مثلا كلاس إسمه Database
-
يُمكن حماية المسار بإستخدام الطبقة الوسيطة أو الmiddleware المُسماة auth بهذا الشكل: Route::post('threads/{thread}/replies', [ReplyController::class, 'store'])->middleware('auth'); أو يُمكنك عمل ذلك في المُتحكم ReplyController لأنه سيعطيك حرية أكثر من خلال الباني: <?php class ReplyController extends Controller { public function __construct() { $this->middleware('auth')->only('store'); } } من خلال التابع only يُمكنك تحديد التوابع التي تريد تطبيق الmiddleware عليها. أما في جزء العرض فيُمكنك إستخدام توجيه مُحرك blade الذي يُكتب: @auth أو إستخدم شرط بسيط للتحقق من أن المُصادقة مُحققة: @if(auth()->check()) بهذا الشكل ككل: @auth <div class="row justify-content-center mt-3"> <div class="col-md-8"> <form action="{{ $thread->path . "/replies" }}" method="post"> @csrf <div class="form-group"> <textarea name="body" class="form-control" rows="5" placeholder="Have something to say?"></textarea> </div> <button type="submit" class="btn btn-secondary">Post</button> </form> </div> </div> @else <p class="text-center mt-3">Please <a href="{{ route('login') }}">sign in</a> to participate in this discussion.</p> @endauth و هكذا سيتم عرض النموذج إلا في حالة كان هناك مُستخدم مُصادق عليه أما إن كان زائر سيتم عرض رابط يُخبره بضرورة تسجيل الدخول لإضافة تعليق.
- 2 اجابة
-
- 2
-
لا نقوم ببذر الصور و إنما أسماء هذه الصور أو المسار الخاص بها بعد رفعها في التطبيق. على سبيل المثال نريد بذر مجموعة من المُستخدمين 5 حيث لكل مُستخدم صورة و ملف التهجير الخاص بالمُستخدمين يحتوي على حقل صورة بهذا الشكل: <?php $table->string('image')->default('default.jpg'); نقوم برفع الصور إلى ملف public و نضعها في مُجلد images و لتكن الصور بالأسماء التالية مثلاً 1.png 2.png 3.png 4.png 5.png لدينا factory خاص بالنموذج User لإنشاء مُستخدم. و قمنا أيضاً بإنشاء Seeder خاص بالمستخدمين في ملف البذر نقوم بالتالي: <?php public function run() { $images = array( '1.png', '2.png', '3.png', '4.png', '5.png' ); foreach($images as $image) { User::factory()->create(['image' => $image]); } } عند تنفيذ أمر البذر سيتم إنشاء 5 مُستخدمين و لكل مُستخدم صورة من الصور التي رفعناها في المُجلد images. حيث للمُستخدم الأول بيانات عشوائية يتم تمريرها عن طريق الfactory أما في الحقل image فسيتم تخزين إسم الصورة png.1 و هكذا بالنسبة لبقية المٌستخدمين. أظن أن طريقة إستخدام الfactories في الإصدار السابع مُختلفة عن الإصدار الثامن لذلك بدل كتابة: User::factory()->create(['image' => $image]); نكتب: factory(App\User::class)->create(['image' => $image]); يعني ملف بذر المُستخدمين يُصبح كالآتي: <?php public function run() { $images = array( '1.png', '2.png', '3.png', '4.png', '5.png' ); foreach($images as $image) { factory(App\User::class)->create(['image' => $image]); } } و بالتالي الآن عند عرض صورة المُستخدم يُمكننا إستخدام <img src="{{asset('images/'. $user->image)}}" alt="user image"> أو <img src="{{asset('images/'. auth()->user()->image)}}" alt="user image">
-
يُمكن جلب المُستخدم عن طريق تحديد مُعرف المُستخدم بهذا الشكل مثلاً: <?php $user = User::find(1); // جلب المُستخدم عن طريق تحديد المُعرف 1 // او يُمكننا إستخدام التابع where $user = User::where('id', 1)->get(); لكن السؤال المطروح عن جلب آخر مُستخدم مُسجل في التطبيق في هذه الحالة لا ندري ماهي قيمة مُعرف هذا المُستخدم لذلك نلجأ لتلك الطريقة أننا نرتب المُستخدمين حسب وقت إنشائهم من الأحدث إلى الأقدم ثم نجلب أول سجل عن طريق إستعلام واحد فقط ، يُمكن بنفس الطريقة ترتيبهم حسب المُعرف من الأكبر إلى الأصغر و جلب أول سجل أما السؤال الثاني فعن جلب سجل عشوائي من جدول ما نحن لا نعرف مُسبقاً مُعرف هذا السجل لذلك نستخدم التابع inRandomOrder ليُرتب السجلات ترتيباً عشوائياً في كل مرة يتم تنفيذه و عن طريق التابع first نجلب أول سجل بعد الترتيب العشوائي.
- 8 اجابة
-
- 1