اذهب إلى المحتوى

Adnane Kadri

الأعضاء
  • المساهمات

    5196
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    52

كل منشورات العضو Adnane Kadri

  1. سنحتاج تحضير مصفوفة تحمل عدد مرات ظهور كل عنصر , ثم سيكون علينا تحديد الفهرس بالقيمة الأكبر أو الأصغر . مثال عملي : يمكننا الإستعانة بالدالة array_count_values لحساب عدد المرات التي ظهر فيها كل عنصر سلسلة نصية أو رقم من المصفوفة . $arr = array('محمد','رضا','أبراهيم','محمد','محمد','رضا','محمد'); $ordered = array_count_values($arr); ثم سيكون علينا قراءة العنصر بالقيمة الأكبر , يمكن ذلك عن طريق الدالة max , أو الأصغر عن طريق الدالة min , التان تقومان بجلب العنصر ذي القيمة الأكبر و الأصغر على التوالي في مصفوفة أعداد . $ordered = array_count_values($arr); $max = max($ordered); $min = min($ordered); و كخطوة أخيرة سنحتاج البحث عن المفتاح المرافق للقيمة الأكبر أو الأصغر المعادة في مصفوفة التي يتم إعادتها من الخطوة 1 . $maxVal = array_search($max, $ordered); $minVal = array_search($min, $ordered); فيكون الكود كاملا : $arr = array('محمد','رضا','أبراهيم','محمد','محمد','رضا','محمد'); $ordered = array_count_values($arr); $maxVal = array_search(max($ordered), $ordered); $minVal = array_search(min($ordered), $ordered); يمكنك الإطلاع على توثيق كل دالة مما تم إستعماله : الدالة array_count_values في PHP . الدالة array_search في PHP. الدالة max في PHP. الدالة min في PHP .
  2. ليس تماما . سيتم إظهار الخطأ في حالة صحة العبارة المنطقية . على عكس abort_unless التي سيتم فيها إظهار الخطأ في حالة خطأ العبارة المنطقية . أي أنه في abort_if سيتم إظهار الخطأ إذا كان : Gate::denies('user_access') يساوي صحيح .
  3. يقوم المساعد abort_if بطرح خطأ HTTP معين إذا تم تحقيق عبارة منطقية معين . مثال : abort_if(!$user->is_admin ,403); هنا سيتم عرض أو إعادة خطأ 403 ممنوع في حالة ما كانت العبارة المنطقية : !$user->is_admin صحيحة . و بنفس المنطق : abort_if(Gate::denies('user_access'), Response::HTTP_FORBIDDEN, '403 Forbidden'); أو يكفي : abort_if(Gate::denies('user_access'), 403); سيتم طرح أو إعادة خطأ 403 في حالة ما كانت العبارة المنطقية التالية : Gate::denies('user_access') صحيحة . و في حالة الخطأ سيتم تجاوز الخطأ و إكمال قراءة الشيفرة البرمجية التالية بشكل عادي . يمكنك التعرف أيضا على المساعدين abort_unless و abort .
  4. ستكون العملية معقدة بعض الشيء , بحيث أنه سيكون عليك تطبيق العملية بالإستعانة بالواجهة البرمجية المقدمة من يوتيوب . سيكون عليك إرسال طلبات HTTP إلى نقاط وصول معينة تقوم فيها بالتحقق من أن مستخدم X مشترك بالقناة X أو لا . و بناء عليه ستقوم إما بعرض المحتوى أو حجب المحتوى و إظهار زر الإشتراك . و طبعا ستعتمد في كتابة الشيفرة البرمجية الخاصة بهاته العملية على اللغة التي تم كتابة الواجهة الخلفية ,يفضل, للموقع بها . يمكنك إرسال الطلب إلى نقطة الوصول هاته : HTTP GET https://www.googleapis.com/youtube/v3/subscriptions?part=id&mine=true&key={YOUR_API_KEY} و ستحتاج إستبدال YOUR_API_KEY بالمفتاح الخاص بك عند فتح حساب مطور . سيتم جلب قائمة بأسماء كل المشتركين , ستحتاج فيها التحقق من إسم مشترك معين . و من ثم عرض الصفحة أو حجبها . كما يمكنك جلب إسم المشترك من ملفات تعريف الإرتباط في متصفح العميل .
  5. يمكنك إستعمال هاته الأداة المقدمة من مطوري غوغل لإنشاء و تضمين شيفرة زر الإشتراك في القناة , يمكنك ذلك عن طريق : التصفح إلى صفحة الأداة هنا . قم بطباعة المعرف الخاص بالقناة أو يكفي مجرد إسمها . يمكنك تخصيص نسق العرض و والوضع , كما يمكنك التحكم في عرض عدد المشتركين أو لا. و أخيرا قم بنسخ الكود الذي يتم توليده في مربع النص أسفل الشاشة و لسقه في الكود المصدري لموقعك .
  6. أظن أن من الخطأ إستعمال نفس قواعد البيانات للتحقق Testing و حل المشاكل Debugging , بهاته الطريقة ستكون البيانات الحقيقية عرضة للفقدان كليا . الطريق الأقصر : و هي الإستعانة بالكثير من الحلول البديلة من مثل : تحضير نسخ إحتياطية Backups لقواعد البيانات قبل تجربة التطبيق أو قبل تحديث التهجير لقواعد البيانات , ثم إعادة التهجير بعد التحقق . تحضير نسخة إحتياطية تجريبية للتطبيق , يمكن إستعمال حزم من مثل laravel-backup من مجموعة spatie لعمل ذلك و التجربة عليه . لكن الأفضل ,و الطريق الأطول, يكون بفصل عملية التحقق Testing بشكل كامل عن نفس إتصال قواعد البيانات الذي يستخدمه تطبيقك . و لارافيل تجعل ذلك سهلا مع phpunit . فعلى سبيل المثال : إن كان تطبيقك يستخدم Mysql فعمليات التحقق يجب أن تستخدم ذاكرة مؤقتة و إتصال sqlite . و إن لم يتم كتابة الاختبارات Tests بشكل إما مواز أو مسبق للأكواد فسيجب لتحقيق هذا كتابة الإختبارات اللازمة لكل أجزاء التطبيق حتى يتم تحقيق هذا الأخير و إختبار التطبيق نفسه , لا نسخة إحتياطية منه ,في بيئة التطوير أو الإنتاج و بدون أي فقد لأية بيانات .
  7. Adnane Kadri

    laravel Gate

    ليس تماما . ففي الشيفرة الأولى : abort_if(Gate::denies('user_create'), Response::HTTP_FORBIDDEN, '403 Forbidden'); أو يكفي : abort_if(Gate::denies('user_create'), 403); أو أيضا : abort_unless( !Gate::denies('user_create'), 403); نحن نقوم بمنع المستخدم من الوصول إلى حدث معين في حالة رفض البوابة Gate ذلك . لكن ما نقوم به هنا : Gate::define('create-post', function (User $user, Category $category, $pinned) { if (! $user->canPublishToGroup($category->group)) { return false; } elseif ($pinned && ! $user->canPinPosts()) { return false; } return true; }); ضمن التابع boot في ملف App\Providers\AuthServiceProvider هو تعريف للترخيص create-post . و لتوضيح العلاقة أكثر بين الشيفرتين ينبغي ذكر أنه : يتم التحكم في صلاحيات و تراخصي المستخدمين عن طريق البوابات Gates , بحيث يتم تعريف البوابة بإستعمال الواجهة Gate ضمن ملف AuthServiceProvider.php في التابع boot على هذا النحو : <?php use App\Models\User; use Illuminate\Support\Facades\Gate; /** * تسجيل أية خدمات ترخيص * * @return void */ public function boot() { $this->registerPolicies(); # تعريف البوابة Gate::define('access-db', function () { # إعادة القيمة البوليانية المسجلة في العمود المستهدف return auth()->user()->is_admin; }); } بعد ذلك يأتي إستعمالها في ترخيص الأحداث بإستعمال التابعين allows و denies على هذا النحو : public function index() { if (! Gate::allows('access-db')) { abort(403); } return view('admin_db); } أو إختصارا : public function index() { abort_if (! Gate::allows('access-db') ,403); return view('admin_db); }
  8. جميل أنك اخترت واحدة من حزم مجموعة spatie . تقوم هاته الحزمة بتنفيذ الأمر بوساطة الأدوار عوضا عن مجموعات الصلاحيات , وتختصر بذلك الكثير . قبل الإستعمال تأكدي أنك قد قمت بالخطوات التالية على نحو صحيح : تثبيت الحزمة : composer require spatie/laravel-permission نشر ملفات التهجير و الإعداد : php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" تنفيذ أمر التهجير : php artisan migrate بعد ذلك نحتاج إستعمالها و ضمها للتطبيق على نحو صحيح . سنحتاج إضافة السمة HasRoles لنموذج المستخدم User.php للإستفادة من التوابع التي توفرها هاته السمة : <?php use Illuminate\Foundation\Auth\User as Authenticatable; use Spatie\Permission\Traits\HasRoles; // تضمين السمة class User extends Authenticatable { use HasRoles; // إستعمال السمة // ... } 2. الان ما علينا إلا إنشاء أدوار Roles و أذونات Permissions , بحيث تتم العملية كالتالي : يتم نسب صلاحية معينة إلى دور معين . يتم نسب دور معين إلى مستخدم معين . مثال : نقوم بإنشاء الأذونات التالية : الحذف . الإضافة . التعديل . => نقوم بنسب الأذونات إلى الدور "Manager" . => نقوم بإعطاء المستخدم A الدور Manager . و بالطبع فإنه يمكن كتابة الشيفرة الخاصة بنسب الأذونات للدور و الدور للمستخدم في أي مكان من التطبيق , وليكن متحكما خاصا نسميه AssignRolesController : <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Permission; class AssignRolesController extends Controller { public function init() { # إنشاء دور $role = Role::create(['name' => 'writer']); # إنشاء صلاحية $permission = Permission::create(['name' => 'edit articles']); # عن طريق التابعين التاليين يمكن إعطاء الدور صلاحية معينة أو إعطاء الصلاحية إلى دور # ملاحظة : يكفي إستعمال أحدهما $role->givePermissionTo($permission); $permission->assignRole($role); # إعطاء مستخدم معين الدور $user = App\Models\User::first(); $user->assignRole('writer'); } } الان ما علينا إلا الوصول للتابع init لتنفيذ الأمر و إنشاء الأدوار و الأذونات . بعد ذلك و كخطوة أخيرة سنحتاج لحماية المسارات و المتحكمات . مثال : يجب علينا عدم السماح لمن ليس له صلاحية تعديل المقالات للوصول إلى المتحكم الخاص بتعديل المقالات . سنتسعمل في ذلك مفهوم الطبقات الوسيطة Middlewares , بحيث تتولى عملية التحقق من إمتلاك المستخدم لدور أو صلاحية معينة . و أبسط طريقة لعمل ذلك هي عن طريق المثال التالي : Route::group(['middleware' => ['can:edit articles']], function () { # كل المسارات التي يتم تمريرها هنا ستكون غير قابلة للوصول إلا لمن يمتلك صلاحية تعديل المقالات }); و متى ما حاول المستخدم اللوصول إلى المتحكمات الخاصة بعملية تعديل المقالات سيتم التحقق إن كان يمتلك صلاحية التعديل , و بشكل اخر : سيتم التحقق من أن المستخدم يمتلك دورا من ضمن صلاحياته تعديل المقالات .
  9. يمكنك التعامل مع الصلاحيات في لارافل عن طريق واحدة من الحزم : laravel-permission من مجموعة spatie . bouncer من JosephSilber . entrust من Zizaco . roles من romanbican . laravel-acl من kodeine . laratrust من santigarcor . تتشابه طريقة عمل هاته الحزم في الفكرة الأساسية و تختلف من حيث بعض المميزات الإضافية . و رغم كل ذلك يمكنك التعامل مع الصلاحيات دون الإستعانة بأي حزمة عن طريق مميزات مبنية ضمن اللارافل نفسه من مثل البوابات Gates و السياسات Policies . كما أحب التعامل مع هذا المفهوم بشكل منفصل و مرن أكثر عن طريق معاملة مجموعات الصلاحيات كنموذج Model و كجدول بقواعد البيانات , ثم إنشاء طبقات وسيطة Middlewares , بناءا على هذا الأخير , تقوم بالتحقق من إمتلاك المستخدم الموثق الحالي لمجموعة صلاحيات أو لا , ثم التحقق إن كانت هاته المجموعة تمتلك صلاحية ما و هكذا .. أي أن الأمر ممكن بكل الطرق , فكلها تشترك في المفهوم الأساسي و تتفاوت فيما بينها من ناحية بعض المميزات الإضافية .
  10. يمكن ذلك عن طريق الإستعانة بمفهوم الويب سوكيت . بحيث نقوم : في الواجهة الخلفية للتطبيق بإنشاء قناة أو قنوات بحدث أو أحداث معينة . في الواجهة الأمامية للتطبيق بالإشتراك في هاته القنوات و الإستماع لهاته الأحداث . مثال عن الإستعمال : لما يضغط عمر زر الإعجاب بمنشور أحمد سيتم إرسال طلب HTTP إلى الخادم . سيقوم الخادم بمعالجة طلب عمر و تسجيل الإعجاب , و في نفس الوقت سيقوم بإثارة الحدث المرتبط بالعملية و ليكن NewLikeEvent ضمن القناة AhmedChannel . أحمد مشترك في القناة AhmedChannel و يستمع لأية إثارة لأحداثها , ففي حالة إثارة أية حدث سيقوم بالتقاط البيانات التي تم تمريرها عبره دون تحديث الصفحة . لما يتم إثارة الحدث NewLikeEvent ضمن القناة AhmedChannel ستقوم الواجهة الأمامية لأحمد بالتصرف بناء على البيانات التي تلتقطها عبر هاته القناة في هذا الحدث . كأن تقوم بإظهار إشعار أو تنبيه نصي . قد نحتاج إلى دريفر لمساعدتنا في تمرير البيانات و إنشاء القنوات من مثل Pusher. و للتوضيح أكثر سنقوم بإستعمال Pusher كونه معدا مسبقا للعمل مع لارافل بشكل متسق , و هو ما سنقوم به في هذا المثال .. يمكن عمل الفكرة عن طريق المنطق التالي : تثبيت حزمة خادم Pusher في تطبيق الللارافل : composer require pusher/pusher-php-server إنشاء تطبيق Pusher : نحتاج في هاته الخطوة إلى التسجيل في pusher.com و تسجيل تطبيق جديد . بعد ذلك سنحتاج نسخ معلومات التوثيق و نقوم بوضعها في ملف الإعداد env. كما يلي : PUSHER_APP_ID=PUT_YOUR_PUSHER_ID_HERE PUSHER_APP_KEY=PUT_YOUR_PUSHER_KEY_HERE PUSHER_APP_SECRET=PUT_YOUR_PUSHER_SECRET_HERE PUSHER_APP_CLUSTER=PUT_YOUR_PUSHER_CLUSTER_HERE كما أنه يجب تغيير قيمة BROADCAST_DRIVER: BROADCAST_DRIVER=pusher نقوم بإنشاء حدث معين : php artisan make:event Notify سنلاحظ إضافة ملف Notify.php داخل مجلد events , لنتأكد من أنه سيتم تعديله ليكون على هذا النحو : <?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Queue\SerializesModels; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class Notify implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public $data; /** * هنا يتم التقاط أية بيانات و تسجيلها ضمن هذا الكائن * * @return void */ public function __construct($passed_data) { $this->data = $passed_data; } /** * هنا يتم تعريف القنوات التي من المفترض أن ينتمي إليها هذا الحدث * * @return \Illuminate\Broadcasting\Channel|array */ public function broadcastOn() { return new Channel('notify-channel'); } } إنشاء متحكم يختص بالعملية : php artisan make:controller NotificationController ثم لنتأكد من وضع المحتوى التالي به : <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class NotificationController extends Controller { public function notify() { // تحضير مصفوفة بيانات لتمريرها $data['message'] = 'قم بتمرير هاته الرسالة'; // Notify إثارة الحدث event(new App\Events\Norify($data)); } } سيكون علينا تعريف مسارين , مسار لإستهداف تابع المتحكم NotificationController و اخر لعرض الصفحة notification.blade.php : //web.php Route::get('notify','NotificationController@notify'); Route::view('/notification', 'notification'); ثم بملف ما بالواجهة الأمامية سيكون علينا فقط : الإشتراك في هاته القناة + الإستماع لأحداث هاته القناة : <!-- notification.blade.php --> <!DOCTYPE html> <head> <title>مثال عن إشعار</title> <script src="https://js.pusher.com/4.1/pusher.min.js"></script> <script> // الإشتراك ضمن نفس تطبيق البوشر var pusher = new Pusher('{{env("MIX_PUSHER_APP_KEY")}}', { cluster: '{{env("PUSHER_APP_CLUSTER")}}', encrypted: true }); // الاشتراك في نفس القناة var channel = pusher.subscribe('notify-channel'); // Notify الاستماع للحدث channel.bind('App\\Events\\Notify', function(data) { // إن تم اثارة الحدث قم بعرض البيانات alert(data.message); }); </script> </head> بدون تحديث الصفحة سيكون علينا التصفح إلى المسار notify/ و سنلاحظ ظهور التنبيه في مسار notifications/ . المسار الأول يمثل الطلب الذي أرسله عمر , و المسار الثاني يمثل صفحة عرض الاشعارات بالنسبة لأحمد . و بالطبع فإن هذا هو الشكل الأبسط للعملية , يمكن تطوير العملية كأن نقوم بتخصيص طريقة العرض في قائمة إشعارات منظمة و منسدلة مع ظهور إشعار جانبي في كل إثارة للحدث , كما يمكن تخصيص قنوات خاصة بكل مستخدم منفرد أو نقوم بتمرير بيانات أخرى و تطبيق العديد من الأفكار عليها .
  11. تذكر جيدا ما أشرت إليه سابقا : لكن هذا لا يمنع من تقديم شيفرة كمثال متكامل . لاحظ المثال التالي : 1. نقوم بإنشاء بنية الملفات التالية : 2. بملف index.html سيكون علينا تعريف بنية مشابهة للتالي , كما أنه يجب علينا تحضير طلب الأجاكس و إرساله : <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>مثال عن رفع ملف</title> </head> <body> <section> <div> <label>قم بتحديد ملف</label> <input type="file" id="my_file"> </div> <div> <button type="button" id="submit_file_form">رفع الملف</button> </div> </section> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script> $(document).ready(function(){ // 1 - إضافة حدث عن تقديم الاستمارة و رفع الملف $("#submit_file_form").click(function(){ // 2 - FormData تحضير نموذج عن الكائن var fd = new FormData(); // 3 - تحديد الملف var files = $('#my_file')[0].files; // 4 - التحقق من تحميل ملف if(files.length > 0 ){ // 5 - إضافة الملف إلى نموذج الكائن fd.append('file',files[0]); // 6 - تحضير طلب الاجاكس و إرسال نموذج الكائن $.ajax({ url: 'file_uploader.php', type: 'POST', data: fd, contentType: false, processData: false, success: function(response){ if(response){ alert('تم رفع الملف'); }else{ alert('لم يتم رفع الملف'); } }, }); }else{ alert("قم بتحديد ملف لرفعه."); } }); }); </script> </body> </html> 3. بملف file_uploader.php سيكون علينا إستقبال الطلب الحامل للملف و معالجته بشكل طبيعي تماما على نحو مشابه : <?php if(isset($_FILES['file']['name'])){ /* جلب اسم الملف */ $filename = $_FILES['file']['name']; /* تحضير وجهة تخزين للملف */ $location = "uploaded/".$filename; /* تحضير متغير يحمل حالة الرد */ $response = false; /* تخزين الملف */ $file_uploaded = move_uploaded_file($_FILES['file']['tmp_name'],$location); /* تغيير الحالة ان تم تخزين الملف بنجاح */ if($file_uploaded){ $response = true; } /* إعادة قيمة بوليانية في الرد */ return $response; } return false;
  12. بداية يجب عليك معاملة أية مشاكل و صعوبات تظهر معك كأشياء طبيعية في المجال و من جانب اخر هي إمتحانات لك و لا يجب عليك التفكير في التوقف عن ما أقدمت عليه بسبب أشياء تواجهها لأنه , و بهاته الطريقة , سيكون لديك الكثير لتتوقف من أجله . كما أنه يجب عليك الإستفادة من الإجابات التي طرحها عليك الزملاء في أسئلتك السابقة : و بشكل عام فإنه يجب عليك فهم منطق هاته العمليات لا التوغل في مثال عن كود واحد و إعتباره كمعيار أو دستور للعملية . فمثلا : التشفير و فك التشفير : للتشفير : سيكون عليك تشفير سلسلة نصية معينة قبل إستعمالها , ولقراءته سنحتاج فك هذا التشفير . مثال عن الإستعمال : تشفير كلمة المرور قبل إدخالها في قاعدة البيانات في عملية تسجيل المستخدم - أ - , ثم فك تشفيرها للتحقق من مطابقتها لكلمة مرور قام المستخدم - أ - بإدخالها في عملية تسجيل دخوله لاحقا. أي : أننا نحتاج دالة تشفير و دالة فك تشفير . أو دالة و دالة معاكسة لها لعمل الفكرة , و قد تكتب خوارزميتك الخاصة للتشفير وفك التشفير أنت ذاتك فالعملية ليست حكرا على أحد لكن يقترح إستعمال المكتبات و الدوال المسبق تعريفها لأمان و سرعة أكثر . و دوال التشفير كثيرة من PHP نذكر من بينها : openssl_encrypt و الدالة المعاكسة لها : openssl_decrypt : توثيق . أمثلة : <?php $example = '@123456'; # السلسلة النصية المراد تشفيرها $cipher_algo = 'AES-128-CTR'; # خوارزمية التشفير $encryption_key = 'HsoubAcademy'; # مفتاح التشفير $options = 0; # خيارات التشفير $encryption_iv = 1234567891011121; # يعبر عن بادئة التشفير $encrypted_example = openssl_encrypt($example , $cipher_algo , $encryption_key , $options , $encryption_iv); echo $encrypted_example; // النتيجة : nLTaaXcr1A== $decrypted_example = openssl_decrypt($encrypted_example , $cipher_algo , $encryption_key , $options , $encryption_iv); echo $decrypted_example; // النتيجة : @123456 base64_encode و الدالة المعاكسة لها : base64_decode . توثيق . أمثلة : <?php $example = '@123456'; # السلسلة النصية المراد تشفيرها $encrypted_example = base64_encode($example); echo $encrypted_example; // النتيجة : QDEyMzQ1Ng== $decrypted_example = base64_decode($encrypted_example); echo $decrypted_example; // النتيجة : @123456 bin2hex و الدالة المعاكسة لها : hex2bin . توثيق و أمثلة . و غيرها الكثير .. كما يمكنك القراءة عن الموضوع أكثر هنا : رفع الصور و الملفات عن طريق الأجاكس : جافاسكربت تجعل ذلك بسيطا عن طريق إستعمال كائن يختص بنماذج البيانات و هو الكائن FormData , و لإرسال صورة أو ملف ما علينا إلا : إرسال نموذج من الكائن FormData يحمل الملف. لاحظ جيدا منطق الخطوات بالمثال التالي : $(document).ready(function(){ // 1 - إضافة حدث عن تقديم الاستمارة و رفع الملف $("#submit_file_form").click(function(){ // 2 - FormData تحضير نموذج عن الكائن var fd = new FormData(); // 3 - تحديد الملف var files = $('#my_file')[0].files; // 4 - التحقق من تحميل ملف if(files.length > 0 ){ // 5 - إضافة الملف إلى نموذج الكائن fd.append('file',files[0]); // 6 - تحضير طلب الاجاكس و إرسال نموذج الكائن $.ajax({ url: 'path/to/endpoint', type: 'POST', data: fd, contentType: false, processData: false, success: function(response){ if(response){ alert('تم رفع الملف'); }else{ alert('لم يتم رفع الملف'); } }, }); }else{ alert("قم بتحديد ملف لرفعه."); } }); }); معيارية MVC : و هي إختصار لـ Model , View , Controller و ببساطة شديدة هو نموذج معيارية Design Pattern يقضي بعزل منطق العمل عن واجهة المستخدم بهدف تحقيق إستقلالية كل منهما و تسهيل التعامل معهما في التطوير , الفحص و الصيانة . و يحقق بذلك أحد مبادئ التصميم المشهورة في علوم الحاسب : مبدأ فصل الإهتمامات separation of concerns (SoC). تقوم معيارية MVC بتقسيم التطبيق إلى ثلاث أجزاء : النموذج Model : يعبر عن المكون المركزي و الرئيسي للنمط Pattern . و يمثل بنية البيانات الخاصة بالتطبيق ، فعن طريقه تتم مباشرة إدارة بيانات وقواعد التطبيق . العرض View : و هي أي تمثيل للمعلومات مثل صفحة ويب , جداول أو نصوص . و تمثل ها هنا واجهة المستخدم . المتحكم Controller : و يقوم بإستقبال المدخلات و التحكم فيها و التحقق من إمكانية تمريرها للنموذج Model حتى يتصرف بناء عليها . هذا الفصل بين المكونات الثلاث هاته يجعلها تتفاعل فيما بينها بهاته الطريقة : النموذج Model مسؤول عن إدارة بيانات التطبيق . بحيث يتلقى مدخلات المستخدم من وحدة التحكم Controller . تستجيب وحدة التحكم Controller لإدخال المستخدم , وتتحقق من سلامتها ثم تقوم بتمرير مدخل المستخدم إلى النموذج Model , أو تقوم إستجابة لمدخل المستخدم بعرض View بتنسيق معين . و بشكل عام فإن أي فصل لهاته الثلاث مكونات , اهتمامات و وظائف هي معيارية تصميم MVC مثلها مثل أي معيارية أخرى , يتطلب التعمق فيها فهما أوسع و أعمق لأنماط ومعياريات التصميم Design Patterns . إن لم يكن لك إطلاع مسبق عنها فيمكنك أخذ فكرة عن الموضوع هنا و أيضا هنا . كما يمكنك الإطلاع عن الكود المصدري لهاته النماذج المصغرة لمعيارية MVC هنا و هنا . و بالطبع فإنه يمكنك التدرب على فصل هاته المكونات الثلاث لتطبيق الفكرة عمليا .
  13. الكود مثال عن رفع ملف إلى الواجهة الخلفية , مكتوب بالجيكوري . يمكنك الإشارة إلى النقطة الغير مفهومة و سيتم شرحها بإسهاب أكثر .
  14. يمكنك إرسال نموذج عن الكائن FormData يتضمن الملف , بإستعمال POST عبر طلب الأجاكس . سيتبع الكود منطقا مشابها : $(document).ready(function(){ // إضافة حدث عن تقديم الاستمارة و رفع الملف $("#submit_file_form").click(function(){ // FormData تحضير نموذج عن الكائن var fd = new FormData(); // تحديد الملف var files = $('#my_file')[0].files; // التحقق من تحميل ملف if(files.length > 0 ){ // إضافة الملف إلى نموذج الكائن fd.append('file',files[0]); // تحضير طلب الاجاكس و إرسال نموذج الكائن $.ajax({ url: 'path/to/endpoint', type: 'POST', data: fd, contentType: false, processData: false, success: function(response){ if(response != 0){ alert('تم رفع الملف'); }else{ alert('لم يتم رفع الملف'); } }, }); }else{ alert("قم بتحديد ملف لرفعه."); } }); });
  15. لا أظن أن الفكرة ممكنة عن طريق تابع ضمن الكائن Blueprint , و لكن يمكنك إضافة أي قيد عن طريق مفهوم المعدلات Mutators قبل أي إدراج بقواعد البيانات . نقوم بتعريف المعدل setSalaryAttribute بداخل ملف النموذج المستهدف على هذا النحو : class YourModel extends Model{ public function setSalaryAttribute($value){ $this->attributes['salary'] = $value < 500.00 ? $value : 500.00; } } في هذا المثال سيقوم بالتحقق , كل مرة نحاول فيها إدراج أو تحديث القيمة salary , إن كانت القيمة salary أقل من 500.00 و إلا فسيضع 500.00 نفسها .
  16. قد تكون المشكلة بسبب تداخل النسخ أو تكرارها , لاحظ تثبيتك لأكثر من حزمة في نفس الأمر : npm install tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ لذلك تأكد أولا أن تقوم بإزالتها , إما عن طريق الأمر : npm uninstall tailwindcss postcss autoprefixer أو إزالة الأسطر الخاصة بالحزم المعنية من ملف package.json ثم تنفيذ الأمر : npm install ثم الان نأتي لتثبيت tailwind على نحو صحيح : يكون أمر تثبيت الحزمة و الحزم المطلوبة على هذا النحو : npm install -D tailwindcss@latest postcss@latest autoprefixer@latest قد لا تحتاج الخطوتين التاليتين كونك تقوم بإنشاء ملف إعداد tailwind على نحو صحيح . 2. قم بإنشاء ملف إعداد tailwind عن طريق طباعة الأمر : npx tailwindcss init 3. قم بهيئة Tailwind لإزالة التنسيقات الغير المستخدمة في بيئة الإنتاج : // tailwind.config.js module.exports = { purge: [], purge: [ './resources/**/*.blade.php', './resources/**/*.js', './resources/**/*.vue', ], darkMode: false, // or 'media' or 'class' theme: { extend: {}, }, variants: { extend: {}, }, plugins: [], } 4. إعداد tailwind عن طريق webpack : mix.js("resources/js/app.js", "public/js") .postCss("resources/css/app.css", "public/css", [ require("tailwindcss"), ]); الان يمكنك استعمال tailwind و تضمينه في ملفات css المعنية . و يمكنك البناء عن طريق تشغيل الأمر : npm run build
  17. بداية يجب عليك إنشاء الحقل و تعيينه كمفتاح أولي بملف التهجير الخاص بالجدول المعني على هذا النحو : Schema::create('users', function (Blueprint $table) { $table->uuid('id')->unique()->primary(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); } لاحظ أن العمود id لا يملك أي قيمة افتراضية و لذلك يجب تعيين ذلك مع كل طلب : App\Models\User::create([ 'id' => $uuid, 'name'=> 'Hsoub', 'email'=> 'Academy', 'password'=> Illuminate\Support\Facades\Hash::make('HsoubAcademy'), ]); و لإختصار الأمر و توليد معرف فريد مع كل استعلام إدراج لصف جديد نحتاج الاستماع للحدث creating ضمن النموذج المستهدف ,وليكن App\Models\User/php , ضمن الثابت boot على هذا النحو : public static function boot() { parent::boot(); self::creating(function($model){ $model->uuid = $uuid; }); } و لتعيين قيمة للمتغير uuid يمكنك إستعمال المساعد Str في لارافل مثل ما شرح المدربان أو يمكنك إستعمال أحد هاته الحزم : webpatser/laravel-uuid أو ramsey/uuid مثلا . كما يمكنك إنشاء مساعدك الخاص الذي يقوم بتوليد معرفات فريدة وفق منطق معين .
  18. يحدث المشكل أحيانا بسبب محاولة فك تشفير نص إما غير مشفر من الأساس أو قد فك تشفيره قبل ذلك . مثال : إن كنت تستخدم مسترجع أو معدل Mutator على خاصية كلمة المرور في ملف النموذج : public function getPasswordAttribute($value) { return Crypt::decryptString($value); } ثم تقوم بقراءتها على هذا النحو : $pass = Crypt::decryptString($user->password); سيؤدي هذا إلى ظهور المشكل لأننا نحاول فك التشفير مرتين , و بالتالي و لحل المشكل تأكد أنك لا تقوم بذلك أو بأي عملية بنفس المنطق . إن لم يحل هذا مشكلتك يرجى إرفاق الكود المسبب للمشكلة حتى يتم النظر فيه بشكل أكثر دقة . يمكنك القراءة عن إرشادات طرح الأسئلة .
  19. ما قصدك بالكود الأصلي للدالة ؟ و في أي لغة تريدين ذلك ؟
  20. يظهر الخطأ في القراءة من الإستعلام في عناصر التوريد و بالضبط في هذا السطر : <input type="text" class="form-control contact-name" placeholder="الاسم" value="<?php echo $item['supplying_items.name']; ?>" disabled > وهذا لأن طريقة القراءة في كود PHP تختلف عن طريقة القراءة في إستعلام SQL . في PHP لا يوجد أي عنصر بالفهرس supplying_items.name من الناتج و لكن يوجد مصفوفة بإسم supplying_items تحوي عنصر بالفهرس name . أي أن القراءة تكون على هذا النحو : <input type="text" class="form-control contact-name" placeholder="الاسم" value="<?php echo $item['supplying_items']['name']; ?>" disabled > أو : <input type="text" class="form-control contact-name" placeholder="الاسم" value="<?php echo $item['name']; ?>" disabled > إن كنت تقوم بالتكرار حول عناصر التوريد supplying_items لأن الدور الخاص بك غير واضح . إن لم يقم هذا بحل مشكلتك يرجى إرفاق كامل الكود .
  21. بالطبع فإنه يمكنك معاملة إستعلام إدراج و إنشاء الجداول كأي إستعلام CRUD اخر مثلا. مثال عملي : <?php /* mysqli تحضير كائن جديد*/ $mysqli = new mysqli("localhost", "root", "", "demo"); // التحقق من الاتصال if($mysqli === false){ die("حدث خطأ في الاتصال " . $mysqli->connect_error); } // جلب مجموعة الاستعلامات من ملف قواعد البيانات $sql = file_get_contents('data.sql'); if($mysqli->query($sql) === true){ echo "تم إنشاء الجداول بقواعد البيانات بنجاح"; } else{ echo "حدث خطأ" . $mysqli->error; } // إغلاق الاتصال $mysqli->close(); ?> قد تحتاج أيضا إضافة شرط الوجود في استعلام الـ sql على هذا النحو : CREATE TABLE IF NOT EXISTS `users` ( `user_id` INT(8) NOT NULL AUTO_INCREMENT, `user_name` VARCHAR (30) NOT NULL, `user_pass` VARCHAR (255) NOT NULL, `user_email` VARCHAR (255) NOT NULL, `user_date` DATETIME NOT NULL, `user_level` INT(8) NOT NULL, UNIQUE INDEX `user_name_unique` (`user_name`), PRIMARY KEY (`user_id`) ) Engine=InnoDB;
  22. يمكنك ذلك عن طريق الإستعانة بطلبات Ajax . بحيث ستحتاج إلى : إرسال طلبات إلى نقاط وصول معينة عن طريق XmlHttpRequest . القراءة من الطلب . تكرار إنشاء الصفوف كذا مرة بحسب البيانات التي تم جلبها و عرضها على الصفحة عن طريق الـ DOM. مثال عملي : ليكن لدينا الجدول التالي : <table id="myTable"> <tr> <th>الاسم</th> <th>اللقب</th> </tr> </table> نقوم بتحضير طلب Ajax لجلب الطلبة مثلا على هذا النحو : var xhttp = new XMLHttpRequest(); // نقوم بتعريف كائن طلب جديد xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var response = JSON.parse(xhttp.responseText); // جلب البيانات response.forEach(element => createRowFromData(element)); // إنشاء صف لكل عنصر من المصفوفة } }; xhttp.open("GET", "path/to/get/students", true); // فتح الطلب xhttp.send(); // إرسال الطلب function createRowFromData(data) { var table = document.getElementById("myTable"), tr = document.createElement("tr"), td = document.createElement("td"), tdText = document.createTextNode(data.name), td2 = document.createElement("td"), td2Text = document.createTextNode(data.family_name); td.appendChild(tdText); td2.appendChild(td2Text); tr.appendChild(td) .appendChild(td2); table.appendChild(tr); }
  23. أظن أن قصدك أن يكون الناتج كالتالي: <ul class="sec-1"> <li>res 1</li> <li>res 2</li> <li>res 3</li> <li>res 4</li> </ul> <ul class="sec-2"> <li>res 5</li> <li>res 6</li> <li>res 7</li> <li>res 8</li> </ul> في لارافيل , يمكنك تقسيم نتائج الإستعلام إلى أكثر من مجموعة عن طريق الإستعانة بمتغيرات الدور التي تكون معرفة ضمن كل تكرار من الدور foreach أو عن طريق الإستعانة بمفهوم المجموعات collections . فمثلا لتقسيم العناصر إلى مجموعات بـ 5 عناصر عن طريق الإستعانة بمتغيرات الدور : @foreach($items as $item) @if($loop->first or $loop->iteration % 5 == 0) <ul> @endif <li> res {{ $loop->iteration }} </li> @if($loop->last == true or $loop->iteration % 5 == 0) </ul> @endif @endforeach حيث أننا نقوم بفتح وسم جديد كل مرة يكون فيها التكرار جديدا أو قابلا للقسمة على 5 . و ليكن في العلم أن الخاصية first تعيد إما true أو false بحسب ترتيب الدور في حين أن الخاصية iteration تمثل التكرار الحالي , و نفس الشيء بالنسبة لغلق الوسم و المتغير last . لكن ,و كطريقة أفضل , يمكنك الإستعانة بالتابع chunk لتشكيل كل مرة مجموعة مستقلة في كل دورة عن طريق : @foreach($items->chunk(5) as $chunk) <ul> @foreach($chunk as $item) <li> res {{ $loop->iteration }} </li> @endforeach </ul> @endforeach بحيث أن هذا سيقوم بتشكيل مجموعات ذات خمسة عناصر , و سيكون من السهل التكرار داخلها أو القراءة منها . طبعا يمكنك بنفس المنطق تطويع العملية بحسب بنية الـ HTML لديك .
  24. هل يمكنك شرح المطلوب أكثر حتى يمكن مساعدتك بشكل أفضل ؟ يمكنك القراءة أكثر عن كيف أحصل على جواب لسؤالي .
  25. يمكنك فعل هذا عن طريق مفهومي معمل النماذج Model Factories و بذر البيانات Database seeding . ستحتاج إنشاء معمل نموذج جديد عن طريق الأمر : php artisan make:factory TaskFactory -m Task ثم نحتاج لإستعمال مكتبة faker لتوليد بيانات حقول تلقائية على هذا النحو في ملف TaskFactory.php ضمن التابع definition : return [ 'name' => $this->faker->name, 'email' => $this->faker->unique()->email, 'contact_number' => $this->faker->phoneNumber, ]; سنحتاج أيضا إلى إضافة المعمل إلى ملف البذر DatabaseSeeder.php إلى التابع run : App\Models\Task::factory(10)->create(); ثم أخيرا يمكننا تشغيل أمر البذر : php artisan db:seed كما يمكن تشغيله بعد أمر التهجير على هذا النحو : php artisan migrate:fresh --seed
×
×
  • أضف...