<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های محمدتقی نقیبی</title>
        <link>https://virgool.io/feed/@mtnaghibi</link>
        <description>بدون تلاش هیچی به دست نمیاد و همیشه خاطرم میمونه برای بدست آوردن چیزی که نیاز به زمان داره باید صبر کنم.</description>
        <language>fa</language>
        <pubDate>2026-04-15 10:17:41</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/70495/avatar/GyPHdl.jpg?height=120&amp;width=120</url>
            <title>محمدتقی نقیبی</title>
            <link>https://virgool.io/@mtnaghibi</link>
        </image>

                    <item>
                <title>کد ریویو : چگونه دشمن بسازیم</title>
                <link>https://virgool.io/@mtnaghibi/%DA%A9%D8%AF-%D8%B1%DB%8C%D9%88%DB%8C%D9%88-%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%AF%D8%B4%D9%85%D9%86-%D8%A8%D8%B3%D8%A7%D8%B2%DB%8C%D9%85-tgxsr5jdnype</link>
                <description>گاهی اوقات افراد در محل کار شما را آزار می دهند و شما احساس می کنید که باید از آنها انتقام بگیرید. آنها را مجبور کنید که برای بی توجهی هایی که در حق شما کردند، هزینه بدهند. اغلب واقعاً راهی وجود ندارد. اما اگر در زمینه توسعه نرم افزار کار می کنید، پس همیشه راهی وجود دارد. و اون چیزی نیست جز کد ریویو!کد ریویو یا بازبینی کد زمانی که به درستی انجام بشود، می تواند ابزاری عالی برای کمک به بهبود کیفیت کد و گسترش دانش در تیم باشد و  به کاهش خطاها کمک کند.  با این حال اگر به درستی انجام نشود، می تواند دردسر بزرگی برای همه باشد که در نهایت منجر به ایجاد دشمنی بین توسعه دهندگان می شود. جای فوق العاده ای برای انتقام گیری از طریق اقدامات passive-aggressive.اونها  قوری چای را پر نمی کنن؟ ۳ سال پیش زمانی که نفهمیدن شما در دفتر هستین به شما صبح بخیر نگفتن؟ الان وقتشه که در طول کد ریویو از اونها انتقام بگیریم!قدم اول : کامنت های مربوط به سبک کد یا code styleاولین قدم در این جنگ علیه همکاران بی خبرتان، کامنت های مربوط به code style است. اکثر شرکت ها دارای دستورالعمل های code style هستند. آنها را یاد بگیرید! و سپس شروع به درخواست تغییراتی کنید که به صراحت ذکر نشده اند. اگر دستورالعمل های code style چیزی را به شکل دقیق ذکر نکرده اند، اینجا فرصت مناسبی برای درخواست تغییرات بی فایده ای است که فقط باعث کار بیشتر  که هدف شماست می شود.آیا آنها به طور صحیح متدها را در کلاس تست type-hint کرده اند؟ نه؟  بهتر است به آنها بگویید که void را اضافه کنند تا در آینده برای همه روشن شود که این unit test چیزی برنمی گرداند!آیا آنها یک متغیر را به بیش از حد طولانی نامگذاری کرده اند؟ آره؟ بهتر است آن را کوتاه کنند.اینجا از شرط های Yoda  استفاده نشده است؟ از آنها بخواهید آن را برعکس بنویسند.با نوشتن کامنت های code style همکارتان را خرد کنید.قدم دوم: درخواست تغییرات بیهودهقدم اول آزاردهنده است، اما به تنهایی نمی تواند نفرت را در قلب دشمن شما ایجاد کند. شما باید به کار خود ادامه دهید. و قدم بعدی درخواست تغییرات بیهوده است.اگر دو راه برای انجام کاری وجود دارد، از آنها بخواهید کد را به گونه‌ای تغییر دهند که به روش شما انجام شود. به دلایلی مانند معایب روش شما یا مزایای روش آنها گوش نکنید. شما باید در رشته نظراتی در مورد اینکه چرا باید این تغییر را انجام دهند، درگیر شوید.می توانید با چیزی شبیه به این به آنها بگویید که دارند غیرمنطقی فکر می کنند:نمی‌دانم چرا اینقدر در مورد این درخواست سخت‌گیری می‌کنی. انجام آن به این روش نیز کار خواهد کرد. لطفا تغییر دهید. با تشکرهمکاران خود را وادار کنید تا بخش زیادی از روز خود را صرف بازنویسی کدی کنند که از قبل کاملاً کار می کرد.قدم سوم: تاخیرهای طولانیپاسخ دادن به نظرات، وقتتون رو که از سر راه نیاوردین. حداقل ۲۴ ساعت، شاید ۴۸ ساعت، طول بکشد تا هر کاری مربوط به کد ریویو را انجام دهید. هنگامی که به چالش کشیده می شوید، ادعا کنید که به کارهای دیگری مشغول هستید.هدف در اینجا این است که مرج ریکوئست آنها را بیات کنید. مرج ریکوئست های باز شده به عنوان بدهی فنی در نظر گرفته می‌شوند زیرا نگهداری آنها کار لازم دارد. این کار آزاردهنده و خسته کننده است. بنابراین، می‌خواهید آن مرج ریکوئست را تا زمانی که ممکن است باز نگه دارید، به طوری که آنها مجبور شوند زمان زیادی را صرف برطرف کردن کد کانفلیکت کنند.یکی از راه‌های خوب برای انجام این کار، امتناع از همکاری در برطرف کردن کد کانفلیکت است، زیرا ممکن است کد پس از  کانفلیکت متفاوت به نظر برسد، و شما نمی‌خواهید وقت خود را برای بررسی آن تلف کنید. تازه بعد از حل کانفلیکت ها باید دوباره مرج ریکوئست آن ها را بررسی کنید. این یک تاکتیک تاخیری عالی است.اگر آنها مجبور نشده‌اند دو تا سه بار در هر مرج ریکوئست کد کانفلیکت ها را برطرف کنند، شما خیلی سریع پاسخ می‌دهید!قدم چهارم: از آنها بخواهید که باگ اضافه کننددرخواست تغییر یک راه عالی برای افزودن کار است، اما درخواست تغییراتی که عوارض جانبی منفی ایجاد می کند، یک راه فوق العاده برای افزودن کار است. آنها باید برای اضافه کردن تغییر کار کنند و سپس زمانی که باگ کشف شد، احمق به نظر می رسند و سپس باید آن باگ را برطرف کنند.قدم پنجم: در درخواست‌های کد ریویو، تغییرات code style ایجاد کنیدهر مرج ریکوئستی که باز می کنید باید شامل حداقل ۵۰ درصد تغییرات  code style و غیر ضروری باشد تا پیدا کردن تغییرات فانکشنال واقعی در مرج ریکوئست آنقدر سخت شود که همکارتان مرج های شما را کورکورانه بپذیرد.قدم ششم: مرج ریکوئست های مگا سایز ایجاد کنیدکد ریویو زمانی که ۱۰ تا ۳۰ خط کد وجود دارد، آسان است. اما آسان چیزی نیست که اینجا به دنبال آن هستید. می‌خواهید وقتی همکارتان درخواست بازبینی کد را از شما دریافت می‌کند، وحشت کند. این بدان معنی است که همه مرج ریکوئست های شما باید شامل ۱۰۰۰ خط تغییر در حداقل ۱۰ فایل باشد.همچنین درخواست اقدام سریع در مورد این مرج ریکوئست ها را داشته باشید. آنها بدهی فنی هستند و شما نمی‌خواهید کد کانفلیکت ها را خودتان برطرف کنید. بنابراین، تا زمانی که مرج ریکوئست شما باز است، همه را آزار دهید. هیچ پاسخی در مورد اینکه چرا شما در پاسخ به مرج ریکوئست های افراد دیگر کند هستید، ندهید و به آنها اطلاع دهید که درخواست‌های باز شما مهم‌تر هستند و مکرراً بدهی فنی ناشی از باز بودن این مرج ریکوئست را ذکر کنید.قدم هفتم: نظرات آنها را نادیده بگیریدتا اینجا شما در طول کد ریویو به آنها ضربه زده اید. ممکن است بخواهند از شما انتقام بگیرند. یک راه عالی برای جلوگیری از هرگونه ضربه برگشتی در طول کد ریویو، نادیده گرفتن آنهاست. آیا آنها کامنتی می گذارند و خواستار تغییر هستند؟ بروید و از دوست خود بخواهید که مرج ریکوئست شما را تأیید کند و بدون رسیدگی به نظر آنها، آن را مرج کند.مانند آبی که از گرده ی اردک می ریزد بگذارید نظرات آنها هم از روی مرج ریکوئست های شما بریزد.نتیجه گیریزمانی که این مراحل به طور مکرر و مداوم به مدت چند ماه انجام شود، دشمن شما از بی توجهی هایی که در حق شما کرده است پشیمان خواهد شد.کارهایی که نباید انجام دهید اگر می خواهید دشمن شما از کد ریویو لذت ببرد:ادیتور خود را به شکلی تنظیم کنید که به طور خودکار به  code styleها رسیدگی کند.فقط زمانی کامنت دهید که تغییرات موجود در مرج ریکوئست را بهبود می‌بخشند.به سرعت به مرج ریکوئست ها پاسخ دهید و روزانه زمانی را برای کد ریویو برنامه‌ریزی کنید.در مرج ریکوئست ها، اطمینان حاصل کنید که تغییرات دارای تست هستند.هنگام اعمال قوانین جدید code style، مرج ریکوئست های جدا باز کنید.مرج ریکوئست های کوچک باز کنید.به همه نظرات پاسخ دهید، خواه موافق باشید یا دلیل عدم موافقت خود را بیان کنید.پیروز باشید...منبع اصلی</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Thu, 12 Oct 2023 18:04:36 +0330</pubDate>
            </item>
                    <item>
                <title>مدیریت خطا در زمان ارسال کار به صف در لاراول</title>
                <link>https://virgool.io/@mtnaghibi/%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AE%D8%B7%D8%A7-%D8%AF%D8%B1-%D8%B2%D9%85%D8%A7%D9%86-%D8%A7%D8%B1%D8%B3%D8%A7%D9%84-%DA%A9%D8%A7%D8%B1-%D8%A8%D9%87-%D8%B5%D9%81-%D8%AF%D8%B1-%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-y63rggwwl2rr</link>
                <description>مقدمهارسال کار به صف‌، یک امکان قدرتمند در لاراول برای اجرای فرآیندهای طولانی و زمان‌بر در پس‌زمینه است. با استفاده از صف‌ها، می‌توانیم وظایفی که زمان زیادی برای اجرا نیاز دارند را به صورت غیرهمزمان در پس زمینه پردازش کنیم. با این حال، ممکن است در برخی مواقع، اتصال به زیرساخت صف با مشکل مواجه شود و منجر به عدم توانایی در پردازش و اجرای کارها شود.در این مقاله، به بررسی مسئله مدیریت خطاهای ارسال کار به صف‌های لاراول می‌پردازیم و راهکاری را برای مدیریت این نوع خطاها ارائه می‌کنیم.مسئلههنگامی که لاراول یک کار را به صف ارسال می‌کند، از اجزای زیرساختی مانند بروکر، پایگاه داده یا ردیس برای مدیریت و اجرای صف استفاده می‌کند. این اجزا ممکن است با مشکلاتی مانند عدم فعالیت، ناموجودی یا خطا در اتصال روبرو شوند. در چنین مواردی، ضروری است که خطاها به شکل موثری مدیریت شوند تا از از دست رفتن کارها جلوگیری شود و سازگاری سیستم حفظ شود.انتشار خطا و تأثیر بر کاربربه طور پیش‌فرض، لاراول خطاهایی که در هنگام ارسال کار به صف به‌وجود می‌آیند را به کاربر ارجاع می‌دهد و این می‌تواند منجر به نقض‌ها و تأثیراتی بر تجربه کاربری شود. به عنوان مثال فرض کنید کاربر در سیستم ثبت نام کرده و برای فعال شدن حساب کاربری اش باید بر روی  لینک فعال سازی ارسالی به ایمیلش کلیک کند. سیستم ما ارسال ایمیل که یک کار زمانبر است را از طریق صف ردیس مدیریت می کند ولی متاسفانه در زمان ارسال کار به صف اتصال ردیس برقرار نشده و خطایی رخ داده است که موجب قطع شدن جریان برنامه می‌شود. برای کنترل این موضوع، می توان خطا را catch کرد ولی کاری که باید انجام می شد یعنی ارسال ایمیل فعال سازی از دست می رود. در این شرایط، برخی سیستم‌ها وظیفه را به کاربر واگذار می‌کنند و با ارائه امکان ارسال مجدد لینک فعال‌سازی، به این مشکل پاسخ می‌دهند. با این حال، آیا بهتر نیست که سیستم خود، از انعطاف و پویایی برخوردار باشد و کاربر را درگیر نکند؟ثبت کارهای ناموفقلاراول یک مکانیزم داخلی برای مدیریت و ثبت کارهای ناموفق در جدولی به نام &quot;failed_jobs&quot; فراهم کرده است. هنگامی که اجرای یک کار با خطا روبرو می‌شود، رفتار پیش‌فرض لاراول این است که خطا را لاگ کرده و payload کار را در جدول &quot;failed_jobs&quot; ذخیره می‌کند. این عملکرد به ما این امکان را می‌دهد که در آینده، کارهای ناموفق را بررسی، اشکال‌زدایی و مجدداً پردازش کنیم. این ویژگی بسیار مفید است، اما فقط برای کارهایی که در صف قرار دارند و با خطا مواجه می‌شوند مورد استفاده قرار می‌گیرد. اگر می‌توانستیم کارهایی که در زمان ارسال به صف با خطا مواجه می‌شوند را هم در این صف ذخیره کنیم، به هدف مهمی که پیگیری می‌کنیم می‌رسیدیم.راه حلدر قطعه کد زیر می بینیم که خطای رخ داده در زمان dispatch شدن کار به همراه payload و یکسری جزئیات  در جدول &quot;failed_jobs&quot; ذخیره می شود و در آینده می توانیم با دستور queue:retry مجدد آن را اجرا کنیم.مدیریت خطا  در زمان ارسال جاب به صف برای سهولت در اعمال این موضوع، می‌توانید این قطعه کد را در یک trait همانند Dispatchable قرار داده و استفاده کنید. همچنین، پکیجی که در این زمینه آماده شده رو هم می توانید استفاده کنید.نتیجه گیریمدیریت خطا در زمان ارسال کار به صف‌های لاراول یک جنبه حیاتی در ساخت برنامه‌ ای مقاوم و قابل اعتماد است که اهمیت دادن به آن می تواند تجربه کاربری بهتری را رقم بزند. راه حلی که پیشنهاد شده است، قطعاً تنها راه حل ممکن نیست. اگر شما هم راهکاری دیگر در ذهن دارید، بسیار خوشحال می‌شوم آن را به اشتراک بگذارید و نظر خود را بیان کنید.امیدوارم براتون مفید بوده باشهپیروز باشید...</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Tue, 23 May 2023 14:14:34 +0330</pubDate>
            </item>
                    <item>
                <title>چجوری حین استقرار یک پایان خوش برای وُرکرها رقم بزنیم</title>
                <link>https://virgool.io/@mtnaghibi/%DA%86%D8%AC%D9%88%D8%B1%DB%8C-%D8%AD%DB%8C%D9%86-%D8%A7%D8%B3%D8%AA%D9%82%D8%B1%D8%A7%D8%B1-%DB%8C%DA%A9-%D9%BE%D8%A7%DB%8C%D8%A7%D9%86-%D8%AE%D9%88%D8%B4-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%88%D9%8F%D8%B1%DA%A9%D8%B1%D9%87%D8%A7-%D8%B1%D9%82%D9%85-%D8%A8%D8%B2%D9%86%DB%8C%D9%85-yvus2abrmubu</link>
                <description>فرض این مقاله اینه که شما با لاراول و هورایزن آشنا هستین. یکی از قابلیت های خوبی که هورایزن میده اینه که به راحتی میشه  بدون اینکه چیزی از دست بره خاموشش کرد (php artisan horizon:terminate) یعنی اگر کاری  توسط ورکرها در حال پروسس باشه منتظر میمونه تا کارشون تموم شه و بعد خاموش میشه که به اصطلاح gracefully shutdown میگن بهش. اینجا Mohamed Said یه مقاله کوتاه راجع به تنظیم پارامترهایی که برای بهتر انجام شدن gracefully shutdown  لازم هست نوشته.حالا فرض کنید ورکرهای شما که کار پروسس جاب ها رو برعهده دارن روی پادهای کوبرنتیز مستقر شده باشن. پادها روی کوبرنتیز قابل جابجا شدن یا به اصطلاح ephemeral هستن بدین معنی که هر زمان مثلا حین انتشار نسخه ی جدید پاد میتونه خاموش بشه و جاش رو به یه پاد دیگه بده. این یه ویژگی خوب برای کوبرنتیز هستش ولی چجوری باید از خاموش شدن پادها ( زمانیکه در حال اجرای یکسری پروسس هستن) جلوگیری کنیم. کوبرنتیز برای این کار یکسری هوک برای Lifecycleش در نظر گرفته (postStart و preStop ) که با اونها میشه خاموش شدن پاد رو به تاخیر انداخت. زمانیکه به هر شکلی پاد kill بشه از حالت Running به حالت Terminating تغییر وضعیت میده و در همون لحظه سیگنال SIGTERM برای تمام کانتینرهای داخل پاد ارسال میشه که ما میتونیم داخل کانتینرهامون این سیگنال رو دریافت کنیم و عمل مناسب رو قبل خاموش شدن انجام بدیم. پادی که در وضعیت Terminating هست دقیقا مثل قبل کارش را ادامه میده یعنی از همون منابعی که بهش اختصاص داده شده استفاده می کنه اما درخواست های جدید از طرف کوبرنتیز برای اون ارسال نمیشه. یک پاد تا ابد نمی تونه در وضعیت Terminating باقی بمونه به همین دلیل یک پارامتر تحت عنوان terminationGracePeriodSeconds وجود داره که بصورت پیشفرض برابر با 30 ثانیه است و پاد نهایتا تا این زمان می تونه در وضعیت Terminating باقی بمونه. البته لازم به ذکر هست که هر زمان که کانتینرها  کارشون تموم شه قبل از رسیدن به این زمان؛ پاد از وضعیت Terminating در میاد و حذف میشه.حالا که با امکاناتی که کوبرنتیز برای gracefully shutdown در اختیار ما گذاشته آشنا شدیم برمی گردیم سر  مسئله خودمون یعنی نحوه ی خاموش کردن هورایزن زمانی که روی پاد اجرا می شه. احتمالا الان حدس زده باشین که برای این کار کافیه یه زمان مناسب مثلا یخورده بیشتر از اندازه ی اجرای طولانی ترین جابی که داریم رو برای terminationGracePeriodSeconds در نظر بگیریم و برای هوک preStop هم اجرای دستور php artisan horizon:terminate کفایت میکنه.به شکل نمونه دیپلویمنتی مثلا به شکل زیر خواهیم داشت:در این مقاله بیشتر سعی شد که  سرنخ هایی به شما داده بشه  که اگر راجع به gracefully shutdown مساله ای دارین راحت تر بتونید دنبال چیزی که میخواین بگردین در ادامه شما رو به خوندن این مقاله دعوت میکنم.امیدوارم براتون مفید بوده باشهپیروز باشید...</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Sun, 16 Apr 2023 14:47:38 +0330</pubDate>
            </item>
                    <item>
                <title>ساخت یک روتر ساده با PHP Attribute</title>
                <link>https://virgool.io/@mtnaghibi/%D8%B3%D8%A7%D8%AE%D8%AA-%DB%8C%DA%A9-%D8%B1%D9%88%D8%AA%D8%B1-%D8%B3%D8%A7%D8%AF%D9%87-%D8%A8%D8%A7-php-attribute-pjkrpjnqgkwq</link>
                <description>در ابتدا یک روتر ساده می نویسیم و در ادامه با Attributeها که در PHP نسخه ی 8 معرفی شدند آن را بازنویسی می کنیم تا با یکی از کاربردی های عملی آن ها آشنا شویم.بخش اول - مسیریاب:به طور خلاصه  روتر یا router تمامی درخواست های ورودی را دریافت کرده و در نهایت متناظر با آن قطعه کدی را اجرا می کند.کلاس زیر را در نظر بگیرید که در ادامه قصد داریم با صدا زدن مسیر / متود index و با صدا زدن مسیر about/ متود about این کلاس اجرا شود.حال به کلاس Router که نقش مسیریاب را بازی می کند دقت کنید:این کلاس درون خود یک آرایه به نام routes دارد که مسیرهای تعریف شده را با استفاده از متود register در خود نگهداری می کند.اصلی ترین کار این روتر را متود resolve به عهده دارد که درخواست های ورودی را به متودهای مورد نظر ما برای اجرا تبدیل می کند. درخواست های ورودی ابتدا تجزیه شده و سپس به متود resolve ارسال می شوند. که در اینجا متود resolve  ابتدا بررسی می کند که درخواست ارسالی تعریف شده است یا خیر و در ادامه با استفاده از تابع call_user_func_array آن را اجرا می کند.برای تجزیه و تحلیل درخواست ورودی می توانیم از کلاسی به شکل زیر استفاده کنیم:نمونه ای از روتر که مسیرها در آن رجیستر شده اند و همچنین نوع متود HTTP و URI  را که از متغیر SERVER_$ گرفته شده را  به کلاس App می دهیم و در ادامه با صدا زدن متود run کار تمام است.کل فایل index ما نیز به شکل زیر خواهد بود:به راحتی با اجرای دستور زیر می توانید خروجی نهایی کار را با وارد کردن مسیرها در مرورگر مشاهده نمایید:بخش دوم - بازنویسی با Attribute:هدف از ایجاد خصوصیت‌ یا Attribute در PHP این است که به روشی ساخت یافته  متادیتا را به کلاس‌ها، متودها، متغیرها و موارد مشابه  اضافه کرده و در زمان اجرا با استفاده از Reflection APIها از آن ها استفاده کنیم. شبیه Annotationهایی هستند که در DocBlock برای اضافه کردن متادیتا استفاده می کردیم که در پکیج  یا فریمورک معروفی مثل Doctrine و symfony به دفعات دیده می شد.یکی از معایب استفاده از Annotationها این بود که چون درون کامنت ها جایگذاری می شدند نیاز به پارس شدن داشتند و این علاوه بر سخت کردن استفاده از متادیتاهای پیچیده باعث بوجود آمدن اثرات جانبی هم می شد.یکی از مثال های استفاده از Annotationها  و معادل آن با استفاده از Attributeها را در تصویر زیر مشاهده می کنید:برای تعریف Attribute به شکل زیر عمل می کنیم:#[Attribute]و برای رجیستر کردن مسیرهای تعریف شده در کلاس HomeController که با اتریبیوت مشخص شده اند یک متود جدید به کلاس Router به شکل زیر اضافه می کنیم:در اینجا با استفاده از متود getAttributes می توان به راحتی به اتریبیوت های تعریف شده دسترسی پیدا کرد. اگر بدون آرگومان صدا زده شود تمامی اتریبوت هایی که برای متود تعریف شده اند برگشت داده می شود ولی می توانیم مثل حالت فوق که اتریبیوت Route برای آن ارسال شده است عمل فیلتر را انجام داده و فقط اتریبیوت هایی که نیاز داریم را دریافت کنیم. در ادامه با استفاده از متود newInstance می توان به مقادیری که برای آن اتریبیوت تعریف شده اند دست یافت.و در نهایت فایل index ما نیز به شکل زیر بازنویسی می شود:این پکیج که برای لاراول توسعه داده شده به شکل پیشرفته ای از Attributeها برای تعریف Route استفاده کرده که می توانید با عمیق شدن در آن درک بهتری به دست بیارید.امیدوارم براتون مفید بوده باشهپیروز باشید...</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Sat, 17 Dec 2022 22:46:51 +0330</pubDate>
            </item>
                    <item>
                <title>ستون های تولید شده و نحوه ی استفاده از آنها در لاراول</title>
                <link>https://virgool.io/@mtnaghibi/%D8%B3%D8%AA%D9%88%D9%86-%D9%87%D8%A7%DB%8C-%D8%AA%D9%88%D9%84%DB%8C%D8%AF-%D8%B4%D8%AF%D9%87-%D9%88-%D9%86%D8%AD%D9%88%D9%87-%DB%8C-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%A2%D9%86%D9%87%D8%A7-%D8%AF%D8%B1-%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-hrtnf25svd5e</link>
                <description>ستون های تولید شده یا Generated Columns که در نسخه ی ۵.۷ برای  MySQL در نسخه ی ۱۲ برای PostgreSQL و در نسخه ی 3.31.0 برای SQLite معرفی شد. آنها را می توان در خلال دستورات create یا alter جداول ایجاد کرد و روشی است برای ذخیره ی داده بدون ارسال آنها در زمان اجرای دستورات insert یا update در واقع ستون های تولید شده ستون های خاصی هستند که همیشه مقدار آنها از ستون های دیگر به دست می آید و پایگاه داده خود مسول مقداردهی آنهاست.دو نوع Generated Columns داریم  Virtual و Stored که از عبارات مثل زیر می توان برای آنها استفاده کرد:عبارات ریاضی مثل product_price * quantityتوابع داخلی مثل ()RIGHT(), CONCAT(), FROM_UNIXTIME(), JSON_EXTRACTلیترال ها مثل 0 , &quot;new&quot; , &quot;2&quot;مثالیک فروشگاه مجازی با جداولی به شکل زیر در نظر بگیرید لینک اسکیما:جدول users که مسئول نگهداری اطلاعات کاربران است.جدول products که مسئول نگهداری اطلاعات محصول مثل قیمت و توضیحات است.جدول orders که شناسه ی کاربر و تاریخ سفارش را نگه می دارد.جدول order_items که شناسه ی محصول - شناسه ی سفارش - تعداد - قیمت و زمان خرید را نگه می دارد.به تعریف جدول order_items توجه کنید:برای گرفتن  قیمت مجموع یک سفارش یعنی total_item_price که با مقدار  product_price * quantity  برابر است روش های مختلفی وجود دارد:می توان این مقدار را محاسبه و در یک ستون ذخیره نمود.می توان از یک view برای این کار استفاده کرد.یا در سطح برنامه هر بار آنرا محاسبه نمود.روش دیگری که استفاده می شود محاسبه در هنگام واکشی به شکل زیر:نوع اول Virtual Columnsمزایا:هیچ فضایی مصرف نمی کنند مگر اینکه آنها را ایندکس کنیدیک عمل INPLACE به حساب می آید بدین معنی که با تغییر جدول نیازی به کپی مجدد تمامی داده ها نیست (اطلاعات بیشتر).مقدار آن در زمان واکشی به اصطلاح on the fly محاسبه می شود.برای داده ای مناسب است که تغییرات آن قابل توجه باشد. هزینه ی virtual columns خود را در زمان واکشی نشان می دهد زیرا که هر دفعه ماشین درگیر محاسبه ی مقدار می شود.نوع Stored Columnsفضای دیسک را اشغال می کنند.همان هزینه ی کپی که اضافه کردن یک ستون جدید دارد را متحمل می کند.مقدار آن در دستورات INSERT و UPDATE به روزرسانی می شود.برای داده ای مناسب است که تغییرات آن زیاد نباشد مثل total_item_price در مثال بالا زیرا زمانی که رکورد ایجاد شد  مقدار price و quantity تغییر نمی کنند.کدبه خطوط 9 و 23 توجه کنید هر دو نوع ستون های تولید شده با استفاده از کلمه ی AS تعریف می شوند ولی اگه بخواهیم از نوع stored باشد باید بعد از عبارت بیان شود.از همین سینتکس می توان در زمان تغییر جدول نیز استفاده کرد:استفاده از ستون های تولید شده در لاراولبه راحتی با استفاده از متد های زیر می توانید هر دو نوع Generated Column را در مایگریشن های خود تعریف کنید:$table-&gt;decimal(&#039;total_item_price&#039;,10,2)-&gt;storedAs(&#039;quantity * product_price&#039;);
$table-&gt;decimal(&#039;total_item_price&#039;,10,2)-&gt;virtualAs(&#039;quantity * product_price&#039;);
پیروز باشید...منبع اصلی</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Sat, 10 Dec 2022 23:25:47 +0330</pubDate>
            </item>
                    <item>
                <title>سرویس کانتینر و سرویس پرووایدر در لاراول</title>
                <link>https://virgool.io/laravel-community/%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%DA%A9%D8%A7%D9%86%D8%AA%DB%8C%D9%86%D8%B1-%D9%88-%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D9%BE%D8%B1%D9%88%D9%88%D8%A7%DB%8C%D8%AF%D8%B1-%D8%AF%D8%B1-%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-g4aiobcdo5k2</link>
                <description> این ویرگول  شما را در درک  مفاهیمی مثل سرویس کانتینر و سرویس پرووایدر در لاراول راهنمایی می کند. با مفاهیم اساسی شروع می کنیم و در پایان شما  ایده ی چگونگی ترکیب این مفاهیم در کنار هم را فرا خواهید گرفت.بخش اول: Dependency Injectionتزریق وابستگی در ساده ترین تعریف به فرآیند انتقال وابستگی کلاس بصورت آرگومان به یکی از متودهای آن کلاس می گویند(معمولاً سازنده).به کد زیر که در آن تزریق وابستگی به کار گرفته نشده است دقت کنید&lt;?php

namespace App;

use App\Models\Post;
use App\Services\TwitterService;

class Publication {

    public function __construct()
    {
        // dependency is instantiated inside the class
        $this-&gt;twitterService = new TwitterService();
    }

    public function publish(Post $post)
    {
        $post-&gt;publish();

        $this-&gt;socialize($post);
    }

    protected function socialize($post)
    {
        $this-&gt;twitterService-&gt;share($post);
    }

}فرض کنید این کلاس بخشی از یک سرویس وبلاگ نویسی است که مسئول انتشار یک پست و به اشتراک گذاری آن در شبکه های اجتماعی است. متود socialize  از نمونه ای از کلاس TwitterService استفاده می کند که شامل یک متود عمومی به نام share است.&lt;?php

namespace App\Services;

use App\Models\Post;

class TwitterService {
    public function share(Post $post)
    {
        dd(&#039;shared on Twitter!&#039;);
    }
}همانطور که مشاهده می کنید ، در سازنده نمونه جدیدی از کلاس TwitterService ایجاد شده است. به جای ساختن نمونه  در داخل کلاس ، می توانیم بصورت زیر یک نمونه را به عنوان آرگومان از خارج به سازنده تزریق کنیم.&lt;?php

namespace App;

use App\Models\Post;
use App\Services\TwitterService;

class Publication {

    public function __construct(TwitterService $twitterService)
    {
        $this-&gt;twitterService = $twitterService;
    }

    public function publish(Post $post)
    {
        $post-&gt;publish();

        $this-&gt;socialize($post);
    }

    protected function socialize($post)
    {
        $this-&gt;twitterService-&gt;share($post);
    }

}برای نمایش این موضوع به قطعه کد زیر نگاهی بیندازید.&lt;?php

// routes/web.php

use App\Publication;
use App\Models\Post;
use App\Services\TwitterService;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    $post = new Post();

    // dependency injection
    $publication = new Publication(new TwitterService());

    dd($publication-&gt;publish($post));

    // shared on Twitter!
});این پایه ای ترین نوع تزریق وابستگی بود. اعمال تزریق وابستگی به یک کلاس باعث وارونگی کنترل(inversion of control) می شود. ابتدا کلاس وابسته یعنی Publication کنترل ایجاد وابستگی کلاس یعنی TwitterService را در اختیار داشت در حالی که بعداً ، این کنترل از حوزه ی اختیاراتش خارج و به کس دیگری سپرده شد.بخش دوم: IoC Containerدر بخش قبلی ، با ایده تزریق وابستگی آشنا شدید و به شما نشان داده شد که چگونه کنترل ایجاد وابستگی ها  از کلاس گرفته می شود. IoC کانتینر می تواند روند تزریق وابستگی را کارآمدتر کند.  IoC کانتینر که به DI کانتینر نیز معروف است یک کلاس ساده است که می تواند در هنگام درخواست داده هایی را که قبلا در خود ذخیره کرده است را ارائه کند. یک IoC کانتینر ساده را می توان به شکل زیر نوشت:&lt;?php

namespace App;

class Container {

    // array for keeping the container bindings
    protected $bindings = [];

    // binds new data to the container
    public function bind($key, $value)
    {
        // bind the given value with the given key
        $this-&gt;bindings[$key] = $value;
    }

    // returns bound data from the container
    public function make($key)
    {
        if (isset($this-&gt;bindings[$key])) {
            // check if the bound data is a callback
            if (is_callable($this-&gt;bindings[$key])) {
                // if yes, call the callback and return the value
                return call_user_func($this-&gt;bindings[$key]);
            } else {
                // if not, return the value as it is
                return $this-&gt;bindings[$key];
            }
        }
    }

}با استفاده از متود bind می توانید هر داده ای را در این کانتینر  نگهداری کنید. در مثال زیر کانتینر یک رشته را نگهداری و سپس برگردانده است.&lt;?php

// routes/web.php

use App\Container;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    $container = new Container();

    $container-&gt;bind(&#039;name&#039;, &#039;Farhan Hasin Chowdhury&#039;);

    dd($container-&gt;make(&#039;name&#039;));

    // Farhan Hasin Chowdhury
});با ارسال callback بعنوان آرگومان دوم که یک نمونه از کلاس را می سازد می توانید برای نگهداری کلاس ها از آن استفاده کنید.&lt;?php

// routes/web.php

use App\Container;
use App\Service\TwitterService;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    $container = new Container;

    $container-&gt;bind(TwitterService::class, function(){
        return new App\Services\TwitterService;
    });

    ddd($container-&gt;make(TwitterService::class));

    // App\Services\TwitterService {#269}
});فرض کنید کلاس TwitterService به کلیدی برای اعتبارسنجی احتیاج دارد. در این مورد می توانیم به شکل زیر عمل کنیم.&lt;?php

