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

Adnane Kadri

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

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

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

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

    52

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

  1. يمكن استعمال دريفر Pusher لتحقيق الغرض . لنقم بإتباع الخطوات التالية : 1. تثبيت حزمة خادم Pusher في تطبيق الللارافل : composer require pusher/pusher-php-server 2, إنشاء تطبيق 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 3. نقوم بإنشاء حدث معين : php artisan make:event NewTemperatureRecord سنلاحظ إضافة ملف NewTemperatureRecord.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 NewTemperatureRecord 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('temperature-channel'); } } إنشاء متحكم يختص بالعملية : php artisan make:controller TemperatureController ثم لنتأكد من وضع المحتوى التالي به : <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class TemperatureController extends Controller { public function update(Request $request) { // تحضير مصفوفة بيانات لتمريرها $data['temp'] = $request->temp; // Notify إثارة الحدث event(new App\Events\NewTemperatureRecord($data)); } } و لتأكد من تعريف المسارات اللازمة , واحد لعرض الصفحة وواحد لإرسال طلبات التحديث : // web.php Route::post('temperature','TemperatureController@update'); Route::view('temperature', 'temperature'); ثم بملف ما بالواجهة الأمامية سيكون علينا فقط : الإشتراك في هاته القناة + الإستماع لأحداث هاته القناة : <!-- temperature.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('temperature-channel'); // Notify الاستماع للحدث channel.bind('App\\Events\\NewTemperatureRecord', function(data) { // إن تم اثارة الحدث قم بعرض البيانات document.querySelector('#temp').textContent = data.temp; }); </script> </head> <body> <div id="temp"> 35 </div> </body> بدون تحديث الصفحة سيكون علينا إرسال طلبات أجاكس إلى المسار temp/ بالفعل POST و سنلاحظ تحدث القيمة في صفحة العرض temp/ .
  2. يفضل فهم مبدأ عمل الالية و منطقها و إنشاء التطبيق على طريقتك الخاصة . ولنقل أنه يمكننا ذلك عن طريق الإستعانة بمفهوم الويب سوكيت web sockets . (يمكنك التعرف أكثر على هذا المفهوم هنا ) بحيث نقوم : - في الخادم (في الواجهة الخلفية للتطبيق) بإنشاء قناة أو قنوات بحدث أو أحداث معينة , ثم تمرير البيانات عبر هاته القنوات مستهدفين أحداثا معينة . - في المتصفح (في الواجهة الأمامية للتطبيق) بالإشتراك في هاته القنوات و الإستماع لهاته الأحداث و التصرف بناء عليها (كأن يتم عرض الرسائل بشكل ) . مثال عن الإستعمال : لما تكتب سارة رسالة بمربع نص و تضغط زر الإرسال إلى شيماء سيتم إرسال طلب HTTP إلى الخادم . سيقوم الخادم بمعالجة طلب سارة و تسجيل الرسالة بقواعد البيانات , و في نفس الوقت سيقوم بإثارة الحدث المرتبط بالعملية و ليكن NewMessageEvent ضمن القناة ShaimaaChannel . شيماء مشتركة في القناة ShaimaaChannel و تستمع لأية إثارة لأحداثها , ففي حالة إثارة أية حدث ستقوم بالتقاط البيانات التي تم تمريرها عبره دون تحديث الصفحة . لما يتم إثارة الحدث NewMessageEvent ضمن القناة ShaimaaChannel ستقوم الواجهة الأمامية لشيماء بالتصرف بناء على البيانات التي تلتقطها عبر هاته القناة في هذا الحدث . كأن تقوم بإظهار تنبيه نصي . و قد نحتاج إلى دريفر لمساعدتنا في تمرير البيانات و إنشاء القنوات من مثل 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 NewMessageEvent سنلاحظ إضافة ملف NewMessageEvent.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 NewMessageEvent 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('chaimaa-sara-channel'); } } إنشاء متحكم يختص بالعملية : php artisan make:controller MessagesController ثم لنتأكد من وضع المحتوى التالي به : <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class MessagesController extends Controller { public function send(Request $request) { // تحضير مصفوفة بيانات لتمريرها $data['message'] = $request->message; // Notify إثارة الحدث event(new App\Events\NewMessageEvent($data)); } } سيكون علينا تعريف مسارين , مسار لإستهداف تابع المتحكم MessagesController و اخر لعرض الصفحة chat.blade.php : //web.php Route::post('chat','MessagesController@send'); Route::view('chat', 'chat'); ثم بملف ما بالواجهة الأمامية سيكون علينا فقط : الإشتراك في هاته القناة + الإستماع لأحداث هاته القناة : <!-- chat.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('sara-chaima-channel'); // Notify الاستماع للحدث channel.bind('App\\Events\\NewMessageEvent', function(data) { // إن تم اثارة الحدث قم بعرض البيانات alert(data.message); }); </script> </head> بدون تحديث الصفحة سيكون علينا إرسال طلبات أجاكس من نموذج سارة إلى المسار chat/ بالفعل POST و سنلاحظ ظهور الرسالة في مسار chat/ . المسار الأول يمثل الطلب الذي أرسلته سارة , و المسار الثاني يمثل صفحة عرض الرسائل بالنسبة لشيماء . و بالطبع فإن هذا هو الشكل الأبسط للعملية , يمكن تطوير العملية كأن نقوم بتخصيص طريقة العرض في قائمة رسائل منظمة بإنزلاق أفقي مع كل تحديث . قد نضيف أيضا إشعارا جانبيا في كل إثارة للحدث , كما يمكن تخصيص قنوات خاصة بكل مستخدم منفرد أو نقوم بتمرير بيانات أخرى و تطبيق العديد و العديد من الأفكار عليها .
  3. يحدث هذا لأنك تعطي عنصري الفقرتين عرضا أكبر من عرض الشاشة المتبقي : 600 بكسل . و هذا في ملف style.css , لاحظ : section.phara .container .row p.aa { font-size: 18px; font-weight: 300; line-height: 35px; padding-bottom: 50px; border-bottom: 1px solid #fff; width: auto; /*هنا*/ } section.phara .container .row p.bb { font-size: 18px; font-weight: 300; line-height: 35px; padding-top: 50px; width: auto; /*هنا*/ } للعنصرين : <section class="phara"> <div class="container"> <div class="row "> <div class="col-md-12 ml-auto"> <h5> Diagoona HTML Template </h5> <p class="aa"> ... </p> <p class="bb"> ... </p> <button type="button" name="button"> Continue... </button> </div> </div> </div> </section> و لإصلاح ذلك لن نحتاج إلا لإسناد قيمتين مناسبتين أكثر أو يفضل عرضا افتراضيا للخاصية width : width: auto; أما عن إضافة الطبقة السوداء فيمكنك إنشاء عنصر بالصف overlay يوضع أسفل عنصر الـ footer : <footer> <div class="copyright"> <p>Copyright 2020 Diagoona Co. | Design: TemplateMo</p> </div> </footer> <div class="overlay"></div> و ليحمل التنسيقات التالية : /* إضافة طبقة سوداء شفافة ثابتة و مربعة ذات طول كامل و نصف عرض*/ .overlay{ position: fixed; height: 100vh; width: 57vw; background-color: rgba(0,0,0,0.16); top: 0px; right:0px; z-index: -99; /* لضمان بقاء باقي العناصر قابلة للوصول */ } /* إضافة مثلث جانبي بنفس طول مربع الطبقة السابقة وبنفس درجة الشفافية */ .overlay::before{ content: ''; position: absolute; top: 0px; left: -150px; height: 100%; border-bottom: 100vh solid rgba(0,0,0,0.16); border-left: 150px solid transparent; } و لتوضيح منطق العملية لاحظ كيفية تداخل التركيبتين : ------------- - | | |\ | المربع | + | \ | | | م\ | | | ثلث\ ------------- ------
  4. لن يمكنك فعل ذلك بإستعمال التابع load , لأن هذا التابع يسمح بتحميل HTML أو محتوى نصي من الخادم ثم إضافته إلى عنصر DOM . أما لتحقيق غرضك فلن نحتاج إلا لتحديد العنصر الحاوي للمحتوى ثم إضافته إلى العنصر div . سيمكن إستعمال التابع append لهذا . رغم أن فكرة تحميل محتوى موجود داخل الـ div و إعادة تضمينه في نفس العنصر غير منطقية إلا أن الشيفرة ستكون مشابه للتالي : <div id="load_posts"></div> <script> setInterval(function(){ var content = $('#load_posts').html(); // $('#load_posts').html(''); لحذف المحتوى و إعادة تحميله $('#load_posts').append(content); }, 1000); </script>
  5. أظن أنه ينبغي عليك أولا معرفة المميزات التي قد تستفيد منها في تعلمك لسكراتش , ثم سيمكنك الحكم إن كان تعلم ذلك واجبا أم لا بالنسبة لك , رغم أن تعلمه يقترح و يفضل . لنقل أن من بعض مميزاته الاتي : هدفه : حيث أن تعلم سكراتش سيقوم بتبسيط تعاملك مع منطق لغات البرمجة و يجعل ذلك مألوفا بشكل كبير . تعلمه : تعلم سكراتش سهل و ممتع نوعا ما , أي أن طريق تعلمه لن يكون مملا بعض الشيء. يطور مهاراتك : واحدة من أهم أهداف سكراتش هي في تطوير مهاراتك في إدارة المشاريع و تسييرها . يطور منطقك : كما أنه سيساعدك بشكل كبير في تطوير المهارات التحليلية و المنطقية لديك . ممتع و تفاعلي : إستعماله مجاني و ذو واجهة تفاعلية .
  6. يمكنك تحريك الشريط الجانبي للأسفل تماما مباشرة بعد نجاح عملية تحميل أية رسائل جديدة و إضافتها إلى الوثيقة . أي إلى الدالة appendMessage . قد لا نحتاج الدالة getMessages في هاته العملية . أي أننا لا يجب أن نرغم المستخدم أن يكون الشريط الجانبي في أسفله تماما و دوما , و إنما أن يتم عمل التحريك التلقائي للشريط الجانبي بعد كل تضمين لعنصر رسالة جديد , و ذلك لعرضها . أي أن الشيفرة الخاصة بالعملية ستتبع المنطق التالي : const messages = document.getElementById('div_show_message'); function appendMessage() { const message = document.getElementsByClassName('message')[0]; const newMessage = message.cloneNode(true); messages.appendChild(newMessage); scrollToBottom(); } function scrollToBottom() { messages.scrollTop = messages.scrollHeight; } scrollToBottom();
  7. كون الدالتين تستعملان نفس الحدث فلن نحتاج إلا لوضعهما بالمكان الصحيح بدل تكرار الكود : أي بعد نجاح طلب الأجاكس , و المقصود هنا هو التابع success . نقوم في الكود الأول بإرسال طلب أجاكس لتخزين بيانات الرسالة بعد تقديم النموذج , لاحظ : $j('#messages_form') .on('submit', function(event) { event.preventDefault(); if ($j('#username') .val() != '' && $j('#message') .val() != '') { var form_data = $j(this) .serialize(); $j.ajax({ url: "send_messages_form.php", method: "POST", data: form_data, success: function(data) { $j('#messages_form')[0].reset(); load_unseen_notification(); } }); } else { alert(" رسالة فارغة رجاءا اكتب شىء "); } }); في حين أننا نقوم بعرض رسالة في قسم الرسائل في النجاح في الكود الثاني , لاحظ : success: function(response) { $j("#norec") .hide(); $j("#div_show_message") .append(response); $j('#messages_form') .trigger('reset'); }, error: function(xhr, ajaxOptions, thrownError) { alert(thrownError); } أي أن دمج الكودين لن يكون إلا في ما بعد نجاح طلب الأجاكس , و بالتالي : $j('#messages_form') .on('submit', function(event) { event.preventDefault(); if ($j('#username') .val() != '' && $j('#message') .val() != '') { var form_data = $j(this) .serialize(); $j.ajax({ url: "send_messages_form.php", method: "POST", data: form_data, success: function(data) { $j('#messages_form')[0].reset(); load_unseen_notification(); // عرض الرسالة $j("#norec") .hide(); $j("#div_show_message") .append(data); $j('#messages_form') .trigger('reset'); }, // إضافة حالة فشل الطلب error: function(xhr, ajaxOptions, thrownError) { alert(thrownError); } }); } else { alert(" رسالة فارغة رجاءا اكتب شىء "); } }); ثم كخطوة أخيرة لن تحتاج إلا تحريك الشريط الجانبي للأسفل , و بالطبع سيكون ذلك بعد نجاح طلب الأجاكس , أي أن العملية ستتبع منطقا واحد . وهو نفس المنطق المتبع في الكود المرفق . يمكنك المحاولة بقيام ذلك ثم سيمكن مساعدتك في حالة الاستعصاء .
  8. من الطبيعي جدا أن تجد بعض الصعوبة في عمل أي تطبيق عملي , ولكنه سيجب عليك تخطي هاته الصعوبة بالمحاولة و التكرار . و لذلك فإنه لن يكون لتقديم الكود أي منفعة . عوضا عن ذلك يمكنك الإنطلاق بالفعل في صياغة الكود الخاص بك , و سنساعدك في ذلك .
  9. لما لا تقوم فقط بإستعمال واحدة من الحزم التي تستعمل طريقة omnipay لتوحيد عمل بوابات الدفع لإضافة بوابة دفع بايسيرا كونك تطبيقك لارافيل ؟ يقترح : semyonchetvertnyh/omnipay-paysera . povils/omnipay-paysera . و لن يكون ذلك مشكلة إن قمت بالتعامل مع أي من حزمها من قبل . كما يمكنك أيضا إستعمال حزمة adumskis/laravel-paysera (لا تنتمي لمجموعة حزم omnipay) و عموما ستكون ملزما بإتباع الخطوات : فتح حساب بايسيرا , خاص أو تجاري (سيكون هذا ضروريا في عمليات توثيق التعاملات). ستحتاج طلب خدمة بوابة الدفع : يمكنك القيام بذلك مجانًا عن طريق تسجيل الدخول إلى حسابك والانتقال إلى الإعدادات > إعدادات الملف الشخصي > إدارة الخدمة . قم بإنشاء مشروع , يمكنك اتباع الخطوات الموضحة في الفيديو التالي . قم بربط بوابة الدفع , إما عن طريق الإضافة التي توفرها بايسيرا , أو عن طريق الواجهة البرمجية . يمكن الإستعانة بواحدة من الحزم السابقة أو إستعمال الواجهة بشكل مباشر .
  10. الكود خاصتك غير منظم جيدا و لذلك هو غير واضح أو غير قابل للقراءة بشكل عادي . و لكن لتنفيذ الفكرة التي تصفها يمكنك عمل تحديث للصفحة و التحريك التلقائي لشريط التمرير بعد نجاح اظهار الرسائل . و لنتأكد من إتباع مبدأ فصل الاهتمامات لتنظيم العملية أكثر , سيتبع الكود المنطق الموصوف سابقا على نحو مشابه : function adjustScroll() {} function loadUnseenNotifications() { // بعد ارسال طلب الاجاكس لتحميل اشعار بالرسائل الغير مقروءة if (data.unseen_notification > 0) { $j('.count').html(data.unseen_notification); // تحميل الرسائل و عرضها ضمن الشاشة ان كانت الرسائل أكثر من 1 loadMessages(); } } function loadMessages() { // بعد تحميل الرسائل نحتاج تحديث الصفحة و عمل الاسكرول التلقايئ adjustScroll(); } setInterval(function() { loadUnseenNotifications(); }, 1000); أي : يتم التحقق كل ثانية إن كان هنالك إشعارات رسائل غير مقروءة . ان كان نعم سيتم تحديث عد الاشعارات غير المقروءة + تحميل رسائل جديدة . سيقوم تحميل رسائل جديدة تلقائيا بعد انتهاء طلب الأجاكس بتحديث الصفحة و عمل اسكرول تلقائي للأسفل لاخر رسالة تم تحميلها . و رغم أن تطبيقات الدردشة تستعمل تقنيات أحدث إلا أنه يعتبر تطبيقا عمليا جيدا . بالطبع فإن العملية وصفية , لكن يمكنك صياغة الكود الخاص بك وفق الخطوات السابقة .
  11. قد يختلف الأمر قليلا خصوصا لو كنت قادم من نظام تشغيل ويندوز , فلن تجد واجهة تفاعلية تخبرك بما عليك فعله . و سيتم كل ذلك عن طريق التارمنل . عن طريق ما يعرف بمدراء الحزم . و بالطبع فإن الأمر ليس دستورا ثابتا , فهو يختلف من توزيعة لينكس إلى أخرى , و من مدير حزم إلى مدير اخر . و لنأخذ على سبيل المثال توزيعة ubuntu الغنية عن التعريف . في ubuntu يمكننا تثبيت البرنامج بـ 3 طرق مختلفة : عن طريق مركز برمجيات أوبونتو أو Ubuntu Software Center : وهو عبارة عن برنامج يوفر واجهة تفاعلية يسهل من عليها استعراض البرامج المتوفرة و تثبيتها عن طريق ضغطة زر . قد توفر توزيعات أخرى نفس الفكرة . عن طريق snap : وهو مدير حزم يقوم بتحميل الحزم و تحميلها من متجر snap , يتوفر snap في عديد من توزيعات لينكس من مثل فيدوار و لينكس مينت . و سنحتاج للتارمنل في التعامل معه لأن snap لا يوفر واجهة تفاعلية . يتم تثبيت البرامج عن طريقه بأوامر مشابهة : sudo snap install <app-name> عن طريق مدير الحزم apt : sudo apt install <app-name> و كوننا قد قمنا بثتبيت البرنامج لن يجعل من المنطقي ان نقوم بتثبيته كل مرة غرض تشغيله , و بالتالي فإنك لن تحتاج ذلك و يكفي تثبيته مرة واحدة . و لتشغيل البرنامج نقوم إما بطباعة اسمه في التارمنل أو بالتصفح إليه في قائمة البرامج . كما يمكنك إنشاء أيقونة سطح المكتب للوصول السهل إليها .
  12. يحاول الخطأ إخبارك أن المشروع الذي تحاول تطبيق الأمر فيه ليس مستودع git , و لذلك سنحتاج تحويله لذلك قبل عمل أي أوامر git عليه . يمكنك ذلك عن طريق الأمر : git init قد تحتاج أيضا ربط ملفات مشروعك مع مستودعك البعيد عن طريق الأمرين : git remote add origin https://your_gitrepo/some_repo ثم : git branch -M main بعد ذلك يمكنك تطبيق الأوامر : git add -A git commit -m "init commit" git push -u origin main
  13. هلا قمت بطباعة الأمور التالية على التوالي : git checkout -b myBranch git checkout master git merge myBranch git branch -d myBranch سيقوم هذا بتبديل الفروع أولا ثم استعادة ملفات المستودع الحالي و دمجها مع ملفات مشروعك , ثم إنشاء فرع جديد للدفع إليه . يمكنك بعد هذا إنشاء commit بطريقة عادية : git commit -m "my commit" ثم الدفع إلى الفرع الجديد في مستودعك : git push -u origin myBranch
  14. ينغبي الفهم أولا أن قاعدة البيانات ، ليست هي إلا مجموعة بيانات أو معلومات يتم تنظيمها لتسهيل تخزينها , استرجاعها , تعديلها وحذفها بالتزامن مع عمليات معالجة البيانات المختلفة . عادة ما يتم ذلك عن طريق نظم إدارة قواعد البيانات , و يشار إلى النظام نفسه مع البيانات بقواعد البيانات . أي أن الهدف واحد و السبل تختلف . عادةً ما يتم نمذجة هاته البيانات الموجودة ضمن الأنواع الأكثر شيوعًا من قواعد البيانات الشغالة اليوم في : صفوف وأعمدة في سلسلة من الجداول لجعل المعالجة والاستعلام عن البيانات فعالا و أبعد قليلا عن التجريد . بحيث يمكن بعد ذلك الوصول إلى البيانات وإدارتها وتعديلها وتحديثها والتحكم فيها وتنظيمها بسهولة . تستخدم معظم قواعد البيانات لغة الاستعلام المهيكلة (SQL) لكتابة البيانات والاستعلام عنها أو إدارتها . يوجد العديد من أنواع قواعد البيانات المختلفة التي يمكن لمؤسسة أو برنامج ما إتباعها نذكر منها : قواعد بيانات علائقية Relational databases : يمكن اعتبارها الأكثر شيوعا الان . بحيث يتم تنظيم العناصر الموجودة في قاعدة البيانات العلائقية كمجموعة من الجداول ذات الأعمدة والصفوف التي يمكن لها أن تحمل علاقات فيما بينها . قواعد بيانات كائنية التوجه Object-oriented databases : بحيث يتم تنظيم البيانات بشكل كائنات يسهل التعامل معها بمنطق مشابه لمنطق البرمجة الكائنية . قواعد بيانات موزعة Distributed databases : يتم تنظيم البيانات بشكل ملفات تكون موزعة على مكانين أو أكثر . قواعد بيانات غير علائقية NoSql: تعتبر الأفضل من ناحية تخزين البيانات غير المهيكلة unstructured و شبه المنظمة semistructured . واحدة من الأكثر شيوعا الان . طبعا ليست هاته الأنواع الوحيدة فقط بل يوجد الكثير غيرها .. كل منها ينفرد بمنطقه و طريقة معالجته للبيانات و تخزينها . و مثلما تم الإشارة فإنه يتم إدارتها عن طريق نظم إدارة قواعد البيانات (database management system) اختصارا : DBMS .بحيث يعمل كواجهة بين قاعدة البيانات والمستخدمين النهائيين أو البرامج ، مما يسمح للمستخدمين باسترداد وتحديث وإدارة كيفية تنظيم المعلومات وتحسينها . و أيضا الإشراف والتحكم في قواعد البيانات ، يوفر هذا مجموعة متنوعة من العمليات الإدارية مثل مراقبة الأداء والضبط والنسخ الاحتياطي والاسترداد و غيرها . و لنأخذ MySql كمثال : MySQL هو نظام إدارة قواعد بيانات علائقية مفتوح المصدر يعتمد على SQL . تم تصميمه وتحسينه لتطبيقات الويب . كانت وراء بعض أفضل مواقع الويب و تطبيقات الويب في العالم ، أمثلة : Airbnb و Uber , LinkedIn , Facebook , Twitter , YouTube . و رغم أنها بالفعل خسرت بعض شعبيتها في الأعوام الأخيرة إلا أنه لا بأس في تعلمها و التعرف عليها و العمل بها , خصوصا في سوقنا العربي فهي : سهلة التعلم. ما تزال شائعة ومهيمنة نوعا ما . توثيقها السهل و وفرة المعلومات حولها . متوفرة بشكل افتراضي في أغلب الاستضافات . مجانية . يمكنك القراءة عن Mysql أكثر هنا . يمكنك أيضا التعرف أكثر على قواعد البيانات على بعض من نظم إدارة قواعد البيانات هنا . كما يمكنك الاستزادة بقراءة بعض من مقالات الأكاديمية بهذا الشأن : الأنواع السبعة لروابط الجداول في SQL مقارنة بين أنظمة إدارة قواعد البيانات العلاقية: SQLite مع MySQL مع PostgreSQL شرح الفروقات بين قواعد بيانات SQL ونظيراتها NoSQL
  15. يمكنك إضافة الخاصيتين data-toggle و data-target لوسم الصورة أو العمود : data-toggle="modal" data-target="#mymodal" سيقوم هذا بفتح المودل بعد الصغط على الصورة أو العمود .
  16. تأكد أن تقوم بحذف ملف index.lock داخل مجلد git. , يمكنك ذلك عن طريق الأمر : rm -f .git/index.lock و في حال ظهر معك خطأ على هذا النحو : 'rm' is not recognized as an internal or external command يمكنك طباعة الأمر : del -f .git/index.lock .. قد نتسبب في هذا المشكل عندما نحاول تطبيق أمري أو عمليتي git في نفس الوقت , و في الغالب تكون واحد عن طريق المحرر vsCode و الاخر عن طريق موجه الأوامر أو التارمنل . و حذف ملف index.lock سيقوم بإلغاء أي عمليات أخرى معدا الحالية و بالتالي حل المشكل.
  17. يمكنك معاملة الصور و أيقونات كزر فتح المودل , سيتبع الكود منطقا مشابها : <button type="button" class="btn" data-toggle="modal" data-target="#mymodal"> <img src="img1.png" /> </button> <button type="button" class="btn" data-toggle="modal" data-target="#mymodal"> <img src="img2.png" /> </button> <button type="button" class="btn" data-toggle="modal" data-target="#mymodal"> <img src="img3.png" /> </button> <button type="button" class="btn" data-toggle="modal" data-target="#mymodal"> <img src="img4.png" /> </button> <!-- المودل يبدأ هنا --> و بالطبع ستحتاج إرسال طلب الأجاكس بشكل منفصل . سنحتاج أولا تعريف النموذج و إضافة حدث عن طريق الجافاسكربت : var myForm = document.querySelector('#myform'); myForm.addEventListener('submit' ,function(e){ e.preventDefault(); // منع تحديث الصفحة sendAjaxRequest(); }); function sendAjaxRequest() { // سيتم إرسال طلب الاجاكس هنا } حيث أن الدالة sendAjaxRequest ستكون المسؤولة عن إرسال هذا الطلب . function sendAjaxRequest() { // XMLHttpRequest تعريف نموذج عن الكائن var xhttp = new XMLHttpRequest(); // جلب البيانات من النموذج var formData = new FormData(document.querySelector('#myForm')) xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { alert('تم إرسال الطلب'); } }; xhttp.open("POST", "http://path.to/endPoint/example", true); // فتح طلب xhttp.send(formData); // إرسال طلب }
  18. تعبر الخطوة السادسة عن طريقة القراءة بإستعمال هاته العلاقة فقط , ففي المثالين تم على الترتيب جلب : المنتجات التي تخص الفئة X . الفئات التي تخص المنتج Y . مثال : المنتجات التي تخص الفئة "ملابس رجالية" . الفئات التي تخص المنتج "تيشرت أزرق" .
  19. يمكن تلخيص الية إنشاءها وفق الخطوات التالية , سنقوم بتعريف العلاقة كمثال بين النموذجين Category و Product : بداية نحتاج إنشاء الجداول و النماذج المراد إنشاء العلاقة بينهما : php artisan make:model Category -m php artisan make:model Product -m سنحتاج أيضا إنشاء جدول وسيط لتحقيق منطق العملية . بحيث يجب أن يتكون اسم الجدول الوسيط من أسماء فردية لكلا الجدولين ، مفصولة برموز شرطة سفلية ، ويجب ترتيب هذه الأسماء بترتيب أبجدي ، لذلك يجب أن يكون لدينا category_product ، وليس product_category : php artisan make:migration create_category_product_table بعد ذلك سنحتاج التأكد من تعريف الحقول اللازمة في ملف تهجير هذا الجدول الوسيط , بحيث يجب أن يمتلك حقلا أجنبيا يعبر عن عمود المعرف id في كلا الجدولين : products و categories : public function up() { Schema::create('category_product', function (Blueprint $table) { $table->increments('id'); $table->integer('category_id')->unsigned(); $table->integer('product_id')->unsigned(); }); } 4. تنفيذ أمر التهجير : php artisan migrate 5. تعريف العلاقات في ملفات النماذج : بداخل ملف النموذج Product.php : class Product extends Model { public function categories() { return $this->belongsToMany(Category::class); } } و أيضا بداخل ملف النموذج Category.php : class Category extends Model { public function products() { return $this->belongsToMany(Product::class); } } 6. ثم كخطوة أخيرة لن يكون علينا إلا احترام العلاقة عند إنشاء أي صفوف بقواعد البيانات و القراءة عن طريق العلاقتين products و categories . $productsOfXCategory = Category::find($ID)->products; $categoriesOfXProduct = Product::find($ID)->categories;
  20. يبدوا أنك تقوم بإخراج الملفات إلى ملف واحد . بالطبع ستحتاج تعديل المخرج أيضا , سنحتاج إخراج الملفات منفصلة بحسب إسم الملف . فعوضا عن مثل هذا : output:{ path:path.join(__dirname,"/dist"), filename:"main.js" }, نحتاج إخراج الملفات على هذا النحو : output:{ path:path.join(__dirname,"/dist"), filename:"[name].js" }, حتى لا يحدث خطأ التعارض الذي ظهر معك , ثم يمكنك بعد ذلك تشغيل أمر البناء بشكل طبيعي : npm run build
  21. تأكد أنك تقوم بإعداد webpack ليقوم بعمل المطلوب على نحو صحيح , ففي الأرجح يتم بناء الملف الأصلي index.js لأنك تقوم بهذا في ملف webpack.config.js : entry: { main: path.resolve(__dirname, './src/index.js'), }, ثم تقوم بتضمينه في ملف الـ html : <script type="text/html" src="{required('index.js')}"></script> في حين أنك تحتاج تمرير عدة نقاط وصول لكائن المدخلات entry : entry: { main: path.resolve(__dirname, './src/scripts/index.js'), about: path.resolve(__dirname, './src/scripts/about.js'), contact: path.resolve(__dirname, './src/scripts/contact.js'), }, ثم يمكنك تضمين كل ملف على حدة في ملفات الـ html التي تقوم ببناءها . يمكنك القراءة أكثر عن الخاصية entry في دليل Webpack الشامل .
  22. في المتصفح , الإسم name لو تم تعريفه كمتغير بشكل عام globally يكون ذا معنى و قيمة خاصة , و مثلما أشار المدرب @عبدالباسط ابراهيم ينتهي الأمر بأي تعريف له إلى إكتشافه على أنه المتغير name الخاص بالكائن window . و كما هو شائع في توابع و متغيرات الكائن window , لا يجب إستدعاءها أو إستعمالها دوما عن طريق الكائن على هذا النحو : window.document.getElementById('#someID') بل يكفي قراءتها مباشرة . و ليكن في العلم أن المتغير window.name يحتوي على غرض خاص ، ويفترض أن يكون سلسلة نصية , لذلك فإن أية تعريفات على هذا النحو : var name = {}؛ ينتهي الأمر بها فعليًا بإعطاء اسم المتغير العام (أي window.name) قيمة . و هنا يحاول المدقق الخاص ببرنامج VsCode توضيح هذا الشأن عن طريق شطب أي إسناد قيمة للمتغير name بشكل عام global . و كما يمكنك رؤية أن الشطب يختفي إذا وضعت نفس الشيفرة داخل دالة و هذا دليل على أن هذا الأمر يقتصر على تعريف المتغير name بشكل عام فقط . و لذلك للتخلص من المشكل بشكل نهائي يمكن الإستعانة بأحد الحلين : تعريف المتغير و إسناد قيمة له داخل دالة , أي بشكل محلي locally . إختيار إسم اخر للمتغير عوضا عن name , و ليكن customerName مثلا .
  23. يجدر الإشارة أن الـ Greedy Algorithms أو الخوارزميات الجشعة ليست خوارزمية Algorithm و إنما هي أسلوب خوارزميات Algorithm Paradigm وهو الشكل العام لتصميم الخوارزمية و منطقها دون التوغل في تفاصيلها . و أصل التسمية نفسه يعود إلى أسلوبها , فهي الأسلوب الذي يفرض أن تجد حلول مثلى محلية localized optimum solution, والتي من الممكن فيما بعد أن تتحول الى حلول مثلى عامة globally optimized solutions. و لذلك سميت بالخوارزميات الجشعة, لأنها تختار الحلول المحلية المثلى , أي أنها تؤمن حلا للخطوة الحالية من الخوارزمية من دون الأخذ بالحسبان تأثير هذه الخطوة على تكملة الحل , فهي جشعة لا تنتظر أو تؤمن حلولا مثلى عامة . و يستعمل لشرحها عادة مسألة الرحالة التاجر الذي يريد أن يمر بعدد من الأحياء لبيع بضاعته. هدف هذا التاجر هو إيجاد المسار الأقصر الذي يمر بكل الأحياء , فيستهدف بذلك كل القرية أو المدينة . وفق طريقة الخوارزمية الجشعة، على التاجر أن ينظر كل مرة إلى خريطته ويسافر إلى أقرب حي لم يزره بعد . أي أن الهدف هنا هو الحل الأمثل المحلي و الخاص بالخطوة الحالية أي الـ localized optimum solution , و ذلك بغض النظر عن تأثير هاته الخطوة على تكملة الحل , فبتطبيق منطق الخوارزميات الجشعة لن نهتم إن كان التاجر سيضطر في نهاية الأمر إلى العودة إلى هذا الحي بنهاية المسار ويسلك طريقاً أطول . أي أننا لا نهتم بالدرجة الأولى بتوفير حلول مثلى عامة globally optimized solutions. يمكنك القراءة عن الكثير من الخوارزميات و المسائل التي تقوم بإستعمال هذا النهج من مثل : مسألة عد العملات counting coins . كما يمكنك التعرف أكثر على الخوارزميات الجشعة طبقا لويكي حسوب . و قد تحتاج أيضا التعرف أكثر الفرق بين الخوارزمية Algorithm و أسلوب الخوارزميات Algorithm Paradigm.
  24. طريقة طرحك للسؤال تقتضي الفصل و توضيح الفرق بينهما . عن جافاسكربت : هي لغة برمجة نصية و تعتبر أفضل أداة لإنشاء صفحات ويب تفاعلية وسهلة الاستخدام. نظرًا لأنه يتم تنفيذ إستعلاماتها في المتصفح . فمن جانب العميل ، تتيح Javascript استجابة سريعة وتحميل أقل على الخادم . وقد اعتادت أن تكون لغة الواجهة الأمامية , و لكن تغير الأمر بعد ظهور Node.js , إذ أصبح يتم إستعمالها لتطوير كل من الواجهتين الخلفية و الأمامية . تعد أيضا جافاسكربت خيارًا مثاليًا لإنشاء أحدث الأنماط من تطبيقات الويب , و هي تطبيقات SPA ديناميكي (تطبيق صفحة واحدة) (يمكنك القراءة أكثر عن الـ SSR , SPA , PWA) . و تجعل أطر عملها و منصاتها الأمر سهلا من مثل AngularJS و ReactJS . و كذلك مع الكثير من تقنيات الخادم من مثل MongoDB و CouchDB و NoSQL. عن PHP : تمامًا مثل جافاسكربت ، تعد PHP لغة برمجة نصية . تم إنشاؤها لتطوير الويب و واجهته الخلفية , و تقوم بالتعامل مع قواعد البيانات و نظم إدارتها . و يتمثل الاختلاف الرئيسي عن جافاسكربت في أن PHP هي لغة من جانب الخادم تُستخدم للواجهة الخلفية فقط و يتم تنفيذ كل إستعلاماتها على الخادم . و يجدر القول أنها تحتوي مميزات و مكتبات الأكثر ثراءً وأمانًا أفضل مقارنةً بـجافاسكربت في هاته النقطة . كما أن أغلب نظم إدارة العمل المشهورة في الساحة تم بناءها عليها , وطبعا لا يجب إغفال حجم المجتمع الخاص بها مقارنة بحجم مجتمع NodeJS . و بالتالي فإن PHP أفضل خيار عندما تكون هناك حاجة للعمل مع نظم إدارة CMS (WordPress و Drupal و Joomla) أو LAMP stack أو تقنيات مثل MariaDB و MySQL و PostgreSQL . و على الرغم من أنه يمكن استخدام جافاسكربت لتطوير كل من الواجهة الأمامية والخلفية بمساعدة منصات مثل Node.js ، لا تزال PHP أداة أفضل للواجهة الخلفية . و لكن ,بحسب رأيي الشخصي, الأفضل تماما ، سيكون فكرة الجمع بينهما من أجل بناء تطبيق ويب ديناميكي قوي , يستعمل مفاهيم تطوير الويب وواجهاته الحديثة . و بغض النظر عن اللغة التي تختارها ، PHP أو جافاسكربت ، لمشروعك . فإنه لا يوجد الأسهل أو الأسرع تعلما . يتحكم في هذا العديد من العوامل و النقاط , قد يكون من بينها حتى إنطباعك و تعودك على سياق الإثنين مثلا ! يمكنك التعرف أكثر على اللغتين في ويكي حسوب : عن PHP عن جافاسكربت كما يمكنك تصفح المقالات الخاصة بكل منهما في الأكاديمية : مقالات في جافاسكربت مقالات في PHP
  25. لا يمكن قراءة خاصية من التابع where مباشرة على هذا النحو : return sections::where("section_name","==","البنوك")->bank; و في حالة المحاولة سيتم إظهار خطأ يتم فيه إخبارك أن الخاصية bank غير موجودة . قبل ذلك نحتاج تنفيذ الإستعلام الذي قمنا للتو ببناءه عن طريق أحد التوابع get أو first : $first = sections::where("section_name","==","البنوك")->get(); $second = sections::where("section_name","==","البنوك")->first(); الأولى ستقوم بإعادة مجموعة كائنات كل منها يمتلك الخاصية bank و بالتالي و للقراءة منها نحتاج عمل دور على عناصر المجموعة على هذا النحو : foreach($first as $item){ echo $item->bank; } أما بالنسبة للثانية فهي سوف تقوم بإعادة أول كائن يحقق الإستعلام و يمكن قراءة الخاصية مباشرة منه : $second->bank أو : return sections::where("section_name","==","البنوك")->first()->bank;
×
×
  • أضف...