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

Adnane Kadri

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

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

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

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

    52

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

  1. يمكنك إما حذف , إخفاء , تعطيل أو حتى إزالة التفاعلية من الزر بعد إستيفاء الغرض منه ( عرض الفيديو ) لتجنب المشكل من الأساس . يمكنك ذلك عن طريق التعديل إلى أحد الأكواد : <!-- حذف الزر --> <button onclick="launchVideo();$(this).remove();">افتح الفيديو</button> <!-- إخفاء الزر --> <button onclick="launchVideo();$(this).hide();">افتح الفيديو</button> <!-- تعطيل الزر --> <button onclick="launchVideo();$(this).attr('disabled', true);">افتح الفيديو</button> <!-- إلغاء تفاعلية الزر --> <button onclick="launchVideo();$(this).attr('onclick', '');">افتح الفيديو</button>
  2. إن كنت تقصد تطبيق طريقة الكود الأول في طريقة وضع الفيديو من الكود الثاني (أي إظهار الفيديو بعد الضغط على الزر في كلتا الحالتين , الأولى و الثانية ) فيمكنك ذلك عن طريق : إنشاء الزر و إضافة حدث عند الضغط عليه : <button onclick="launchVideo();">افتح الفيديو</button> إنشاء عنصر الفيديو و تضمينه بالصفحة : <div class="videoyoutube"><div class="video-responsive"><div class="video-youtube loader lazyload" data-src="//player.vimeo.com/video/90429499"></div></div></div> تعريف الدالة المسؤولة عن بدء الفيديو على هذا النحو : function launchVideo() { $(".video-youtube") .each(function(){ var iframe = '<iframe class="video-youtube loader" src="'+$(this).data("src")+'" allowfullscreen="allowfullscreen" height="281" width="500"></iframe>'; $(this).replaceWith(iframe); }); } فيكون الكود كاملا على هذا النحو : <button onclick="launchVideo();">افتح الفيديو</button> <div class="videoyoutube"> <div class="video-responsive"> <div class="video-youtube loader lazyload" data-src="//player.vimeo.com/video/90429499"> </div> </div> </div> <script> function launchVideo() { $(".video-youtube") .each(function(){ var iframe = '<iframe class="video-youtube loader" src="'+$(this).data("src")+'" allowfullscreen="allowfullscreen" height="281" width="500"></iframe>'; $(this).replaceWith(iframe); }); } </script> هذا سيقوم بتضمين الفيديو بعد الضغط على الزر فقط . بنفس الطريقة فم بإضافة الزر المسؤول عن ملئ الشاشة أسفل عنصر الفيديو : <div id="demo-element"> <button id="go-button" style="background-position: 0% 100%, 100% 0%, 0px 0px, 0px 0px; background-repeat: no-repeat; border-radius: 8px; display: inline-block; font: 25px calibri, Tajawal, sans-serif; padding: 10px 20px; position: relative; text-decoration: none; text-shadow: rgba(255, 255, 255, 0.4) 1px 1px 0px; vertical-align: baseline; white-space: nowrap;">افتح الفيديو في كامل الشاشة</button> </div> ثم قم بإضافة التفاعلية الخاصة بالزر بعد الضغط على تشغيل الفيديو (الموصوفة في التعليق السابق) . ربما قد تحتاج بعض التنسيقات الإضافية . فيكون الكود كاملا مشابها للتالي : <style> #go-button{ background-position: 0% 100%, 100% 0%, 0px 0px, 0px 0px; background-repeat: no-repeat; border-radius: 8px; display: inline-block; font: 25px calibri, Tajawal, sans-serif; padding: 10px 20px; position: relative; text-decoration: none; text-shadow: rgba(255, 255, 255, 0.4) 1px 1px 0px; vertical-align: baseline; white-space: nowrap; } </style> <button onclick="launchVideo();">افتح الفيديو</button> <div class="videoyoutube"> <div class="video-responsive"> <div class="video-youtube loader lazyload" data-src="//player.vimeo.com/video/90429499"> </div> </div> </div> <div id="demo-element"> <button id="go-button">افتح الفيديو في كامل الشاشة</button> </div> <script> // قم ببدء الفيديو function launchVideo() { $(".video-youtube") .each(function(){ var iframe = '<iframe class="video-youtube loader" src="'+$(this).data("src")+'" allowfullscreen="allowfullscreen" height="281" width="500"></iframe>'; $(this).replaceWith(iframe); }); // إضافة تفاعلية لزر ملئ الشاشة setEventForGoButton(); // إضافة تفاعلية لنص الزر handleFullScreen(); } function handleFullScreen() { $(document).on('fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange', function() { if(IsFullScreenCurrently()) { $("#demo-element span").text('opn'); $("#go-button").text('bak'); } else { $("#demo-element span").text('bak'); $("#go-button").text('opn'); } }); } function setEventForGoButton() { $("#go-button").on('click', function() { if(IsFullScreenCurrently()) GoOutFullscreen(); else GoInFullscreen($("#demo-element").get(0)); }); } function GoInFullscreen(element) { if(element.requestFullscreen) element.requestFullscreen(); else if(element.mozRequestFullScreen) element.mozRequestFullScreen(); else if(element.webkitRequestFullscreen) element.webkitRequestFullscreen(); else if(element.msRequestFullscreen) element.msRequestFullscreen(); } function GoOutFullscreen() { if(document.exitFullscreen) document.exitFullscreen(); else if(document.mozCancelFullScreen) document.mozCancelFullScreen(); else if(document.webkitExitFullscreen) document.webkitExitFullscreen(); else if(document.msExitFullscreen) document.msExitFullscreen(); } function IsFullScreenCurrently() { var full_screen_element = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null; if(full_screen_element === null) return false; else return true; } </script>
  3. أظن أن قصدك "وضع الكود الثاني و الثالث بداخل الأول" (و هذا تحقيقا للغرض المطلوب). لا حاجة لذلك , يمكنك فصل كل الدوال بحسب المهمة و من ثم إستدعاءهم في دالة واحدة . بداية يمكنك تبسيط العملية أكثر عن طريق التالي : قم بوضع كل الأكواد الأول و الثاني و الثالث بداخل دوال على هذا النحو (وهذا بحسب مبدأ فصل الإهتمامات) : function openVideoFile() { if(!$('#iframe').length) { $('#iframeHolder').html('<iframe id="iframe" src="//player.vimeo.com/video/90429499" width="700" height="450"></iframe>'); } } و : function putVideoInPage() { setTimeout(function(){$(".video-youtube").each(function(){$(this).replaceWith('<iframe class="video-youtube loader" src="'+$(this).data("src")+'" allowfullscreen="allowfullscreen" height="281" width="500"></iframe>')})},5e3); } و : function GoInFullscreen(element) { if(element.requestFullscreen) element.requestFullscreen(); else if(element.mozRequestFullScreen) element.mozRequestFullScreen(); else if(element.webkitRequestFullscreen) element.webkitRequestFullscreen(); else if(element.msRequestFullscreen) element.msRequestFullscreen(); } function GoOutFullscreen() { if(document.exitFullscreen) document.exitFullscreen(); else if(document.mozCancelFullScreen) document.mozCancelFullScreen(); else if(document.webkitExitFullscreen) document.webkitExitFullscreen(); else if(document.msExitFullscreen) document.msExitFullscreen(); } function IsFullScreenCurrently() { var full_screen_element = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null; if(full_screen_element === null) return false; else return true; } و : function setEventForGoButton() { $("#go-button").on('click', function() { if(IsFullScreenCurrently()) GoOutFullscreen(); else GoInFullscreen($("#demo-element").get(0)); }); } و : function handleFullScreen() { $(document).on('fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange', function() { if(IsFullScreenCurrently()) { $("#demo-element span").text('opn'); $("#go-button").text('bak'); } else { $("#demo-element span").text('bak'); $("#go-button").text('opn'); } }); } ثم يمكنك دمج و إستدعاء كل الدوال بعد الضغط على زر تشغيل الفيديو على هذا النحو : $(function(){ $('#button').click(function(){ // تضمين الفيديو في الصفحة openVideoFile(); // وضع رابط فيديو بصفحة النشر بدون وضع اكواد فريم putVideoInPage(); // إضافة التفاعلية لزر ملئ الشاشة setEventForGoButton(); // تغيير النصوص بحسب وضع ملئ الشاشة // #demo-element span النصوص المعرفة بـ handleFullScreen(); }); }); ملاحظات : الكثير من الأكواد غير واضحة المهمة في الأكواد التي أرفقتها و لا يظهر بالنسبة لي أي ترابط بين الكود الثاني و الأكواد الأخرى , و رغم ذلك قد قمت بتضيمنها في الأكواد التي وصفتها لك (يمكن لأن ذلك راجع إلى غياب باقي عناصر الصفحة ) . يمكنك تتبع نفس المنطق لكتابة دالة تجمع عمل كل الدوال المعرفة (ألف دالة تقوم بألف مهمة أفضل من دالة تقوم بألف مهمة) , سيكون الكود أفضل قراءة و أكثر وضوحا.
  4. لا يمكنك طباعة كل المتغيرات مرة واحدة , عوضا عن ذلك يجب تمرير اسم المتغير لتتم القراءة بشكل صحيح أثناء البناء , و ببساطة هذا ﻷن متصفح الواجهة الأمامية نفسه ليس له أي وصول لملف البيئة فالعملية تخص الخادم وحده و لذلك أثناء البناء يتم إستبدال أي متغير معرف على هذا النحو : process.env.MY_VAR بقيمته الفعلية و يتم البناء بشكل عادي . في حين أن المتغير : process.env يتم تجاهله بطبيعة الحال و يتم إعادة كائن فارغ عن طريقه . فعوضا عن طباعة كل المتغيرات يمكنك فقط طباعة المتغير الذي تحتاج و إستعماله بشكل عادي .
  5. لما لا تقوم فقط بتحميله تزامنيا ثم تضمينه بالصفحة ؟ componentDidMount() { // script إنشاء عنصر بوسم const script = document.createElement("script"); // تعريف المسار أو الرابط script.src = "/path/to/my_scripts.js"; // تفعيل التزامن و الوصول اليه script.async = true; script.onload = () => this.scriptLoaded(); // تضمينه في البودي document.body.appendChild(script); }
  6. يمكنك تضمين useLocation من @reach/router و من ثم قراءة القيمة على هذا النحو : import * as React from 'react'; import { useLocation } from '@reach/router'; const Current = () => { const location = useLocation(); console.log(location); }; سيتم طباعة كائن يسهل قراءة الخواص منه على هذا النحو : { pathname: "/", href: "http://localhost:8000/", origin: "http://localhost:8000" }
  7. يمكنك استبدال المسار الأخير (تأكد أنه الأخير دوما) على هذا النحو : <Route component = {NotFound} /> // هذا <Redirect to="/" /> // بهذا سيتم تتبع كل المسارات التي تختلف عن المسارات التي هي ما قبل هذا المسار و بدل عرض مكون react سيعاد توجيه المستخدم إلى الصفحة الرئيسية . و يمكنك عمل ذلك عن طريق مكتبة Gatspy على هذا النحو : ليكن في العلم أن صفحة 404 المنشئة من طرف المكتبة تكون بـ src/pages/404.jsx أو src/pages/404.js يمكنك تعديلها على هذا النحو لتقوم بنفس المهمة : import React from 'react' import { navigate } from 'gatsby' const NotFoundPage = () => { return navigate('/') } export default NotFoundPage
  8. هل يمكنك ذكر نوع محرر النصوص الذي تستخدمه ؟ أو على الأقل إرفاق صورة لذلك
  9. و هذا هو دور مطوري الواجهة الخلفية و قواعد البيانات . فهم المسؤولون عن جعل عملية إضافة المنتجات ( أو أي نوع اخر من المدخلات ) في قاعدة البيانات و التحكم بها عملية بسيطة من خلال واجهة إدخال يهتم مطور الواجهة الأمامية بتصميمها . يستعملون لإدارة قواعدة البيانات أشياء من مثل MySQL , MongoDB , Oracle , SQLServer , Redis .. الخ . أو ربما بعض اليات التخزين المؤقتة من مثل varnish , Memcached , redis .. الخ . و يحتاجون على الأقل للغة برمجة لهندسة الواجهة الخلفية و تولي كل الأشياء التي تحدث على مستوى الخادم . لغات من مثل Java , Python , Ruby , Php , .net .. الخ . فالمواقع من مثل مثالك لا تكتمل إلا بجزئيها و واجهتيها , الأمامية و الخلفية .
  10. تقريبا هي نفس العملية و كل خطوة من الاتي تتبع نفس منطق كل خطوة من التعليق السابق . بداية يجب عليك الإتصال بقاعدة البيانات <?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDB"; // إنشاء اتصال $conn = new mysqli($servername, $username, $password, $dbname); // تفحص الإتصال و طباعة الأخطاء ان وجدت if ($conn->connect_error) { die("فشل الإتصال بقاعدة البيانات: " . $conn->connect_error); } كتابة الإستعلام بشكل string : <?php $sql = "INSERT INTO YourTableName (column1, column2, column3) VALUES ('value 1', 'value 2', 'value 3')"; عمل Excution للإستعلام المطبوع حديثا : <?php if ($conn->query($sql) === TRUE) { echo "تم ادراج عنصر جديد بقاعدة البيانات"; } else { echo "خطأ: " . $sql . "<br>" . $conn->error; } فيكون الكود كاملا : <?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDB"; // إنشاء اتصال $conn = new mysqli($servername, $username, $password, $dbname); // تفحص الإتصال و طباعة الأخطاء ان وجدت if ($conn->connect_error) { die("فشل الإتصال بقاعدة البيانات: " . $conn->connect_error); } // طباعة إستعلام $sql = "INSERT INTO YourTableName (column1, column2, column3) VALUES ('value 1', 'value 2', 'value 3')"; // تنفيذ الإستعلام if ($conn->query($sql) === TRUE) { echo "تم ادراج عنصر جديد بقاعدة البيانات"; } else { echo "خطأ: " . $sql . "<br>" . $conn->error; } و قد تحتاجين إغلاق الإتصال أحيانا , يمكنك ذلك عن طريق : <?php // تنفيذ إغلاق الإتصال $conn->close();
  11. هل يمكنك تفعيل الDebug Mode و إرفاق الأخطاء التي ظهرت ؟ سيساعد هذا في حل المشكل أكثر يمكنك ذلك عن طريق تعديل ملف php.ini . قم بتغيير قيمتي error_reporting و display_errors , إلى : error_reporting = E_ALL display_errors = On ملاحظة : طبعا لا ينبغي وضع الأكواد حرفيا فهي وصفية و إنما يجب صياغة نفس المنطق في كتابة كود مشابه أو تنسيق الكود بما يلائم تضمينه
  12. هل يمكنك وصف المشاكل التي واجهتها أو أي أخطاء ظهرت ؟
  13. بإستخدام phpmyadmin يمكنك ذلك عن طريق : التصفح إلى http://localhost/phpmyadmin الدخول إلى قاعدة البيانات المقصودة بالقائمة الجانبية . الضغط على زر SQL في قائمة التصفح أعلى الصفحة . طباعة إستعلام الإدراج و الضغط على GO , يكون كود الإستعلام على هذا النحو : INSERT INTO blood_groups (blood_group_name) VALUES ('O+'); INSERT INTO benefactor (fk) VALUES (/* من جدول الفصائلid قم بطباعة اخر */); ملاحظات : يجب مراعاة القيم الإفتراضية للأعمدة بالجداول السابقة و التأكد من أن لها قيم إفتراضية بالفعل . لا ينصح بإدخال البيانات يدويا إلا في حالات إستثنائية , عوضا عن ذلك يمكنك فعل ذلك بالـ php .
  14. كل الخطوات صحيحة و سليمة , يبدوا أن المشكلة في إستعمال سرفر smtp . قم بتغيير العنوان إلى : smtp.googlemail.com أي MAIL_HOST بملف الإعداد على هذا النحو : MAIL_DRIVER=smtp MAIL_HOST=smtp.googlemail.com MAIL_PORT=465 MAIL_USERNAME=YOUR_EMAIL_ADDRESS MAIL_PASSWORD=PASSWORD MAIL_ENCRYPTION=ssl و لا تنسى محو الكاش : php artisan cache:clear php artisan config:cache
  15. لو أحببت أن تترك الأمر لجانب الباك اند فقط فيمكنك تطبيق العملية وفق المنطق التالي : جلب كل العناصر الغير مميزة . جلب العناصر المميزة . تكرار العناصر المميزة كذا مرة . دمج العناصر المميزة مع غير المميزة وفق ترتيب معين . مثال عملي : يمكنك جلب كل العناصر التي لا تحتوي على 1 في حقل المنتج المميز على هذا النحو : $sql = "SELECT * FROM Prodect WHERE is_special = 0 ORDER BY RAND()"; ثم جلب العناصر المميزة و تكرارها : <?php // تحضير الاستعلام $sql2 = "SELECT * FROM Prodect WHERE is_special=1 ORDER BY RAND()"; function getRepeated($query) { $repeat_times = 10; $counter = 0; $rows = []; $result = mysql_query($query); // تحضير كل الحقول while($row == mysql_fetch_row($result)) { $rows[] = $row; } // تحضير مصفوفة تحمل عناصر مميزة ومكررة $repeated = []; for($index = 0; $counter < $repeat_times; $counter++) { $repeated[] = $rows[$i]; $index++; // إعادة الدور إلى الصفر لملئ المصفوفة بعناصر مكررة if($index == count($rows)) { $index = 0; } } return $repeated; } $special = getRepeated($sql2); المزج وفق الترتيب و التكرار : <?php $non_special = [...]; // ناتج الاستعلام الاول $special = [...]; // ناتج الاستعلام الثاني مكرر $total = []; $offset = 0; for($i = 0; $i < count($non_special); $i++) { if(is_float($i / 10)) { array_push($total ,$non_special); } else { // قطعة من مصفوفة المنتجات المميزة لدمجها $pieceOfSpecial = array_slice($special,$offset,5); $offset += 5; array_merge($total ,$pieceOfSpecial); } } // =======> return $total الان ستسهل عملية عرضها مباشرة تحديث : يمكن أن لا تكون هناك أي حاجة من تكرار العناصر المميزة كذا مرة لدمجها مع الغير مميزة و يمكن تحقيق نفس الغرض في حالة جلب عدد معين من العناصر المميزة . فتكون عوض الخطوة كاملة و عوضا عن اقتطاع المصفوفة كل مرة في المرحلة الأخيرة يمكنك فقط دمج المصفوفة كلها (قد يكون هذا البديل مفيد في حالة وجود عدد محدود جدا من العناصر المميزة بقاعدة البيانات) .
  16. تحديث : يمكنك أيضا إضافة الevents المتعلقة بالخيارات المنشئة بعد إضافتها . مثال : function setListeners(){ document.querySelectorAll('select#products option').addEventListener('click' ,function(){ // }); } ومن ثم إنشاء الأحداث بعد إنشاء العناصر : function getProducts(target) { let getProducts = new XMLHttpRequest(); getProducts.open('GET', '/invoices/getProducts/' + target); getProducts.onload = function() { if (this.readyState === 4 && this.status === 200) { // succes let products = JSON.parse(this.responseText); products.forEach(function(item) { let option = document.createElement('option'), text = document.createTextNode(item['product_name']); option.appendChild(text); option.value = item['id']; productsSelect.appendChild(option); }); setListeners(); // إستدعاء الدالة } else { alert('لقد حدث خطأ غير متوقع'); } } getProducts.send(); }
  17. يبدوا أن المشكلة في تحديد العناصر فقط : و بالفعل فإن العنصر select بالمعرف products غير موجود من ضمن الDOM . عوضا عن ذلك يوجد بالمعرف product فتكون : var productsSelect = document.getElementById('product'); ثم تحتاج إستدعاء الدالة getProducts من المكان الصحيح , أي بعد أي تغير في قائمة الأقسام على هذا النحو : <select name="section" onchange="getProducts(this.value)" class="form-control @error('section') is-invalid @enderror" id="section"> <option value="NULL" disabled>إختر القسم</option> أو أيضا : document.getElementById('section').addEventListener('change' ,getProducts(this.value)); فيكون كود الجافاسكربت كاملا على هذا النحو : var productsSelect = document.getElementById('product'); document.getElementById('section').addEventListener('change' ,getProducts(this.value)); function getProducts(target) { let getProducts = new XMLHttpRequest(); getProducts.open('GET', '/invoices/getProducts/' + target); getProducts.onload = function() { if (this.readyState === 4 && this.status === 200) { // succes let products = JSON.parse(this.responseText); products.forEach(function(item) { let option = document.createElement('option'), text = document.createTextNode(item['product_name']); option.appendChild(text); option.value = item['id']; productsSelect.appendChild(option); }); } else { alert('لقد حدث خطأ غير متوقع'); } } getProducts.send(); }
  18. بشكل عام . فكرة الكوبونات , قسائم الشراء و البرومو كودس هي أشياء يتم تقديمها للعملاء كحافز للشراء , وقد تكون خصم نسب مئوية معينة ,خصم مبلغ معين ثابت أو حتى الشحن و التوصيل المجاني و ربما أفكار أخرى . أما إن كنت تقصد الكوبونات كمفهوم برمجي فيمكن معاملتها كغيرها من المفاهيم و من ثم إستعمالها في عمليات حساب سعر المنتج و الدفع . مثال عملي عن الإستعمال : قم بإنشاء جدول كوبونات بقاعدة البيانات يحوي الأعمدة : coupon_code // معبرا عن كود الكوبون coupon_type // معبرا عن نوع الكوبون coupon_amount // معبرا عن مقدار الخصم بحيث ينحصر نوع الكوبون في الأنواع الثلاثة الممثلة بأرقام 1,2,3,على التوالي , بـ : 1 => fixed_card_amount // مبلغ خصم ثابت 2 => percentage_off // خصم نسبة مئوية 3 => free_shipping // شحن مجاني 2. في نموذج إدخال كود الكوبون بصفحة الدفع قم بالتحقق من وجود كوبون يحمل نفس الكود المدرج أو لا . 3. إن كان نعم يمكنك تحديد نوع و مقدار الكوبون . 4. و من ثم عمل العملية الحسابية لحساب السعر الجديد و إظهاره للمستخدم . (طبعا يجب أخذ الحيطة و إدراج إحتمال التلاعب بالسعر و التصرف وفق ذلك , مثال :تخزين السعر في الباك اند بعد إدخال كود كوبون أكثر أمانا ) . طبعا هذا هو الشكل الأبسط للعملية , و هي وصفية بحتة يمكنك تطبيقها باللغة التي تبرمج وفقها . كما يمكنك إضافة الكثير من المميزات مثل : كوبون للمسجلين حديثا فقط , كوبون بتاريخ إنتهاء صلاحية , كوبون بعدد منتهي للإستعمال .. إلخ .
  19. الوظيفة openssl_cipher_iv_length هي جزء من مكتبة openSSL PHP المضمنة في اعتمادات الphp بالفعل . في حالات قد يكون هذا الإمتداد مثبتا بالفعل , فيمكنك مباشرة تفعيله عن طريق تعديل ملف الإعداد php.ini مثل ما قام الأخ @يوسف احمد9بالإشارة . إن لم تحل المشكلة يستحسن تحديث إعتمادات اللارافل الخاصة بالمشروع , يمكنك ذلك عن طريق الأمرين : composer install composer update و في أحيان أخرى لن يكون الإمتداد مثبتا و هذا قد يدفعك إلى تحميل ملف الـ dll الخاص بالإضافة ( ssleay32.dll ) و من ثم إضافته إلى مجلد الphp . ملاحظات : قد تحتاج إعادة تشغيل السرفر في هذا الأمر أو الأمر الأول .
  20. يمكنك إرسال طلب إلى نقطة الوصول هاته للتحويل من عملة معينة إلى أخرى : https://data.fixer.io/api/convert ? access_key = API_KEY & from = GBP & to = JPY & amount = 25 كما يمكنك جلب معدلات التحويل بالنسبة لعملة رئيسية عن طريق هاته النقطة : https://data.fixer.io/api/2013-12-24 ? access_key = API_KEY & base = USD & symbols = JPY,CAD,EUR,DZD لاحظ أنه قم تم تخصيص تاريخ معين يتم فيه جلب معدل التحويل الخاص بذاك التاريخ . يمكنك جعل العملية ديناميكية عن طريق : const date = new Date().toISOString().slice(0, 10); ثم تمرير الثابت date . لاحظ أيضا أنه يمكنك تخصيص العديد من العملات في مرة واحدة و هذا شيء جميل . مثال عن رد من التوثيق الرسمي للواجهة : { "success": true, "historical": true, "date": "2013-12-24", "timestamp": 1387929599, "base": "GBP", "rates": { "USD": 1.636492, "EUR": 1.196476, "CAD": 1.739516 } }
  21. أسعار العملات بالنسبة لعملة رئيسية و معدلات التحويل الخاصة بها متغيرة في الغالب و تحتاج ديناميكية لوضع الأسعار . تستطيع إما تخزين السعر بالدولار كـ base currency و من ثم جعل عملية التحويل ديناميكية عن طريق معدل تحويل . لا أظن أنه توجد حزمة جاهزة لتقوم بالعملية . لكن يمكنك إستعمال أحد هاته الـ APIS : هذا أو هذا لجلب معدلات التحويل من الدولار أو من أي base currency تستعملها . كما يمكنك مباشرة إرسال طلبات GET إلى نقطة الوصول هاته فقط و قراءة الخاصية geoplugin_currencyConverter لجلب معدل التحويل الذي يخص بالمستخدم نفسه (الذي تم إرسال الطلب عن طريقه) من الدولار من الرد مباشرة أيضا (مثلا لإظهار العملة بحسب بلد المستخدم حسب تحليل الـ IP) . أيا كانت طريقتك في جلب معدل التحويل يمكن حساب السعر الجديد بسهولة عن طريق : var new_price = base_price * exchange_rate_base_to_target /*من الرسبونس*/; و كإقتراح لتحسين تجربة المستخدم و جعل عملية تثبيت العملة المحول إليها سهلة , قم بتخزين العملة و معدل التحويل في الجلسة أو الكوكي أو التخزين المحلي بدل إرسال طلب مع كل مرة . ملاحظات : يمكنك أيضا الإستغناء عن هاته العملية ككل و إدخال أسعار لمختلف العملات في حالة كان عدد العملات محدود جدا و تريد تحكم أكبر في الأسعار بحسب البلد أو العملة (خذ إحتمال أسعار السوق السوداء مثلا , فهي لا ترسل في الردود من أي API و قد تحتاجها لوضع تسعيرة معقولة في حال كان هنالك تباعد كبير بين سعر الصرف و سعر السوق السوداء) . و بنفس منطق واجهات التطبيق البرمجية المشار إليها يمكنك تخصيص نقطة وصول لجلب معدلات التحويل بتطبيقك نفسه و ليكن من جدول تنشأه : معدلات التحويل exchange_rates , و من ثم التحكم في هاته المعدلات على نطاق أوسع و التعديل بما يلائم سعر الصرف الحالي أو السعر الذي يناسب فرع المتجر بالعملة الفلانية .
  22. يمكنك رفع الملفات من المشروع إلى المستودع المحلي عن طريق اﻷمرين : أولا : // إضافة كل الملفات المعدلة git add -A // إضافة ملفات محددة git add changedDirectory // أو git add changedFile ثم : git commit -m "A changes title" و أخيرا رفع الملفات إلى الـبرانش الخاص بك على الـ remote repo عن طريق : git push -u origin yourBranch ستلاحظين اخر commit قمت بعمله على المستودع الخاص بك على هذا النحو :
  23. لك الخيار في أن تقوم مباشرة بإستعمال المكتبة التي تقدمها و ربطها مع الـ Laravel كمكتبة خارجية أو بإستعمال أحد الحزم التي تبسط العملية . ولعل هاته الحزمة الأفضل على الإطلاق.
  24. لا حاجة لتشفير الـ ID لحل المشكلة فعليا , عوضا عن ذلك يمكنك إنشاء دالة أو middleware يقوم بالتحقق من ملكية العنصر item قبل عمل أي تعديلات عليه . مثال عملي : <?php class YourController extends Controller { public function editItem(Request $request ,Item $item){ if(! $this->isOwner($item)){ return 'لا يمكنك تعديل العنصر'; } // تكملة العملية } private function isOwner($item){ if(auth()->user()->id == $item->user_id){ return true; } return false; }
  25. في العادة إرسال رسائل sms قد تحتاج تكلفة و إشتراك لتطبيق العملية و الإستعانة بها. و يمكنك تطبيق العملية كلها وحدك مثل ما أشار الأخ @بلال زيادة. وقد تحتاج الإستعانة بأحد هاته الواجهات Twilio أو Plivo . مثال عن إرسال رسالة بإستعمال Twilio : <?php use Twilio\Rest\Client; # إرسال رسالة ... $client = new Client($account_sid, $auth_token); # تعطى مع حساب تويليو $client->messages->create($receiverNumber, [ 'from' => $twilio_number, # يعطى مع حساب تويليو 'body' => $activation_code ]); # قم تخزين الكود ... $currentUser->update([ 'activation_code' => $activation_code , ]); ثم براوت اخر يمكنك عمل المصادقة بشكل مشابه : <?php ... if($user_input == $activation_code){ $current_user->update([ 'phone_is_activated' => true, ]); return 'أنت مفعل'; } return 'كود التفعيل خاطئ'; و بالطبع فإن هذا هو الشكل الأبسط للعملية , يمكنك إضافة العديد من الأشياء كإنتهاء صلاحية الكود أو ربط كود التفعيل بمودل اخر غير مودل المستخدم و غيرها . كما يمكنك إستعمال حزم جاهزة مثل هاته الحزمة بحيث توفر عليك الكثير من الأشياء من مثل الError Reporting و كل الBack end Logic بحيث تقوم بإرسال بيانات إلى نقاط وصول معينة و القراءة من الرد . و مثل ما تقدم هذا في نفس الوقت هي تزيل عنك حرية التصرف و التطوير بما يلائم مشروعك .
×
×
  • أضف...