// routes/web.php

use App\Container;
use App\Service\TwitterService;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    $container = new Container;

    $container-&gt;bind(&#039;ApiKey&#039;, &#039;very-secret-api-key&#039;);

    $container-&gt;bind(TwitterService::class, function() use ($container){
        return new App\Services\TwitterService($container-&gt;make(&#039;ApiKey&#039;));
    });

    ddd($container-&gt;make(TwitterService::class));

    // App\Services\TwitterService {#269 ▼
    //     #apiKey: &amp;quotvery-secret-api-key&amp;quot
    // }
});زمانیکه یک داده ای را به کانتینر بایند می کنید هر زمان که نیاز داشته باشید فقط کافیست آن را درخواست کنید. با این روش تنها یکبار از new استفاده می کنید. هدف این نیست که بگوییم استفاده از new بد است اما هر بار که از new استفاده می کنید مجبور هستید که مراقب ارسال صحیح وابستگی ها به کلاس ها باشید. با Ioc کانتینر دیگر شما نگرانی از بابت تزریق وابستگی نخواهید داشت. IoC کانتینر حتی کد شما را منعطف تر هم خواهد کرد. وضعیتی را در نظر داشته باشید که در آن می خواهید به جای استفاده از کلاس TwitterService از کلاس دیگری مثلا کلاس LinkedInService استفاده کنید.کد پیاده سازی شده ی فعلی خیلی مناسب این کار نیست چرا که برای تعویض کلاس TwitterService شما باید یک کلاس جدید به کانتینر بایند کنید و تمامی رفرنس ها به کلاس قبلی را تغییر دهید.شما می توانید این کار را با استفاده از Interfaceها خیلی راحت تر انجام دهید. برای شروع اینترفیسی با نام SocialMediaServiceInterface می سازیم:&lt;?php

namespace App\Interfaces;

use App\Models\Post;

interface SocialMediaServiceInterface {
    public function share(Post $post);
}و در ادامه کلاس TwitterService باید اینترفیس را پیاده کند:&lt;?php

namespace App\Services;

use App\Models\Post;
use App\Interfaces\SocialMediaServiceInterface;

class TwitterService implements SocialMediaServiceInterface {
    protected $apiKey;

    public function __construct($apiKey)
    {
        $this-&gt;apiKey = $apiKey;
    }

    public function share(Post $post)
    {
        dd(&#039;shared on Twitter!&#039;);
    }
}بجای اینکه کلاس concrete را به کانتینر بایند کنیم اینترفیس را بایند می کنیم. و در callback یک نمونه از کلاس TwitterService را مثل قبل می سازیم.&lt;?php

// routes/web.php

use App\Container;
use Illuminate\Support\Facades\Route;
use App\Interfaces\SocialMediaServiceInterface;

Route::get(&#039;/&#039;, function () {
    $container = new Container;

    $container-&gt;bind(&#039;ApiKey&#039;, &#039;very-secret-api-key&#039;);

    $container-&gt;bind(SocialMediaServiceInterface::class, function() use ($container){
        return new App\Services\TwitterService($container-&gt;make(&#039;ApiKey&#039;));
    });

    ddd($container-&gt;make(SocialMediaServiceInterface::class));

    // App\Services\TwitterService {#269 ▼
    //     #apiKey: &amp;quotvery-secret-api-key&amp;quot
    // }
});کد مثل سابق کار می کند. ولی زمانی که قصد استفاده از لینکدین بجای توئیتر را داشته باشید با اینترفیسی که ساخته ایم این کار به شکلی ساده قابل انجام است. تنها با دو قدم به آن دست پیدا می کنید.کلاس LinkedInService را می سازیم که باید اینترفیس SocialMediaServiceInterface را پیاده کند:&lt;?php

namespace App\Services;

use App\Models\Post;
use App\Interfaces\SocialMediaServiceInterface;

class LinkedInService implements SocialMediaServiceInterface {
    public function share(Post $post)
    {
        dd(&#039;shared on LinkedIn!&#039;);
    }
}این بار در callback  به جای برگشت نمونه ای از کلاس TwitterService کافیست LinkedInService را برگردانید.&lt;?php

// routes/web.php

use App\Container;
use App\Interfaces\SocialMediaServiceInterface;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    $container = new Container;

    $container-&gt;bind(SocialMediaServiceInterface::class, function() {
        return new App\Services\LinkedInService();
    });

    ddd($container-&gt;make(SocialMediaServiceInterface::class));

    // App\Services\LinkedInService {#269}
});این رویکرد باعث می شود قسمت های دیگر کد بدون تغییر بماند و تنها متود bind را آپدیت نماییم. تا زمانیکه یک کلاس اینترفیس SocialMediaServiceInterface را پیاده کند به راحتی می تواند به کانتینر بایند شود و از آن بعنوان سرویس جدید استفاده کنیم.بخش سوم: Service Container and Service Providersلاراول یک Ioc کانتینر قدرتمند به نام service container دارد که در این بخش می خواهیم مثال های قبل را با کمک آن بازنویسی کنیم.&lt;?php

// routes/web.php

use App\Container;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    app()-&gt;bind(&#039;App\Interfaces\SocialMediaService&#039;, function() {
        return new App\Services\LinkedInService();
    });

    ddd(app()-&gt;make(&#039;App\Interfaces\SocialMediaService&#039;));

    // App\Services\LinkedInService {#262}
});در هر برنامه ی لاراولی هلپر ()app یک نمونه از کانتینر را برمی گرداند. درست مشابه کانتینر سفارشی که ساخته بودیم سرویس کانتینر لاراول نیز متود های make , bind را برای بایند کردن و بازیابی سرویس ها استفاده می کند. سرویس کانتینر لاراول متود دیگری با نام singleton هم دارد که برای بایند کردن کلاس هایی که نیاز داریم singleton (تنها یک نمونه از کلاس در طول اجرای برنامه وجود داشته باشد) باشند مورد استفاده قرار می گیرد. این مورد را با مثال زیر بهتر متوجه می شوید.&lt;?php

// routes/web.php

use App\Container;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    app()-&gt;bind(&#039;App\Interfaces\SocialMediaService&#039;, function() {
        return new App\Services\LinkedInService();
    });

    ddd(app()-&gt;make(&#039;App\Interfaces\SocialMediaService&#039;), app()-&gt;make(&#039;App\Interfaces\SocialMediaService&#039;));

    // App\Services\LinkedInService {#262}
    // App\Services\LinkedInService {#269}
});همانطور که در انتها می بینید دو نمونه ی بازیابی شده  [ 262# , 269# ]  متفاوت هستند. اگه شما کلاس را به شکل singleton بایند کنید آنگاه هر چند بار هم که سرویس را بازیابی کنید نمونه های یکسانی را دریافت خواهید کرد.&lt;?php

// routes/web.php

use App\Container;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    app()-&gt;singleton(&#039;App\Interfaces\SocialMediaService&#039;, function() {
        return new App\Services\LinkedInService();
    });

    ddd(app()-&gt;make(&#039;App\Interfaces\SocialMediaService&#039;), app()-&gt;make(&#039;App\Interfaces\SocialMediaService&#039;));

    // App\Services\LinkedInService {#262}
    // App\Services\LinkedInService {#262}
});الان که متودهای bind, make, singleton را شناختید زمان آن فرا رسیده که مکان مناسب قرارگیری این متود ها را یاد بگیرید. به وضوح مشخص است که نباید در فایل مسیر یا کنترلر ها باشند. مکان مناسب سرویس پرووایدر ها هستند. سرویس پرووایدرها کلاس هایی هستند که در مسیر app/Providers قرار دارند. سرویس پرووایدر هامسئول راه اندازی اکثر سرویس های فریمورک می باشند.هر پروژه ی لاراولی بصورت پیشفرض 5 سرویس پرووایدر دارد. که در میان آن ها AppServiceProvider با دو متود خالی [ boot, register ] هم وجود دارد. متود register برای ثبت سرویس های جدید مورد استفاده قرار می گیرد یعنی همان جایی که باید bind یا singleton قرار داده شوند.&lt;?php

namespace App\Providers;

use App\Interfaces\SocialMediaService;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this-&gt;app-&gt;bind(SocialMediaService::class, function() {
            return new \App\Services\LinkedInService;
        });
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}در داخل پرووایدرها به کانتینر به سادگی از طریق this-&gt;app$ بجای هلپر ()app دسترسی دارید.در متود boot هر آن چیزی که برای راه اندازی سرویس های رجیستر شده لازم است قرار می گیرد. ?بعد از اینکه تمامی پرووایدرها رجیستر شدند نوبت به بوت شدن آنها می رسد که این عمل منجر به فراخوانی متود boot در تمامی پرووایدرها خواهد شد. زمانی که از سرویس پرووایدرها استفاده می کنیم اشتباه متداولی که رخ می دهد این است که در یک سرویس پرووایدر از سرویسی که در یک پرووایدر دیگر رجیستر شده است استفاده می کنیم و از آنجائیکه تضمینی در بارگذاری تمامی پرووایدرهای دیگر نیست ممکن است سرویسی که مورد نیاز است هنوز در دسترس نباشد. بنابراین کدهایی که در سرویس پرووایدری نیاز به دیگر سرویس ها دارند باید در متود boot قرار داده شوند. بطور خلاصه متود register تنها برای رجیستر کردن سرویس ها داخل کانتینر استفاده می شود و در داخل متود boot شما هر کدی را که تصور می کنید می توانید قرار دهید از رجیستر کردن event listeners ها گرفته تا include کردن routeها.یک مثال خوب برای این مورد BroadcastingServiceProvider است.&lt;?php

