-
المساهمات
5232 -
تاريخ الانضمام
-
تاريخ آخر زيارة
-
عدد الأيام التي تصدر بها
52
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو Adnane Kadri
-
المشكلة الوحيدة لديك هي أن قاعدة البيانات التي تحاول القراءة من عليها فارغة , فمن المنطقي أن لا يتم الإنطلاق في الدور foreach و القراءة من عليه . أي أن أي شيفرة بداخل الدور كالتالي : foreach($stnt as $val) { echo 'يوجد بيانات في قاعدة البيانات'; سيتم تجاهلها في حالة ما كان المعاد من تنفيذ الإستعلام stnt مصفوفة فارغة . في حين أن نفس الشيفرة سيتم تنفيذها في حالة كان المعاد من تنفيذ الإستعلام مصفوفة بعناصر يمكن القراءة من عليها عن طريق الدور . و لذلك تأكد من أن الجدول data الذي تحاول القراءة من عليه يمتلك على الأقل قيمة أو أكثر افتراضيا حتى يكون ما داخل الدور foreach قابلا للوصول . و لكن أفهم أن الفكرة التي تحاول تطبيقها هي : و لكن ما هو عيب هاته الطريقة ؟ => هو أنه لن يتم تسجيل أي عضو في حالة ما لم يتم تسجيل على الأقل عضو أو أكثر يدويا من قبل , فهذه هي الطريقة الوحيدة للوصول إلى ما داخل الدور . و لتجاوز هاته المشكلة سنقوم بتطبيق المنطق التالي : يتم قبول أي عضو تلقائيا ما ان لم تكن بياناته مطابقة لعضو اخر مسجل بالفعل . و ذلك عوضا عن : التحقق من أن كامل الأعضاء لا يطابقون بيانات هذا العضو كشرط لتسجيله , بحيث يقوم هذا بإغفال احتمال فراغ قاعدة البيانات . لنقم بالتالي : تعريف متغير isAlreadyRegistered كمتغير يحمل قيمة false افتراضيا . يتم تغيير قيمة isAlreadyRegistered إلى true في حالة مطابقة بيانات أحد الأعضاء المسجلين لبيانات العضو الذي يحاول التسجيل . يتم في مرحلة أخيرة التحقق من قيمة isAlreadyRegistered و التصرف بناء عليها . فإن كانت isAlreadyRegistered تحمل القيمة false تم تسجيل العضو و إلا فلن يمكن ذلك و ستظهر رسالة الخطأ . ستتبع الشيفرة نحوا مشابها : $isAlreadyRegistered = false; foreach($stnt as $val) { if ($val["emailw"] == $this-> mail) { // لاحظ شرط التطابق $isAlreadyRegistered = true; // إعادة تعيين قيمة المتغير break; } } if (!$isAlreadyRegistered) { // return $val["emailw"]; $conn-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // send data to database .. $stmt = $conn - > prepare("INSERT INTO data (namew, emailw, passwordw, datew) VALUES (:name, :mail, :pass, :date)"); $stmt-> bindParam(':name', $namep); $stmt-> bindParam(':mail', $mailp); $stmt-> bindParam(':pass', $passp); $stmt-> bindParam(':date', $datep); $namep = $this-> name; $mailp = $this-> mail; $passp = $this-> pass; $datep = $this-> date; $stmt-> execute(); return "Successfully connected .."; } else { return 'this email has created ..'; } ثم سيمكنك إنشاء أعضاء في كامل الحالات و وفقا لأي احتمالات . ملاحظة : الشيفرة لديك قد تحتاج بعض التنظيم و التنظيف حتى تصبح مفهومة و سهلة التشخيص و القراءة , و قد كان ذلك ضروريا حتى أستطيع التوغل في شيفرتك و أفهم مرادك منها . يمكنك التحصل على نسخة أكثر تنظيما و تنسيقا لملفك هنا : index.php .
- 7 اجابة
-
- 1
-
-
هلا تأكدت من أن مزود الاستضافة الخاص بك يسمح لك بإرسال رسائل البريد الإلكتروني ولا يحد من إرسال رسائل البريد الإلكتروني ؟ و ذلك لأن العديد من مضيفات الويب المشتركة ، وخاصة موفري الاستضافة المجانية ، إما لا تسمح بإرسال رسائل البريد الإلكتروني من خوادمها أو تحد من العدد الذي يمكن إرساله خلال أي فترة زمنية معينة . و قد تحتاج إلى التواصل مع فريق دعمهم للتحقق مما إذا كانت هناك أي قيود مفروضة على إرسال رسائل البريد الإلكتروني أو لا . في مثل هاته الحالات يلحظ سلوك مشابه لدالة mail , إذا تقوم بإعادة قيمة صحيحة و تعتبر أن إرسال الرسالة تام , في حين أنه لا يتم إستقبال أي رسالة في صندوق البريد . شيء اخر قد تحتاج التأكد منه و هو أن القيمة الممررة في : From قيمة صحيحة أي أن عنوان البريد الإلكتروني التالي : info@yhyasyrian.cf موجود بالفعل . ان كان كل شيء صحيحا , قد تحتاج تمكين سجل الأخطاء الخاصة بالوظيفة أو الدالة mail , و لنتأكد أن نقوم بوضع هذا قبل الشيفرة لديك : ini_set("mail.log", "/tmp/mail.log"); ini_set("mail.add_x_header", TRUE); و قد تحتاج في حالات أخرى إستعمال خدمات أو موفرات SMTP أخرى لإرسال و إدارة البريد الإلكتروني , و ذلك لأنها توفر مميزات إضافية و خيارات إرسال أخرى . يقترح أحد التالي : PHPMailer (شائع إستعماله) swiftmailer pearMailer يمكنك التعرف على كيفية إرسال رسالة بإستعمال PHPMailler و إرسال بريد إلكتروني باستخدام php. كما يمكنك القراءة أكثر عن طريقة إرسال بريد إلكتروني في PHP بإستخدام الوظيفة mail .
- 2 اجابة
-
- 2
-
-
في الحقيقة فكرة حماية عرض مكون في تطيبقات الصفحة الواحدة أو تطبيقات الويب التقدمية فكرة تعاب فيها هاته التطبيقات , إذ أن اقصى حماية لأي مكون أو أية صفحة عرض هي عن طريق طبقات وسيطة تستعمل قيما و شروطا مهما تم التلاعب فيها وتطبيق الأفكار عليها ستبقى مخزنة أو متحقق منها محليا و على المتصفح . ولكنه يجب الإنتباه إلى أن عرض مكون دون بيانات ليس له معنى فسيكون مجرد قالب , و لذلك التركيز الحقيقي لا يكون على حماية صفحات العرض و المكونات و إنما على البيانات التي تستجلب من الواجهة الخلفية . كما أن التوجه إلى تطبيقات الـ ssr أو الـ server side rendering سيقوم بتجاوز هذا الإشكال و حله بشكل نهائي , و كونك تستخدم vueJS فسيكون إستعمال NuxtJs موافقا و سهلا .
- 3 اجابة
-
- 1
-
-
يجب أولا فهم الغرض من القنوات الخاصة أساسا , فالقنوات الخاصة في الويب سوكيت وجدت للتحقق ما ان كان سيسمح للمستخدمين بالاستماع إلى هاته القنوات الخاصة أو لا , و ذلك بالإعتماد على شروط تتوفر فيمن يقوم بطلب الإستماع مثلا أو أية شروط أخرى . يتم تحديد قواعد ترخيص القناة الخاصة هاته بنا في ملف : route / channels.php الخاص بتطبيقنا . تحتاج أولا تعريف القناة بالملف المذكور كالتالي : Broadcast::channel('new-notification.{postUserId}' , function ($postUserId) { }); كما أنها ستحمل شيفرة ما يتم التحقق ما إن كان للمستخدم الحالي الحق في الإستماع لأحداث هاته القناة , كأن يتم مطابقة معرف القناة الخاصة و التأكد من امتلاك المستخدم لمنشور بهذا الإسم , أو أية طريقة تحقق كانت . يمكنك صياغة منطق الشيفرة وفق حاجتك للقناة الخاصة من الأساس . مثلا : Broadcast::channel('new-notification.{postUserId}' , function ($postUserId) { if(auth()->user()->can_view_notfs_of($postUserId)){ return true; } }); بحيث سيكون هذا المسار نقطة تحقق قبل الإشتراك في القناة بالنسبة لمستخدم معين أو تحقق شرط معين . و هذا من جانب الواجهة الخلفية , أما من جانب الواجهة الأمامية فسيتم تحديد نقطة الوصول هاته -نقطة التحقق- بإستعمال الخاصية authEndpoint مرفقا بـ csrf_token : var pusher = new Pusher("4fb4fa908d87ec86abf9", { cluster: '{{ env('PUSHER_APP_CLUSTER') }}', authEndpoint: '/broadcasting/auth', auth: { headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}', } } }); بعد ذلك ستعمل القنوات الخاصة وفق المطلوب .
- 3 اجابة
-
- 1
-
-
القناة بالإسم : 'new-notification.'.$this->post_user_id بالفعل قناة خاصة Private Channel لديك , هلا قمت بتوضيح سؤالك أكثر ؟ يمكنك الإستغناء عن laravel ehco إن كنت تستخدم pusher كويب سوكيت دريفر , و لا علاقة لذلك بنوع القناة .
-
بإنهائك لدورة تطوير واجهات المستخدم ستصبح مطور واجهات مستخدم , و هذا لأنك ستتعرف على كل من : مفهوم الواجهة الأماميّة للموقع front-end وكيفية عملها . أساسيات لغات تطوير واجهات المستخدم: HTML و CSS و JavaScript . استخدام أحدث أدوات التطوير: Bootstrap 4 و jQuery و Sass . التعامل مع خدمة استضافة المشاريع البرمجية GitHub و GitLab . نشر صفحات الموقع على الإنترنت . إعداد هيكل الموقع ووضع خطة العمل . التصميم المتجاوب مع مختلف الأجهزة والشاشات . و مطور واجهة المستخدم هو المسمى الوظيفي لمن يكون مسؤولا عن بناء الموقع من الجانب الشكلي العام من هيكلية و تصميم و تفاعلية . يشمل هذا المسمى الوظيفي الفروع التالية : البرمجة بإستخدام الجافاسكربت و أدواتها , و تصميم الويب بإستخدام الـ css و أدواتها . أي أن التعبير مطور واجهات مستخدم وفق المقدم في دورة واجهات المستخدم يتضمن صفتي " مبرمج " و " مصمم " معا . و للتفصيل أكثر يمكن تعريف كل منهم وفق التعريفات التالية : مصمم الويب : يهتم بالتصميم الخارجي للموقع . مبرمج الويب : الشخص المفوض إليه عمليات التكويد و كتابة الشيفرة , له إمكانية كتابة أكواد و خوارزميات أكثر تعقيدا , لا يعير إهتمام لشخص المستخدم أو تجربته . مطور الويب : إهتمامه أكثر بتجربة المستخدم نحو التطبيق المفوض إليه , معرفته بالمستخدم أكثر و بالتكويد و التعقيد أقل عادة .
- 1 جواب
-
- 1
-
-
مثلما ذكر المدرب حسن حيدر فإن الخاصية ليست قياسية أو على المسار القياسي الذي تحترمه كامل متصفحات الويب كما أنها تابعة لمجموعة الإضافات ذات السابقة webkit- . و يقصد بغير قياسي: أن استخدامها لا يكون في مواقع الإنتاج التي تستهدف كامل المتصفحات و الأجهزة , فالخاصية قد لن تعمل مع كل مستخدم . كما أنه قد يكون هناك أيضا عدم توافق كبير بين عمليات التنفيذ , أو ربما قد يتغير السلوك في المستقبل . يمكنك التعرف على قائمة المتصفحات التي تدعم مجموعات الإضافات webkit هنا . و بشكل عام , تحدد الخاصية -webkit-text-fill-color لون " تعبئة أحرف النص" . فإذا لم يتم تعيين هذه الخاصية ، يتم استخدام خاصية اللون color لها . أي أن : يتم تأويل إستعمال -webkit-text-fill-color على إستعمال الخاصية color إن تم إعطاء لكل منهما قيمة مخالفة للثانية : مثال 1 . الخاصية -webkit-text-fill-color تقبل إستعمال القيمة transparent لها على عكس الخاصية color مما يسمح بتطبيق العديد من الأفكار عليها : مثال 2 . يتم إستعمال الخاصية -webkit-text-fill-color عادة بمحاذاة الخاصيتين -webkit-text-stroke-color و -webkit-text-stroke-width , على عكس الخاصية color التي تستعمل وحدها . الخاصية -webkit-text-fill-color هي خاصية ليست قياسية أي أنها ليست مدعومة من قبل كامل المتصفحات على عكس الخاصية color . إليك قائمة المتصفحات الداعمة : المصدر : https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-text-fill-color
- 2 اجابة
-
- 1
-
-
يمكنك إستخدام ما يعرف بالتعليقات الشرطية لحجب المحتوى أو عرض رسالة معينة بناءا على متصفح المستخدم في أي صفحة أو مكون , و كونك تستخدم تطبيق nuxt.js يمكنك مباشرة إضافة هاته الأسطر : <div> <!--[if IE]> <p>عذرا, Internet Explorer غير مدعوم.<p> إستعمل <a href="http://google.com">Chrome</a> بدلا. <![endif]--> <![if !IE]> <Nuxt /> <![endif]> </div> إلى ملف default.vue قبل إخراج ملف dist عن طريق الأمر : npm run generate كما يمكنك إنشاء مكون كامل ليتم عرضه بدلا من رسالة بسيطة : <template> <div> <!--[if IE]> <IENotSupportedComponent /> <![endif]--> <![if !IE]> <Nuxt /> <![endif]> </div> </template> <script> import IENotSupportedComponent from '@/components/IENotSupportedComponent'; export default defineComponent({ name: 'Default', components: { IENotSupportedComponent }, }); </script>
- 2 اجابة
-
- 1
-
-
قبل التحدث عن وسم div ينبغي معرفة أن وسوم HTML تنقسم إلى ثلاث فئات رئيسية : Block level Tags : تشمل كل العناصر و الوسوم التي تأخذ كامل عرض حاوياتها افتراضيا . Inline Level Tags : تشمل كل العناصر و الوسوم التي توضع تلقائيا في خط أفقي افتراضيا ، و عندما تنفد المساحة على المحور الأفقي ، فإنها تلتف في السطر التالي وهكذا . Meta Level tags : تشمل كل العناصر و الوسوم التي لا تظهر في الصفحة كعناصر أو تقسيمات أو حاويات , و لكنها تستعمل لمهام أخرى (مثل توجيه محركات البحث نحوها) . وسم div هو وسم Block level tag , و يعبر عن اختصار division بالإنجليزية أو تقسيمة بالعربية . و يستخدم لإنشاء تقسيمات أو أقسام حاوية منفصلة للمحتوى في صفحة الويب مثل حاويات لكل من : استمارة أو نموذج , نص ، صور ، رأس ، تذييل ، شريط تنقل ، إلخ . و بالتالي فإن الغرض من استخدام علامة div هو تقسيم صفحة ويب ليس إلا . إذا نظرت إلى موقع ويب نموذجي ، يمكنك تقسيمه إلى أقسام منطقية. على سبيل المثال ، إذا نظرت إلى صفحة أسئلة البرمجة في أكاديمية حسوب ، يمكنك تقسيمه إلى شريط التنقل أعلى الشاشة ، وقسم المحتوى أي ينقسم إلى شريط تصفح علوي و اخر سفلي و قسم للمحتوى الرئيسي . يمكن تقسيم قسم المحتوى الرئيسي إلى سلسلة من الأسئلة والشريط الجانبي الأيسر . كل عنصر من هذه العناصر موضوع في وسم div لفصله كتقسيمة و عنصر . رغم أن هنالك العديد من الوسوم الأخررى التي يمكن لها أن تقسم صفحة الويب إلى حاويات و أقسام إلا أن إستعمال div شائع لعدة أسباب نذكر من بينها : أن وسم div يحتوي كل من علامة الفتح (<div> ) وعلامة الإغلاق (</div>) بشكل إلزامي لإغلاق الحاوية . يجعلنا هذا نتعرف بسهولة على بداية و نهاية كل حاوية . وسم div هو Block level tag , أي أنه يقوم بالنزول سطرا تلقائيا عند كل وسم فتح له , على عكس وسوم من مثل span أو label التي هي وسوم سطرية inline level tags . وسم div هو عنصر حاوية عامة , على عكس وسم body مثلا الذي يجب أن يتوفر مرة واحدة في هيكلية الـ HTML لكل صفحة . داخل وسم div يمكننا وضع أكثر من عنصر HTML و يمكن تجميعها معًا ويمكننا تطبيق CSS عليها على خلاف لو قمنا مثلا بتعريف هاته العناصر بشكل مباشر في وسم الـ body . كما أنه يقبل أية أنواع من العناصر و الوسوم داخله على عكس وسوم أخرى تشترط امتلاك عناصر محدودة . مثلا : يمكن استخدام وسم div لإنشاء تخطيط لصفحات الويب أو Layouts بالإنجليزية بسهولة و مرونة . لاحظ التخطيط : يمكن تخصيص عرضه و إرتفاعه بشكل مرن جدا , على عكس وسوم أخرى تشترط أن لا تتجاوز عرضا معينا . و هذا في الغالب ما جعل صاحب الفيديو يعتمد تقسيم الصفحة وفق وسوم div , كونه يريد أقصى مرونة و سهولة في تحكمه بعناصر صفحته . ومع ذلك ، اتجاه تطوير الويب في الاونة الأخيرة أصبح يتحرك نحو الاتجاه الدلالي أو الـ semantic direction . فبدلاً من عناصر div العامة ، من المفترض أن تستخدم العلامات الدلالية الأحدث التي تشير بشكل أفضل إلى أي شيفرة تبحث عنها في الصفحة . لذلك أصبح لدينا علامات التنقل nav والقسم section والرأس headere ،و غيرها . و لذلك فمن الناحية النظرية , ستجد البعض يطالبون أو يعتبرون أن من المفترض أن تتم إزالة الحاجة إلى علامات div العامة بشكل نهائي . أما من الناحية العملية ، فلا يزال معظم الأشخاص يستخدمون divs فقط . كونها طريقة مهيمنة و شائعة جدا , أو على الأقل أفضل من الأيام التي كان فيها يتم تصميم الصفحات باستخدام الجداول و الإطارات ! و طبعا هذا بجانب إمتلاكها للمميزات التي تم ذكرها سابقا . تعرف أكثر عن : و أيضا : توثيق وسم div : هنا .
- 2 اجابة
-
- 2
-
-
قد يكون سؤالك متشعب كثيرا كونك لم تحدد ما تقصده بالضبط بـ "التعديل على الكود و بناء المواقع " , فعملية بناء المواقع عملية متسلسة و تتفرع إلى كثير من التخصصات و يستعمل فيها الكثير من اللغات . فالمواقع و تطبيقات الويب بصفحة عامة تنقسم إلى قسمين : واجهات خلفية Backend : تمثل كل العمليات و المنطق الحاصل على مستوى الخادم , يتم في هاته المرحلة عادة بناء واجهات تطبيق برمجية لتسهيل ربطها مع الواجهة أو الواجهات الأمامية . واجهات أمامية Frontend : تمثل مجموع التصاميم و التفاعليات و بنى العناصر , يتم في مرحلة بناء الواجهات الأمامية بناء شاشات و قوالب قد تكون تفاعلية و قد تكون صماء . و كون أغلب العمليات تبتدئ من الخادم فسيكون المسؤول الأول عن عرض الصفحة لديك بشكل أو بتنسيق أو تفاعلية معينة , و لذلك نجد صفحات بلواحق php. تحمل شيفرات واجهات أمامية من مثل HTML أو جافاسكربت أو CSS . و لذلك فإن التعديل على هاته الصفحات يكون موجها و مقيدا بالهدف من التعديل : فإن كان الهدف التعديل على الواجهات الأمامية , مثل القوالب , فسيمكن مباشرة التعديل على بنية الـ HTML أو الملفات أو الأسطر المسؤولة عن تنسيق العناصر أو عن تفاعليتها , دون المساس بأي منطق داخل محددي الـ PHP : <?php // PHP هنا شيفرة ?> <div class="container-fluid"> .. </div> <?php // PHP هنا شيفرة ?> أما ان كان الهدف تغيير طريقة تعامل الخادم مع الطلبات و كل عمليات الخادم فسيتطلب التعديل على ما داخل المحددين , و إن لزم خارجهما . فاﻷول هو ما يقوم به مطورو الواجهة الأمامية , و الثاني هو ما يقوم به مطورو الواجهة الخلفية . نعم يمكن و هو المفترض أن يكون , فلا دخل لما يحدث على الواجهة الخلفية في الواجهة الأمامية . و قد لا تتطلب الكثير من التطبيقات و المواقع واجهة خلفية أصلا , مثل قوالب الـ HTML أو صفحات العرض أو أي من المواقع ثابتة المحتوى . و لذلك فإن إستعمال HTML , JS , CSS كاف جدا بهذا الخصوص . التعديل على واجهات المستخدم لا يلزم في الغالب أي معرفة مسبقة بخصوص الواجهات الخلفية في التطبيقات و المواقع المبنية بتنظيم , و لكن كون الواجهة الخلفية هي المحرك الأول فسيكفي - في الغالب - امتلاك معرفة سطحية لسهولة التصفح و التنقل بين الملفات و فهم الشيفرة , قبل على التعديل على ما يخص الواجهة الأمامية منها .
- 1 جواب
-
- 1
-
-
الكود النظيف بشكل عام هو أمر شخصي و ذاتي و لكل مطور وجهة نظر شخصية بخصوصه . ولكن هناك بعض الأفكار التي يتفق عليها الأغلب و يعتبرونها أفضل الممارسات لما يشكل شيفرة نظيفة , مفهومة , قابلة للقراءة و التعديل على نطاق واسع . أي باختصار : و لنأخذ المفهوم بشكل أعمق كالتالي : سهولة الفهم تعني سهولة قراءة الكود ، سواء كان ذلك القارئ هو المؤلف الأصلي للكود أو أي شخص آخر . لذا فهو يقلل من الحاجة إلى التخمين وإمكانية حدوث سوء فهم . من السهل أن نفهمه على كل المستويات ، وعلى وجه التحديد : منطق العمل للتطبيق بأكمله . كيفية تعاون الكائنات و الأصناف المختلفة مع بعضها البعض . دور ومسؤولية كل فئة و كائن . ما تفعله كل دالة و تابع . الغرض من كل تعبير يتم تعريفه , سواء متغير , ثابت أو خاصية . أما سهولة التعديل تعني أن الشيفرة سهلة التوسيع , التطوير وإعادة البناء . كما أنه من السهل إصلاح و تشخيص الأخطاء فيها , و نفس الأمر ينطبق أيضا : سواء كان ذلك القارئ هو المؤلف الأصلي للكود أو أي شخص آخر . و يشمل ذلك النقاط : الكائنات و التوابع صغيرة الحجم ولا تتحمل سوى مسؤولية واحدة (و ذلك احتراما لمبدأ فصل المهام ) . تتوفر الكائنات على واجهات برمجية عامة واضحة و موجزة . يمكن التنبؤ بكبفية عمل الكائنات و توابعها . الكود قابل للاختبار بسهولة ولديه اختبارات وحدة (أو على الأقل من السهل كتابة الاختبارات) . الاختبارات - إن توفرت- فهي سهلة الفهم والتغيير بسهولة . و لكن لما نحتاج الإهتمام أصلا بالكود النظيف ؟ لنقم بتلخيص أهمية الأمر في النقاط التالية : يجب أن تهتم لأن الشفرة (في الغالب ) لا تتم كتابتها مرة واحدة و فقط . و إنما في معظم الأوقات ، تحتاج أنت أو أي شخص آخر إلى العمل على الكود. ولكي تكون قادرًا على العمل عليه بكفاءة ، فأنت بحاجة إلى فهمه بالدرجة الأولى . مبادئ كتابة كود نظيف تمنحك الثقة أثناء كتابة شيفرتك . تكون الأخطاء أسهل للتشخيص و الحل . تجعل الكود سهل للصيانة و التطوير . و قد يتعلق مفهوم الكود النظيف بكثير من المفاهيم الأخرى , من مثل أنماط التصميم و مبادئه و غيرها . و لذلك قد تجد بعضهم يستعير بعض مبادئ تصميم البرمجيات ليستعملها كمبادئ للكود النظيف , من مثل مجموعة مبادئ SOLID (سنأتي لإرفاق سلسلة مقالات تخص كل مبدأ) أو DRY (اختصارا لترجمة لا تكرر نفسك Don't Repeat Yourself ) أو YAGNI (اختصارا لترجمة أنت لن تحتاجها You Aren't Gonna Need It) أو غيرها من المبادئ . و لذلك فهي عملية متشعبة جدا . و لعل الكود النظيف هو ما يصنع الفارق بين مبرمجي نفس اللغة و نفس إطار العمل , فإن كنت لا توليه أهمية أو أولوية فسيجب عليك ذلك . لأنك لن تلتفت إليه بداية كونك بكامل تركيزك وإستيعابك للكود, و لكنك ستجد نفسك في حاجة إليه عندما تبتعد قليلا عن تطوير تطبيقك ثم تقرر العودة إليه . و أتذكر جيدا إضطرار أحد فرق التطوير لنسف الكود بأكمله (الذي كان بحجم 400 ميغا) و إعادته لمجرد أن مطوريه نفسهم عجزوا عن فهمه بعد أقل من سنة من إنطلاقه . يمكنك التعرف أكثر على مبادئ SOLID لتصميم البرمجيات في سلسلة المقالات التالية : S O L I D تعرف أكثر على الشيفرة النظيفة هنا و هنا . كما يمكنك التعرف أكثر على مفهوم الكود النظيف في HTML , CSS و Sass هنا .
- 4 اجابة
-
- 1
-
-
لنقم بتناول الأمر بشكل عام على هذا النحو : الـ devDependencies : هي مجموع التبعيات و الحزم المطلوبة للتشغيل على بيئة التطوير , أي تلك التي يتم إستعمالها فقط أثناء التطوير أو الإصدار ، على سبيل المثال : الحزم المستعملة في اختبارات الوحدة . مثل حزمة jest في تطبيقات الـ node , react , angular و الـ vueJS , عناصر و حزم webpack . بحيث تشكل مجموع الأدوات التي تساعدك على إدارة كيفية تطوير التطبيق لديك . هاته الحزم يتم تثبيتها عن طريق مدير الحزم npm مثلا بإضافة الخيار save-dev-- : npm install pakcageName --save-dev الـ Dependencies : و هي مجموع التبعيات و الحزم التي يحتاجها مشروعك ليكون قادرًا على العمل في بيئة الإنتاج . على سبيل المثال : الحزم المستعملة في عرض أو تنسيق أو تفاعلية جزء من أجزاء الصفحة , فلو احتجنا إلى حزمة للحصول على اليوم و الشهر . فسنجد أننا نقوم مثلا باستيراد {getDate} من الحزمة "date-fns" في مكون ما , و بالتالي فإنه بدون هذه الحزمة لن يعمل كودنا . هاته الحزم يتم تثبيتها عن طريق مدير الحزم npm مثلا بدون إضافة أي خيار : npm install myPackage الـ PeerDependencies : هي مجموع الحزم التي تحتاجها حزمة ما لكي تشتغل بشكل طبيعي , و نادرا ما يتم التعامل مع هاته التبعيات و الحزم . و يقصد بها أي حزمة B تتطلبه حزمة معينة A ما ولكنها لا تشمله مع نفسه عند تثبيته . على سبيل المثال : حزمة popper.js مع بوتستراب , فهي حزمة يستعملها Bootstrap 4 لإظهار النوافذ المنبثقة و بعض التأثيرات و التفاعليات في بوتستراب , و لكن بوتستراب لا يتضمنها عند التثبيت و قد نغفل في كثير من الحالات عن تثبيتها فتسبب بعض المشاكل من مثل : مثال 2 : . يطلق هنا على popper.js و مثلها من الحزم لفظ peer dependecies لـ bootstrap . يمكن نمذجة طريقة التعامل معها عن طريق مدير الحزم npm كالتالي : ./node_modules/ | | | +- devDependency | | | | +- dependency/node_modules/ | | | +- peerDependency-1/ | | +- dependency | | | | | +- devDependency/node_modules/ | +- peerDependency-2/ كما يوجد أيضا : الـ bundledDependencies و الـ OptionalDependencies . قد لا يختلف الأمر كثيرا مع بيئات و لغات مختلفة , كما قد تختلف طريقة التعامل مع كل منها مع مدراء الحزم من مثل npm , composer , yarn , pip . سواء في أسماءها أو اللواحق أو الخيارات التي إضافتها لتحديد نوع الحزمة أو التبعية , أو ربما في طريقة تنسيق بنية ملفات الحزم و التبعيات أو أيضا في ملف مدير الحزمة (مثل composer.json و package.json) . و لكن يبقى منطقها و تقسيمها سواءا مهما اختلف كل ذلك .
- 1 جواب
-
- 2
-
-
التعريفات و الأفكار حول هندسة البرمجيات متفاوتة و كثيرة . و قد يصب مجملها و سياقها العام في مفهوم واحد جامع . بحيث يمكن القول على أنها فرع من فروع الهندسة حيث يقوم على مجموعة من الأسس التي تهدف إلى تصميم و تطوير البرامج بجودة عالية تلبي بالدرجة الأولى احتياجات المُستخدمين . يمكن أيضا الاستعانة ببعض المراجع و المصادر العالمية في التعريف بها : و أيضا : مما سبق يمكن فهم أن هندسة البرمجيات ليست كتابة شيفرة أو تكويدا و فقط , فمثل ما شرح المدرب عبد الحميد في تعليق سابق هي جزء من مرحلة التنفيذ . يمكن من هذا إستنتاج أن هندسة البرمجيات عملية إنتاجية لها عدة مراحل أساسية وضرورية للحصول على المُنتج البرمجي النهائي . بحيث يكون الهدف النهائي من أي برنامج هو الحصول على أفضل كفاءة ممكنة بأقل كلفة ممكنة. بحيث يطلق على مجمل هذه المراحل اسم دورة حياة تطوير النظام البرمجي أو بالإنجليزية : Software Development Life Cycle , و اختصارها " SDLC " . و كون فلسفاتها و نماذج بناءها كثيرة و متفاوتة سنأخذ أحد النماذج الكلاسيكية مثالا , هذا النموذج يعرف بنموذج الشلال أو Waterfall Model . لنقل أن هندسة البرمجيات وفق هذا النموذج تتبع بشكل عام المراحل التالية : تحليل المتطلبات Requirement Analysis : في هاته المرحلة يتم تجميع المتطلبات لفهم المشكلة و متطلبات الزبون أو المشروع ، هنا أيضا يتم تقسيم أو توزيع كل موضوع كبير أو معقد إلى اجزاء اصغر من اجل اكتساب فهم أفضل وأسهل للمشكلة والاهداف . التصميم Design : في هاته المرحلة يتم تصميم حلول للمتطلبات التي جمعناها، عملية تحتوي على انشطة معينة مثل صياغة وترتيب، لتحقيق الاهداف , و لا يعنى بالتصميم التصميم بمعناه و إنما تصميم حلول افتراضية أو منمذجة في مخططات لأفضل ما يليق أو ما قد يليق بالمشروع . التنفيذ Implementation : بعد تحديد المتطلبات والأهداف والاتفاق على لغة البرمجة ووضع الخطوط الأساسية للبرنامج وبنيته، يقوم الفريق بتنفيذ “ نموذج أولي Prototype ” للبرنامج . الاختبار Testing : في مرحلة الاختبار، يقوم الفريق باختبار البرنامج والتأكد من أنه يقوم بكافة الوظائف المطلوبة أو يتناسب مع المتطلبات التي تم تحديدها مسبقا . التطوير Evolution : يقوم الفريق بالبحث عن سبل تطوير البرنامج أو تطويره إنطلاقا من MVP (الحد الأدنى للمنتج أو Minimum Viable Product) . يتم اقتراح و إضافة ميزات جديدة له، كما تتم ماقشة إمكانية أو سبل جعله أكثر فاعلية وأكثر كفاءة . المخطط التالي يشرح خطوات النموذج : و بالتالي فإنها عملية منهجية و منظمة للغاية , و في الغالب تتم بالتنسيق بين فرق من مجالات مختلفة . يمكنك الاستزادة عن طرييق قراءة المقالات التالية : ما هي هندسة البرمجيات . مراحل تطوير البرامج في هندسة البرمجيات . دورة حياة البرنامج أو المشروع في هندسة البرمجيات .
-
يبدوا أن لديك خطأ بسياق تعليمة الـ SQL , و لذلك سيجب إعادة صياغتها على نحو أدق و أصح . هلا قمت بتجربة هاته التعليمة بدلا من تلك التي لديك : CREATE TRIGGER `on_comment` BEFORE INSERT ON `article_likers` FOR EACH ROW BEGIN UPDATE `articles` SET `likes` = `likes` + 1 WHERE `id` = new.`article_id` END ( فلا حاجة لتحديد الجدول في aricles.id عند التعليمة WHERE ) يرجى التأكد أيضا من أن لديك جدولا بإسم article_likers
-
ستحتاج في هذا إنشاء : ملف عرض : لعرض نموذج الإدخال و رفع الصورة و تقديمها إلى الواجهة الخلفية . متحكم : ليحتوي تابعا يتولى مهمة التحقق من المدخلات و فحص ملف الصورة و تخزينه . مسارين : واحد لعرض نموذج رفع الصورة أو الملف و واحد لإستهداف تابع المتحكم الخاص بالرفع . تعريف المسارين بداخل ملف web.php سيكون كالتالي : Route::view('/upload-image' ,'upload-image'); # إعادة ملف عرض Route::post('/upload-image' , 'UploadImageController@store'); # store إستهداف تابع المتحكم ملف العرض upload-image.blade.php سيحتوي بنية HTML مشابهة للتالي : <form action="/upload-image" method="POST" enctype="multipart/form-data" > <!-- يجب تحديد نوع التشفير --> @method('POST') @csrf <div class="form-group"> <label>صورة</label> <input type="file" name="image" required> </div> <button type="submit">رفع الملف</button> </form> المتحكم UploadImageController.php سيحتوي التابع store بالشيفرة التالية : public function store(Request $request) { // التأكد من أن الطلب يمتلك بالفعل ملف if ($request->hasFile('image')) { // التحقق من الملف صورة بلاحقة ملف صورة $request->validate([ 'image' => 'mimes:jpeg,bmp,png' ]); // images في مجلد app/storage/public تخزين الملف محليا في مجلد $request->image->store('images', 'public'); } return back(); } بعد تقديم النموذج و نجاح التحميل سيمكنك الوصول إلى الملفات المخزنة عن طريق التصفح إلى المسار : app/storage/public/images و ستلاحظ وجود ملف الصورة المرفوعة حديثا . هذا لن يكفي لجعل الصورة قابلة للوصول , فلا يزال عليك إنشاء الرابط الرمزي بين المسارين : storage/public/ و : public/storage سيمكن هذا عن طريق تنفيذ الأمر : php artisan storage:link ستلاحظ إنشاء رابط رمزي بين المجلد storage داخل public و public داخل app/storage . و يمكنك الوصول إلى رابط هاته الصور عن طريق التابع hashName في : // images في مجلد app/storage/public تخزين الملف محليا في مجلد $request->image->store('images', 'public'); $filePath = '/storage' .$request->file->hashName();
-
يمكنك إستخدام الكائن Date في جافاسكربت و توابعه لطباعة التاريخ المرافق بشكل dd-mm-yy . نحتاج أولا تعريف نموذج عن الكائن Date , مع تمرير التاريخ المراد إلى الدالة البانية الخاصية بالكائن : var date = new Date("Tue Aug 31 2021 14:29:37 GMT+0200 (EET)"); ثم لنقم بقراءة اليوم و الشهر و السنة عن طريق التوابع على الترتيب : getDate و getMonth و getFullYear على هذا النحو : var date = new Date("Tue Aug 31 2021 14:29:37 GMT+0200 (EET)"); var year = date.getFullYear(); var month = date.getMonth() + 1 // لأن عد الأشهر في الكائن يبدأ من الصفر var day = date.getDate(); ثم لنقم بتركيب سلسلة نصية تجمع كل منهم : var date = new Date("Tue Aug 31 2021 14:29:37 GMT+0200 (EET)"); var year = date.getFullYear(); var month = date.getMonth() + 1; // لأن عد الأشهر في الكائن يبدأ من الصفر var day = date.getDate(); var formatted = year + "-" + month + "-" + day; و أخيرا طباعة السلسلة الناتجة : var date = new Date("Tue Aug 31 2021 14:29:37 GMT+0200 (EET)"); var year = date.getFullYear(); var month = date.getMonth() + 1; // لأن عد الأشهر في الكائن يبدأ من الصفر var day = date.getDate(); var formatted = year + "-" + month + "-" + day; console.log(formatted); // "2021-8-31" يمكنك الإطلاع على مثال حي من هنا . كما يمكنك التعرف أكثر على الكائن Date في جافاسكربت هنا و هنا .
- 1 جواب
-
- 1
-
-
تحتاج في هذا إستعمال واجهة خلفية و قاعدة بيانات و هذا لأنك تحتاج حفظ بيانات المستخدمين لإستعمالها مستقبلا في عمليات تسجيل الدخول و الخروج . يعني هذا أن الذاكرة المحلية للتخزين في الجافاسكربت لن تكفي و ستحتاج إلى واجهة خلفية و قاعدة بيانات , و لن يكفي إستعمال الجافاسكربت وحدها لتحقيق ذلك . إن كانت برمجة الواجهة الخلفية مألوفة لديك , فيمكنك تحديد لغة أو إطار عمل الواجهة الخلفية و نظام إدارة قواعد البيانات و سيحاول مدربوا الأكاديمية تبسيط العملية لك . أما إن لم يكن إستعمالها مألوفا لديك و كان جديدا عليك فأنصحك أولا بتعلم برمجة الواجهة الخلفية و التعامل مع قواعد البيانات و من ثم نمذجة نظم مثل الذي تريده بشكل برمجي . و عموما , سيكون منطق العملية كالتالي : يتم إرسال بيانات العضو المراد تسجيله إلى الواجهة الخلفية للتطبيق عن طريق نموذج form . تقوم الواجهة الخلفية بإستقبال البيانات , معالجتها و فحصها . تقوم الواجهة الخلفية بكتابة إستعلام قواعد بيانات ﻹدراج بيانات العضو في قواعد البيانات . يتم تسجيل العضو و حفظ بياناته كعضو غير مؤكد التسجيل . يتم في نفس الوقت عن طريق الواجهة الخلفية توليد سلسلة نصية أو token يتم حفظه في قواعد البيانات و أيضا إرساله إلى البريد الإلكتروني للمستخدم أو بشكل رسالة نصية SMS . يتم لاحقا التقاط و إستقبال الكود أو السلسلة النصية التي يقوم المستخدم بإدخالها محاولا تأكيد حسابه , ثم مطابقتها مع المخزنة في قواعد البيانات . و إن تم التطابق يتم تأكيد حساب المستخدم و يتم تسجيله كعضو مؤكد التسجيل . و قد تختلف بعض التفاصيل بشأن كل خطوة بين لغة برمجية و أخرى .
-
بجانب ما قام المدربان شرف و أبو عواد بشرحه , فإنه يتم الإعتماد عليها في الإستعلامات أيضا لأن استخدام المفاتيح الرئيسية شائع أيضا كطريقة لتقييد أو ربط البيانات ذات الصلة ببعضها في قاعدة بيانات . و هذا يضمن أن تظل البيانات متسقة وأن قاعدة البيانات لا تحتوي على أية بيانات زائدة عن الحاجة . على سبيل المثال ، إذا قمت بحذف جدول (أو حتى صف في جدول) تعتمد عليه الجداول الأخرى ، فستتم إزالة البيانات المكررة . و يساعد هذا في منع مشاكل تكامل البيانات التي يمكن أن تسبب مشاكل مع التطبيقات التي تستخدم مثل هذه البيانات . و يعني هذا أنه بجانب أن المفاتيح الرئيسية سهلة في الإستعلام و فريدة و غير مكررة هي ضرورية جدا أيضا إذا كان الجدول مؤهلاً كجدول علائقي , أي أن يكون جدول يرتبط بغيره من الجداول بعلاقة ما . أي أنه له دورا علائقيا أيضا . كما أن هناك مشكلة أخرى تتعلق باستخدام السلاسل النصية مثلا كمفتاح أساسي وهي : نظرًا لأنه يتم وضع الفهرس في ترتيب تسلسلي باستمرار ، فإنه عند إنشاء مفتاح جديد يكون في منتصف الترتيب ، يتطلب علينا إعادة ترتيب الفهرس ... لكن إستخدامنا لمفتاح رئيسي يكون تلقائيا كعدد صحيح مرتب يجعلنا نضيف المفتاح الجديد فقط إلى نهاية الفهرس دون أي تداخل . أي أنه له بجانب دوره التبسيطي , و العلائقي دورا ترتيبيا و منطقيا أيضا . و لنأخذ على سبيل المثال , تطبيقات السجلات . فمن غير المنطقي طبعا أن يتغير ترتيب السجل كل مرة يتم فيها إدخال حقل جديد . فكل هذا يؤول إستخدام المفاتيح الرئيسية في أغلب الإستعلامات . و طبعا كل هذا لا يعني هذا الإستغناء عن باقي الأعمدة و الإكتفاء بالإستعلام عن البيانات بمفتاح رئيسي , فقد نحتاج في كثير من الحالات الإستعلام عن البيانات عن طريق أعمدة أخرى من مثل الإستعلامات التي يتم كتابتها في عمليات البحث و الفهرسة .
-
يبدوا أن مشكلة تثبيت webpack قد تم تجاوزها . يظهر من الخطأ أنه هنالك مشكلة بتثبيت حزمة popper.js و popperjs core أيضا . و ليكن في العلم أن حزمة popper.js هي حزمة يستعملها Bootstrap 4 لإظهار النوافذ المنبثقة و بعض التأثيرات و التفاعليات في بوتستراب. يطلق على popper.js و مثلها من الحزم لفظ peer dependecies , و يقصد بها أي حزمة B تتطلبه حزمة معينة A ما ولكنها لا تشمله مع نفسه عند تثبيته . و بسبب عدم تثبيتها أو تثبيتها على نحو خاطئ , نواجه مثل هاته الأخطاء التي تخبرنا أن واحدة من الحزم تتطلب حزمة أخرى . و لذلك سنحتاج أيضا تثبيت popper.js بشكل مستقل , لنقم بتنفيذ الأمر : npm install popper.js --save أما ان كنت تستعملين نسخ x.5 من بوتستراب فسيتطلب عليك تثبيت popperjs core عوضا عن popper.js , لنتأكد عندها من تثبيت الحزمة عن طريق الأمر : npm install @popperjs/core --save ثم سيكون عليك أخيرا تشغيل أمر البناء مجددا : npm run build إن استمرت مشكلتك بالظهور يرجى إخباري بشأن أيضا أخطاء تظهر .
-
لتفادي المشكل يمكننا تكبير المهلة الزمنية التي يتم فيها التحقق ما إن كان المستخدم قد قام بتحريك الشريط الجانبي إلى مهلة تراها مناسبة أكثر ، يمكننا بهذا إعطاء المستخدم وقتا أكثر لقراءة الرسائل بدون عمل أي إنزلاق للشريط الجانبي .
- 11 اجابة
-
- 1
-
-
تشير في الغالب الخطوط و الألوان الحمراء في vs code إلى أخطاء بالسياق في ملف web.php و ملف ForgetPasswordController.php , هلا تأكدت من عدم وجود أية أخطاء بهما ؟ كما أنه سيكون من المساعد لنا في تعقب المشكل و حله لو قمت بإرفاق الملفين أو نسخهما بشكل أكواد بإستعمال محرر الأكواد .
-
يحدث هذا لأنك تقوم بتغيير قيمة num في كل دورة من التكرار . فإن كانت قيمة num في الدورة الأولى 5 فهي أقل من القيمة الأولى لـ i و هي الصفر , و بالتالي فإن 5 أقل أيضا من 1 و 6 من 2 و 7 من 3 و هكذا . أي أن الشرط لن يتوقف . و لتدارك هاته المشكلة لنقم بتخزين القيمة الافتراضية لـ num في متغير ثان لا يكون له تأثير في ما داخل الدور سوى تحديده : function addUp(num) { var myNum = num; for (i = 0; i < myNum; i++) { num += i } return num } سيقوم هذا بإصلاح المشكلة و تحديد الدور من الأعلى في حالة بلوغ i قيمة num الإفتراضية . يمكنك الإطلاع على هذا المثال التجريبي .
-
بالإضافة إلى ما قام المدرب سامح بشرحه يمكننا تلخيص الوظيفة في دالة مستقلة تماما يتم إستدعاءها عند الحاجة لها . لنقم أولا بتعريف الدالة المسؤولة عن العملية : function scrollToBottom() { var div = $('#div1'); div.scrollTop(div.prop("scrollHeight")); } لنقم الان بإستدعاء الدالة في كل من الوظائف المعبر عنها بهاته الحالات : أي أن الدالة تستدعى عند كل تحميل لموارد الصفحة : scrollToBottom(); نحتاج في هذا تعقب الوظيفة المسؤولة عن عرض رسائل جديدة و إستدعاء الدالة المسؤولة عن تعديل الاسكرول عند كل عرض لرسالة جديدة . أي : <script> $(document) .ready(function(e) { function getMessages(letter) { var message = $('#div_show_message_groups'); $.get('show_pages/display_messages_groups.php', function(data) { message.html(data); // ضبط الشريط الجانبي بعد كل تضمين لرسالة جديدة scrollToBottom(); }); } }); </script> هاته العملية هي خطوتان مركبتان , نحتاج أولا تعقب إرسال رسائل جديدة و إستدعاء الدالة عند كل تضمين (وهو ما تم عمله بالفعل في الخطوة الثانية) , و ثانيا : التحقق من أن المستخدم لا يقوم بتحريك الشريط للأعلى . لنقم بتعريف متغير يحمل قيمة بوليانية تعبر عن ما إن كان المستخدم يقوم بتحريك الشريط أو لا , و لنقم بربط هذا بفترة تقوم بالتحقق ما إن توقف المستخدم بتحريك الشريط أو لا : var myDiv = $('#div1'); var userIsScrolling = false; /*يتم تغيير فيمة المتغير عند كل تحريك للشريط الجانبي*/ myDiv.scroll(function(){ userIsScrolling = true; }); /*ان توقفف المستخدم عن تحريك الشريط الجانبي لأكثر من ثلاث ثواني سيتم تغيير قيمة المتغير*/ setInterval(function(){ userIsScrolling = false; }, 3000); ثم سيتم إستعمال قيمة هذا التغير في التحقق قبل ضبط الشريط الجانبي عند كل إرسال لرسالة جديدة : <script> $(document) .ready(function(e) { function getMessages(letter) { var message = $('#div_show_message_groups'); $.get('show_pages/display_messages_groups.php', function(data) { message.html(data); // ضبط الشريط الجانبي للأسفل عند كل رسالة جديدة , و في حالة عدم تحريكه من طرفف المستخدم if(! userIsScrolling){ scrollToBottom(); } }); } }); </script> ثم لنقم بدمج الشيفرة كاملة , لتكون : $(document) .ready(function(e) { /*الوظيفة المسؤولة عن عمل الاسكرول*/ function scrollToBottom() { var div = $('#div1'); div.scrollTop(div.prop("scrollHeight")); } /*استدعاء الدالة عند كل تحميل جديد للصفحة*/ scrollToBottom(); var userIsScrolling = false; /*يتم تغيير فيمة المتغير عند كل تحريك للشريط الجانبي*/ $('#div1') .scroll(function() { userIsScrolling = true; }); /*ان توقفف المستخدم عن تحريك الشريط الجانبي لأكثر من ثلاث ثواني سيتم تغيير قيمة المتغير*/ setInterval(function() { userIsScrolling = false; }, 3000); /*الدالة المسؤولة عن جلب الرسائل من الواجهة الخلفية*/ function getMessages(letter) { var message = $('#div_show_message_groups'); $.get('show_pages/display_messages_groups.php', function(data) { message.html(data); // ضبط الشريط الجانبي للأسفل عند كل رسالة جديدة , و في حالة عدم تحريكه من طرفف المستخدم if (!userIsScrolling) { scrollToBottom(); } }); } setInterval(function() { getMessages("letter"); }, 100) /*إرسال طلب إلى الواجهة الخلفية بتسجيل رسالة جديدة*/ $("#messages_form_groups") .on('submit', function(e) { e.preventDefault(); $.ajax({ type: 'POST', url: 'send_pages/send_messages_form_groups.php', data: new FormData(this), dataType: 'json', contentType: false, cache: false, processData: false, success: function(response) { if (response.status == 1) { $('#messages_form_groups')[0].reset(); } } }); }); }); و بالطبع فإنه يمكنك التعديل من سلوك التحريك كإضافة بعض الأنيميشن أو ربما تغيير المهلة التي يتم فيها إعتبار أن المستخدم توقف عن السكرول . تأكد فقط أن الكثير من الأفكار قد تحتاج تجزئة و تبسيط لها ,و لما لا نمذجة في سبورة أو ورقة , فهو صحيح أن البرمجة ومفاهيمها أشياء تجريدية , و لكنها تنطلق من الواقع و تحاول نمذجته و تبسيطه و لذلك حاول دوما تقسيم الفكرة إلى أفكار جزئية و لا يجب عليك أبدا النظر إلى أية فكرة بمجملها كفكرة واحدة موحدة غير قابلة للتقسيم .
- 11 اجابة
-
- 1
-
-
ستحتاج أولا التسجيل بحساب تجاري في بيبال .ثم سنحتاج الدخول إلى لوحة تحكم المطور , أين يمكنك التعرف على نمطين و حسابين : حساب تجريبي , أو حساب sandbox (لأغراض الإختبار و التطوير). حساب حي , أو حساب live (لأغراض الدفع و التعامل الحقيقي) . سنقوم بتثبيت مكتبة paypal/rest-api-sdk-php عن طريق مدير الحزم composer : composer install paypal/rest-api-sdk-php 2. لنقم بإنشاء ملف إعداد paypal.php في مجلد config , و لنتأكد من إمتلاكه المحتوى التالي : <?php return [ 'client_id' => env('PAYPAL_CLIENT_ID',''), 'secret' => env('PAYPAL_SECRET',''), 'settings' => array( 'mode' => env('PAYPAL_MODE','sandbox'), 'http.ConnectionTimeOut' => 30, 'log.LogEnabled' => true, 'log.FileName' => storage_path() . '/logs/paypal.log', 'log.LogLevel' => 'ERROR' ), ]; 3. لنتوجه إلى ملف البيئة env. و لنتأكد من تعريف المتغيرات التالية : PAYPAL_CLIENT_ID=xxxxxxxxx PAYPAL_SECRET=xxxxxxxxx PAYPAL_MODE=xxxx حيث أن المتغيرين PAYPAL_CLIENT_ID و PAYPAL_SECRET يجلبان من لوحة تحكم المطور . 4. لنقم بإنشاء متحكم PaymentController يلخص بعض العمليات و لنتأكد من إمتلاكه المحتوى التالي : <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use PayPal\Rest\ApiContext; use PayPal\Auth\OAuthTokenCredential; use PayPal\Api\Agreement; use PayPal\Api\Payer; use PayPal\Api\Plan; use PayPal\Api\PaymentDefinition; use PayPal\Api\PayerInfo; use PayPal\Api\Item; use PayPal\Api\ItemList; use PayPal\Api\Amount; use PayPal\Api\Transaction; use PayPal\Api\RedirectUrls; use PayPal\Api\Payment; use PayPal\Api\PaymentExecution; use Illuminate\Support\Facades\Input; use Redirect; use URL; class PaymentController extends Controller { public function __construct() { /** إعداد سياق العملية و بدءها **/ $paypal_conf = \Config::get('paypal'); $this->_api_context = new ApiContext(new OAuthTokenCredential( $paypal_conf['client_id'], $paypal_conf['secret']) ); // حفظ الاعدادات $this->_api_context->setConfig($paypal_conf['settings']); } public function payWithpaypal() { $amountToBePaid = 100; // قيمة افتراضية يفترض أن تستجلب من الطلب $payer = new Payer(); $payer->setPaymentMethod('paypal'); /*تعريف عنصر*/ $item_1 = new Item(); $item_1->setName('هاتف نقال') /** اسم العنصر **/ ->setCurrency('USD') ->setQuantity(1) ->setPrice($amountToBePaid); /** سعر العنصر **/ /*تعريف قائمة عناصر و إضافة العنصر المعرف سابقا*/ $item_list = new ItemList(); $item_list->setItems(array($item_1)); /*تعريف مقدار*/ $amount = new Amount(); $amount->setCurrency('USD') ->setTotal($amountToBePaid); /** تخصيص روابط إعادة **/ $redirect_urls = new RedirectUrls(); $redirect_urls->setReturnUrl(URL::route('status')) ->setCancelUrl(URL::route('status')); /*تعريف تحويل جديد*/ $transaction = new Transaction(); $transaction->setAmount($amount) ->setItemList($item_list) ->setDescription('وصف التحويل'); /*تعريف مدفوعة و إضافة عملية الدفع إليها*/ $payment = new Payment(); $payment->setIntent('Sale') ->setPayer($payer) ->setRedirectUrls($redirect_urls) ->setTransactions(array($transaction)); /*تنفيذ العملية*/ try { $payment->create($this->_api_context); } catch (\PayPal\Exception\PPConnectionException $ex) { if (\Config::get('app.debug')) { \Session::put('error', 'فشل الاتصال تحقق من الاتصال'); return Redirect::route('/'); } else { \Session::put('error', 'حدث خطأ'); return Redirect::route('/'); } } foreach ($payment->getLinks() as $link) { if ($link->getRel() == 'approval_url') { $redirect_url = $link->getHref(); break; } } /** إضافة معرف الدفع إلى الجلسة **/ \Session::put('paypal_payment_id', $payment->getId()); if (isset($redirect_url)) { /** redirect to paypal **/ return Redirect::away($redirect_url); } \Session::put('error', 'حدث خطأ'); return Redirect::route('/'); } public function getPaymentStatus(Request $request) { /** جلب معرف العملية من الجلسة **/ $payment_id = Session::get('paypal_payment_id'); /** حذف المعرف من الجلسة **/ Session::forget('paypal_payment_id'); if (empty($request->PayerID) || empty($request->token)) { session()->flash('error', 'فشل الدفع'); return Redirect::route('/'); } $payment = Payment::get($payment_id, $this->_api_context); $execution = new PaymentExecution(); $execution->setPayerId($request->PayerID); /**تنفيذ العملية **/ $result = $payment->execute($execution, $this->_api_context); if ($result->getState() == 'approved') { session()->flash('success', 'نجح الدفع'); return Redirect::route('/'); } session()->flash('error', 'فشل الدفع'); return Redirect::route('/'); } } و بالطبع فإننا سنحتاج تعريف مسارين : واحد للدفع . واحد لتتبع مسار أو حالة الدفع . و ليكن : Route::post('/payment', ['as' => 'payment', 'uses' => 'PaymentController@payWithpaypal']); Route::get('/payment/status',['as' => 'status', 'uses' => 'PaymentController@getPaymentStatus']); حيث يتم إرسال طلب POST بمعلومات العنصر + تفاصيل عملية الدفع , ثم طلب GET لجلب حالة الدفع . و هذا هو الشكل الأبسط لعملية الدفع عبر بيبال , و بالطبع فإنه يمكن تخصيصها على نطاق واسع و إضافة الكثير من التفاصيل , كأن نقوم بحفظ تفاصيل العملية في قواعد البيانات لدينا و هكذا . كما يمكن أيضا إستخدام أحد الحزم التي تلخص العملية أكثر , من مثل حزمة srmklive/laravel-paypal .
-
يمكنك للتخلص من المشكلة تثبيت webpack بشكل global , تأكد أن تقوم بطباعة الأمر التالي : npm install -g webpack أما إذا كان لديك Webpack مثبت محليًا ، ففي حالات خاصة جدا سنحتاج تحديد المكان الذي يجب أن يبحث فيه موجه الأوامر بشكل صريح للعثور عليه ، مثل : node_modules\.bin\webpack يكون هذا في ملف package.json أين يتم تعريف الأوامر ضمن الكائن script (هذا بافتراض أنك داخل دليل المشروع بالفعل وأنك قمت بالفعل بتسطيب الحزمة عن طريق الأمر webpack ) .