-
المساهمات
5129 -
تاريخ الانضمام
-
تاريخ آخر زيارة
-
عدد الأيام التي تصدر بها
51
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو Adnane Kadri
-
يمكنك عمل ذلك عن طريق تمرير عدة نقاط وصول لملفات scss الخاصة بك عن طريق : module.exports = { entry: { 'about': ['./src/css/about.scss'], 'contact': ['./src/css/contact.scss'], 'index': ['./src/css/index.scss'] }, plugins: [ new MiniCssExtractPlugin( { filename: "./css/[name].css" } ), ] } الwebpack ستقوم بقراءة مفاتيح المدخلات و تقوم بإستبدالها بالوسم name داخل الfilename فتكون المخرجات على هذا النحو : dist css about.min.css contact.min.css index.min.css ثم بملفات الHTML يمكنك تضمين كل ملف css داخل dist/css حسب الحاجة أو حسب صفحة الHTML الحالية. ملاحظة : تأكد أن تقوم بتضمين الminifier على نحو صحيح : const MiniCssExtractPlugin = require('mini-css-extract-plugin'); و في حالة ظهور أي أخطاء على هاته الشاكلة : could not resolve module mini-css-extract-plugin تأكد أن تقوم بتثبيت الـ Plugin : npm install --save-dev mini-css-extract-plugin
- 5 اجابة
-
- 3
-
إضافة إلى ما تفضل الأخ @Wael Aljamalبشرحه . طبقا للتوثيق الرسمي فإن الخاصية query عبارة عن كائن يحتوي كل الخصائص لكل بارمتر ممرر في الروات . و في حالة تعطيل الquery-parser فإن الخاصية query ستقوم بإعادة كائن فارغ و بطبيعة الحال فإن أي قراءة لخاصية عن طريق query ستقوم بإعادة undefined , ويخص بالقول طلبيات الـ GET فقط أي أنه معطل في ما غير ذلك . فحل المشكلة هو إما بتغيير الطريقة إلى GET فيكون : <form id="login" action="userlogin" method="GET"> <div> <label for="email">Email: </label> <input type="text" id="email" name="email"></input> </div> <input type="submit" value="Submit"></input> </form> أو بالقراءة من الPOST . قد تحتاج تسطيب body parser في نسخ متقدمة من Express (+4.16) و من ثم استعماله على هذا النحو : قم بتسطيب الحزمة : npm install --save body-parser ثم استعمالها بشكل Globally : var bodyParser = require('body-parser') app.use( bodyParser.json() ); // لدعم تشفير الجيسون في البودي app.use(bodyParser.urlencoded({ // لدعم تشفير اليو ار ال في البودي extended: true })); أما ان كنت تستخدم نسخ أقل من 4.16 فتستطيع مباشرة : app.use(express.json()); // دعم تشفير الجيسون في البودي app.use(express.urlencoded()); // دعم تشفير اليو ار ال في البودي ومن ثم القراءة على هذا النحو : app.post('/your-end-point', function(req, res) { var email = req.body.email; });
- 3 اجابة
-
- 2
-
لأنك نفسك تقوم بتعطيل الـ Input بإضافة الخاصية disabled في حالة الإختبار منجز . عوضا عن ذلك يمكنك إستعمال الخاصية checked على هذا النحو : <form action="/projects/{{$project->id}}/tasks/{{$task->id}}" method="POST" class="w3-bar-item w3-left w3-large" style="display:inline;padding:0;margin:0;"> @method('PATCH') @csrf <input type="checkbox" name="done"class="w3-check cnsb-bor-green w3-border-left" {{$task->done ? 'checked':''}} onchange="this.form.submit()"> </form>
-
بداية تأكد أن تقوم بتحديث الflutter plugin في الأندرويد ستوديو عن طريق : > File > Settings > Plugin > Updates و قد تتعطل الاقتراحات تلقائيا بمجرد تفعيلك لوضع حفظ الطاقة , فإن كان كذلك تأكد أن تقوم بإلغاء التفعيل عن طريق : > File > Power Save Mode إن لم تختف المشكلة قم بالتأكد أنك غير معطل لإقتراحات المحرر عن طريق : > File > Settings > Editor > General > Code Completion إن لم تختف المشكلة بعد هاته المراحل تأكد أن تقوم بمسح الملفات المؤقتة وإعادة التشغيل عن طريق : File Invalidate caches / Restart Invalidate and Restart
- 3 اجابة
-
- 2
-
يمكنك تسجيل serviceProvider الخاص بالحزمة لأشخاص معينين فقط , وجعل عملية تسجيله ديناميكية عن طريق التعديل بملف AppServiceProvider.php : <?php namespace App\Providers; use Barryvdh\Debugbar\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { } public function register(){ if(auth()->user() && in_array(auth()->id(), [1,2,3])) { $this->app->register(new Barryvdh\Debugbar\ServiceProvider()); } }
- 2 اجابة
-
- 1
-
هل يمكنك إرفاق رابط الموقع ؟
-
لتحليل هاته الخوارزمية قمت بالعمل التالي : 1 - إيجاد كل المصفوفات الفرعية التي يمكن تشكيلها من عنصر فأكثر من عناصر المصفوفة الأصلية . 2 - حساب مجموع أعداد كل مصفوفة فرعية . و أيضا لا يجب أن ننسى مجموع كل المجموعات الفرعية التي يمكن تشكيلها من هاته المجموعة الفرعية (قد تبدوا الفكرة معقدة لكن ينبغي تبسيطها و فهم أيضا أنه يمكن معاملة المجموعة الفرعية على أنها مجموعة أصلية غير محسوب مجموعها بعد و قد يحتوي مجموع إحداها على المجموع المطلوب فلا ينبغي أبدا إغفالها ). 3 - في كل دورة لحساب المجاميع يتم تسجيل هذا المجموع , و لا داعي لتسجيله إن كان محصلا بالفعل من عدد n عناصر من قبل . 3 - الان و قد تم حساب كل المجاميع الممكنة , يجب أخذ أكبرها قيمة و فقط . الان و قد تم فهم الخوارزمية يمكن تطبيقها عن طريق عملية متكررة للعثور على مجموع أعداد كل مصفوفة فرعية يمكن تشكيلها عن طريق مصفوفة . بالنسبة للكود سيكون مشابها لما يطبق نفس المنطق , و قد قمت بكتابته على هذا النحو : إنشاء دالة تتولى الخطوة 2 و 1 معا , بحيث تقوم بإيجاد المصفوفات الفرعية و المصفوفات الفرعية الممكن تشكيلها من هاته المصفوفة الفرعية و هكذا . و كل مرة يتم تشكيل مصفوفة فرعية يتم تسجيل مجموع عناصرها : var sums = []; // تحضير مصفوفة مجاميع فارغة function getAllPossibleSums(group, sub_group) { // if( group.length == arr.length || (group.length <= arr.length && sub_group.length == 0) ){ // لا حاجة لتسجيل مجموع في بداية الدور وفي حال عدم وجود أي مصفوفة if( group.length > 0 ){ // حساب المجموع var total = group.reduce(function(a,b){return a+b;},0); // لا حاجة لتسجيل المجموع إلا إن كان غير مسجل if(sums.indexOf(total) == -1){ sums.push(total); } } } // بداية التكرار تكون هنا else{ // ايجاد و تسجيل مجموع كل العناصر getAllPossibleSums(group.concat(sub_group[0]),sub_group.slice(1)); // ايجاد وتسجيل مجموع كل العناصر الممكن تشكيلها من المصفوفة الفرعية getAllPossibleSums(group,sub_group.slice(1)); } // إعادة المجاميع return sums; } 2. عمل دالة تقوم بالخطوة رقم 3 : function getMaxNumInArray(arr){ let i; // البدء بالعنصر الأول let max = arr[0]; // اجتياز العناصر بعد الاندكس المختار ومقارنة كل عنصر مع العنصر المختار for (i = 1; i < arr.length; i++) { // في حالة وجود قيمة أكبر سجلها if (arr[i] > max){ max = arr[i]; } } // إعادة أكبر عنصر return max; } 3. عمل دالة تلخص عمل الماضيتين : function getMaxSubSum(arr) { var all = getAllPossibleSums([],arr); return getMaxNumInArr(all); } ثم أخيرا دمج الأكواد على هذا النحو : function getMaxSubSum(arr) { var all = getAllPossibleSums([],arr); return getMaxNumInArr(all); } var sums = []; /** * هاته الدالة تقوم بتلخيص منطق العملية * @param arr : array */ function getMaxSubSum(arr) { var all = getAllPossibleSums([],arr); return getMaxNum(all); } /** * هاته الدالة تقوم بتسجيل أي مجموع يمكن تشيكله من المصفوفة * @param group : array , sub_group: array */ function getAllPossibleSums(group, sub_group) { if( group.length == arr.length || (group.length <= arr.length && sub_group.length == 0) ){ if( group.length > 0 ){ var total = group.reduce(function(a,b){return a+b;},0); if(sums.indexOf(total) == -1){ sums.push(total); } } } else{ getAllPossibleSums(group.concat(sub_group[0]),sub_group.slice(1)); getAllPossibleSums(group,sub_group.slice(1)); } return sums; } /** * إيجاد العدد اﻷكبر قيمة في قائمة أعداد * @param arr : array */ function getMaxNumInArr(arr){ let i; let max = arr[0]; for (i = 1; i < arr.length; i++) { if (arr[i] > max){ max = arr[i]; } } return max; } و من ثم إستدعاء الدالة على هذا النحو : var arr = [ 1, -2, 3, 4, -9, 6]; console.log(getMaxSubSum(arr)); // 14
- 6 اجابة
-
- 1
-
يمكنك تحقيق الغرض كالتالي : <?php $output = ''; while($row = mysqli_fetch_array($result)) { $output .= substr($row['message'], 0, 35); } echo $output; ?>
- 3 اجابة
-
- 1
-
بالفعل هي مثل ما قلت ، وقد تم تصليح الأخطاء الإملائية التي وردت بارك الله فيك و وفقك الله لما يحبه و يرضاه.
- 4 اجابة
-
- 1
-
يمكنك تخصيص نوع البيانات في البارمتر الممرر في الراوت عن طريق التابع where , الذي يقبل البارمترز على الترتيب : param : معبرة عن اسم البارمتر الذي تقوم بتمريره . regex : تعبر عن Regular Expression تخص المقبول في هذا البارمتر فقط . و يتم تعريف التابع where التابع للinstance الذي اسمه Route في مثالك عن طريق : <? Route::get('news/edit/{id}', 'YourController@your_method')->where('id', '$[0-9]+^'); غير أن هاته الطريقة لن تحقق الغرض و سيتم رمي Exception Not Found 404 في حالة ما كان البارمتر id لا يماثل العبارة [0-9]+ , أي أنه ليس integer . أما في حالة ما أردت عمل Redirect لصفحة تريدها من داخل الController فيمكنك عمل validation بسيط للـ ID الممرر بهذا الشكل : <?php use Illuminate\Support\Facades\Validator; // لا تنسى تضمين الواجهات الللازمة class MyController extends Controller{ public function myMethod(Request $request){ $validator = Validator::make($request->all() , ['id' => 'integer']); if($validator->fails()){ // قم باعادة التوجيه } } }
- 4 اجابة
-
- 1
-
ﻷن السطر الأخير يقوم بطباعة المتغير friends قبل حدوث الـxhr أصلا أي قبل أن تطرأ عليه أي تغيرات , على عكس ما داخل التابع then الذي هو مرتبط بما بعد حدوث الطلب . و لحل المشكلة يمكنك فقط إنشاء ميثود تقوم بإستعمال المتغير بمنطق معين من ضمن المكون يتم استدعاءها داخل التابع then , و هذا هو الأصح عمله على هذا النحو : var friends = {} axios.get('http://localhost:8080/api/people') .then(function (response) { friends = response.data[0] // استدعاء الدالة بعد عمل تغيرات على المتغير useFriends(); }) .catch(function (error) { console.log(error) }) function useFriends(){ console.log(friends); }
-
بملف index.js قم بتضمين الجيكويري على نحو صحيح : import '@laylazi/bootstrap-rtl/dist/css/bootstrap-rtl.min.css'; import '@laylazi/bootstrap-rtl/dist/js/bootstrap.min.js'; // import 'jquery/dist/jquery.min.js' عوضا عن هذا import $ from 'jquery'; // هذا import 'popper.js/dist/popper.min.js'; import '../sass/style.scss'; import '@fortawesome/fontawesome-free/js/all'; $(document).ready(function(){ console.log('جي كويري الان تعمل!'); }); أما عن المشكلة الثانية فلم أواجهها و تم الدخول عن طريق الرابط التشعبي بشكل عادي . و مثل ما أشار الأخ @سامح أشرف قد تكون لديك مشكلة في الملفات المؤقتة الخاصة بالمتصفح ،قم بتجربة متصفح آخر أو حذف الملفات المؤقتة.
- 3 اجابة
-
- 1
-
طبعا هذا ستحدده حاجتك لتعلم جافاسكربت من الأساس , فيمكن تعلم JS كلغة برمجة فقط مثلها أي لغة أخرى , أي يمكن تعلمها بمعزل تماما عن الـ Document Object Models API الذي هو المسؤول عن عمليات التلاعب بعناصر صفحة الويب . فإن كان هدفك تصميم و برمجة المواقع فستحتاج لهما بشكل كبير لتحسين تعاملك و تحكمك بعناصر الموقع , أما من جانب الجافاسكربت فأنت ستحتاج التعامل مع ما الـ Browser Object Models و الDocument Object Models (اختصارهما DOM , BOM) و الأساليب التي ستواجهها هناك ستهتم بشكل أساسي بتحديد العناصر والتلاعب بمظهرها ومحتواها . و للقيام بذلك ، ستحتاج إما إلى معالجتها مباشرة عبر محددات تشبه CSS ، أو عن طريق شجرة عناصر . و كلاهما يتطلب أن يكون تعاملك مألوفًا مع الـ Html و الـ css . أما إن كنت تريد تعلمها لعمل تطبيقات الهاتف فلن تحتاج التوغل فيهما حد الإحتراف و سيكفيك فيهما مستوى متوسط و هذا طبعا ﻷنك ستحتاج التعامل مع DOM افتراضية تتبع نفس منطق الDOM الفعلية . خلاصة الأمر أنك ستحتاج تعلمهما للتعامل مع جافاسكربت بشكل أمتع و أكثر حيوية و أكثر اختصارا للوقت و المفاهيم و ستخير بين تعلمهما إن قمت بإتخاذ مسار اخر غير تصميم و تطوير المواقع .
-
طبعا العملية ستصبح سهلة مع التعود على مواجهة الأخطاء و حلها , لكن هذا لا يمنع من جعلها منهجية و منظمة لغرض إختصار الوقت و تنظيم العمل أكثر فحل مشكلة ما ,برأيي, يتطلب : مشكلة ! فبالطبع يجب أن تكون لديك مشكلة و من الواجب قراءتها و التأني في ذلك . إعادة إنتاج المشكلة و عزل كود مصدر المشكلة : أحب عادة حذف الأسطر التي تكون مسؤولة عن المشكلة , فإختفاء الخطأ يعني ثبوتها . ثم أقوم بإعادة انتاج المشكلة من جديد . هذا يجعلك تقوم بعزل كود المصدر المسؤول و وضع نظرتك على نطاق أضيق و أدق , فالتركيز في ثلاث أسطر أو أربع أفضل من التركيز في مشروع كامل أو ملف كامل. قم بوصف المشكلة : كأن تحاول الحصول على أكبر عدد من المعلومات عن هاته المشكلة . (مثال عن ذلك : الزر يشتغل و يستدعي دالة بالفعل لكن الـ console يقول أن هاته الدالة غير معرفة , و أرى أني قد عرفتها بالفعل في ملف index.js) بناءا على ذلك حاول الإجتهاد في حل المشكلة مما جمعت من وصف للمشكلة و تحديد لكود المصدر المسؤول , و لا بأس ببحث على الانترنت عن مشاكل إما مشابهة في الخطأ الظاهر أو في الوصف و الطرح أو السياق أو كود مصدر المشكلة . و ستصبح العملية سهلة و أبسط مع مرور الوقت و التعود على الأخطاء و على حلها . و قد يقودك إنتقال المشاكل من بسيطة , إلى معقدة إلى معقدة جدا , إلى تعلم الخوارزميات و الproblem solving التي ستنقل الأمر إلى مستوى اخر من التنظيم و المنهجية.
- 3 اجابة
-
- 1
-
و عليكم السلام و رحمة الله . بالنسبة لسؤالك الأول : لا يزال عليك عمل التفاعلية المطلوبة بنفسك , بملف index.js قم بإضافة الأسطر التالية : $('.collapse') .on('show.bs.collapse', function () { $(this).prev().find('svg') .removeClass('fa-angle-down') .addClass('fa-angle-up') }) .on('hide.bs.collapse', function () { $(this).prev().find('svg') .removeClass('fa-angle-up') .addClass('fa-angle-down') }); . و بالطبع يجب عليك تعريف الحالة الإفتراضية للأسهم , إما فوق أو تحت : <i class="fa fa-angle-down" aria-hidden="true"></i> 2. السؤال الثاني : لم يعمل الفيديو بسبب أنك تقوم بتعريف الدالة بعد نسبها للـ Event Listener على هذا النحو : var myvideo=document.getElementById("video1"); myvideo.addEventListener("click", function playPause() { if(myvideo.paused) myvideo.play(); else myvideo.pause(); }, false); و : <section class="video"> <video id="video1"> <source src="./videos/video.mp4" type="video/mp4"> </video> <div class="overlay "> <button onclick="playPause()"> <i class="fa fa-video-camera" aria-hidden="true"></i> مشاهدة الفيديو </button> </div> </section> في حين أنك تستدعي دالة غير معرفة أصلا وإسم هاته الدالة داخل تعريف الـ Event Listener متجاهل أصلا . فحل المشكلة إما بتعريف الدالة خارجا على هذا النحو : myvideo.addEventListener("click", function(){ playPause(); } , false); function playPause() { if(myvideo.paused) myvideo.play(); else myvideo.pause(); } أو بربط الEvent Listener بالزر عوضا عن الفيديو نفسه فيكون : var myvideo=document.getElementById("video1"); var playVideoButton=document.getElementById("playVideoButton"); playVideoButton.addEventListener("click", function playPause() { if(myvideo.paused) myvideo.play(); else myvideo.pause(); }, false); و طبعا لا تنسى تعريف الزر بـ ID: <section class="video"> <video id="video1"> <source src="./videos/video.mp4" type="video/mp4"> </video> <div class="overlay "> <button id="playVideoButton"> <i class="fa fa-video-camera" aria-hidden="true"></i> مشاهدة الفيديو </button> </div> </section> و أفضل إستعمال الطريقة الثانية لأن العنصر بالايدي video غير ظاهر و لاحظ أن الoverlay فوقه فهو غير قابل للوصول أما عن الزر فهو غير ذلك . أما عن تنسيق زر تشغيل الفيديو فيمكنك إستبدال الأيقونة بغيرها : <div class="overlay "> <button id="playVideoButton"> <i class="fa fa-play" aria-hidden="true"></i> مشاهدة الفيديو </button> </div> و بالطبع لا تنسى أن تقوم بإعادة compile للملفات عن طريق : npm run build ملاحظات : لا أعلم إن كنت قد واجهت نفس الأخطاء بالنسبة للwebpack على هذا النحو : > product@1.0.0 build > webpack serve --mode development sh: 1: webpack: Permission denied بحيث تم حلها عن طريق تغيير الوضع : chmod 775 -R /product و لا ألزمك طبعا و لكن من اﻷفضل , و كشيء من الشائع بين الأوساط , تعريف السكربت watch عوضا عن build بملف package.json , كما يجب أيضا عمل سكربت للproduction : "scripts": { "watch": "webpack serve --mode development", "prod" : "webpack serve --mode production" }, فيتم الإستدعاء كالتالي : npm run watch npm run prod
- 3 اجابة
-
- 1
-
كشيء جميل في اللارافل فإنه تم تم بناءه مع وضع الاختبارات في الاعتبار على عكس أطر عمل أخرى (مثال : الcodegniter) , فقد تم تضمين دعم الاختبارات باستخدام الphp Unit و يأتي كل Fresh Laravel Application مع ملف اعداد phpunit.xml و مجلد tests . بحيث يحتوي المجلد tests افتراضيًّا على مجلّدين : Feature (تعبر عن مجموعة اختبارات كل منها هو اختبار جزء من الشيفرة) و Unit (تعبر عن مجموعة اختبارات الوحدة). يتم تشغيل الاختبارات التي قمت بإنشاءها عن طريق طباعة الأمر في التارمنل : phpunit أو : vendor/bin/phpunit أي أن الاختبارات التي يتم عملها ببيئة عمل الphpunit في اللارافل هي أحد الخيارين : اختبار وحدة unit test : و يقصد بها اختبارات مكتوبة من منظور المبرمجين. وهي مصممة للتأكد من أن طريقة معينة (أو وحدة) للclass تؤدي مجموعة من المهام المحددة. اختبار ميزة feature test: و يقصد بها اختبار جزء أكبر من التعليمات البرمجية الخاصة بك ، بما في ذلك كيفية تفاعل العديد من الكائنات مع بعضها البعض أو حتى طلب HTTP إلى نقطة نهاية من الاي بي اي الخاص بك . أما عن الأشياء التي تحتاج إختبارها فلارافل توفر أغلب ذلك , خصوصا و قد تم تحسينها في النسخ الأخيرة . فكما ذكر @Sam Ahwيمكنك إختبار كل جانب من التطبيق : جانب الHTTP : بحيث يوفر اللارافل مجموعة من الmethods لمحاكاة طلب الى الخادم و التحقق من تفاصيله . مثال : <?php class TasksTest extends TestCase { /**@test */ // هكذا يتم تعريف الاختبار public function a_task_can_be_retrieved() { $response = $this->json('GET', '/api/v1/task/12'); // محاكاة الطلب $response->assertStatus(200); // التحقق من ان كود الحالة هو كما متوقع } /** * يمكن تعريفه هكذا ايضا * */ public function test_a_task_can_be_updated() { $response = $this->json('PATCH', '/api/v1/task/12' ,$some_data); // محاكاة الطلب $response->assertStatus(200); // التأكد من كود الحالة } /**@test */ public function a_task_name_is_required() { $response = $this->json('POST', '/api/v1/task' ,$some_data_that_has_not_a_name); // محاكاة الطلب $response->assertStatus(422); // التأكد من كود الحالة } } اختبارات المتصفح . Browser Tests أو كما هو شائع : Laravel Dusk . بحيث يمكنك إختبار كل ما يخص الواجهات . (التفاعل مع الواجهة , ضغط أزرار , نقر على روابط , التعامل مع القوائم المنسدلة , إرفاق الملفات عن طريق مدخلات الملفات .. و غيرها ) غير أن هاته الإختبارات تحتاج تسطيب حزمة laravel/dusk . و ستتلقى عنك عناء اختبار التطبيق بنفسك . مثال من ويكي حسوب : <?php namespace Tests\Browser; use App\User; use Tests\DuskTestCase; use Laravel\Dusk\Chrome; use Illuminate\Foundation\Testing\DatabaseMigrations; class ExampleTest extends DuskTestCase { use DatabaseMigrations; /** * مثال عن اختبار متصفح بسيط. * * @return void */ public function testBasicExample() { $user = factory(User::class)->create([ 'email' => 'taylor@laravel.com', ]); $this->browse(function ($browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'secret') ->press('Login') ->assertPathIs('/home'); }); } } 3 . اختبارات قواعد البيانات : عن طريق الmodel factories و الdatabase seeders يمكنك ملئ قواعد البيانات الخاصة بك ببيانات مزيفة عن طريق مكتبة faker و من ثم اختبارها عن طريق مجموعة من التوكيدات . 4 . اختبارات تزييف الأحداث أو الـ Mocking : ويقصد بالأحداث أشياء مثل أحداث إرسال الايميلات App\Mails أو الأحداث داخل App\Events أو الإشعارات داخل App\Notifications أو تزييف الJobs داخل App\Jobs بل و حتى تزييف التخزين و التوكيد على عمله بشكل صحيح . فلارافل يمكنك من محاكاة ذلك و التوكيد على عمله دون عمله فعليا . إنشاء الاختبارات : يكون عن طريق الterminal : php artisan make:test UserTest 2. و من ثم التعديل على ملف الtest المنشئ بإضافة اختبارات بشكل methods معرفة بشكل صحيح (كما تم ذكر ذلك) . <?php class UserTest extends TestCase { /**@test*/ public function a_user_can_be_banned() { } } 3 . و من ثم محاكاة العملية التي تنوي إجراء الإختبار عليها : <?php class UserTest extends TestCase { /**@test*/ public function a_user_can_be_banned() { $response = $this->json('PATCH', '/users/34', ['is_banned' => true]); // } } 4 . و أخيرا استعمال التوكيد الصحيح : <?php class UserTest extends TestCase { /**@test*/ public function a_user_can_be_banned() { $response = $this->json('PATCH', '/users/34', ['is_banned' => true]); $response->assertStatus(200)->assertExactJson(['is_banned' => true,]); } } .. التوغل في كتابة الإختبارات و إختبار كل صغيرة و كبيرة بجوانب موقعك سيأخذ بك و تطبيقاتك إلى مستوى اخر من التطوير و يجعلك تمارس أحد مبادئ التطوير المتقدمة و هو الTDD أو الـ Test Driven Development و لن تضطر للعمل بطرق الإختبار التقليدية و ستكتفي بطباعة أمر واحد في التارمينل لإختبار تطبيقك ككل , في مرة واحدة.
- 3 اجابة
-
- 1
-
طبعا لن تحتاج لتثبيت تطبيقك بحقوق ملكية أو حق ترخيص الاستعمال إلا في حالة ما كنت تقوم ببيع السكربتات و البرامج الخاصة بك و ترغب في إدارة مفاتيح التراخيص عن بُعد في السكربتات التي تباع . و لا أظن إنه يوجد حزم جاهزة في اللارافل لتطبيق العملية . ولكن يمكنك بسهولة إنشاء حزمة تحقق من حقوق الملكية خاصة بك كأن تنصب على السرفر و تتوسط العمليات بين الواجهة الأمامية و الخلفية للتحقق من صلاحية الترخيص . مثال عن منطق العملية : تقوم بعرض خطط اشتراك (مثلا : سنويا , شهري , 3 شهور ) . يختار العميل الذي يقوم بشراء السكربت خطة ويتلقى مفتاحًا عامًا public_key يتم إنشاؤه. هذا المفتاح العام سيكون غير صالح حتى يتم تفعيله. للتفعيل ، يرسل لك العميل المفتاح العام من الخادم الخاص به. تقوم بإرسال المفتاح الخاص prvate_key إلى المجال الذي تم إرسال طلب التنشيط منه. يتلقى العميل ردك ويحفظ المفتاح الخاص على الخادم الخاص به. الآن تطبيقه يعمل بكامل طاقته. في المستقبل ، سيرسل العميل بشكل دوري طلبات لتحديث مفتاحه الخاص. إذا لم يتم تلقي تحديثات خلال فترة معينة ، فسيتوقف السكربت الخاص به عن العمل. و بالطبع سيمكنك إدارة هاته المفاتيح التي يميز كل منها نسخة من التطبيق الذي قمت بالبيع منه. و أظن أنه هو نفس منطق ما تعمل به برامج الترخيص الإضافية مثل ايون كيوب . فهي تعمل بشكل جد جيد مع الـphp لكنني لم أتحقق من ذلك باستخدام اللارافل.
-
سؤالك غير واضح أخي الكريم يرجى توضيحه أكثر , هل تقصد تثبيت تطبيق ما بحقوق ملكية أم عن كيفية تطبيق مبادئ تطوير الويب الأخلاقي ؟
-
الان و بعد الإنتهاء من جانب الباك اند يتطلب عليك التحقق إن كان الرد من الـ API يحمل أخطاء بأكواد حالات معينة ومن ثم التصرف بناء عليه , كأن تقوم بتعطيل عملية التسجيل أو مواصلة العملية بعد تسجيل التوكن و اعادة التوجيه . و هذا طبعا يخضع لأكواد الحالات بالـ API الذي تقوم بجلب منه البيانات و يخضع أيضا لتعريفك للـ errors . فعلى سبيل المثال يكون الكود كالتالي : // قم باستدعاء الدالة من المكان الصحيح login() async{ var response = await http.post('/your-end-point',auth_data); if(response.statusCode == 422){ print(jsonDecode(response.body['errors'])) // طباعة الاخطاء في حالة وجودها } else{ // اكمال عملية تسجيل الدخول و عمل اعادة التوجيه بعد تسجيل التوكن وحفظه } } ومن المفضل في الباك اند في اللارافل استعمال الواجهة : <?php use Illuminate\Support\Facades\Validator; .. عوضا عن الميثود validate ضمن الـ instance الذي اسمه Request : <?php class myController extends Controller{ public function myMethod(Request $request){ $request->validate($rules); } } حتى تتحصل على حرية أكبر ولا تترك الـ Laravel Exceptions يتولى إعادة التوجيه و تسجيل الأخطاء بالجلسة التي هي من المفروض خارج العملية فيما يخص بناء الAPI و باقي العملية.
- 7 اجابة
-
- 1
-
مكونات الـ regular expression التي سيتم استعمالها : ^ : بداية العبارة . 0-9 : رقم بين 0 و 9 . + : محدد التكرار , اي قبول عنصر واحد في التجميعة أو أكثر . / : علامة الـ / الفاصلة بين العددين . [ .. ] : حاضنتين لتشكيل تجميعة . $ : نهاية العبارة . فتكون العبارة كالتالي : ^[0-9]+/[0-9]+$ أي نقبل فقط : الأرقام بين 0 و 9 , قابلة للتكرار / الأرقام بين 0 و 9 قابلة للتكرار . و يكون كل ما هو ليس pos_num/pos_num غير مقبول . أمثلة : 12/100 مقبول في حين أن e0/100 غير مقبول .
- 2 اجابة
-
- 1
-
ليس من الخطأ استعمال fetch عوضا عن axios فكلاهما مكتبتان لطلبات الhttp مثلها مثل : Node http node-fetch fetch-polyfill reqwest .. وغيرها الكثير .. و اختيار مكتبة الاجاكس قد يخضع لعدة معايير نذكر منها : دعم المتصفحات , فالمكتبة التي تدعمها أغلب المتصفحات تكون لها الأفضلية . على سبيل المثال فإن fetch لا تعمل في النسخة 11 من انترنت اكسبلورر و لا توجد طريقة لتحقيق ذلك كون fetch طريقة تخص المصتفح في حين أن مكتبة axios تعمل في كلها . مهلة الاستجابة , و أقصد بهذا التحكم في المهلة الاختيارية قبل إحباط الطلب فليست كل المكتبات توفر هاته الميزة , وإن كانت فليست كلها توفرها بطريقة بسيطة وسهلة مثل تلك التي تقدمها مكتبة axios . التحويل التلقائي للبيانات الى صيغة JSON . رغم أن العملية جد بسيطة و لا تحتاج الا عمل parse للبيانات المستدعية عن طريق الـAPI لكن الافضلية تبقى لمن يبسط العمليةإاكثر . فعلى سبيل المثال تحتاج لتحويل البيانات الى json باستعمال fetch عن طريق : // fetch() fetch('https://my.api.co/api/v1/items') .then(response => response.json()) // تحويل .then(data => { console.log(data) }) .catch(error => console.error(error)); في حين أنك باستعمال axios لن تضطر لتحويلها : // axios axios.get('https://my.api.co/api/v1/teachers') .then(response => { console.log(response.data); // لا حاجة لتحويل البيانات }, error => { console.log(error); }); و طبعا , كود أقصر يعني كود أفضل . وقس على ذلك العشرات من طلبات الـ HTTP . 4. اعتراضات HTTP أو ( HTTP interceptors ) : القدرة على اعتراض طلبات الHttp بشكل globally مفهوم ستحتاج للتعامل معه بشكل كبير في بناء تطبيقات الصفحة الواحدة SPA و تطبيقات الويب التقدمية , فقبل عرض أي نتائج تحتاج طبعا إلى فحص طلبات HTTP ( كأن تتفحص حالة الطلب أو كود الحالة ) ومن ثم التصرف بناءا عليها , كالتسجيل والمصادقة و ما إلى ذلك , ولن تضطر لكتابة رمز منفصل لكل طلب HTTP. و مكتبة axios تجعل الأمر جد سهل فعلى سبيل المثال : // تعريف بملف اعداد axios axios.interceptors.request.use(response => response, config => { // يشير الكود 403 في توثيق الاي بي اي لهذا التطبيق الى ان التوكن قد استهلك استعماله وهو غير صالح if(response.data.status == 403){ alert('يرجى اعادة تسجيل الدخول'); } return config; }); // هنا يمكنك ارسال طلب في حين أن مكتبة fetch لا توفر طريقة مباشرة لإعتراض الطلبات و هذا ما يجعل axios إفضل بهاته التقطة . و كنقطة فرعية لا ينبغي إغفال المجتمع المستعمل لمكتبة axios في الـ vue و الreact الangular و الnode و غيرها , و كونها شعبية يعني وفرة المعلومة و سهولة الوصول إليها , وهذا شيء نحتاجه كمطورين . اما عن رأيي الشخصي فأفضل استعمال مكتبة axios , فهي توفر كود أقصر و أفضل قراءة . و لها شعبية مستعملين كبيرة و واسعة , كما أنها سهلة الادارة و الاعداد . وفي النهاية يبقى الاختيار لك , فـ axios توفر حزمة مضغوطة لمعظم إحتياجات اتصال HTTP الخاصة بك. ومع ذلك , فان استخدام طريقة fetch التي توفرها متصفحات الويب لا تحتاج منك استدعاء و استعمال عميل HTTP API . فذلك شيء يحدده درجة تعقيد مشروعك و تعاملك مع الAPI و حاجتك لمختلف مفاهيم اتصال HTTP الخاصة بك .
- 6 اجابة
-
- 2
-
طبعا قد يعتمد هذا على نوع البيانات المدرجة بقاعدة البيانات فالظاهر أن user_Received_id و user_send_id عبارة عن strings او نوع اخر فتأكد أن تقوم بتمرير النوع الصحيح هل يمكن الاطلاع على بنية بيانات الجدول بالphpmyadmin ؟
- 13 اجابة
-
- 1
-
لتفحص في المشكل أكثر يمكنك تفحص الخطأ عن طريق : <?php $binding_params = $stmt->bind_param("sss",$topic_id,$user_Received_id,$user_send_id); if(! $binding_params){ die( "يوجد خطأ في تمرير المتغيرات : (" .$conn->errno . ") " . $conn->error); } لكن يبدو أن السبب في ظهور المشكلة هو أن الدالة bind_param تقبل أن يكون البارمتر اﻷول عن نوع البيانات الممررة بالترتيب , فان كنا نقوم بتمرير 3 strings : <?php $stm->bind_param ('sss', $first_str ,$second_str ,$third_str) أما في هاته الحالة فنحن نقوم بتمرير معرفات ID فالمفروض يتم تمرير i ترميزا لinteger عوضا عن تمرير s فيقوم بتجاهل كل ما هو ليس string فتكون : <?php $stm->bind_param ('iii', $first_int ,$second_int ,$third_int) و لربما يكون السبب في ارجاع عمود واحد user_send_id هو أن هذا العمود مسجل بنوع string أو varchar و ليس id , فحتى تتجنب مشكل تحديد الuser_Received_id و الtopic_id فقط قم بتمرير iis عوضا عن iii فتكون : <?php $stm->bind_param ('iis', $first_int ,$second_int ,$im_a_string)