namespace App\Providers;

use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes();

        require base_path(&#039;routes/channels.php&#039;);
    }
}همانطور که می بینید ابتدا متود routes را فراخوانی و سپس فایل channels.php را لود کرده تا در ادامه مسیرهای broadcasting فعال و در دسترس باشند.برای بایند کردن یک یا دو مورد ساده شما می توانید از همان AppServiceProvider استفاده نمایید ولی در مواردی که تعداد بایند ها بیشتر می شود یا به یک لاجیک پیچیده برای اجرا شدن نیاز دارید می توانید یک پرووایدر جدید با دستور زیر بسازید.php artisan make:provider &lt;provider name&gt; بخش چهارم: The Full Pictureحال که با مفاهیم مختلفی مثل dependency injection, inversion of control, service container, service providers آشنا شده اید وقت آن رسیده که که نشان دهیم چگونه در کنار هم کار میکنند.به کلاس Publication که در بخش های قبل با آن کار کردیم برمی گردیم. همانطور که به یاد دارید  کلاس Publication به کلاس TwitterService وابستگی داشت که ما اینترفیسی را تعریف کردیم و حالا می خواهیم کلاس Publication از آن بهره بگیرد.&lt;?php

namespace App;

use App\Models\Post;
use App\Interfaces\SocialMediaServiceInterface;

