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

Adnane Kadri

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

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

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

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

    52

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

  1. يمكنك تسجيل 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. هل يمكنك إرفاق رابط الموقع ؟
  3. لتحليل هاته الخوارزمية قمت بالعمل التالي : 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
  4. يمكنك تحقيق الغرض كالتالي : <?php $output = ''; while($row = mysqli_fetch_array($result)) { $output .= substr($row['message'], 0, 35); } echo $output; ?>
  5. بالفعل هي مثل ما قلت ، وقد تم تصليح الأخطاء الإملائية التي وردت بارك الله فيك و وفقك الله لما يحبه و يرضاه.
  6. يمكنك تخصيص نوع البيانات في البارمتر الممرر في الراوت عن طريق التابع 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()){ // قم باعادة التوجيه } } }
  7. ﻷن السطر الأخير يقوم بطباعة المتغير 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); }
  8. بملف 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('جي كويري الان تعمل!'); }); أما عن المشكلة الثانية فلم أواجهها و تم الدخول عن طريق الرابط التشعبي بشكل عادي . و مثل ما أشار الأخ @سامح أشرف قد تكون لديك مشكلة في الملفات المؤقتة الخاصة بالمتصفح ،قم بتجربة متصفح آخر أو حذف الملفات المؤقتة.
  9. طبعا هذا ستحدده حاجتك لتعلم جافاسكربت من الأساس , فيمكن تعلم JS كلغة برمجة فقط مثلها أي لغة أخرى , أي يمكن تعلمها بمعزل تماما عن الـ Document Object Models API الذي هو المسؤول عن عمليات التلاعب بعناصر صفحة الويب . فإن كان هدفك تصميم و برمجة المواقع فستحتاج لهما بشكل كبير لتحسين تعاملك و تحكمك بعناصر الموقع , أما من جانب الجافاسكربت فأنت ستحتاج التعامل مع ما الـ Browser Object Models و الDocument Object Models (اختصارهما DOM , BOM) و الأساليب التي ستواجهها هناك ستهتم بشكل أساسي بتحديد العناصر والتلاعب بمظهرها ومحتواها . و للقيام بذلك ، ستحتاج إما إلى معالجتها مباشرة عبر محددات تشبه CSS ، أو عن طريق شجرة عناصر . و كلاهما يتطلب أن يكون تعاملك مألوفًا مع الـ Html و الـ css . أما إن كنت تريد تعلمها لعمل تطبيقات الهاتف فلن تحتاج التوغل فيهما حد الإحتراف و سيكفيك فيهما مستوى متوسط و هذا طبعا ﻷنك ستحتاج التعامل مع DOM افتراضية تتبع نفس منطق الDOM الفعلية . خلاصة الأمر أنك ستحتاج تعلمهما للتعامل مع جافاسكربت بشكل أمتع و أكثر حيوية و أكثر اختصارا للوقت و المفاهيم و ستخير بين تعلمهما إن قمت بإتخاذ مسار اخر غير تصميم و تطوير المواقع .
  10. طبعا العملية ستصبح سهلة مع التعود على مواجهة الأخطاء و حلها , لكن هذا لا يمنع من جعلها منهجية و منظمة لغرض إختصار الوقت و تنظيم العمل أكثر فحل مشكلة ما ,برأيي, يتطلب : مشكلة ! فبالطبع يجب أن تكون لديك مشكلة و من الواجب قراءتها و التأني في ذلك . إعادة إنتاج المشكلة و عزل كود مصدر المشكلة : أحب عادة حذف الأسطر التي تكون مسؤولة عن المشكلة , فإختفاء الخطأ يعني ثبوتها . ثم أقوم بإعادة انتاج المشكلة من جديد . هذا يجعلك تقوم بعزل كود المصدر المسؤول و وضع نظرتك على نطاق أضيق و أدق , فالتركيز في ثلاث أسطر أو أربع أفضل من التركيز في مشروع كامل أو ملف كامل. قم بوصف المشكلة : كأن تحاول الحصول على أكبر عدد من المعلومات عن هاته المشكلة . (مثال عن ذلك : الزر يشتغل و يستدعي دالة بالفعل لكن الـ console يقول أن هاته الدالة غير معرفة , و أرى أني قد عرفتها بالفعل في ملف index.js) بناءا على ذلك حاول الإجتهاد في حل المشكلة مما جمعت من وصف للمشكلة و تحديد لكود المصدر المسؤول , و لا بأس ببحث على الانترنت عن مشاكل إما مشابهة في الخطأ الظاهر أو في الوصف و الطرح أو السياق أو كود مصدر المشكلة . و ستصبح العملية سهلة و أبسط مع مرور الوقت و التعود على الأخطاء و على حلها . و قد يقودك إنتقال المشاكل من بسيطة , إلى معقدة إلى معقدة جدا , إلى تعلم الخوارزميات و الproblem solving التي ستنقل الأمر إلى مستوى اخر من التنظيم و المنهجية.
  11. و عليكم السلام و رحمة الله . بالنسبة لسؤالك الأول : لا يزال عليك عمل التفاعلية المطلوبة بنفسك , بملف 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
  12. كشيء جميل في اللارافل فإنه تم تم بناءه مع وضع الاختبارات في الاعتبار على عكس أطر عمل أخرى (مثال : ال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 و لن تضطر للعمل بطرق الإختبار التقليدية و ستكتفي بطباعة أمر واحد في التارمينل لإختبار تطبيقك ككل , في مرة واحدة.
  13. طبعا لن تحتاج لتثبيت تطبيقك بحقوق ملكية أو حق ترخيص الاستعمال إلا في حالة ما كنت تقوم ببيع السكربتات و البرامج الخاصة بك و ترغب في إدارة مفاتيح التراخيص عن بُعد في السكربتات التي تباع . و لا أظن إنه يوجد حزم جاهزة في اللارافل لتطبيق العملية . ولكن يمكنك بسهولة إنشاء حزمة تحقق من حقوق الملكية خاصة بك كأن تنصب على السرفر و تتوسط العمليات بين الواجهة الأمامية و الخلفية للتحقق من صلاحية الترخيص . مثال عن منطق العملية : تقوم بعرض خطط اشتراك (مثلا : سنويا , شهري , 3 شهور ) . يختار العميل الذي يقوم بشراء السكربت خطة ويتلقى مفتاحًا عامًا public_key يتم إنشاؤه. هذا المفتاح العام سيكون غير صالح حتى يتم تفعيله. للتفعيل ، يرسل لك العميل المفتاح العام من الخادم الخاص به. تقوم بإرسال المفتاح الخاص prvate_key إلى المجال الذي تم إرسال طلب التنشيط منه. يتلقى العميل ردك ويحفظ المفتاح الخاص على الخادم الخاص به. الآن تطبيقه يعمل بكامل طاقته. في المستقبل ، سيرسل العميل بشكل دوري طلبات لتحديث مفتاحه الخاص. إذا لم يتم تلقي تحديثات خلال فترة معينة ، فسيتوقف السكربت الخاص به عن العمل. و بالطبع سيمكنك إدارة هاته المفاتيح التي يميز كل منها نسخة من التطبيق الذي قمت بالبيع منه. و أظن أنه هو نفس منطق ما تعمل به برامج الترخيص الإضافية مثل ايون كيوب . فهي تعمل بشكل جد جيد مع الـphp لكنني لم أتحقق من ذلك باستخدام اللارافل.
  14. سؤالك غير واضح أخي الكريم يرجى توضيحه أكثر , هل تقصد تثبيت تطبيق ما بحقوق ملكية أم عن كيفية تطبيق مبادئ تطوير الويب الأخلاقي ؟
  15. الان و بعد الإنتهاء من جانب الباك اند يتطلب عليك التحقق إن كان الرد من الـ 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 و باقي العملية.
  16. مكونات الـ regular expression التي سيتم استعمالها : ^ : بداية العبارة . 0-9 : رقم بين 0 و 9 . + : محدد التكرار , اي قبول عنصر واحد في التجميعة أو أكثر . / : علامة الـ / الفاصلة بين العددين . [ .. ] : حاضنتين لتشكيل تجميعة . $ : نهاية العبارة . فتكون العبارة كالتالي : ^[0-9]+/[0-9]+$ أي نقبل فقط : الأرقام بين 0 و 9 , قابلة للتكرار / الأرقام بين 0 و 9 قابلة للتكرار . و يكون كل ما هو ليس pos_num/pos_num غير مقبول . أمثلة : 12/100 مقبول في حين أن e0/100 غير مقبول .
  17. ليس من الخطأ استعمال 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 الخاصة بك .
  18. طبعا قد يعتمد هذا على نوع البيانات المدرجة بقاعدة البيانات فالظاهر أن user_Received_id و user_send_id عبارة عن strings او نوع اخر فتأكد أن تقوم بتمرير النوع الصحيح هل يمكن الاطلاع على بنية بيانات الجدول بالphpmyadmin ؟
  19. لتفحص في المشكل أكثر يمكنك تفحص الخطأ عن طريق : <?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)
  20. يبدوا أن سبب الخطأ كان إما في نسيان إنشاء نوع أو خطأ في تسجيله . فالexception يقول أن العائد من الدالة type داخل ملف ال queries ليس متوافق مع المتوقع فالأرجح هو أن الدالة الاخيرة تقوم باعادة null في حين أنها يجب أن تقوم بارجاع النوع المرادف للQuery التي يتم العمل عليها . فطبقا للتوثيق الرسمي للحزمة على الجيت هب فان انشاءgraphql query يتطلب الخطوات التالية : 1 - أولاً ، تقوم بإنشاء نوع تريد إرجاعه من الاستعلام : <?php namespace App\GraphQL\Types; use App\Item; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Type as GraphQLType; class ItemType extends GraphQLType { protected $attributes = [ 'name' => 'Item', // لاحظ تعريف المودل في النوع 'description' => 'An Item of Graphql Type', 'model' => Item::class, ]; // يتطلب تعريف الحقول في النوع public function fields() { return [ 'id' => [ 'type' => Type::nonNull(Type::int()), 'description' => 'The id of the item' ], ]; } public function resolve($root, $args) { return Item::findOrFail($args['id']); } } 2 - ثم تحتاج الى اضافة النوع المنشئ حديثا و تسجيله . اما باضافته مباشرة الى المخطط الخاص بك schemas : <?php 'schemas' => [ 'default' => [ // ... 'types' => [ App\GraphQL\Types\ItemType::class, ], او اضافته بشكل عام globally في ملف الاعداد graphql.php : <?php .. 'types' => [ App\GraphQL\Types\ItemType::class, ], او باستعمال الواجهة GraphQL : <?php GraphQL::addType(\App\GraphQL\Types\ItemType::class); 3 - الان وبعد اضافة النوع يمكنك انشاء الqueries الخاصة بك والتي تنتمي لهذا النوع على هذا النحو : <?php namespace App\GraphQL\Queries; use Closure; use App\Item; use Rebing\GraphQL\Support\Facades\GraphQL; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Query; class ItemsQuery extends Query { protected $attributes = [ 'name' => 'items', ]; public function type() // يجب أن تعيد instance من Type المرافق { return Type::nonNull(Type::listOf(Type::nonNull(GraphQL::type('Item')))); } public function args() { return [ 'id' => [ 'name' => 'id', 'type' => Type::int(), 'rules' => ['required'] ], ]; } public function resolve($root, $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields) { return Item::findOrFail($args['id']); } } 4 - يتبقى فقط تسجيل الQuery المنشئة حديثا بملف الاعداد graphql.php : <?php .. 'schemas' => [ 'default' => [ 'query' => [ App\GraphQL\Queries\ItemsQuery::class ], // ... ] ] و الان المفروض كل شيء سيعمل بشكل سليم .
  21. مرحبا . إن كانت حاجتك لعمل slug فأقترح إستعمال الدالة slug ضمن المساعد Str كالتالي : <?php use Illuminate\Support\Str; $slug = Str::slug('make a good slug', '-'); // make-a-good-slug لكن ان احتجت تعميم العملية على الكثير من الموديلات و الاستفادة من باقي الـأشياء التي تقدمها مكتبة cviebrock/eloquent-sluggable فتأكد أن تستعمل الTrait الصحيح <?php use Cviebrock\EloquentSluggable\Sluggable; .. class myModel extends Model{ use Sluggable; .. } وبدل تعريف الsluggable attributes في attribute يجب عليك استعمال الabstract method التي اسمها sluggable() ضمن الTrait المستعمل , ومن ثم تعريفها بداخلها فيكون : <?php use Cviebrock\EloquentSluggable\Sluggable; class myModel extends Model { use Sluggable; /** * قم بتعريف القيم هنا * * @return array */ public function sluggable() { return [ 'slug' => [ 'slugable_column' => 'title' ] ]; } } و الان قم بتجريب إنشاء item جديد وسيتم حفظ الslug بشكل عادي .
  22. بداية يجب عليك حسم موقفك و توضيح جيدا لما قد تريد الإنتقال من لغة برمجية إلى أخرى , و لا يكفي هذا أيضا بل ويجب التحقق إن كانت هاته الأسباب بالفعل تدفعك إلى التخلي عن اللغة التي قد تعلمتها و تعلم أخرى جديدة . و شيء جميل أنك قد اوضحت هدفك من الانتقال من الـ php , لكن لا أرى أنها بأسباب فعلية و لنأخذ على سبيل المثال إطار العمل الغني عن التعريف Laravel و لنسقط عليه هاته الأسباب . - فلو كنت تريد تطبيقات متزامنة فإطار العمل هذا يمتلك الكثير من الأشياء التي تسهل فعلا التعامل مع تقنيات الويب سوكيتس و الويب ار تي سيز ( socket.io , pusher , Laravel echo system .. وغيرها الكثير ) - أما لو كانت تريد بناء Restuful API قوية فكثير من الأشياء تجعل Laravel في الصدارة في هذا الأمر ( الـ Restful Controllers , Laravel Passport , jwt auth .. وغيرها ) . و كون لارافل مفتوح المصدر فهو أيضا يعطيك تحكم كامل بدون محدوديات ولك أن تعدل حتى الcore الخاص بإطار العمل . - وطبعا لم أتحدث عن مزايا إطار العمل هذا التي تجعل حوالي مليون و نصف موقع تقوم عليه , فقد اختصصت قولي بالنقاط التي أردت التغيير من أجلها . بجانب أن تعلم لارافيل يختصر عليك طريقا طويلا أنت على وشك أن تسلكه , فقبل التوغل في منصة أو اطار عمل ما ينبغي عليك تعلم اللغة أولا . ومن ثم تعلم أشياء تعطيك نظرة تبسط لك التعامل مع أطر العمل على هاته اللغة ككل كالبرمجة الكائنية و معماريات التصميم بهاته اللغة ومن ثم فقط يأتي إختيار إطار العمل . فأنا أدعوك الى جدية أكثر في توضيح لنفسك الأسباب التي تريد بها الإنتقال و من ثم مراجعتها و التحقق منها قبل الحسم في موضوع قد يأخذ الكثير من الوقت . و أرشح لك دورة تطوير تطبيقات الويب بلغة الphp من حسوب فبها قسم كامل عن كيف تقوم ببناء تطبيقات إعتمادًا على إطار العمل Laravel . وكملاحظة بسيطة فان الوردبرس ليس إطار عمل و انما هو نظام إدارة محتوى , والفرق بينهما ببساطة هو : أن نظام إدارة المحتوى هو عبارة عن برمجية تساعدك على إيجاد حلول رقمية كأن تقوم ببناء تطبيق ويب أو صفحة هبوط , وأمثلة عن ذلك : الووردبرس , جوملا , ويكس وغيرها . أما إطار العمل فهو شيء اخر تماما فهو إضافة على لغة ، يجمع مجموعة من المكتبات و الحزم . و يوفر الأساس الذي يبني عليه مطورو الويب التطبيقات. و أمثلة عن ذلك : لارافل , روبي ان ريلز , دجانقو . فبإطار العمل تستطيع حتى بناء نظام إدارة محتوى كامل ومتكامل اما العكس فغير ممكن . وهذه هي ميزة إستعمال أطر العمل , أي غير المحدودية في مقابل نظم إدارة المحتوى . بالتوفيق
  23. للأسف سرفرات هيروكو تمتلك تخزين " سريع الزوال " , أي انك تستطيع اضافة الملفات والصور الى القرص غير أن هاته الملفات لن تكون حاضرة في حالة رفع جديد أو اعادة تشغيل التطبيق وهذا خلال 24 ساعة فحل المشكلة هو اما بـ : 1 . استعمال التخزين العام بداخل مجلد الpublic مباشرة , وهذا بالتعديل على ملف config/filesystems.php : <?php 'heroku_public' => [ 'driver' => 'local', 'root' => public_path() . '/uploads', ], ومن ثم استعمال نمط التخزين على هذا النحو : <?php use Illuminate\Support\Facades\Storage; ... Storage::disk('heroku_public')->put($your_path, $your_file_content) غير أن هذا لن يحل المشكلة ككل و ستبقى الملفات عامة و ظاهرة و هذا لن يكون في الصالح في حال ما أردت حماية خصوصية المستخدمين . فالحل النهائي هو باستخدام تخزين خارجي تماما . مثل : cloudinary , aws s3 . وخصوصا مع الكثير من الأشياء التي يجعل لارافل العملية بها سهلة . و اقترح بقوة استعمال cloudinary cloud storage فسرفرات هيروكو تتوفر على اضافة add-ons تسهل ذلك باسم cloudinary . و من جانب اللارافل موجود على الgithub باكج مفتوحة المصدر تسهل ربط التطبيق بتخزين الكلاود الخاص بك على كلاوديناري باسم laravel-cloudinary .
  24. - أولا قم بالتأكد أنك تستعمل الTrait الصحيح ففي النسخة الثامنة من المكتبة تم تغيير الtrait من HasMediaTrait الى InteractsWithMedia . فيكون هكذا : <?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; class myModel extends Model implements HasMedia { use InteractsWithMedia; // use HasMediaTrait; تم التخلي عنه } و بكل حال من الاحوال , لا يزال عليك تخصيص وسط واحد فالدالة toMediaCollection معرفة بكلاس الوسط في حين أنك تقوم بتطبيقها على مجموعة من الوسائط و بطبيعة الحال فان الدالة غير معرفة على هذا النحو و سيتم رمي خطأ حالما قمت باستدعاءها . و كحلان مقترحان يمكنك : 1 . اما تخصيص وسط واحد و تطبيق الدالة toMediaCollection عليه و ذلك بـ : <?php public function update(Request $request, Channel $channel) { if($request->hasFile("image")){ // بدل هذا // $blog->addAllMediaFromRequest('image')->toMediaCollection('images'); // قم بهذا $blog->addMediaFromRequest('image')->toMediaCollection('images'); } } ?> وهذا بحالة ما كنت تقوم برفع وسط واحد على الاكثر 2 . تطبيق دور حول مجموعة الوسائط و تطبيق الدالة على كل منها مثل ما هو موصوف بالتعليق السابق , وهذا بحالة ما كنت تقوم برفع مجموعة وسائط , أي اثنان فأكثر .
×
×
  • أضف...