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

Sam Ahw

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

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

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

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

    16

كل منشورات العضو Sam Ahw

  1. إن مسارات التوجيه في لارافيل تستخدم آلية first-come-first-serve أي تتلقى المسارات المختلفة بالترتيب ضمن الملف بدءً من المسار الأول. لذلك في حال كانت إضافة الدومين (اسم النطاق) بعد المسار الأساسي لن يتم تمييزه في لارافيل وسيتم التوجيه إلى المسار الأساسي الأول (النطاق الأساسي). مثال: Route::group(['domain' => 'admin.localhost'], function () { Route::get('/', function () { return "هذه المجموعة ستتلقى الطلبات عبر 'admin.localhost/'"; }); }); Route::get('/', function () { return "ثم المجموعة الأساسية لتلقي المسارات الأساسية للنطاق الأساسي"; }); أما في حال تمت كتابة المسارات بالترتيب التالي فلن يتم تمييز مسارات النطاق الفرعي: Route::get('/', function () { return "سيتم تلقي جميع المسارات هنا وبالتالي لن يتم التعرف على المجموعة."; }); Route::group(['domain' => 'admin.localhost'], function () { Route::get('/', function () { return "وبالتالي هذه المجموعة لن تكون مرئية للرافيل"; }); });
  2. عند تعريف القيم ومحاولة الوصول لها ضمن مكونات Vue يجب إضافة القيم ضمن AppServiceProvider أيضاً بالشكل التالي: Inertia::share('appName', config('app.name')); حيث يمكن استخدام config أو env ثم ضمن المكوّن يتم الاستدعاء بوضع $inertia متبوعة باسم المتحول كالتالي: {{ $inertia.page.props.appName }} ويتم تعريف المتحولات ضمن مصفوفة Array على شكل مفاتيح وقيم، بحيث كل مفتاح يشير إلى قيمة المتحول الموجودة ضمن ملف env بالشكل التالي: Inertia::share(function () { return [ 'app' => [ 'name' => config('app.name'), ], ]; }); بحيث يمكن استدعائها مباشرة كالتالي: <template> <div> App name: {{ $page.app.name }} </div> </template>
  3. إن @inertia تعمل ولكن لا يستطيع لارافيل تحميلها ضمن الصفحة لأنه يجب عليك تحميل adapter الخاص بها. عن طريق: npm install @inertiajs/inertia @inertiajs/inertia-vue ثم يجب إعداد webpack ضمن المشروع على الشكل التالي (webpack.mix.js): const mix = require('laravel-mix') const path = require('path') mix.js('resources/js/app.js', 'public/js') .webpackConfig({ output: { chunkFilename: 'js/[name].js?id=[chunkhash]' }, resolve: { alias: { vue$: 'vue/dist/vue.runtime.esm.js', '@': path.resolve('resources/js'), }, }, }) وأيضاً تهيئة Vue ضمن الملف الرئيسي (resources/js/app.js) . بحيث يتم إضافة InertiaApp من المكتبة inertia-vue في رأس الصفحة: import { InertiaApp } from '@inertiajs/inertia-vue' import Vue from 'vue' Vue.use(InertiaApp) const app = document.getElementById('app') const pages = { 'Auth/Login': require('./Pages/Auth/Login.vue').default, } new Vue({ render: h => h(InertiaApp, { props: { initialPage: JSON.parse(app.dataset.page), resolveComponent: name => pages[name], }, }), }).$mount(app)
  4. لوضع المجلد ضمن هذا المسار يمكنك استخدام الأمر التالي: export PATH="$PATH:$HOME/.composer/vendor/bin" والذي يقوم بدوره بإضافة المجلد إلى المسار PATH الأساسي الموجود. وهو متاح فقط للجلسة الحالية للمستخدم الحالي على النظام. أما في حال أردت بأن يتم تحديدها بشكل أوتوماتيكي فباستخدام bash يمكنك تنفيذ التالي: echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> ~/.bashrc وللتأكد من أن الأمر تم بشكل صحيح، يمكنك تنفيذ التالي: source ~/.bashrc ملاحظة: للنسخ الحديثة من لارافيل، يجب أن تقوم بالتأكد من وضع المسار التالي ضمن PATH الخاص بك: $HOME/.config/composer/vendor/bin أما عند إنشاء مشروع جديد مختلف عن المشروع القديم، يمكن اختصار السابق بتنفيذ الأمر التالي فقط: curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
  5. يمكنك تحميل إضافة اسمها TinyMCE ِAdvanced: ثم القيام بتفعيل الخيار التالي لإتاحة جميع عناصر تنسيق الجداول والخطوط الموجودة: Enable Editor Menu كما يمكنك التحكم بكامل عناصر التأثير من إضافة وحذف أو تغيير في الترتيب والعديد من الخصائص الأخرى التي يمكنك الاطلاع عليها من قائمة الإعدادات الخاصة بهذه الإضافة.
  6. يمكن تنفيذ ذلك كالتالي: @section('custom_css') //....نضع هنا CDN @endsection مثال: @section('stylesheet') @livewireStyles <link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet" /> @endsection أما للجافاسكريبت: @section('script') <script src="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js"></script> @livewireScripts @endsection أو عن طريق Stack / Push كالتالي: @stack('styles')
  7. باختصار، إن لغة PHP اختصاراً ل (Hypertext Pre Processor) هي واحدة من أشهر لغات البرمجة التي يتم استخدامها في إنشاء مواقع الويب (من طرف خادم الويب). حيث يقوم خادم الويب بتفسير و تنفيذ الكود الخاص بها ثم يرسل النتيجة ليتم عرضها في متصفح المستخدم، و تستخدم لغة PHP لإنشاء صفحات ويب ديناميكية أي صفحات متغيرة المحتوى حيث تتعامل PHP مع قواعد البيانات وجميع العمليات الأخرى التي يتم تنفيذها على خادم الويب. من أهم ميزاتها: السهولة هي أهم مميزات لغة “php” حيث تعتبر من أسهل اللغات البرمجية و تعتبر الافضل لدي المطورين للويب و خصوصا لمن يتقن لغات برمجية أخري مثل السي و البيرل و حتي لمن ليس لديه خبرة فهي سهلة التعلم . تتوافق مع العديدة من الانظمة بالرغم من انها تحتوي علي نسخ متعددة، و تعمل كل منها في بيئات مختلفة و لكن النسخ جميعها تنبث من نواة أصلية مما يجعلها تنفذ السكريبتات بنفس الطريقة . تحتوي علي ملف إعدادت مما يسمح بالتحكم بالمزايا و الخصائص التي توفرها و هذا يوفر نوع من الحماية و الأمان في الاستخدام وكذلك السهولة في التخصيص لكل مشروع أو موقع الكتروني. تتميز أيضا بالمرونة و القابلية للتوسع فيمكن للمبرمج الاضافة عليها بواسطة لغات برمجية أخرى، وذلك بفضل شفرتها البرمجية المفتوحة . تحتوي علي العديد من المزايا الاضافية حيث ان يوجد بها دوال معالجات حسابية و رياضية، وتوفر الوصول الي مزودات بيانات مختلفة مثل سي كيو إل وغيرها . إلى جانب هذه المميزات فهي تتميز ايضا بالسرعة الكبيرة في إنشاء البرامج . ويضاف إلى ذلك الدليل على قوة ومتانة هذه اللغة هو بأن أشهر نظم إدارة المحتوى مبنية بلغة PHP مثل wordpress , Joomla, Drupal وغيرها. أخيراً، لا يمكن القول بأنها تستخدم أكثر من أي لغة أخرى، فتبعاً للعديد من المصادر الرسمية نجد python ولغات برمجة أخرى تتفوق بنسبة الاستخدام على PHP ولمزيد من المعلومات حول اللغة واستخداماتها يمكنك البحث على الانترنت ومراجعة التوثيق الرسمي للغة عبر الموقع الرسمي ل PHP.
  8. تتيح websockets في لارافيل إنشاء أحداث خاصة بدءً من إنشاء الاتصال وحتى إنهائه عن طريق استخدام Ratchet: Ratchet\WebSocket\MessageComponentInterface. حيث ستمكنك من استخدام onOpen - onClose - onError - onMessage لكل اتصال يتم إنشاؤه مع أي مستخدم، حيث تصبح بالشكل التالي: namespace App; use Ratchet\ConnectionInterface; use Ratchet\RFC6455\Messaging\MessageInterface; use Ratchet\WebSocket\MessageComponentInterface; class MyCustomWebSocketHandler implements MessageComponentInterface { public function onOpen(ConnectionInterface $connection) { // TODO: Implement onOpen() method. } public function onClose(ConnectionInterface $connection) { // TODO: Implement onClose() method. } public function onError(ConnectionInterface $connection, \Exception $e) { // TODO: Implement onError() method. } public function onMessage(ConnectionInterface $connection, MessageInterface $msg) { // TODO: Implement onMessage() method. } } وأيضاً يمكن دمجها مع WebSocketsRouter facade للحصول على الأحداث في صفحة أو route محدد في لارافيل. حيث يتم استخدام مسارات محددة ضمن routes/web.php بالشكل التالي: WebSocketsRouter::webSocket('/my-websocket', \App\MyCustomWebSocketHandler::class);
  9. إن Laravel Valet يقوم بإنشاء ما يدعى بـ symlinks ضمن المسار التالي على نظام لينكس: /usr/local/bin ويمكن إنشاء أول رابط عن طريق تنفيذ الأمر التالي: brew link php7 حيث سيتم طباعة رسالة النجاح أو الفشل مع تحديد المشكلة في حال وجودها لتتمكن من معرفة السبب بدقة. غالباً تكون المشكلة في الصلاحيات الموجودة، للتأكد يجب القيام بالتالي: sudo chown -R `whoami`:admin /usr/local/bin ثم: lrwxr-xr-x 1 YOURUSER admin 29 10 May 21:40 php -> /usr/local/Cellar/php7/7.1/bin/php (مع استبدال نسخة PHP بالنسخة الموجودة في النظام). ولمعرفة نسخة PHP الموجودة نقوم بتنفيذ الأمر: brew list وبعدها يمكن إجراء override من جديد على هذه النسخة للقيام بإنشاء link : brew link php@7.1 --force --overwrite وأخيراً، نقوم بالتحميل من جديد: valet install
  10. في نسخ لارافيل ماقبل 5.0 كان التابع dd بهذا الشكل: function dd() { array_map(function($x) { var_dump($x); }, func_get_args()); die; } ولكن بدءً من النسخة 5 وما فوق أصبح بالشكل التالي: function dd() { array_map(function ($x) { (new Dumper)->dump($x); }, func_get_args()); die(1); } بما أن Dumper يستخدم Symfony VarCloner وبالتالي AbstractCloner وهذا الصف بدوره له قيمة $maxItems تساوي بشكل افتراضي 2500. وفي حال كان لديك 17 عنصر في كل مصفوفة، إن ناتج الضرب ب 147 = 2499 ولذلك المصفوفة بعد العنصر 147 يتم إزالة مقطعها الأخير أي العناصر الأبناء. في حال أردت زيادة القيمة الافتراضية لصف Dumper، يمكن ذلك بعمل Override له كالتالي: public function dump($value) { if (class_exists(CliDumper::class)) { $dumper = 'cli' === PHP_SAPI ? new CliDumper : new HtmlDumper; $cloner = new VarCloner(); $cloner->setMaxItems(5000); $dumper->dump($cloner->cloneVar($value)); } else { var_dump($value); } } ومن إحدى الحلول الأخرى، نقوم بإنشاء صف مساعد جديد helper وتضمينه في bootstrap: use Illuminate\Support\Debug\HtmlDumper; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; function ddd() { $args = func_get_args(); $defaultStringLength = -1; $defaultItemNumber = -1; $defaultDepth = -1; foreach ($args as $variable) { $dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper(); $cloner = new VarCloner(); $cloner->setMaxString($defaultStringLength); $cloner->setMaxItems($defaultItemNumber); $dumper->dump($cloner->cloneVar($variable)->withMaxDepth($defaultDepth)); } die(1); }
  11. يمكن إيجاد ملف الإعدادات للموقع الخاص بك، عن طريق terminal كالتالي: cd ~/.config/valet/Nginx أما للوصول للإعدادات الرئيسية في nginx الخاصة ب valet، فيتم التوجه لها عن طريق: cd /usr/local/etc/nginx/valet حيث يمكن تغييرها ضمن الملف valet.conf أما لتغيير مكان الطباعة فيجب تغيير السطرين التاليين إلى المكان المناسب الذي سيتم فيه طباعة الرسائل: access_log "/Users/[user_id]/.config/valet/Log/access.log"; error_log "/Users/[user_id]/.config/valet/Log/nginx-error.log"; حيث يتم استبدال user_id بالمستخدم المسجّل دخوله إلى النظام. وبعدها يجب إعادة التشغيل لضمان حفظ الإعدادات الجديدة: valet restart sudo systemctl restart nginx
  12. يوجد ثلاث طرق لتنفيذ السكريبت الخارجي الخاص ببايثون عن طريق PHP فلا داعي لاستخدام تابع في لارافيل لتنفيذ ذلك: أولاً: system('C:\Python34\python H:\myapp\app\python\questionPopulator.py'); ثانياً: exec('C:\Python34\python H:\myapp\app\python\questionPopulator.py'); ويمكن أيضاً عن طريق هذا التابع تمرير متحولات أو قيم، مثال: <?php // outputs the username that owns the running php/httpd process $output=null; $retval=null; exec('whoami', $output, $retval); echo "Returned with status $retval and output:\n"; print_r($output); ?> ثالثاً وهي الطريقة الأفضل: $result = shell_exec('C:\Python34\python H:\myapp\app\python\questionPopulator.py'); وهي بدورها تعيد string، ثم يمكنك ترميز النتيجة لنمط JSON وبذلك يمكنك إبقاء النظامين منفصلين دون أن يؤثر أحدهما على الآخر.
  13. إنك تحوال جمع group by عامود واحد في الجدول. الحل المختصر للمشكلة بالتوجه إلى ملف config\database.php وتعديل التالي: 'strict' => false وبذلك يمكنك إجراء group by بدون ظهور هذه المشكلة في حال كان هذا الاستعلام الوحيد الذي يمكنك القيام به ولا يوجد بديل له. أو يمكنك تعديل نفس الملف كالتالي: 'mysql' => [ ... .... 'strict' => true, 'modes' => [ //'ONLY_FULL_GROUP_BY', // الغاء هذه الخاصية سيسمح لك بالجمع عن طريق عمود واحد 'STRICT_TRANS_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'ERROR_FOR_DIVISION_BY_ZERO', 'NO_AUTO_CREATE_USER', 'NO_ENGINE_SUBSTITUTION' ], ] ولكن من غير المرجّح تغيير القيمة 'strict' => false لضرورات أمنية في لارافيل ولتجنب بقية المشاكل في المستقبل. لذلك، يمكنك فصل الاستعلام السابق إلى مرحلتين عن طريق اجراء get() أولاً، ثم groupBy('answer_no) كالتالي: $load_id = explode("#@*", $answers->loading_id); $loading_data = DB::table('loading')->whereIn('id', $load_id)->get(); $grouped = $loading_data->groupBy('answer_no');
  14. أولاً يجب تحميل الإضافة الخاصة بـ PHP ليستطيع التعامل مع Mongodb بتعديل ملف php.ini وإضافة السطر التالي: extension=mongo.so ويكن أيضاً تحميله بشكل يدوي كالتالي: Installing '/usr/lib/php/extensions/no-debug-non-zts-20060613/mongo.so' ولمزيد من المعلومات حول ذلك يمكنك الاطلاع على الإضافة الخاصة ب mongodb في التوثيق الرسمي ل PHP. بعد ذلك، يجب التوجه إلى مجلّد المشروع الرئيسي وتنفيذ الأمر التالي: composer require jenssegers/mongodb وبعدها يجب إضافة المزوّد الخاص بها قبل تعريف Facades أو Eloquent وإلا لن تعمل بالشكل المطلوب: $app->register(Jenssegers\Mongodb\MongodbServiceProvider::class); $app->withFacades(); $app->withEloquent(); وأخيراً، يجب تحميل الإعدادات تلقائياً وقبل تعريف المسارات نظراً لأن lumen لا يقوم بالتحميل التلقائي لها: $app->configure('database'); وعندها يمكن استخدام الاتصال وتعريف المودل كالتالي: <?php namespace App; use Jenssegers\Mongodb\Model as Eloquent; class Example extends Eloquent { protected $connection = 'mongodb'; protected $collection = 'example'; protected $primaryKey = '_id'; } كما يوجد حل بديل لما سبق عن طريق تحميل المكتبة التالية: composer require nordsoftware/lumen-doctrine-mongodb-odm
  15. بشكل إفتراضي يعمل تيليسكوب فقط على بيئة التطوير مع حظر الوصول له عند النشر على خادم الويب وتغيير APP_ENV لتصبح جاهزة للنشر. ولكن يمكن تعديل ذلك بالتوجه إلى المسار التالي: app/Providers/TelescopeServiceProvider.php وتعديل محتوى gate المسؤول عن منع الوصول إلى تيليسكوب وإضافة بعض الحسابات الاستثنائية كالتالي: * @return void */ protected function gate() { Gate::define('viewTelescope', function ($user) { return in_array($user->email, [ // المستخدمين المسموح لهم الوصول إليه 'user@yourapp.com', ]); }); } يجب أيضاً إجراء الأمر التالي عند التغيير على قيم .env لتجنب حدوث أي مشاكل: php artisan config:cache
  16. يمكن الحصول على token بعد الضغط على الرابط المطلوب عن طريق: request::query() بفرض رابط إعادة تعيين كلمة المرور يحوي token كالتالي: http://localhost/forgot?c2108023762b4f86029d5758207cb4156fd58052ad9d6b13b729ce84092937de فيكون المسار: Route::get('forgot', function (Illuminate\Http\Request $request) { $query = $request->query(); $token = (array_keys($query))[0]; echo $token; // c2108023762b4f86029d5758207cb4156fd58052ad9d6b13b729ce84092937de ويفضّل أيضاً إحاطة الكود الخاص بالمتحكم ب try catch نظراً لإحتمالية حدوث أخطاء أثناء العملية. فيصبح الكود الخاص بالمتحكّم على الشكل التالي: public function recover(Request $request) { $user = Admin::where('email', $request->email)->first(); if (!$user) { $error_message = "Your email address was not found."; return redirect()->back()->with(['errors' => $error_message]); } try { Password::sendResetLink($request->only('email'), function (Message $message) { $message->subject('Your Password Reset Link'); }); } catch (\Exception $e) { $error_message = $e->getMessage(); return redirect()->back()->with(['errors' => $error_message]); } return redirect()->back()->with(['success' => 'A reset email has been sent! Please check your email.']); }
  17. تلجأ العديد من الشركات الآن إلى تضمين أدوات مماثلة ضمن حلول الاستضافة التي تقدمها بما يتيح سهولة نقل وإنشاء مشاريع الويب على خوادمها، ولكن تبقى الأفضلية دوماً للأدوات المتخصصة في مهمّتها، فأصبح Docker كغيره من الأدوات التي لا يستغني عنها المطوّر خصوصاً في المشاريع الكبيرة التي يعمل عليها أكثر من شخص/فريق. كما أنه أصبح متاحاً بواجهات رسومية وتطبيق سطح مكتب وبالتالي يمكن استخدامه بدءً من بيئة التطوير المحلية وصولاً إلى الخادم الويب الفعلي أو السحابي. ولكن تبقى الخيارات متاحة والتطوير مستمّر للوصول لآليات أكثر فعالية وبميّزات أكثر تنافسية بين الشركات التي تقدم هذه الحلول.
  18. يوجد مشكلة في الاعتماديات المستخدمة ضمن هذه الصورة، فالصورة التي تستخدمها بشكل تلقائي لديها الاعتمادية mbstring والتي بدورها تحتاج مكتبة oniguruma لتشغيل الكود بالشكل المناسب. يجب عليك إزالة السطر: RUN docker-php-ext-install pdo mbstring وسيتم اعتماد المكتبة الافتراضية الموجودة. وللتأكد من استخدامها بالشكل الصحيح يمكن إجراء التالي: $> docker run --rm -it php:7 php -r "var_dump(mb_ereg_match('^99.*', '123456'));" bool(false) $> docker run --rm -it php:7 php -r "var_dump(mb_ereg_match('^12.*', '123456'));" bool(true) كما يجب إضافة السطر التالي للكود المرفق في آخر الملف ليتم فتح المنفذ وتجنب حدوث مشاكل ضمن docker: EXPOSE 8000
  19. إن ظهور Kill في composer وتوقفه هو دليل على أن الإجرائية تقوم باستهلاك موارد كبيرة بالنسبة للمتوفرة على الجهاز، فلذلك ستحتاج لإضافة المزيد من الموارد Ram على جهازك إن أمكن. والسعة المفضلة لذلك هي حوالي 700MB بأقل حد. ولكن في حال كنت تقوم بالإجرائية على خادم الويب مباشرةً، فلا يجب أبداً إجراء composer update. بدلاً من ذلك: قم بإجراء composer update على جهازك المحلي (بيئة التطوير) فسيكون لديك موارد أكبر من الموجودة على خادم الويب في حال كانت موارده قليلة. ثم قم بنقل المشروع عن طريق استخدام git push. ثم قم بإجراء composer install على الخادم. حيث سيقوم الإجراء composer install بالقراءة من ملف .lock واستخدام جميع الإصدارات التي تم تعريفها ضمن المشروع بدلاً من البحث عن آخر إصدارات من جميع المكاتب المضمنة ضمن المشروع و المستخدمة أيضاً في بناء Laravel. وذلك بدوره سيخفف من العبء على الذاكرة والموارد الموجودة على الجهاز. بشكل ممثائل، يمكنك رفع مجلد Vendor مباشرةً ضمن المشروع إلى الخادم، وبالتالي ستستغني عن الحاجة لإجراء composer install على الخادم أيضاً. ولكن عندها يجب عليك القيام بالأمر التالي بعد إجراء عملية النقل: composer dump-autoload --optimize وأيضاً من إحدى الحلول هي بإنشاء swap file. مثال بسيط: mkdir -p /var/_swap_ cd /var/_swap_ #1M * 2000 ~= 2GB of swap memory. هنا يتم إضافة dd if=/dev/zero of=swapfile bs=1M count=2000 chmod 600 swapfile mkswap swapfile swapon swapfile #لتشغيلها بشكل أوتوماتيكي عند الإقلاع echo "/var/_swap_/swapfile none swap sw 0 0" >> /etc/fstab
  20. إن الخطأ Component template should contain exactly one root element يظهر فقط عندما يتم استخدام أكثر من عنصر على مستوى الجذر ضمن الصفحة الواحدة أو المكوّن الواحد. في حال كنت تستخدم نسخة Vue 2.0 فيوجد قيد على العنصر الجذر ضمن الصفحة أو المكوّن، وهو بأن يكون عنصر واحد فقط، على الشكل التالي: <div> <div class="form-group"> ... </div> <div class="col-md-6"> ... </div> </div> بدلاً من أن يكون أكثر من عنصر على مستوى الجذر في المكوّن أو الصفحة الواحدة، أي على الشكل التالي: <div class="form-group"> ... </div> <div class="col-md-6"> ... </div> //-> سيسبب خطأ ولكن تم إزالة هذا القيد في النسخة الجديدة من Vue 3.0 وأصبح بالإمكان استخدام أكثر من عنصر على مستوى الجذر في الملف أو المكون الواحد. يوجد أيضاً حل آخر باستخدام إضافة: vue-fragment ، يتم تحميلها كالتالي: npm install vue-fragment ولاستخدامها نقوم بتضمنيها كالتالي: import Fragment from 'vue-fragment'; Vue.use(Fragment.Plugin); // or import { Plugin } from 'vue-fragment'; Vue.use(Plugin); ثم يمكننا وضع أكثر من عنصر ضمن الـ fragment: <template> <fragment> <tr class="hola"> ... </tr> <tr class="hello"> ... </tr> </fragment> </template>
  21. يظهر هذا الخطأ عند عدم وجود ذاكرة RAM كافية على الخادم أو الجهاز الذي يقوم بتشغيل المشروع. إن الحل الأفضل هو بزيادة RAM ضمن الجهاز في حال كانت الموارد الموجودة لا تتناسب مع حجم المشروع، ولكن يمكن تدارك ذلك بإنشاء swap لإضافة مساحة إضافية لمعالجة التعليمات ضمن المشروع كالتالي: /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024 /sbin/mkswap /var/swap.1 /bin/chmod 0600 /var/swap.1 /sbin/swapon /var/swap.1 ويمكن أيضاً إنشاء ملف swap دائم، على سبيل المثال لنفترض أننا سنقوم بإنشاء ملف 4Gigabyte يمكننا إجراء ذلك عن طريق تحديد بلوك بسعة 1Gigabyte وعداد على القيمة 4 كالتالي: sudo dd if=/dev/zero of=/swapfile bs=1G count=4 4+0 records in 4+0 records out 4294967296 bytes (4.3 GB) copied, 18.6227 s, 231 MB/s ويوجد أيضاً طريقة مختصرة لما سبق، عن طريق تنفيذ أمر واحد هو: sudo fallocate -l 4G /swapfile ملاحظة: عند إجراء أي أمر من الأوامر السابقة يجب أن يتم تنفيذه عن طريق المستخدم root.
  22. إن الفرق الأساسي بينهما هو في طريقة استخدامهما. فاستخدام roles هو عند الاتصال المباشر مع التطبيق، أما Oauth-2 أو scopes يغطي الوصول إلى مصادر API لمستخدم خارجي بالنيابة عن المستخدم المباشر. لتطبيق ذلك يجب أولاً تهئية مكتبة laravel/passport بالشكل الصحيح من التوثيق الرسمي باتباع الخطوات. ثم يجب تعريف ال scopes بشكل مفصّل بحيث يتم ذكر كافة الصلاحيات التي سيتم استخدامها، ففي ملف AuthServiceProvider نقوم بكتابة التالي: Passport::tokensCan([ 'manage-order' => 'Manage order scope' 'read-only-order' => 'Read only order scope' ]); ثم نقوم بكتابة ملف المتحكم الخاص بالتوثيق: namespace App\Http\Controllers; class OrderController extends Controller { public function index(Request $request) { } public function store(Request $request) { // عملية مخصصة للمدير } public function show($id) { // الإظهار للمدير والمستخدم العادي } } ثم في ملف api نقوم بتعريف الموجهات مع استخدام auth المناسب لها: Route::get('/api/orders', 'OrderController@index') ->middleware(['auth:api', 'scopes:manage-order']); Route::post('/api/orders', 'OrderController@store') ->middleware(['auth:api', 'scopes:manage-order']); Route::get('/api/orders/{id}', 'OrderController@show') ->middleware(['auth:api', 'scopes:manage-order, read-only-order']); حيث نقوم بتمرير 'scopes:manage-order, read-only-order' حسب الصلاحيات التي قمنا بتعريفها في الباسبورت وأيضاً، لإصدار token للمستخدم، يجب أولاً التحقق من صلاحيات هذا المستخدم ولتنفيذ ذلك نحتاج متحكم إضافي كالتالي: namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; class ApiLoginController extends Controller { use AuthenticatesUsers; protected function authenticated(Request $request, $user) { // التحقق من صلاحيات المستخدم من قاعدة البيانات $role = $user->checkRole(); // إعطاء scope تبعاً لصلاحيات المستخدم if ($role == 'admin') { $request->request->add([ 'scope' => 'manage-order' // grant manage order scope للمدير ]); } else { $request->request->add([ 'scope' => 'read-only-order' // read-only order scope للمستخدم ]); } // تحويل الطلب إلى oauth $tokenRequest = Request::create( '/oauth/token', 'post' ); return Route::dispatch($tokenRequest); } } أخيراً، نقوم بتوجيه المستخدم عندما يقوم بتسجيل الدخول إلى هذا المتحكم كالتالي: Route::group('namespace' => 'Auth', function () { Route::post('login', 'ApiLoginController@login'); });
  23. إن المشروع سيعمل باستخدام xampp أو أي برنامج رديف على جهازك المحلي لأن xampp بطبيعته يحوي جميع الإضافات اللازمة ومنها ext-dom، أما على خادم الويب فهذه الإضافة ناقصة. ولكن يوجد أيضاً رسالة تحذير بأنه لا يجب أن تقوم بتشغيل composer من المستخدم الجذر (لأسباب الحماية). فالأفضل أن تقوم بإنشاء مستخدم آخر قبل البدء بالعمليات على المشروع لتجنب أي خطأ أو مشكلة على الخادم. أما بالنسبة للمكتبة، فعند تحميل php-xml يتم معها تحميل جميع المكتبات اللازمة، عن طريق الأمر التالي: sudo apt-get update sudo apt install php-xml وأيضاً على الأرجح أنه ينقص لديك mbstring، يتم تحميلها كالتالي: sudo apt-get install php-mbstring وأخيراً نقوم بتحديث composer والإضافة كالتالي: composer update composer require cviebrock/eloquent-sluggable
  24. يمكنك استعمال التابع array_sum في php كالتالي: <?php $matrix = array([1,2,3], [4,5,6], [7,8,9]); $sum = 0 ; foreach ($matrix as $numbers) $sum += array_sum($numbers); echo($sum); ?>
  25. يعتمد Next JS على React ليسهّل العمل على المطورين ويختصر الكثير من الوقت عن طريق ما يقدمّه من توجيه routing وفصل الكود ببنية متينة، ودعمه ل webpack بشكل افتراضي والعديد من الميزات الأخرى التي تكون متاحة بشكل تلقائي بمجرد إنشاء مشروع عن طريقه. وبالتالي لا يحتاج المطوّر لتضمين هذه الأمور من الصفر في المشروع الذي يعمل عليه. فمثلاً من أهم الفروقات الموجودة بينهما: عند إنشاء مشروع جديد باستخدام react يتم إنشاء مجلدين أساسيين هما public و src بالمحتويات التالية: ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── serviceWorker.js │ └── setupTests.js └── yarn.lock أما إنشاء مشروع عن طريق Next فيتم تلقائياً تهئية بنية ملفات المشروع لتكون جاهزة مباشرةً للعمل كالتالي: . ├── README.md ├── package.json ├── node_modules ├── pages │ ├── _app.js │ ├── api │ └── index.js ├── public │ ├── favicon.ico │ └── vercel.svg ├── styles │ ├── Home.module.css │ └── globals.css └── yarn.lock حيث تم إضافة مجلد pages ويمكنك مباشرةً البدء بتنسيق الوجهات وتكون جاهزة للربط والتوجيه routing، وأيضاً مجلد public الذي سيحوي الملفات الثابتة لمشروعك مثل الصور ولن تحتاج لإجراء require في كل مرة لإدخال الصور إلى المكونات على سبيل المثال. وبالنسبة للتوجيه تستطيع مباشرةً استخدام Link للتنقل بين الصفحات: <Link href="/"> <a className="header__anchor">Home</a> </Link> وأيضاً، بالنسبة للتعامل مع البيانات، يقدّم Next بشكل افتراضي آليات data fetch للتعامل مع API وجلب البيانات إلى الواجهات بدلاً من تعريفها من الصفر وقبل تحميل الوجهات مما يتيح سهولة للمستخدم في استعراض الموقع والبيانات. يوجد العديد من الخصائص والميزات الأخرى التي يقدمها Next والتي يمكنك التعرف عليها وعن كيفية استخدامها من الموقع الرسمي. أخيراً، مع استخدام Next سيبقى بإمكانك استخدام جميع خصائص React ولا يتم الاستغناء عن أي شيء أو تبديله، فهو فقط يبسط الأمور ويسرّع العمل للانطلاق بالمشروع.
×
×
  • أضف...