class Publication {
    protected $socialMediaService;

    public function __construct(SocialMediaServiceInterface $socialMediaService)
    {
        $this-&gt;socialMediaService = $socialMediaService;
    }

    public function publish(Post $post)
    {
        $post-&gt;publish();

        $this-&gt;socialize($post);
    }

    protected function socialize($post)
    {
        $this-&gt;socialMediaService-&gt;share($post);
    }

}به جای وابستگی به یک کلاس خاص Publication هر کلاسی را که SocialMediaServiceInterface را پیاده کرده باشد را می پذیرد. در اینجا بدلیل اینکه SocialMediaServiceInterface را به LinkedInService بایند کردیم app()-&gt;make(SocialMediaServiceInterface::class) یک نمونه از LinkedInService را بر می گرداند.با توجه به اینکه کلاس Publication را در کانتینر بایند نکردیم. به نظر شما اگر app()-&gt;make(Publication::class) را اجرا کنیم چه اتفاقی می افتد.&lt;?php

// routes/web.php

use App\Publication;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function () {
    $publication = app()-&gt;make(Publication::class);

    ddd($publication);

    // App\Publication {#273 ▼
    //     #socialMediaService: App\Services\LinkedInService {#272}
    // }      
});همانطور که میبینید لاراول با موفقیت بدون اینکه قبلا کلاس Publication را بایند کرده باشیم یک نمونه از آن را برای ما بر می گرداند. در نگاه اول به نظر می رسد یک معجزه اتفاق افتاده است اما واقیت آن است که زمانیکه لاراول به خط app()-&gt;make(Publication::class) می رسد در کانتینر به دنبال آن می گردد. زمانیکه برای آن ورودی پیدا نمی کند به سازنده ی کلاس نگاه می کند و متوجه می شود که به کلاسی که اینترفیس SocialMediaServiceInterface را پیاده کرده باشد نیاز دارد و زمانیکه ورودی مورد نیاز را در کانتینر پیدا کرد یک نمونه از آنرا ساخته و بر می گرداند و با موفقیت یک نمونه از کلاس Publication را می سازد.مادامی که اینترفیسی ها به درستی بایند شده باشند و وابستگی هاtype-hint شده باشند لاراول به راحتی نمونه را برای شما می سازد.&lt;?php

