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

Sam Ahw

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

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

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

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

    16

إجابات الأسئلة

  1. إجابة Sam Ahw سؤال في ماهو non-zero code في لارافيل ضمن Docker كانت الإجابة المقبولة   
    يوجد مشكلة في الاعتماديات المستخدمة ضمن هذه الصورة، فالصورة التي تستخدمها بشكل تلقائي لديها الاعتمادية 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  
  2. إجابة Sam Ahw سؤال في مشكلة composer kill في لارافيل كانت الإجابة المقبولة   
    إن ظهور 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  
  3. إجابة Sam Ahw سؤال في خطأ Vue template syntax error في لارافيل كانت الإجابة المقبولة   
    إن الخطأ 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>  
  4. إجابة Sam Ahw سؤال في ظهور خطأ proc_open في لارافيل كانت الإجابة المقبولة   
    يظهر هذا الخطأ عند عدم وجود ذاكرة 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.
  5. إجابة Sam Ahw سؤال في كيفية استخدام Laravel Passport Scopes كانت الإجابة المقبولة   
    إن الفرق الأساسي بينهما هو في طريقة استخدامهما. فاستخدام 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'); });  
  6. إجابة Sam Ahw سؤال في مشكلة في تحميل ext-dom لارافيل كانت الإجابة المقبولة   
    إن المشروع سيعمل باستخدام 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  
  7. إجابة Sam Ahw سؤال في كيفية إجراء unit test على task في لارافيل كانت الإجابة المقبولة   
    إن الاختبار يتم بتفيذ الأمر مباشرةً ورؤية النتائج:
    php artisan schedule:run ولكن في حال كان الهدف هو طباعة رسائل الخطأ المخصصة في حالات معيّنة، فإن scheduler لا يقوم بالطباعة بطبيعته، ولكن يمكنك توجيه الطباعة للكود الذي يتم تنفيذه لأي ملف آخر عن طريق استخدام:
    writeOutputTo() أو:
    appendOutputTo() وهو مايعرف في TaskOutput في التوثيق الرسمي للارافيل، مثال:
    $schedule->command('emails:send') ->daily() ->sendOutputTo($filePath); حيث نستبدل $filepath بمسار الملف الذي نريد الطباعة عليه.
    أما لإجراء Unit Test للعمل بشكل مخصص أكثر، فيمكن إضافة التالي ليتم اختبار schedule محدد مثل الكود السابق لديك:
    public function testIsAvailableInTheScheduler() { /** @var \Illuminate\Console\Scheduling\Schedule $schedule */ $schedule = app()->make(\Illuminate\Console\Scheduling\Schedule::class); $events = collect($schedule->events())->filter(function (\Illuminate\Console\Scheduling\Event $event) { return stripos($event->command, 'NewCommand'); }); if ($events->count() == 0) { $this->fail('No events found'); } $events->each(function (\Illuminate\Console\Scheduling\Event $event) { // This example is for hourly commands. $this->assertEquals('0 * * * * *', $event->expression); }); }  
  8. إجابة Sam Ahw سؤال في ظهور خطأ أثناء استخدام لارافيل Envoy كانت الإجابة المقبولة   
    يوجد نقص في بعض التعاريف في الملف، فيجب التأكد من تعريف ملف bootstrap بشكل صحيح وربطه ضمن kernel التطبيق قبل البدء بإجراء أي task، مثال شامل:
    @servers(['localhost' => '127.0.0.1']) @setup define('LARAVEL_START', microtime(true)); $app = require_once __DIR__.'/bootstrap/app.php'; $kernel = $app->make(Illuminate\Contracts\Console\Kernel::class); $kernel->bootstrap(); dump(config('database')); @endsetup @task('new', ['on' => 'localhost']) ls @endtask وبمجرد الدلالة على bootstrap ضمن kernel و إضافة Laravel_START لا داعي لإدخال ملفات vendor فسيتم اعتمادها بشكل تلقائي.
    ثم تأكد من إجراء العمليات التالية لتجنّب أي مشاكل:
    php artisan config:clear php artisan cache:clear composer dump-autoload php artisan view:clear php artisan route:clear  
  9. إجابة Sam Ahw سؤال في اختبار تجاوبية الصفحة في Laravel Dusk كانت الإجابة المقبولة   
    يمكن إجراء تنفيذ scripts بداخل الاختبار، ولكنها يجب ألا تكون متتالية. بل يجب تعريف كل جزء على حدى، مثال:
    public function testExample() { $this->browse(function ($browser) { $browser ->visit('http://localhost:8000/home') ->driver->executeScript('window.scrollTo(0, 500);'); // browser لا يمكن إجراء أوامر أخرى هنا مباشرةً يجب تعريف غرض جديد من $browser->click('label[for=test_1]') ->pause(500) }); } حيث قمنا باستخدام الدالة window.scrollTo، في حال كنت تستخدم نسخة أقدم من لارافيل، يمكنك استخدام jquery لتنفيذ ذلك:
    public function scrollTo($selector) { $this->ensurejQueryIsAvailable(); $selector = $this->resolver->format($selector); $this->driver->executeScript("jQuery(\"html, body\").animate({scrollTop: jQuery(\"$selector\").offset().top}, 0);"); return $this; }  
  10. إجابة Sam Ahw سؤال في خطأ allowed memory exhausted في لارافيل كانت الإجابة المقبولة   
    يجب تغيير الإعدادات الافتراضية في إعدادات php في حال كنت تقوم بإجراء عمليات على جداول كبيرة الحجم.
    ويمكن ذلك عن طريق الذهاب إلى ملف تعريف إعدادات php ضمن خادم الويب ويكون عادةً ضمن المسار : /etc/php7/fpm/php.ini
    في حال لديك إصدار آخر يجب أن تستبدل رقم الإصدار 7 بالرقم الذي لديك، ولكنه سيكون موجود ضمن etc غالباً، ثم نقوم بتعديل الحد الأقصى للذاكرة بأن نقوم بالبحث عن التالي:
    القيمة السابقة memory_limit = 512M القيمة الجديدة memory_limit = 2048M ثم يجب بعد ذلك إعادة تشغيل خادم الويب:
    sudo systemctl restart nginx  
  11. إجابة Sam Ahw سؤال في Localization في لارافيل لا تعمل كانت الإجابة المقبولة   
    يجب أولاً أن تقوم بتغيير الكود الموجود في المتحكم لاستخدام لغة افتراضية في حال الفشل، كالتالي:
    public function handle($request, Closure $next) { if (Session::has('locale')) { App::setLocale(Session::get('locale')); } else { //تقوم لارافيل تلقائياً باستعادة اللغة الافتراضية الموجودة App::setLocale(Config::get('app.fallback_locale')); } return $next($request); } ثم تأكد من إضافة middleware في Kernal.php:
    \App\Http\Middleware\Language::class, وأخيراً ضمن المتحكم الخاص باللغة:
    public function index($locale) { session(['locale' => $locale]); App::setLocale($locale); return Redirect::back(); } وأيضاً يتم تعريف اللغة الافتراضية للتطبيق ضمن ملف .env :
    APP_LOCALE=en ويتم الدلالة عليها في ملف config/app.php كالتالي:
    'locale' => env('APP_LOCALE', 'en'), أما للتغيير إلى أكثر من لغة فيمكن إنشاء قائمة باللغات بحيث عندما يتم الضغط على خيار لغة معيّنة يتم التوجيه إلى مسارات هذه اللغة:
    <ul class="dropdown-menu" role="menu"> <li>{!! link_to('lang/en', trans('menus.language-picker.langs.en')) !!}</li> <li>{!! link_to('lang/es', trans('menus.language-picker.langs.es')) !!}</li> <li>{!! link_to('lang/fr-FR', trans('menus.language-picker.langs.fr-FR')) !!}</li> <li>{!! link_to('lang/it', trans('menus.language-picker.langs.it')) !!}</li> <li>{!! link_to('lang/pt-BR', trans('menus.language-picker.langs.pt-BR')) !!}</li> <li>{!! link_to('lang/ru', trans('menus.language-picker.langs.ru')) !!}</li> <li>{!! link_to('lang/sv', trans('menus.language-picker.langs.sv')) !!}</li> </ul> ويكون المسار لذلك كالتالي:
    get('lang/{lang}', 'LanguageController@changeLang');  
  12. إجابة Sam Ahw سؤال في ظهور خطأ is not instantiable في لارافيل كانت الإجابة المقبولة   
    يجب التأكد من تعريفه ضمن config في providers والإشارة له ضمن aliases:
    'providers' => [ .... Laravel\Socialite\SocialiteServiceProvider::class ], 'aliases' => [ .... 'Socialite' => Laravel\Socialite\Facades\Socialite::class ], ثم عند استخدامه في أي متحكم، يجب استخدام alias الذي قمنا بتعريفه:
    namespace App\Http\Controllers; use Illuminate\Http\Request; use Socialite; use App\Http\Requests; use App\Http\Controllers\Controller; class SocialAuthController extends Controller { public function redirect() { return Socialite::driver('facebook')->redirect(); } public function callback() { } }  
  13. إجابة Sam Ahw سؤال في كيف تتم إضافة Contracts في لارافيل كانت الإجابة المقبولة   
    يمكنك الإشارة إلى هذا الصف على شكل اعتمادية أو dependency في أي متحكم آخر، فسيتم إنشاؤه حتى لو لم تقم باستخدام واجهة Interface بداخل هذا المتحكم.
    مثال:
    <?php namespace App\Http\Controllers; use App\Users\Repository as UserRepository; class UserController extends Controller { /** * The user repository instance. */ protected $users; /** * Create a new controller instance. * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } } أما في حال كنت ستستخدم واجهة، تأكد من أن الصف يقوم بعمل implement لهذه الواجهة ثم يجب القيام باستدعائه عن طريق التابع bind في أي مقدّم خدمة. على الشكل التالي:
    $this->app->bind(UserRepository::class, EloquentUserRepository::class);  
  14. إجابة Sam Ahw سؤال في كيفية الحصول على حدث الإدخال في queue ضمن لارافيل كانت الإجابة المقبولة   
    يمكنك الدخول إلى الغرض والحصول على قيمة المتغيّر jobPushed عن طريق استخدام Laravel Horizon عن طريق الاستماع إلى الحدث jobPushed.
    فإن البيانات المرسلة مع هذا الحدث فيها جميع البيانات المتعلقة بالعمل الذي يتم إدخاله مثل: ID, name, connection, queue إلخ. وبذلك يمكنك معرفة عند إدخال هذا العمل إلى الرتل وإجراء أي عمليات معالجة ترغب بها بمجرّد تشغيل الحدث.
    ويمكنك تنفيذ ذلك كالتالي:
    Event::listen(JobPushed::class, function(JobPushed $event){ \Log::debug('JobPushed Event Fired ', [ 'connection' => $event->connectionName, 'queue' => $event->queue, 'payload' => [ 'id' => $event->payload->id(), 'displayName' => $event->payload->displayName(), 'commandName' => $event->payload->commandName(), 'isRetry' => $event->payload->isRetry(), 'retryOf' => $event->payload->retryOf(), ] ]); });  
  15. إجابة Sam Ahw سؤال في مشكلة في Cross Domain Requests في لارافيل كانت الإجابة المقبولة   
    المشكلة تحدث هنا لأن متصفح الويب أو تطبيق Angular سيقوم فقط بإرفاق الـ cookie للطلبات التي تنتمي لنفس اسم النطاق التي يتم عبره استقبال الطلبات.
    لحل هذه المشكلة أولاً تأكد من أنك تقوم باستخدام relative routes فمثلاً بدلاً من:
    /api/sanctum/crsf نقوم بكتابة:
    http://example.com/sanctum/crsf ثم يجب عليك إعداد خصائص البروكسي ضمن ملف proxy.conf.json ونضعه في المجلّد الجذر للمشروع:
    { "/api/*": { "target": "http://example.ocm", "secure": false, "changeOrigin": true, "logLevel": "debug", "pathRewrite": { "^/api": "" } } } ثم نقوم بتعديل الملف angular.json:
    "architect": { ... "serve": { ... "options": { .... "proxyConfig": "proxy.conf.json" } } } ثم أخيراً في ملف .env نقوم بالتعديلات التالية للتأكد من أن sanctum يقوم بالتعرف على الطلبات وإرفاق cookies معها:
    SANCTUM_STATEFUL_DOMAINS=localhost,.example.com SESSION_DRIVER=cookie SESSION_DOMAIN=localhost  
  16. إجابة Sam Ahw سؤال في ظهور خطأ عند التطوير لنسخة Laravel 8 كانت الإجابة المقبولة   
    قد يحدث تضارب عند تحديث النسخة إلى 8 مع blade في استخدام routes خاصةً في حال تم اختيار Jetstream
    لحل هذه المشكلة أولاً يمكن إنشاء مجلد resources كالتالي:
    composer require tightenco/ziggy npm install ziggy-js php artisan ziggy:generate "resources/js/ziggy.js" ثم يجب تعديل ملف webpack.mix.js:
    mix.js('resources/js/app.js', 'public/js') .webpackConfig(require('./webpack.config')); وأيضاً الملف ./webpack.config: لكي يتم التعرف على المسارات routes:
    const path = require('path'); module.exports = { resolve: { alias: { '@': path.resolve('resources/js'), ziggy: path.resolve('vendor/tightenco/ziggy/src/js/route.js'), }, }, }; وأخيراً ضمن الملف app.js:
    import route from 'ziggy'; import { Ziggy } from './ziggy'; ... Vue.mixin({ methods: { route: (name, params, absolute) => route(name, params, absolute, Ziggy), }, }); ... new Vue({ el: "#app", render: (h) => h(InertiaApp, { props: { initialPage: JSON.parse(app.dataset.page), resolveComponent: (name) => require(`./Pages/${name}`).default, }, }), }); وبذلك يتم الاستغناء عن vue-router ويتم أخذ jetstreams ليصبح توجيه المسارات من قبل Laravel
  17. إجابة Sam Ahw سؤال في لقد حملت jdk وتم تنصيب بنجاح ولاكن عندما اكتب java version يقول توجد خطئ عندي؟ كانت الإجابة المقبولة   
    لا يوجد فرق في بيئة التطوير التي تختارها، فسيبقى التعامل والتطوير بلغة البرمجة هو نفسه على جميع بيئات العمل
  18. إجابة Sam Ahw سؤال في كيفية تعديل المسارات في Laravel Fortify كانت الإجابة المقبولة   
    إن استخدام Laravel Fortify هو فقط لتسهيل الإجراءات الأساسية لعمليات التحقق وتسجيل الدخول وإعادة تعيين كلمة المرور...إلخ. بالإضافة إلى أنه يقوم بإنشاء المسارات لها وبذلك يسهّل العمل ويختصر الوقت.
    في حال الحاجة لوجود مسارات مخصصة أو تعديل هذه المسارات التي يقوم fortify بإنشائها فعندها لا حاجة لاستخدامه، ويمكن إنشائها بشكل مخصص كما هو الوضع الطبيعي في أي مشروع.
    لأن أي تعديل على الملف التالي:
    /vendor/laravel/fortify/routes/routes.php وعند القيام بالأمر:
    composer update ستذهب أي تعديلات تم إجرائها ضمن المجلد vendor. وبالتالي لن يتم حفظها بشكل دائم.
    أما عند استخدام Fortify وإضافة مسارات أخرى في المشروع فيتم ذلك عن طريق وضع وسيط middleware باسم fortify ضمن نفس مجلد تعريف مسارات المشروع web.php كالتالي:
    Route::group(['middleware' => config('fortify.middleware', ['web'])], function () { Route::get('home', function () { return 'Home'; }) }); ويمكن أيضاً استخدام auth لمسارات معيّنة عن طريق إضافة:
    Route::get('newpage', function () { return 'newpage'; }) ->middleware(['auth']);  
  19. إجابة Sam Ahw سؤال في ظهور خطأ أثناء تحميل ملفات مشروع لارافيل على الخادم كانت الإجابة المقبولة   
    معنى هذا الخطأ هو عدم وجود صلاحيات للكتابة على المسار المذكور.
    حيث سيتم المتابعة بتحميل المكتبات المستخدمة في Laravel ولكن لن يملك المشروع القدرة على استخدام الكاش بسبب عدم امتلاكه الصلاحيات للكتابة أو التعديل على المجلد cache.
    لذلك يجب عليك تعديل الصلاحيات على مجلد المشروع بشكل عام أو فقط مجلد الكاش في حال كانت المشكلة موجود فقط ضمنه
    أولاً: نقوم بتغيير صلاحيات المجموعة على المجلد كالتالي:
    sudo chown -R amir123 /home/amir123/.composer/cache/repo/mynewwebsite.org بافتراض أن اسم المستخدم الجذر لديك هو كما مذكور في نص السؤال amir123
    وأيضاً نقوم بتعديل صلاحيات الكتابة على المجلد Files:
    sudo chown -R amir123 /home/amir123/.composer/cache/files/ وفي حال بقيت المشكلة، أيضاً حاول تعديل الصلاحيات على composer:
    sudo chown -R amir123 /home/amir123/.composer ليتمكن من الكتابة وتعديل الملفات في حال كانت إعدادات الخادم لديك عكس ذلك.
  20. إجابة Sam Ahw سؤال في خطأ عند تشغيل websockets في لارافيل كانت الإجابة المقبولة   
    سبب المشكلة التي تواجهها هو عدم توافق بين الإصدارات، فيبدو أنك تقوم باستخدام مكتبة React /DNS ضمن التطبيق، و إن البعض من إصداراتها غير متوافق مع آخر نسخة من Laravel websockets.
    الحل هو بأن تقوم بتخفيض النسخة المستخدمة من Reac/DNS  إلى النسخة 0.4.19 عن طريق composer كالتالي:
    composer require react/dns:^0.4.19 بعدها يمكنك إعادة التشغيل عن طريق نفس الأمر للتأكد من أن الإصدار 0.4.19 متوافق ويعمل بشكل صحيح مع laravel websockets:
    php artisan websockets:serve  
  21. إجابة Sam Ahw سؤال في كيفية تشغيل websockets في لارافيل ضمن حاوية docker كانت الإجابة المقبولة   
    أولاً يجب عليك التأكد من استخدام نفس المنفذ الذي يتم استعماله في websockets ضمن الحزمة، ووضعه في ملف dokcer-compose. علماً بأن المنفذ الافتراضي في حال لم تقم بتغييره هو 6001.
    ثم يمكنك فصّل الخصائص عن بعضها لحاويتين منفصلتين، بحيث تقوم الحاوية الأولى بتشغيل تطبيق لارافيل والحاوية الأخرى تقوم بالاتصال مع websockets على الشكل التالي:
    ملف الحاوية الأولى app.dockerfile
    FROM php:7-cli-alpine RUN apk --update add wget \ curl \ git \ grep \ build-base \ libmemcached-dev \ libmcrypt-dev \ libxml2-dev \ imagemagick-dev \ pcre-dev \ libtool \ make \ autoconf \ g++ \ cyrus-sasl-dev \ libgsasl-dev RUN docker-php-ext-install mysqli pdo pdo_mysql tokenizer xml RUN pecl channel-update pecl.php.net \ && pecl install memcached \ && pecl install imagick \ && pecl install mcrypt-1.0.3 \ && docker-php-ext-enable memcached \ && docker-php-ext-enable imagick \ && docker-php-ext-enable mcrypt RUN rm /var/cache/apk/* && \ mkdir -p /var/www ENTRYPOINT ["/usr/bin/php", "/var/www/html/websocket-service/artisan", "websockets:serve"] ملف web.dockerfile:
    FROM php:7-fpm-alpine RUN apk --update add wget \ curl \ git \ grep \ build-base \ libmemcached-dev \ libmcrypt-dev \ libxml2-dev \ imagemagick-dev \ pcre-dev \ libtool \ make \ autoconf \ g++ \ cyrus-sasl-dev \ libgsasl-dev RUN docker-php-ext-install mysqli pdo pdo_mysql tokenizer xml RUN pecl channel-update pecl.php.net \ && pecl install memcached \ && pecl install imagick \ && pecl install mcrypt-1.0.3 \ && docker-php-ext-enable memcached \ && docker-php-ext-enable imagick \ && docker-php-ext-enable mcrypt RUN rm /var/cache/apk/* && \ mkdir -p /var/www ولجعل المنفذ 6001 مرئياً خارج الحاوية، نقوم بتغيير التوجيهات لتصبح كالتالي:
    app: build: context: ./ dockerfile: app.dockerfile working_dir: /var/www/html volumes: - ./:/var/www/html ports: - "6001:6001" environment: - DB_PORT=${DB_PORT} - DB_HOST=${DB_HOST}  
  22. إجابة Sam Ahw سؤال في استخدام أكثر من وسيط أثناء التعامل مع pusher في لارافيل كانت الإجابة المقبولة   
    يمكنك إنشاء middleware جديد خاص بال broadcast وربطه مع kernel.php:
    'broadcast' => \App\Http\Middleware\Broadcast::class ثم تعديل broadcast.php ليصبح كالتالي:
    public function handle($request, Closure $next) { $web = Auth::guard('web')->user(); if ($web) { return response()->json(\Illuminate\Support\Facades\Broadcast::auth($request)); } return response()->json('Unauthorized.', 500); } ثم للمصدر الآخر المختلف عن الويب، يجب إرسال التحقق على الشكل التالي:
    Route::post('/guard/broadcast/auth', function(\Illuminate\Support\Facades\Request $req){ return true; })->middleware('broadcast'); بحيث يتم استخدام middleware نفسه.
    ثم عند إرسال الطلب من جهة المستخدم pusher، يجب الإرسال للقناة التابعة ل guard معيّن:
    <script> let pusher = new Pusher("{{ env('PUSHER_APP_KEY') }}", { cluster: 'ar2', encrypted: true, auth: { headers: { 'X-CSRF-TOKEN': "{{ csrf_token() }}" } }, authEndpoint: '{{ env('APP_URL') }}' + '/guard/broadcast/auth', }); let channel = pusher.subscribe('private-channel.{{ Auth::user()->id }}'); channel.bind('my-event', addMessage); function addMessage(data) { console.log(data); } </script> وبذلك يمكن تحديدها عن طريق تزويد الطلب ب parameter يدعى authEndpoint
    authEndpoint: '{{ env('APP_URL') }}' + '/guard/broadcast/auth',  
  23. إجابة Sam Ahw سؤال في فشل العمل ضمن الرتل queue في لارافيل كانت الإجابة المقبولة   
    يحدث هذا الخطأ عندما تمرر قيمة null إلى الحلقة، أي بمعنى آخر عند عدم وجود أعمال للقيام بها. وبالتالي يتم التوقف عن إرسال العمليات إلى الرتل ويعطي رسالة الخطأ لعدم وجود أي بيانات لإجراء حلقة التكرار عليها.
    يوجد أمر آخر لمنع حدوث ذلك أثناء تشغيل الرتل هو:
    php artisan queue:work --stop-when-empty ويقوم بدوره بإيقاف العمل عند عدم وجود أي عمليات ضمن الرتل.
    ولكن هذه الطريقة متبعة فقط للأعمال الصغيرة والتي لا تتطلب الكثير من الوقت. فبفرض تراكم عدد من الأعمال أكبر من 20 مثلاً وسيتم تكراره كل دقيقة، فذلك أيضاً سيسبب خطأ آخر أو تضارب في المعلومات لأن العملية السابقة لم تكن قد انتهت قبل البدء بالعملية التالية وهكذا.
    الأسلوب المتبع لحل هذه المشاكل وخاصة عند وجود كمية أكبر من العمليات هو كالتالي:
    أولاً نقوم بإنشاء أمر جديد لإرسال الرسائل:
    php artisan make:command SendContactEmails ضمن الملف SendContactEmails.php نقوم بالتغيير التالي:
    protected $signature = 'emails:work'; وضمن التابع handle:
    return $this->call('queue:work', [ '--queue' => 'emails', '--stop-when-empty' => null, ]); ثم ضمن app/Console/Kernal.php نضيف الأمر السابق:
    protected $commands = [ \App\Console\Commands\SendContactEmails::class ]; وأخيراً يتم جدولة الأمر السابق كل دقيقة بالشكل التالي:
    protected function schedule(Schedule $schedule) { $schedule->command('emails:work')->everyMinute()->withoutOverlapping(); } حيث سيسمح استخدام withoutOverlapping من تضارب العمليات وانتهاء العملية السابقة قبل البدء بالعملية التي تليها
    ويتم بعدها تشغيل cron بالأمر التالي:
    * * * * * /usr/local/bin/php /home/username/project/artisan schedule:run > /dev/null 2>&1  
  24. إجابة Sam Ahw سؤال في العودة للكاش الافتراضي في حال فشل redis ضمن لارافيل كانت الإجابة المقبولة   
    يمكنك معالجة هذه المشكلة باستخدام قيم متغيّرة بدلاً من القيم الثابتة أثناء تعريف Redis. فأولاً يجب تغيير تعريف redis ضمن config/database.php ليصبح على الشكل التالي:
    'redis' => [ 'cluster' => false, 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], 'session' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 1, ], ], وبذلك يتم استخدام قيم قابلة للتغير من بين القيم المعرفة ضمن .env
    وبعدها ستحتاج لتغيير ioc binding باستخدام الصف Illuminate\Cache\CacheManager :
    class MyCacheManager extends Illuminate\Cache\CacheManager { protected function createRedisDriver(array $config) { try { return parent::createRedisDriver($config); } catch (\Exception $e) { //يتم العودة للتخزين الافتراضي Redis في حال حدوث خطأ في return $this->resolve('file'); } } } ثم ضمن ملف مزود الخدمة ServiceProvider تأكد من استخدام النمط singleton أثناء التعامل مع البيانات وتعديل التابع الخاص بذلك بإضافة الصف الذي قمت بإنشائه:
    $this->app->singleton('cache', function($app) { return new MyCacheManager($app); }); وأيضاً هنالك بعض المكتبات والحزم التي أنجزها مطورين لحل هذه المشكلة، ومنها حزمة Laravel-Redis-Fallback وأيضاً حزمة Laravel-cache-fallback
  25. إجابة Sam Ahw سؤال في مشكلة إرسال حجم كبير من البيانات عبر Pusher في لارافيل كانت الإجابة المقبولة   
    يوجد طريقتين لمعالجة هذا الخطأ عند الحاجة لإرسال كمية كبيرة من البيانات دفعة واحدة:
    إما يتم فقط إرسال ID معيّن ونوع الحدث إلى pusher وبالتالي تجعل المستخدم هو من يقوم بطلب البيانات عن طريق HTTP:
    public function broadcastWith() { return [ 'id' => $this->content->id, 'event_type' => 'request_content' ]; } أو عن طريق تخفيض حجم البيانات المرسلة باستخدام JsonResource:
    public function broadcastWith() { return [ 'content' => new \App\Http\Resources\PostResource($this->content), ]; } وعندها يتم الوراثة من صف JsonResource كالتالي:
    class ContentResource extends JsonResource { public function toArray($request) { return [ 'id' => $this->id, 'title' => $this->title, 'body' => $this->body, ]; } } ومع ذلك ، فإن هذا النهج آمن فقط إذا كنت تعرف بالتأكيد أن البيانات التي ترسلها لا يمكن بأي حال من الأحوال تجاوز حد 10 كيلوبايت. ويمكن ضمان ذلك من خلال التحقق من صحة الإدخال ، والقيود المفروضة على أعمدة قاعدة البيانات (الحجم المحدد لكل عمود) أو وسائل أخرى إضافية مثل Request Validations.
×
×
  • أضف...