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

Adnane Kadri

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

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

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

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

    52

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

  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
  2. كشيء جميل في اللارافل فإنه تم تم بناءه مع وضع الاختبارات في الاعتبار على عكس أطر عمل أخرى (مثال : ال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. طبعا لن تحتاج لتثبيت تطبيقك بحقوق ملكية أو حق ترخيص الاستعمال إلا في حالة ما كنت تقوم ببيع السكربتات و البرامج الخاصة بك و ترغب في إدارة مفاتيح التراخيص عن بُعد في السكربتات التي تباع . و لا أظن إنه يوجد حزم جاهزة في اللارافل لتطبيق العملية . ولكن يمكنك بسهولة إنشاء حزمة تحقق من حقوق الملكية خاصة بك كأن تنصب على السرفر و تتوسط العمليات بين الواجهة الأمامية و الخلفية للتحقق من صلاحية الترخيص . مثال عن منطق العملية : تقوم بعرض خطط اشتراك (مثلا : سنويا , شهري , 3 شهور ) . يختار العميل الذي يقوم بشراء السكربت خطة ويتلقى مفتاحًا عامًا public_key يتم إنشاؤه. هذا المفتاح العام سيكون غير صالح حتى يتم تفعيله. للتفعيل ، يرسل لك العميل المفتاح العام من الخادم الخاص به. تقوم بإرسال المفتاح الخاص prvate_key إلى المجال الذي تم إرسال طلب التنشيط منه. يتلقى العميل ردك ويحفظ المفتاح الخاص على الخادم الخاص به. الآن تطبيقه يعمل بكامل طاقته. في المستقبل ، سيرسل العميل بشكل دوري طلبات لتحديث مفتاحه الخاص. إذا لم يتم تلقي تحديثات خلال فترة معينة ، فسيتوقف السكربت الخاص به عن العمل. و بالطبع سيمكنك إدارة هاته المفاتيح التي يميز كل منها نسخة من التطبيق الذي قمت بالبيع منه. و أظن أنه هو نفس منطق ما تعمل به برامج الترخيص الإضافية مثل ايون كيوب . فهي تعمل بشكل جد جيد مع الـphp لكنني لم أتحقق من ذلك باستخدام اللارافل.
  4. سؤالك غير واضح أخي الكريم يرجى توضيحه أكثر , هل تقصد تثبيت تطبيق ما بحقوق ملكية أم عن كيفية تطبيق مبادئ تطوير الويب الأخلاقي ؟
  5. الان و بعد الإنتهاء من جانب الباك اند يتطلب عليك التحقق إن كان الرد من الـ 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 و باقي العملية.
  6. مكونات الـ regular expression التي سيتم استعمالها : ^ : بداية العبارة . 0-9 : رقم بين 0 و 9 . + : محدد التكرار , اي قبول عنصر واحد في التجميعة أو أكثر . / : علامة الـ / الفاصلة بين العددين . [ .. ] : حاضنتين لتشكيل تجميعة . $ : نهاية العبارة . فتكون العبارة كالتالي : ^[0-9]+/[0-9]+$ أي نقبل فقط : الأرقام بين 0 و 9 , قابلة للتكرار / الأرقام بين 0 و 9 قابلة للتكرار . و يكون كل ما هو ليس pos_num/pos_num غير مقبول . أمثلة : 12/100 مقبول في حين أن e0/100 غير مقبول .
  7. ليس من الخطأ استعمال 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 الخاصة بك .
  8. طبعا قد يعتمد هذا على نوع البيانات المدرجة بقاعدة البيانات فالظاهر أن user_Received_id و user_send_id عبارة عن strings او نوع اخر فتأكد أن تقوم بتمرير النوع الصحيح هل يمكن الاطلاع على بنية بيانات الجدول بالphpmyadmin ؟
  9. لتفحص في المشكل أكثر يمكنك تفحص الخطأ عن طريق : <?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)
  10. يبدوا أن سبب الخطأ كان إما في نسيان إنشاء نوع أو خطأ في تسجيله . فال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 ], // ... ] ] و الان المفروض كل شيء سيعمل بشكل سليم .
  11. مرحبا . إن كانت حاجتك لعمل 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 بشكل عادي .
  12. بداية يجب عليك حسم موقفك و توضيح جيدا لما قد تريد الإنتقال من لغة برمجية إلى أخرى , و لا يكفي هذا أيضا بل ويجب التحقق إن كانت هاته الأسباب بالفعل تدفعك إلى التخلي عن اللغة التي قد تعلمتها و تعلم أخرى جديدة . و شيء جميل أنك قد اوضحت هدفك من الانتقال من الـ php , لكن لا أرى أنها بأسباب فعلية و لنأخذ على سبيل المثال إطار العمل الغني عن التعريف Laravel و لنسقط عليه هاته الأسباب . - فلو كنت تريد تطبيقات متزامنة فإطار العمل هذا يمتلك الكثير من الأشياء التي تسهل فعلا التعامل مع تقنيات الويب سوكيتس و الويب ار تي سيز ( socket.io , pusher , Laravel echo system .. وغيرها الكثير ) - أما لو كانت تريد بناء Restuful API قوية فكثير من الأشياء تجعل Laravel في الصدارة في هذا الأمر ( الـ Restful Controllers , Laravel Passport , jwt auth .. وغيرها ) . و كون لارافل مفتوح المصدر فهو أيضا يعطيك تحكم كامل بدون محدوديات ولك أن تعدل حتى الcore الخاص بإطار العمل . - وطبعا لم أتحدث عن مزايا إطار العمل هذا التي تجعل حوالي مليون و نصف موقع تقوم عليه , فقد اختصصت قولي بالنقاط التي أردت التغيير من أجلها . بجانب أن تعلم لارافيل يختصر عليك طريقا طويلا أنت على وشك أن تسلكه , فقبل التوغل في منصة أو اطار عمل ما ينبغي عليك تعلم اللغة أولا . ومن ثم تعلم أشياء تعطيك نظرة تبسط لك التعامل مع أطر العمل على هاته اللغة ككل كالبرمجة الكائنية و معماريات التصميم بهاته اللغة ومن ثم فقط يأتي إختيار إطار العمل . فأنا أدعوك الى جدية أكثر في توضيح لنفسك الأسباب التي تريد بها الإنتقال و من ثم مراجعتها و التحقق منها قبل الحسم في موضوع قد يأخذ الكثير من الوقت . و أرشح لك دورة تطوير تطبيقات الويب بلغة الphp من حسوب فبها قسم كامل عن كيف تقوم ببناء تطبيقات إعتمادًا على إطار العمل Laravel . وكملاحظة بسيطة فان الوردبرس ليس إطار عمل و انما هو نظام إدارة محتوى , والفرق بينهما ببساطة هو : أن نظام إدارة المحتوى هو عبارة عن برمجية تساعدك على إيجاد حلول رقمية كأن تقوم ببناء تطبيق ويب أو صفحة هبوط , وأمثلة عن ذلك : الووردبرس , جوملا , ويكس وغيرها . أما إطار العمل فهو شيء اخر تماما فهو إضافة على لغة ، يجمع مجموعة من المكتبات و الحزم . و يوفر الأساس الذي يبني عليه مطورو الويب التطبيقات. و أمثلة عن ذلك : لارافل , روبي ان ريلز , دجانقو . فبإطار العمل تستطيع حتى بناء نظام إدارة محتوى كامل ومتكامل اما العكس فغير ممكن . وهذه هي ميزة إستعمال أطر العمل , أي غير المحدودية في مقابل نظم إدارة المحتوى . بالتوفيق
  13. للأسف سرفرات هيروكو تمتلك تخزين " سريع الزوال " , أي انك تستطيع اضافة الملفات والصور الى القرص غير أن هاته الملفات لن تكون حاضرة في حالة رفع جديد أو اعادة تشغيل التطبيق وهذا خلال 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 .
  14. - أولا قم بالتأكد أنك تستعمل ال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 . تطبيق دور حول مجموعة الوسائط و تطبيق الدالة على كل منها مثل ما هو موصوف بالتعليق السابق , وهذا بحالة ما كنت تقوم برفع مجموعة وسائط , أي اثنان فأكثر .
  15. بقراءة متمعنة للخطأ الظاهر نجده يشير الى خطأ بسياق اللغة فهو لم يتوقع ادراج المتغير الذي اسمه $admin و الجائز في اللغة أن يعرف اما ثابت const أو دالة function : أي كلاس class و بداخله دوال methods و بداخل هاته الدوال يكون الكود و الlogic لا خارجها فالتخلص من هاته المشكلة بسيط و هو باضافة هذا الكود : $admin = new Role(); $admin->name = 'admin'; $admin->display_name = 'Project Admin'; $admin->description = 'admin is the owner of a project'; $admin->save(); الى داخل دالة معينة ننشئها . لكن هذا قد يحل المشكلة لكنه لن يجعل الباكاج تعمل بشكل صحيح و لربما قد يضيف مشاكل اخرى فالحل هو : بعدما قمنا بانشاء كلاس باسم Role الان نحتاج الى انشاء ادوار , أي انشاء نماذج من هذا الكلاس فالأصح ليس استعمال الكود السابق داخل الكلاس , بل استعمالها في أي مكان ثان غير داخل هذا الكلاس حتى يكون سهل الوصول و قابل للاستنتساخ منه . فالان أنت قد قمت بعمل الكلاس , وقد قمت بتوريثه دوال معينة باستعمال extends و لا تحتاج الى تعريف دوال اخرى , فتحتاج فقط الى انشاء هاته النماذج و عن نفسي احبذ انشاءها داخل ملف التهجير الخاص بالمستخدمين بدالة خاصة يتم استدعاءها قبل انشاء المستخدم الافتراضي أو السوبر ادمن ومن ثم اعطاء الدور له . فيكون ملف Role.php هكذا : <?php namespace App; use Zizaco\Entrust\EntrustRole; class Role extends EntrustRole { // } و يكون ملف التهجير الخاص بالمستخدمين هكذا : <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Hash; use App\Role; // لا تنسى تضمين الكلاس بشكل صحيح class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); // استدعاء الدالة التي تقوم بانشاء الادوار الافتراضية $adminRole = $this->createeSuperAdminRole(); // انشاء العضو الافتراضي او السوبر ادمن $user = App\Models\User::create([ 'name'=>'SuperAdmin', 'email'=>'super@admin.co', 'password' => Hash::make('12345678'), ]); // اضافة الدور للعضو $user->attachRole($adminRole); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } private function createeSuperAdminRole() { $admin = new Role(); $admin->name = 'admin'; $admin->display_name = 'Project Admin'; $admin->description = 'admin is the owner of a project'; $admin->save(); return $admin; // نقوم باعادته حتى يسهل اعطاء العضو الافتراضي هذا الدور } } و يمكنك معاملة الاذونات و الملف باسم Permission.php بنفس المنطق و انشاء الاذونات واضافتها للادوار بمنطق مشابه
  16. السلام عليكم الاخوة الكرام قمت بالتعامل مع احد العملاء بموقع Freelancer (كان بناء على طلبه), الشغل انتهى واستلمت المال على الموقع ولكنه بقى محجوز و تحويله يطلب تأكيد الهوية KYC تأكيد الهوية يطلب تأكيد العنوان , العنوان حاولت بالكارت البيومترية ولكنه اترفض , يطلب اشيا مثل رخصة سياقة , كشف كهرباء و حاجات هك وكلها تقريبا ما عنديش خفت استعمل الخاصة بالوالد او الاخ الاكبر و ينقفل الحساب خصوصا وانو مطلعلي مسج انو اي محاولة احتيال هوية ينقفل بيها الحساب يا ريت اللي عدا الاختبار يخبرني كيف عملها وقام بتأكيد الادراس, وحبذا لو من الجزائر بالضبط
  17. الثغرة الأمنية أو الـ Security Bug هي أوسع من تحصر في موقع أو تطبيق , قد نجد الثغرات في أنظمة التشغيل أو السيرفرات أيضا , أما عن الثغرات الأمنية في مواقع الويب أو تطبيقاته هي << غالبا >> ما تكون مرتبطة بحقول الادخال ( الـ Forms ) و أغلب الهجمات تكون عن طريق الفورمز تلك . اما بتحميل فايل ملغم على السيرفر عن طريقها وهي ما تعرف بهجمات الـ Remote File Uploads , أو عن طريقة كتابة سكربت أو كود يقوم بعملية تخريبية ما (هجمات الـ Cross Site Scripting) أو عن طريق حقن أمر SQL (ولعلها الأشهر على الاطلاق , الـ Sql Injections), فالفورمز ومدخلاتها هي المدخل الوحيد الذي يستطيع الاتصال بالسرفر و هو ما يستغله المخرب او المخترق . وهنا يأتي دور الـ Validation و الـ sanitizing على السرفر سايد وعلى الكلاينت سايد . فالثغرة الأمنية بموقع تكون اما بثغرة على السيرفر نفسه , او ربما على نظام التشغيل . أو في ضعف أو ربما غياب التعقيم و توثيق المعلومات قبل وبعد وأثناء ارسالها الى السيرفر , و قبل أي عملية حقن في قاعدة البيانات أو التعامل مع ملفات السيرفر . بعض المفاهيم والأساليب في البرمجة الكائنية التوجه OOP قد يكون لها دور كبير ايضا في الامن المعلوماتي مثل مفهوم التغليف أو الـ Encapsulation . وهو الاتجاه البرمجي الذي يتجه نحوه العالم . فالثغرة الأمنية قد لا تكون غالبا خطأ في السكريب أو خطأ في كتابة الكود , بل في الغفلة عن تغليف المعلومات أو معالجتها وتوثيقها و تعقيمها من أي ما قد يكون مضرا بالموقع. أي بصف جميع الاحتمالات الممكن عملها بحقل ما و معالجتها (وهو نفسه ما قاله الاخ في تعليق سابق) تحياتي
  18. اما ان العميل يثبت لوكل هوست ويجرب الموقع لو كان الموقع بقاعدة بيانات و باك اند . وهذا رح يتعب العميل و يشتتو خصوصا لو كان خارج المجال. أو تعمل تريك بسيطة , وهي الأفضل . ترفع الموقع على استضافة مجانية , وتضيف فورم دخول للموقع مثلا وتسلملو بيانات الدخول (ولو حقل واحد , رقم تسلسلي مثلا) وبعد الاتفاق على المطلوب تزيل الفورم و تحذف بيانات الموقع من السي بانل للمستضيف المجاني . استضافات مثل نتلفاي Netlify (لو كان الموقع ستاتيك) أو 000webhost أو freewha (ان كان الموقع بقاعدة بيانات و سرفر سايد) ستكون مناسبة جدا
  19. <form> Age : <input type='number' class='ageField' /> nationality : <select class='nationalityField'> <option value='Saudian'>Saudian</option> <option value='American'>American</option> <option value='Algerian'>Algerian</option> </select> <input type='submit' class='submitBtn'> </form> var btn =document.querySelector('.submitBtn'); // function called when submitting the button function checkForUser(){ // declaring variables var nationality=document.querySelector('.nationalityField'), age =document.querySelector('.ageField'); // check : if(nationality.value=='saudian' && age>=18){ window.alert('Welcome'); }else{ window.alert('sorry'); } } // Add event handler btn.addEventListener('click',checkForUser()); بعد ما يدخل المعلومات تأخذ قيم الفيلدس وتعمل اللي حابه بالجافاسكربت
  20. وعليكم السلام , سأجيبك من داخل مجالي (الويب) , تحريك الـ Illustrations في المتصفح أغلب الـ Illustrations مثل تلك التي يوفرها موقع unDraw او موقع Ouch تتوفر على صيغة الـ SVG . ببرامج مثل الFigma أو الفوطوشوب يمكنك التعديل على الـ SVG وتجميع أجزاءه ( Vectors ) و تعريفها جزءا جزءا بID معين . صيغة الـSVG بواسطة المتصفح تقرأ على أنها أجزاء مجمعة ولها خصائصها في اصدار الـ HTML5 , تتذكر الأجزاء اللي عرفتها منذ قليل؟ بالـ CSS3 Animations تقدر تبتكر أي انيميشن تجي فبالك . وبالـ Javascript رح تقدر تبتكر ما لا يأتي بال .
×
×
  • أضف...