// routes/web.php

use App\Publication;
use Illuminate\Support\Facades\Route;

Route::get(&#039;/&#039;, function (Publication $publication) {
    ddd($publication);

    // App\Publication {#276 ▼
    //     #socialMediaService: App\Services\LinkedInService {#275}
    // }
});بخش پنجم:  تست با کمک Service Containerاستفاده از سرویس کانتینر این مزیت را به ما می دهد که به راحتی بتوانیم یک سرویس ماک شده بنویسیم و در تست ها از آن استفاده کنیم. در مثال بالا که از سرویسی مثل توییتر یا لینکدین برای اشتراک گذاری محتوا استفاده می کردیم چگونه می توانستیم فانکشنالیتی های کلاس Publication را تست کنیم در صورتیکه به سرویس بیرونی وابستگی داشت. با استفاده از سرویس کانتینر به راحتی می توانیم در تست هایمان سرویس ماک شده ی خودمان را بایند کرده و در ادامه کلاس Publication از سرویس ماک شده ای که ما تعریف کردیم استفاده خواهد کرد و تست ها بدون وابستگی به سرویس بیرونی کار خود را ادامه می دهند.سخن پایانیامیدوارم با خواندن مطلب بالا سرویس کانتینر و مفاهیم مرتبط با آن کمی برای شما روشن شده باشد و از این به بعد با اعتماد به نفس بیشتری وابستگی های type-hint شده را در سازنده ی کلاس استفاده می کنید.پیروز باشید...منبع اصلی</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Wed, 08 Sep 2021 01:04:49 +0430</pubDate>
            </item>
                    <item>
                <title>اجرای چند فرایند بصورت ناهمگام در لاراول</title>
                <link>https://virgool.io/@mtnaghibi/%D8%A7%D8%AC%D8%B1%D8%A7%DB%8C-%DA%86%D9%86%D8%AF-%D9%81%D8%B1%D8%A7%DB%8C%D9%86%D8%AF-%D8%A8%D8%B5%D9%88%D8%B1%D8%AA-%D9%86%D8%A7%D9%87%D9%85%DA%AF%D8%A7%D9%85-%D8%AF%D8%B1-%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-gd8u6epofzl9</link>
                <description>پردازش موازی در لاراولدر پی اچ پی نسخه ی 7 به بعد  با اکستنشن pthread می توانیم برای سریعتر شدن اجرای کارهای طولانی کار را بین چندین نخ تقسیم کنیم. اما اگر این اکستنشن روی سرور نصب نباشد چه باید کرد؟همانطور که در مقاله ی قبل هم گفته شد می توانیم پردازش موازی را بصورت multi-process داشته باشیم. برای مثال قصد دارید بالای 100 هزار ایمیل را ارسال کنید، این بهترین مثال برای استفاده از multi processing در پی اچ پی است.برای Execute Command می توانیم بغیر از  exec، exec_shell یا passthru از کامپوننت Process که در سیمفونی معرفی شد در پروژه ی لاراولی خود استفاده کنید چرا که لاراول برخی از کتابخانه ها و کامپوننت های سیمفونی را در خود جا داده است و کامپوننت Process نیز یکی از آنهاست.شاید با خود بگویید که چرا از job ها در لاراول استفاده نکنیم، دلیل اول اینکه مسئله ی timeout را داریم اگر بخواهیم بصورت Sync اجرا کنیم و دلیل دوم اینکه نباید 100 هزار رکورد را در جدول jobs وارد کنیم. علاوه بر این هر job برای اتصال به دیتابیس بحث connect/disconnect را دارد که خود باعث سربار شده و کارایی را پایین می آورد.ایجاد فرایند:فرض کنید که شما قصد دارید در کنترلر خود یک کامند را در background اجرا کنید، شما به سادگی می توانید یک نمونه از کلاس Process را ایجاد کنید.$process = new Process(&#039;php &#039; . base_path(&#039;artisan&#039;) . &#039; task:long-running-task &amp;&#039;);
$process&gt;setTimeout(0);
$process-&gt;run();توجه داشته باشید که از متود run استفاده کرده ایم که بصورت synchronous&amp;blocking است. اما ما asynchronous می خواهیم. شما می توانید از متود start بجای متود run استفاده کنید که asynchronous است اما فرایند سریعا بعد از اینکه کنترلر پاسخ را به سمت کلاینت برگرداند kill میشود و تسک شما کامل نمی شود.بگذارید ابتدا دلیل kill شدن را توضیح دهم زمانیکه متود start اجرا میشود، کامند در زمینه اجرا میشود اما وقتی فرایند اصلی که در اینجا کنترلر است پاسخ را ارسال می کند کارش تمام شده و تمامی sub-process های آن هم kill می شوند و این دلیل kill شدن فرایند background ماست.اهمیت “&amp;” : اگر توجه داشته باشید یک علامت “&amp;” در انتهای دستور گذاشته ایم‘php ‘ . base_path(‘artisan’) . ‘ task:long-running-task &amp;’که نقش بسیار مهمی را ایفا میکند. &amp; باعث اجرای فرایند شما را در background می شود(مثل daemon) و فرایند شما بعنوان یک فرایند جداگانه تلقی می شود. اتمام فرایند اصلی تاثیری روی فرایند daemon/background ما نخواهد داشت.با این کار کامند شما یک فرایند اصلی است و می توانید چندید فرایند را برای انجام کارتان به اجرا در بیاورید.for ($i = 0; $i &lt; $numberOfProcess; $i++) {
$process = new Process(&#039;php &#039; . base_path(&#039;artisan&#039;) . &amp;quot task {$i}&amp;quot);
$process-&gt;setTimeout(0);
$process-&gt;disableOutput();
$process-&gt;start();
$processes[] = $process;
}همانطور که میبینید از متود start برای ایجاد sub-process ها استفاده کرده ایم تا عملیات بصورت asynchronous اجرا شود. نکته ی مهم در اینجا این است که این کد که در واقع در حال حاضر فرایند اصلی ما بحساب می رود نباید قبل از اتمام sub-process ها تمام شود و باید تا کامل شدن تسک ها ی دیگر صبر کند.for ($i = 0; $i &lt; $numberOfProcess; $i++) { 
  ... // above code
}
// wait for above processes to complete
while (count($processes)) {  foreach ($processes as $i =&gt; $runningProcess) {
    // specific process is finished, so we remove it 
   if (! $runningProcess-&gt;isRunning()) {
      unset($processes[$i]);   
       }
       sleep(1);
  }
}
//Executes after all processes are done with their taskبصورت خلاصه در ذهن داشته باشید که  main process نباید تمام یا کشته شود تا child process ها زنده مانده و به کار خود ادامه دهند در غیر اینصورت child process ها هم کشته می شوند.پیروز باشید...</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Sat, 14 Mar 2020 18:52:49 +0330</pubDate>
            </item>
                    <item>
                <title>پردازش موازی در پی اچ پی</title>
                <link>https://virgool.io/@mtnaghibi/%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D8%B4-%D9%85%D9%88%D8%A7%D8%B2%DB%8C-%D8%AF%D8%B1-%D9%BE%DB%8C-%D8%A7%DA%86-%D9%BE%DB%8C-k04ue3yamdep</link>
                <description>پردازش موازیپردازش موازی(Parallel Processing) چیه؟ طبق تعریف ویکیپدیا به استفاده ی همزمان بیشتر از یک پردازنده برای اجرای برنامه. فرض کنید میخواهیم هزار ایمیل را راس یک ساعت خاص برای کاربران ارسال کنیم. قاعدتا ارسال این ایمیل ها بصورت ترتیبی نیازمند زمان زیادی است و در یک زمان مشخص برای همه ی کاربران ارسال نمی شود. اینجاست که پردازش موازی به داد ما میرسد و می توانیم از تمامی منابع سیستم برای ارسال ایمیل ها استفاده کرده و کمترین تاخیر را در ارسال ها داشته باشیم.زبان های برنامه نویسی مثل C, Java و Erlang ذاتا از چندنخی پشتیبانی می کنند. متاسفانه پی اچ پی اینگونه نیست. پی اچ پی رو بخاطر فقدان پشتیبانی از چندنخی سرزنش نکنید و به یاد داشته باشید که پی اچ پی یک زبان اسکریپتی سطح بالاست و هدف اصلی آن سرو کردن درخواست های stateless پروتکل HTTP بود. ولی با گذشت زمان که محبوب تر و تواناتر شد دولوپرها برنامه های پیچیده ای را با پی اچ توسعه دادند. و بدین ترتیب با گذشت زمان قابلیت های پیشرفته ای مثل پردازش موازی از پی اچ پی درخواست می شد.برای انجام این کار در پی اچ پی 3 راهکار داریم:Multi-ThreadMulti-ProcessDistributedچندنخی(Multi-Thread):همانطور که قبلا هم اشاره کردم پی اچ پی بصورت ذاتی از چندنخی پشتیبانی نمیکند. اما اکستنشن pthreads در پی اچ پی این امکان را در اختیار شما قرار می دهد. شخصا خیلی با pthreads کار نکرده ام چون فکر میکنم چندنخی در پی اچ پی اشتباه است. شما می توانید کد thread safe خود را داشته باشید ولی زمانیکه از دیگر اکستنشن های  پی اچ پی استفاده می کنید میتوانید مطمئن باشید که کد همچنان thread safe است. متاسفانه اکثر اکستنشن های مشهور  thread safe نیستند.چندپردازشی(Multi-Process):برای دستیابی به پردازش موازی می توانیم چندین فرایند را بصورت همزمان در پی اچ پی اجرا کنیم. 3 راه برای این کار وجود داردForkExecute CommandPipingروش Fork:پی اچ پی چند فانکشن برای کنترل فرایندها مهیا کرده که به شما اجازه می دهند تا فرایندهای فرزند را بوجود آورید. زمانیکه شما pcntl_fork را صدا میزنید یک فرایند فرزند را بوجود میاورید که دقیقا یک کپی از فرایند والدش است. و این به این معنی است که فرایند فرزند می تواند تمامی منابع و متغیرهای والدش را مثل کانکشن MySQL را به ارث ببرد. این ماژول در CLI و FastCGI در دسترس است. و در نظر داشته باشید که دسترسی فرایندهای فرزند به منابع اشتراکی والد خطرناک است، برای مثال بستن کانکشن MySQL بدون اینکه والد در جریان باشد.کد نمونه برای نمایش استفاده از process forking‍‍‍‍‍$workload = &amp;quotsome work load&amp;quot
$processId = pcntl_fork();
if ($processId &lt; 0){
die(&#039;Fork failed!&#039;);
} else if ($processId == 0) {
// child starts working here
trim($workload);
} else {
// parent waits for child
pcntl_wait($status);
}روش Execute Command:استفاده از فانکشن های زیر که باعث بوجود آمدن فرایند های کامل و مجزا می شود.تابع exec که آخرین خط خروجی فرایند جدید را برمی گرداندتابع exec_shell که تمامی خروجی فرایند جدید را در قالب رشته برمی گرداندتابع passthru که خروجی فرایند جدید را در قالب باینری برمی گردانددر نظر داشته باشید که اجرای این دستورات یک عمل ارزان تلقی نشود مخصوصا زمانیکه شما از این دستورات در حلقه استفاده می کنید. زمانیکه شما هزاران فرایند را روی یک سرور به اجرا در میاورید سرور برای سوئیچ کردن بین آنها خیلی مشغول میشود و عملکرد کلی سیستم پایین می آید.روش Piping:اگر به دو روش قبلی توجه کرده باشید متوجه یک مشکل خواهید شد. شما نمی توانید بین فرایندهایی که در حال اجرا هستند هماهنگی بوجود آورید و در واقع عدم ارتباط بین فرایندها فقدانی است که باید برطرف گردد.روش Piping این اجازه را به ما می دهد که دو فرایند برای همدیگر دستوراتی را ارسال کنند و خیلی شبیه دستور پایپ در لینوکس عمل میکند. تابع کلیدی که یک فرایند جدید ایجاد میکند و یک هندل را برای کار با فرایند در اختیار ما می گذارد تابع proc_open است. برای نحوه ی چگونگی کار piping نمونه کدی را آورده ایم. کلاینت کلمه ی Hello را برای Worker ارسال می کند و Worker بعد از دریافت کلمه ی Hello کلمه ی World را به آن می چسباند و به کلاینت پس می دهد.// pipe_client.php, uses proc_open() function to create the
// worker process, and send instructions to it
$descriptorspec = array(
0 =&gt; array(&amp;quotpipe&amp;quot, &amp;quotr&amp;quot), // stdin for worker
1 =&gt; array(&amp;quotpipe&amp;quot, &amp;quotw&amp;quot), // stdout for worker
);
$worker = proc_open(&amp;quotphp pipe_worker.php&amp;quot, $descriptorspec, $pipes);
if ($worker) {
fwrite($pipes[0], &amp;quothello&amp;quot);
while (!feof($pipes[1])) {
echo fgets($pipes[1]). &amp;quot\n&amp;quot
}
proc_close($worker);
}
// pipe_worker.php, all it does is to read instructions
// from STDIN, and write response to STDOUT
$line = fread(STDIN,4096);
fwrite(STDOUT, &amp;quot$line world&amp;quot);پردازش موازی توزیع شده(Distributed Parallel Processing):تا اینجا نگاهی به مواردی مثل  نخ ها، fork کردن فرایند، ایجاد فرایند جدید و برقراری ارتباط بین فرایندها با Piping انداختیم. این روش ها زمانی قابل استفاده هستند که روی یک سرور هستیم. در اینحالت شما با افزایش پردازنده و هسته های داخل سرور به کار خود Scale می دهید ولی اگر به چیزی فراتر نیاز دارید باید به سمت پردازش موازی توزیع شده بروید.در جهان توزیع شده برنامه نویسی تحت شبکه اجتناب ناپذیر است، خوشبختانه فریمورک و کتابخانه های منبع باز کاملی موجود هستند که شما را از برنامه نویسی سوکت در پی اچ پی بی نیاز می کنند. اینجاست که Gearman و ZeroMQ پا به عرصه وجود گذاشتند.ابزار Gearman: این فریمورک توسط خالق Memcached یعنی Danga توسعه داده شد. توجه داشته باشید برای اجرای کد زیر باید (Gearman deamon (GearmanD نصب شده باشد در اینجا localhost:4731 و همچنین اکستنشن Gearman نیز برای پی اچ پی نصب باشد. کد زیر همان مثال Hello World ی است که در بالا داشتیم.// gearman_client.php
$gmclient= new GearmanClient();
$gmclient-&gt;addServer(); //localhost
// the function -&gt;do blocks, wait for worker response
// to do tasks in non-blocking mode, use doBackground function
// Also not &#039;getWorld&#039; is a job name, and &#039;Hello&#039;
// is the job payload
$result = $gmclient-&gt;do(&amp;quotgetWorld&amp;quot, &amp;quotHello &amp;quot);
echo &amp;quot$result\n&amp;quot
// gearman_worker.php
$gmworker= new GearmanWorker();
$gmworker-&gt;addServer(); //localhost
// register the job &#039;getWorld&#039; handler &#039;getWorldFn&#039;
// which is defined below as a function
$gmworker-&gt;addFunction(&amp;quotgetWorld&amp;quot, &amp;quotgetWorldFn&amp;quot);
// loops here wait for jobs, and let handler deal with it
while($gmworker-&gt;work()) {}
function getWorldFn($job) {
return $job-&gt;workload() . &amp;quotWorld!&amp;quotابزار ZeroMQ:طبق لینکدین یکی از مهارتهای فنی سریع در حال رشد  ZeroMQ است، اگر هنوز نمی دانید چیست بهتر است آنرا بررسی کنید. در واقع یک گلوله ی نقره ای نیست که بصورت جادویی همه چیز را برای شما حل کند اما ساخت سیستم های توزیع شده را برای شما خیلی ساده می کند.برای اجرای کد زیر باید ZeroMQ C library نصب شده باشد و همچنین اکستنشن ZeroMQ نیز برای پی اچ پی نصب باشد. کد زیر همان مثال Hello World ی است که در بالا داشتیم.//zmp_client.php
//creates context
$context = new ZMQContext();
//create DEALER socket http://api.zeromq.org/2-1:zmq-socket#toc6
$socket = new ZMQSocket($context, ZMQ::SOCKET_DEALER);
//client connects
$socket-&gt;connect(&#039;tcp://127.0.0.1:15000&#039;);
//send 100 Hellos
for ($i = 0; $i &lt; 100; $i++){
$socket-&gt;send(&amp;quot$i - Hello&amp;quot);
echo $socket-&gt;recv() . &amp;quot\n&amp;quot
sleep(1);
}
//zmp_server.php
//creates context
$context = new ZMQContext();
//create ROUTER socket, http://api.zeromq.org/2-1:zmq-socket#toc7
$socket = new ZMQSocket($context, ZMQ::SOCKET_ROUTER);
//worker binds
$socket-&gt;bind(&#039;tcp://*:15000&#039;);
//poll the socket, like event dispatcher
$poll = new ZMQPoll();
$poll-&gt;add($socket, ZMQ::POLL_IN);
$readable = $writeable = array();
while(true) {
$events = $poll-&gt;poll($readable, $writeable, 1000);
foreach($readable as $s) {
//When there is incoming message, deal with it
$message = $socket-&gt;recvmulti();
$socket-&gt;sendmulti(array($message[0], $message[1] . &amp;quot World!&amp;quot));
}
}پیشنهاد میکنم کد client را قبل از راه اندازی worker  اجرا کنید و ببینید چه اتفاقی می افتد. و سپس worker را راه اندازی کنید و ببینید چه اتفاقی می افتد. در حالیکه client حلقه ی 100 تایی را تکرار می کند worker را برای چند ثانیه متوقف کنید و دوباره شروع کنید و ببینید چه اتفاقی می افتد، چند بار این کار را تکرار کنید.به این فکر کنید که شما با 30 خط کد چه دستاورد بزرگی دارید آن هم بدون هندل کردن یک خطا و همچنین به یاد داشته باشید هیچ message broker مثل RabbitMQ یا Gearman در کار نبوده است.پیروز باشید...منبع اصلی</description>
                <category>محمدتقی نقیبی</category>
                <author>محمدتقی نقیبی</author>
                <pubDate>Thu, 12 Mar 2020 18:16:23 +0330</pubDate>
            </item>
            </channel>
</rss>