
در روزگار قدیم جاوا اسکریپت از callback استفاده میکرد که در آن درون هر تابع یک تابع ناهمگام نیز قرار میگرفت و بدین ترتیب چیزی ایجاد میشد که به نام «هرم مرگ» (pyramid of doom) یا «جهنم کالبک» (callback hell) مشهور بود. مثال زیر یک نمونه ساده از آن است:
در ES6 ساختار جدیدی معرفی شد که کار دیباگ کردن کدهای ناهمگام را بسیار سادهتر و آسانتر میساخت. این ساختار بر اساس شیئی به نام Promise و متدهای then و catch بنا شده بود:
در نهایت ES7 دو کلیدواژه به نامهای Async و Await معرفی کرد که امکان کدنویسی ناهمگام را به صورتی که تا حد امکان به کد همگام جاوا اسکریپت شبیه باشد فراهم میساخت. نمونهای از آن را در مثال زیر میبینید. این توسعه اخیر به تدریج خواناترین روش برای اجرای وظایف ناهمگام در جاوا اسکریپت تلقی شد و در مقایسه با ساختار معمولی Promise حتی از نظر کارایی حافظه نیز موجب ارتقا میشود.
در گذشته بازیابی دادهها از دامنه دیگر مستلزم استفاده از XMLHttpRequest یا شیء XHR بود. امروزه میتوانیم از API واکشی جاوا اسکریپت به این منظور استفاده کنیم. متد ()fetch یک آرگومان الزامی دارد که نشاندهنده مسیر منبعی است که میخواهیم واکشی کنیم و یک Promise بازگشت میدهد.
برای استفاده از ()fetch در Node.js باید یک پیادهسازی از fetch را ایمپورت کنید. Isomorphic Fetch یک گزینه رایج محسوب میشود. آن را با وارد کردن دستور زیر در ترمینال نصب کنید:
npm install isomorphic-fetch es6-promise
سپس آن را در ابتدای سند به صورت زیر الزام (require) کنید:
اگر میخواهید دادههای JSON را واکشی کنید، باید پیش از پردازش کردن پاسخ، متد ()json را روی آن اجرا کنید:
JSON دریافت دادههای مورد نیاز و پردازش کردن آنها را به فرایندی نسبتاً سرراست تبدیل کرده است. اما اگر دادهها در قالب JSON نباشند چطور؟
در مورد اغلب وبسایتها باید دادههایی را که میخواهیم، از قالب HTML استخراج کنیم. در وبسایتهای استاتیک، دو روش به این منظور وجود دارد:
اگر نیازهای شما ساده هستند و با نوشتن regex نیز مشکلی ندارید، میتوانید به سادگی از متد ()text استفاده کنید و سپس دادههایی که لازم دارید را با استفاده از متد match استخراج کنید. برای نمونه، در ادامه کدی را میبینید که برای استخراج محتوای تگ نخست h1 در یک صفحه مورد استفاده قرار میگیرد:
اگر با سندهای پیچیدهتری سروکار دارید، بهتر است از آرایهای از متدهای داخلی جاوا اسکریپت برای کوئری زدن به DOM استفاده کنید. به این منظور از متدهایی مانند getElementById و querySelector استفاده کنید.
اگر بخواهیم کد فرانتاند را بنویسیم، میتوانیم از اینترفیس DOMParser استفاده کنیم. از آنجا که ما از Node.js استفاده میکنیم، میتوانیم از ماژول node نیز به جای آن بهره بگیریم. یک گزینه رایج jsdom است که میتوان با دستور زیر آن را نصب کرد:
npm i jsdom
همچنین با دستورهای زیر آن را require میکنیم:
با استفاده از jsdom میتوانیم HTML ایمپورت شده را مانند شیء DOM خود و با بهرهگیری از querySelector و متدهای مرتبط ایمپورت کنیم:
اگر بخواهیم دادهها را از یک وبسایت دینامیک مانند یک شبکه اجتماعی دریافت کنیم چطور؟ محتوای چنین وبسایتهایی به صورت در لحظه تولید میشود و لذا فرایند کار کاملاً متفاوت خواهد بود. در این حالت اجرای یک درخواست fetch عملی نخواهد بود، زیرا کدِ استاتیکِ سایت را بازگشت میدهد و نه محتوای دینامیک آن را که احتمالاً مورد نظر ما است.
اگر چنین نیتی در سر دارید بهترین ماژول node برای اجرای این کار puppeteer است، چون جایگزین اصلی آن PhantomJS دیگر توسعه نمییابد.
Puppeteer امکان اجرای کروم یا کرومیوم را روی پروتکل DevTools فراهم ساخته است و قابلیتهایی مانند ناوبری خودکار صفحه و تهیه تصویری از صفحه را دارد. DevTools به صورت پیشفرض یک مرورگر headless را اجرا میکند، اما تغییر دادن این تنظیمات برای دیباگ کردن مفید خواهد بود.
برای نصب Puppeteer به دایرکتوری پروژه در ترمینال بروید و عبارت زیر را وارد کنید:
npm i puppeteer
در ادامه مقداری کد اولیه برای شروع کار را مشاهده میکنید:
ابتدا puppeteer را راهاندازی میکنیم. حالت adless را نیز غیرفعال میکنیم به طوری که میتوانیم ببینیم چه کار میکنیم. سپس یک برگه جدید باز میکنیم. متد زیر اختیاری است و امکان استفاده از متدهای abort ،continue و respond را در ادامه میدهد. در نهایت به صفحه منتخب میرویم.
page.setRequestInterception(true)
در مثال DOM Parser فوق میتوانیم عناصر را با استفاده از document.querySelector و متدهای مرتبط کوئری کنیم.
اگر لازم باشد در یک وبسایت لاگین کنیم این کار با استفاده از متدهای type و click به سادگی انجامشدنی است. بدین ترتیب عناصر DOM با استفاده از همان ساختار querySelector شناسایی میشوند:
وبسایتهای دینامیک عموماً از طریق مکانیسم اسکرول بینهایت محتوا را به نمایش میگذارند. برای فائق آمدن بر این مشکل، باید کاری کنیم که puppeteer بر مبنای نوعی معیار اقدام به اسکرول کردن بکند.
در ادامه مثال سادهای را میبینید که 5 بار اسکرول میکند و به مدت 1 ثانیه بین هر اسکرول صبر میکند تا محتوا بارگذاری شود.
از آنجا که زمانهای بارگذاری متفاوت هستند، کد فوق لزوماً هر بار تعداد نتیجه یکسانی را بارگذاری نمیکند. اگر با چنین مشکلی مواجه شدید، میتوانید تا زمانی که تعداد مشخصی از عناصر پیدا نشدهاند، اسکرول کنید و یا معیار دیگری را انتخاب کنید.
در نهایت چند روش وجود دارند که میتوانند موجب بهینهسازی کدهای ما شوند و از این رو کد تا حد امکان سریع و روان اجرا شود. به عنوان مثال در ادامه روشی را ملاحظه میکنید که موجب میشود puppeteer از بارگذاری فونتها و تصاویر منع شود.
همچنین میتوان CSS را به روش مشابهی غیرفعال کرد، اما در پارهای موارد CSS در دادههای دینامیکی که میخواهید بارگذاری کنید، یکپارچهسازی شده است و از این رو باید در این زمینه هوشیار باشید.
مطالبی که در این نوشته مطرح کردیم تقریباً همه آن چیزی بود که برای ساخت یک وب اسکرپر کارآمد لازم بود. زمانی که دادهها را در حافظه گردآوری کردید، میتوانید آنها را با استفاده از ماژول fs در یک سند محلی ذخیره کنید، روی پایگاه داده آپلود کنید یا با استفاده از یک API مانند گوگل شیتز مستقیماً به یک سند ارسال کنید. اگر در زمینه وب اسکرپینگ تازهکار هستید یا در این زمینه معلوماتی دارید اما در زمینه Node.js مبتدی هستید، این مقاله احتمالاً برای شما مفید بوده است و شما را با برخی از ابزارهای قدرتمند Node.js که امکان وب اسکرپینگ را مهیا میسازند آشنا ساخته است.
منبع: فرادرس
لاراول تابعهای کمکی زیادی دارد که روشی آسان برای کار با مسیرها، آرایهها و رشتهها به دست میدهند. البته شناخت همه آنها کاری تقریباً ناممکن است. اغلب توسعهدهندگان انواع بسیار رایجتر را میشناسند، اما برخی تابعهای کمکی بسیار مفید دیگر نیز وجود دارند که در صورت کمی تأمل بیشتر با آنها آشنا میشوید. در این مقاله تابعهای کمکی لاراول که باید با آنها آشنا شوید را معرفی میکنیم.
تابع کمکی Logger میتواند برای نوشتن پیامی با سطح debug در لاگ مورد استفاده قرار گیرد.
که در نتیجه خط زیر را به لاگ اضافه میکند:
اگر هیچ مقداری به تابع Logger ارسال نشود، یک وهله از Logger بازگشت میدهد. بدین ترتیب میتوانیم پیامهایی با سطوح مختلف در لاگ بنویسیم:
کد فوق خط زیر را به لاگ اضافه میکند:
متد ()Arr::divide امکان افراز یک آرایه به دو آرایه را فراهم میسازد. متد تقسیم دو آرایه بازگشت میدهد که یکی شامل کلیدها و آرایه دیگر شامل مقادیر است.
تابع کمکی Blank بررسی میکند که آیا یک مقدار خالی است یا نه. منظور از مقدار خالی null است، یعنی یک رشته که صرفاً شامل کاراکتر فاصله یا آرایه یا رشته خالی است.
نکته: مقادیر بولی به عنوان مقادیر خالی تلقی میشوند.
معکوس این تابع کمکی، تابع کمکی filled است.
دامپ کردن متغیرها در صورتی که بخواهیم یک یا چند متغیر را دیباگ کنیم بسیار کارآمد خواهد بود.
امکان دامپ کردن متغیرهای چندگانه با ارسال متغیرهای دیگر به تابع dump نیز وجود دارد:
در کنار تابع کمکی dump، تابع کمکی دامپ دیگری نیز وجود دارد. این تابع کمکی به نام dd شناخته میشود که به معنی «dump and die» است. تابع مذکور همانند تابع دامپ کار میکند و تنها تفاوت این است که تابع dd به جای این که صرفاً متغیر را دامپ کند، اجرای اسکریپت را نیز خاتمه میبخشد.
لاراول چند تابع کمکی دارد که میتوان برای دریافت مسیر کامل به دایرکتوریهای خاص مورد استفاده قرار گیرد. اینها تابعهای کمکی هستند که لاراول در زمان استفاده از مسیرها استفاده میکند:
همچنین میتوانید یک آرگومان را به تابعهای کمکی مسیر ارسال کنید که به مسیر الحاق میشود:
برای تولید رشته مناسب URL از یک رشته میتوان از تابع کمکی Str::slug استفاده کرد.
جداکننده پیشفرض خط تیره (-) است، اما میتوانید این کاراکتر را با ارسال آرگومان دوم به تابع بازنویسی کنید:
متد Arr:has میتواند با بهرهگیری از نمادگذاری نقطه (.) برای بررسی این که یک یا چند آیتم در یک آرایه وجود دارند یا نه استفاده شود.
برای بررسی وجود آیتمهای چندگانه کافی است به جای یک رشته، آرایهای را به متد ارسال کنید:
متد Str::uuid یک UUID ایجاد میکند:
تابع کمکی Optional امکان دسترسی به مشخصهها را با فراخوانی متدها روی یک شیء که به صورت آرگومان ارسال شده فراهم میسازد. هر آرگومانی در این تابع پذیرفته است.
اگر شیء ارسالی به تابع null باشد، مشخصهها و متدها به جای ایجاد خطا مقدار null بازگشت میدهند.
اگر نویسنده بلاگ در مثال فوق تنظیم شده باشد، در این صورت نام کامل نویسنده نمایش خواهد یافت. اگر به هر دلیلی نویسنده تعیین نشده باشد، خطایی وجود نخواهد داشت و هیچ اتفاقی هم نمیافتد.
متد Arr::pluck همه مقادیر را از یک کلید مفروض در آرایه بازیابی میکند.
در این مقاله قصد داریم به بررسی مبانی مدیریت رویداد (Event) در فریمورک وب لاراول بپردازیم. این یکی از قابلیتهایی است که شما به عنوان یک توسعهدهنده باید در فریمورک مورد نظر خود به آن تسلط داشته باشید. ما در این مسیر با روش ایجاد یک مثال واقعی از رویدادهای سفارشی در لاراول نیز آشنا خواهیم شد. همچنین یک شنونده برای رویداد خود میسازیم.
مفهوم رویدادها در لاراول مبتنی بر الگوی طراحی نرمافزار بسیار رایجی به نام الگوی مشاهدهگر (observer) است. در این الگو، تصور میشود که سیستم به رویدادها گوش میدهد و بر همین مبنا واکنش میدهد. این قابلیتی بسیار مفید است، زیرا امکان جداسازی کامپوننتها را در یک سیستم فراهم میسازد و بدین ترتیب از ایجاد یک کد به شدت درهمتنیده و پیچیده جلوگیری میکند.
برای نمونه تصور کنید، میخواهید وقتی فردی وارد وبسایت شما میشود، این واقعه را به همه ماژولها در یک سیستم اطلاع دهید. بدین ترتیب، ماژولها میتوانند به این رویداد لاگین کردن واکنش نشان دهند. این واکنش میتواند از ارسال ایمیل یا نوتیفیکیشن درون اپلیکیشن یا هر چیزی که قرار است در پاسخ به آن رویداد اتفاق بیفتد متفاوت باشد.
در این بخش، به بررسی روش مورد استفاده از سوی لاراول برای پیادهسازی رویدادها و شنوندهها در هسته مرکزی فریمورک میپردازیم. اگر با معماری لاراول آشنا باشید، احتمالاً میدانید که لاراول مفهوم یک ارائهدهنده سرویس را پیادهسازی میکند و بدین ترتیب میتوان سرویسهای متفاوتی را به اپلیکیشن تزریق کرد. به طور مشابه، لاراول یک کلاس داخلی به نام EventServiceProvider.php دارد که امکان تعریف کردن نگاشت شنونده رویداد برای یک اپلیکیشن را فراهم میسازد. در ادامه فایل app/Providers/EventServiceProvider.php را باز کنید:
اگر نگاهی دقیق به مشخصه listen$ داشته باشید، میبینید که این مشخصه امکان تعریف یک آرایه از رویدادها و شنوندههای مرتبط را فراهم میسازد. کلید آرایه متناظر با رویدادها در سیستم است و مقادیر آن متناظر با شنوندههایی است که در زمان رخ دادن رویداد متناظر در سیستم تحریک میشوند. در ادامه از یک مثال دنیای واقعی برای توضیح بیشتر این مفهوم استفاده میکنیم. چنان که شاید بدانید، لاراول یک سیستم احراز هویت داخلی دارد که قابلیتهایی مانند ثبت نام، لاگین کردن و غیره را تسهیل میکند.
فرض کنید میخواهید وقتی فردی وارد اپلیکیشن میشود، به عنوان معیار امنیتی، یک نوتیفیکیشن ایمیل برای وی ارسال کنید. اگر لاراول از قابلیت شنونده رویداد پشتیبانی نمیکرد، در نهایت مجبور بودید کلاس مرکزی لاراول را ویرایش کنید و یا این که نوعی کد دیگر را برای ارسال ایمیل مورد استفاده قرار دهید. در واقع، ما خوششانس هستیم که لاراول از طریق استفاده از شنونده رویداد به حل این مشکل کمک میکند. در ادامه فایل app/Providers/EventServiceProvider.php را طوری تغییر میدهیم که به صورت زیر درآید:
Illuminate\Auth\Events\Login رویدادی است که وقتی فردی وارد اپلیکیشن میشود، از سوی پلاگین Auth ایجاد میشود. ما این رویداد را به شنونده App\Listeners\SendEmailNotification متصل میکنیم به طوری که در زمان رویداد لاگین تحریک شود. البته باید کلاس شنونده App\Listeners\SendEmailNotification را نیز نوشته باشید. در این مورد هم لاراول از طریق استفاده از دستور آرتیزان زیر، امکان ایجاد یک کد قالب برای شنونده را فراهم میسازد:
php artisan event:generate
دستور فوق کلاسهای رویداد و شنونده را زیر مشخصه listen$ تولید میکند. در این حالت، رویداد Illuminate\Auth\Events\Login از قبل موجود است، به طوری که صرفاً کلاس شونده App\Listeners\SendEmailNotification ایجاد میشود. در واقع، در این وضعیت باید کلاس رویداد Illuminate\Auth\Events\Login نیز در صورتی که از قبل موجود نیست، ایجاد شود.
در ادامه شنوندهای که در مسیر app/Listeners/SendEmailNotification.php ایجاد شده را بررسی میکنیم:
این handle است که در زمان تحریک شدن شنونده به همراه وابستگیهای مناسب فراخوانی میشود. در این مثال، آرگومان event$ باید شامل اطلاعات زمینهای در مورد رویداد لاگین یعنی کاربر وارد شده به اپلیکیشن باشد.
همچنین میتوان از شیء event$ برای اجرای پردازش بیشتر در متد handle استفاده کرد. در این مثال، ما میخواهیم یک نوتیفیکیشن ایمیل به کاربر لاگین کرده ارسال کنیم. متد handle پس از بازبینی موارد فوق به صورت زیر درمیآید:
بنابراین استفاده از قابلیت رویداد در لاراول به این صورت است. در بخش بعدی پا را فراتر میگذاریم و یک رویداد سفارشی و کلاس شنونده متناظرش را در لاراول میسازیم.
در سناریوی مثال بخش قبل که در مثال این بخش نیز مورد استفاده میدهیم، قرار است کارهای زیر را انجام دهیم:
بنابراین در ادامه فایل app/Providers/EventServiceProvider.php را بازبینی میکنیم و رویداد سفارشی و نگاشتهای شنوندههای خود را در آن ثبت میکنیم:
چنان که میبینید، ما رویداد App\Events\ClearCache و کلاس شنوندههای مرتبط App\Listeners\WarmUpCache را زیر مشخصه listen$ تعریف میکنیم. سپس باید فایلهای کلاس مرتبط را ایجاد کنیم. به خاطر داشته باشید که همواره میتوانید از دستور artisan استفاده کنید و یک کد قالب مبنا تولید کنید.
php artisan event:generate
دستور فوق کلاس رویدادی را در فایل app/Events/ClearCache.php ایجاد کرده و کلاس شنونده را در فایل app/Listeners/WarmUpCache.php قرار میدهد. کلاس app/Events/ClearCache.php با چند تغییر به صورت زیر درمیآید:
چنان که احتمالاً متوجه شدهاید، ما مشخصه جدیدی به نام cache_keys$ اضافه کردهایم که از آن برای نگهداری اطلاعات ارسال شده به همراه یک رویداد استفاده خواهیم کرد. در این مثال، گروههای کش را که پاک شدهاند ارسال میکنیم. سپس نگاهی به کلاس شنوندهای خواهیم داشت که دارای یک متد handle بهروزرسانی شده در فایل app/Listeners/WarmUpCache.php است.
زمانی که شنونده فراخوانی میشود، متد handle به همراه وهلهای از رویداد مرتبط ارسال میشود. در این مثال، این مورد باید وهلهای از رویداد ClearCache باشد که به عنوان آرگومان اول متد handle ارسال میشود. سپس کافی است روی همه کلیدهای کش، حلقهای تعریف کنیم و کش های مرتبط را آمادهسازی کنیم.
اکنون همه چیز را آماده تست ساختهایم. در ادامه نگاهی به فایل کنترلر در مسیر app/Http/Controllers/EventController.php میاندازیم تا نشان دهیم که یک رویداد چگونه تحریک میشود.
قبل از هر چیز یک آرایه از کلیدهای کش در زمان ایجاد یک وهله از رویداد ClearCache به عنوان آرگومان نخست ارسال میشود. تابع کمکی رویداد برای تحریک یک رویداد از هر کجا درون یک اپلیکیشن مورد استفاده قرار میگیرد. زمانی که یک رویداد تحریک میشود، لاراول همه شنوندهها را فرامیخواند تا به آن رویداد خاص گوش دهند.
در مورد مثال خودمان، شنونده App\Listeners\WarmUpCache طوری تنظیم شده است که به رویداد App\Events\ClearCache گوش دهد. از این رو متد handle شنونده App\Listeners\WarmUpCache زمانی که یک رویداد از کنترلر تحریک میشود، فراخوانی خواهد شد. باقی کد برای آمادهسازی کش ها جهت پاکسازی استفاده میشود. بنابراین اینک شما با روش ایجاد رویدادهای سفارشی در اپلیکیشن خود آشنا شدهاید و میتوانید با آنها کار کنید.
«اشتراک رویداد» (Event Subscriber) امکان ثبت نام در چند شنونده رویداد را در یک مکان منفرد فراهم میسازد. چه بخواهید از نظر منطقی شنوندههای رویداد را گروهبندی کنید و چه بخواهید رویدادهای زیادی را در یک مکان منفرد گرد هم آورید، اشتراک رویداد گزینه مناسبی برای استفاده خواهد بود.
اگر بخواهیم مثالهایی را که تا به اینجا مورد بررسی قرار دادیم، با استفاده از اشتراک رویداد پیادهسازی کنیم، چیزی مانند زیر خواهد بود:
متد subscribe مسئول ثبت شنوندهها است. آرگومان اول متد subscribe وهلهای از کلاس Illuminate\Events\Dispatcher است که میتوان برای اتصال رویدادها به شنوندهها با استفاده از متد listen استفاده کرد. آرگومان اول متد listen رویدادی است که میخواهید به آن گوش دهید و آرگومان دوم شنوندهای است که هنگام تحریک رویداد فراخوانی خواهد شد.
به این ترتیب میتوانید چندین رویداد و شنونده را در خود کلاس اشتراک تعریف کنید. کلاس اشتراک رویداد به صورت خودکار انتخاب نمیشود. شما باید آن را در کلاس EventServiceProvider.php زیر مشخصه subscriber$ چنان که در قطعه کد زیر میبینید ثبت کنید.
بنابراین کلاس اشتراک رویداد در اختیار شما قرار دارد و بدین ترتیب به پایان این مقاله میرسیم.
در این مقاله به بررسی چند قابلیت جالب لاراول پرداختیم که شامل رویدادها و شنوندهها است. این قابلیتها مبتنی بر الگوی طراحی مشاهدهگر هستند که امکان تحریک رویدادها در تمام نقاط اپلیکیشن را فراهم میسازد و به ماژولهای دیگر امکان میدهد که به این رویدادها گوش دهند و بر همین مبنا واکنش نشان دهند.
زمانی که یک اپلیکیشن iOS ایجاد میکنید، در اغلب موارد نیاز است که بین کلاسهای Model ،View و Controller ارتباطهایی برقرار کنید. در این مقاله به بررسی روشهای مختلف برای برقراری ارتباط بین کلاس ها در سوئیفت 5 میپردازیم. تصویر زیر الگوی معماری مشهور به MVC را نمایش میدهد که روشی برای طراحی کردن یک گردش داده در پروژهها محسوب میشود.
یکی از مزایای استفاده از یک الگوی معماری این است که کد شما به سادگی درک خواهد شد، ماژولار میشود و قابلیت نگهداری آن ارتقا مییابد. با تجزیه کلاسها به دستههای مختلف نیازمند یک روش مؤثر برای برقراری ارتباط در مسیر model -> controller -> view و برعکس خواهیم بود. ما در ادامه 3 روشی که برای نیل به این مقصود مورد نیاز است را مورد بررسی قرار دادهایم. این سه روش به صورت خلاصه شامل موارد زیر هستند:
با ما همراه باشید تا با بررسی این موارد درکی مقدماتی از مزایا و معایب هر روش پیدا کنید و بتوانید راهحل مناسب خود را انتخاب نمایید.
استفاده از نوتیفیکیشن زمانی مناسب خواهد بود که مشاهدهگرهای زیادی داشته باشیم که برای بهروزرسانی نیازمند «شنیدن» باشند. برای نمونه اگر 5 کلاس دارید که همگی دادههای ذخیره شده را بارگذاری میکنند میتوانید به یکباره به هر 5 کلاس هشدار دهید که یک درخواست موفق شبکه برقرار شده است.
ساختار مقدماتی چنین است:
نکته: تگ obj@ در ابتدای هر تابعی که از طریق selector# فراخوانی شود، ضروری خواهد بود.
گرچه امکان ارسال داده از طریق نوتیفیکیشن وجود دارد، اما به این منظور ابزار بهینهای محسوب نمیشوند. در هر حال، بهترین کاربرد آنها برای هشدار به یک کلاس است که دادههای جدیدی موجود شدهاند. فرض کنید مدل دادهای دارید که در آن دادههایی را از شبکه دانلود میکنید، زمانی که این دادهها در حافظه ذخیره شدند، به کنترلرهای «نما» (View) هشدار میدهید تا این دادههای اخیراً ذخیره شده را در نما وارد کنند. در ادامه مثالی از طرز کار ساختار نوتیفیکیشن را میبینید:
«نمایندگی» (Delegation) روشی است که در اغلب موارد برای برقراری ارتباط بین کلاسهای مدل، نما و کنترلر مورد استفاده قرار میگیرد. در الگوی طراحی نمایندگی از یک پروتکل برای تعریف متدها، مشخصهها و دیگر الزامات مورد نیاز برای پیادهسازی یک کلاس استفاده میشود. پروتکل را میتوان به عنوان یک قرارداد تصور کرد که با اجرای قرارداد موجود در پروتکل متعهد میشویم الزامات آن را پیادهسازی کنیم.
برای پیادهسازی الگوی نمایندگی باید یک پروتکل را راهاندازی کنیم:
در کلاس متد، یعنی کلاسی که این نمایندگی را بر عهده دارد، باید یک ارجاع ضعیف به ModelDelegate داشته باشید.
نکته: ارجاع به نماینده باید ضعیف یا unowned باشد. با استفاده از یک ارجاع قوی، ممکن است متوجه شوید در حال ایجاد یک چرخه هستید که در آن نماینده ارجاعی به کلاس والد نگه میدارد و کلاس والد نیز به نماینده ارجاع دارد. با ایجاد چنین حلقه ارجاع قوی، هر دو شیء در حافظه به همدیگر ارجاع میدهند و از این رو ARC به محض «مقدارزدایی» (de-initialization) از شیء نمایندگی شده آن را تخصیصزدایی میکند.
اکنون یک وهله از Model در کلاس Controller ایجاد میکنیم و نماینده آن را به Self انتساب میدهیم.
برای انتساب نماینده مدل به Self، باید ViewController با پروتکل ModelDelegate هماهنگ باشد و توجه داشته باشید که در این مثال Self همان کلاس ModelDelegate است. ما میتوانیم این هماهنگی را بدین طریق به دست آوریم که یک بسط از کنترل نما که از این پروتکل استفاده میکند به طرحبندی تعریفشده در ModelDelegate اضافه کنیم. زمانی که مدل با موفقیت دادهها را دانلود کرد، تابع didReceiveData را درون ViewController فراخوانی خواهد کرد. زمانی که این تابع فراخوانی شد، میتوانید کلاس View را درون ViewController بهروزرسانی کنید.
راهاندازی Callback-ها ساده است. برخی برنامه نویسان از این روش کمتر استفاده میکنند چون پایداری الگوی نمایندگی را بیشتر میپسندند. با این حال، Callback-ها برای ایجاد ارتباطهای ساده مفید هستند.
تصور کنید در یک کلاس نما تابعی داریم که یک انیمیشن را اجرا میکند. ما میخواهیم به محض تکمیل شدن انیمیشن به ViewController خود هشدار دهیم که انیمیشن به پایان رسیده است.
به این منظور در ViewController یک وهله از کلاس View ایجاد میکنیم که تابع ()runAnimation را فراخوانی میکند:
نکته: به «weak self in» درون بستار روی ()runAnimation توجه خاصی داشته باشید. با تعیین این self به صورت یک ارجاع ضعیف ما از ایجاد چرخههای پایدار جلوگیری میکنیم. اگر self را به صورت قوی در اختیار بگیریم، آن گاه بستار یک ارجاع قوی به self میگیرد و بنابراین امکان تخصیصزدایی از آن در حافظه از دست میرود.
همچنین امکان ارسال دادهها به صورت مستقیم از طریق Callback وجود دارد:
نکته: کاراکتر زیرخط درون تعریف تابع به آن معنی است که نیازی به گنجاندن نام پارامتر در زمان فراخوانی یک متد نداریم.
شما با مطالعه این مقاله با برخی از گزینههای برقراری ارتباط در سوئیفت آشنا شدید. اغلب برنامهنویسان در پروژههای خود از انواع مختلفی از این روشهای برقراری ارتباط بین کلاسها استفاده میکنند، چون هر کدام از آنها کاربردهای خاص خود را دارند. از نمایندگی برای طرحبندی پایدار بین کلاسها و اجرای ارتباطهای زیاد استفاده میشود. از Callback برای کارکردهای سادهای مانند ارسال Callback در زمان پایان یافتن یک اکشن استفاده میشود. همچنین از نوتیفیکیشن برای ارسال هشدار به چند کلاس جهت اطلاع دادن دانلود شدن دادهها یا تغییر یافتن آنها استفاده میکنیم.
در این مقاله قصد داریم به بررسی مبانی مدیریت رویداد (Event) در فریمورک وب لاراول بپردازیم. این یکی از قابلیتهایی است که شما به عنوان یک توسعهدهنده باید در فریمورک مورد نظر خود به آن تسلط داشته باشید. ما در این مسیر با روش ایجاد یک مثال واقعی از رویدادهای سفارشی در لاراول نیز آشنا خواهیم شد. همچنین یک شنونده برای رویداد خود میسازیم.
مفهوم رویدادها در لاراول مبتنی بر الگوی طراحی نرمافزار بسیار رایجی به نام الگوی مشاهدهگر (observer) است. در این الگو، تصور میشود که سیستم به رویدادها گوش میدهد و بر همین مبنا واکنش میدهد. این قابلیتی بسیار مفید است، زیرا امکان جداسازی کامپوننتها را در یک سیستم فراهم میسازد و بدین ترتیب از ایجاد یک کد به شدت درهمتنیده و پیچیده جلوگیری میکند.
برای نمونه تصور کنید، میخواهید وقتی فردی وارد وبسایت شما میشود، این واقعه را به همه ماژولها در یک سیستم اطلاع دهید. بدین ترتیب، ماژولها میتوانند به این رویداد لاگین کردن واکنش نشان دهند. این واکنش میتواند از ارسال ایمیل یا نوتیفیکیشن درون اپلیکیشن یا هر چیزی که قرار است در پاسخ به آن رویداد اتفاق بیفتد متفاوت باشد.
در این بخش، به بررسی روش مورد استفاده از سوی لاراول برای پیادهسازی رویدادها و شنوندهها در هسته مرکزی فریمورک میپردازیم. اگر با معماری لاراول آشنا باشید، احتمالاً میدانید که لاراول مفهوم یک ارائهدهنده سرویس را پیادهسازی میکند و بدین ترتیب میتوان سرویسهای متفاوتی را به اپلیکیشن تزریق کرد. به طور مشابه، لاراول یک کلاس داخلی به نام EventServiceProvider.php دارد که امکان تعریف کردن نگاشت شنونده رویداد برای یک اپلیکیشن را فراهم میسازد. در ادامه فایل app/Providers/EventServiceProvider.php را باز کنید:
اگر نگاهی دقیق به مشخصه listen$ داشته باشید، میبینید که این مشخصه امکان تعریف یک آرایه از رویدادها و شنوندههای مرتبط را فراهم میسازد. کلید آرایه متناظر با رویدادها در سیستم است و مقادیر آن متناظر با شنوندههایی است که در زمان رخ دادن رویداد متناظر در سیستم تحریک میشوند. در ادامه از یک مثال دنیای واقعی برای توضیح بیشتر این مفهوم استفاده میکنیم. چنان که شاید بدانید، لاراول یک سیستم احراز هویت داخلی دارد که قابلیتهایی مانند ثبت نام، لاگین کردن و غیره را تسهیل میکند.
فرض کنید میخواهید وقتی فردی وارد اپلیکیشن میشود، به عنوان معیار امنیتی، یک نوتیفیکیشن ایمیل برای وی ارسال کنید. اگر لاراول از قابلیت شنونده رویداد پشتیبانی نمیکرد، در نهایت مجبور بودید کلاس مرکزی لاراول را ویرایش کنید و یا این که نوعی کد دیگر را برای ارسال ایمیل مورد استفاده قرار دهید. در واقع، ما خوششانس هستیم که لاراول از طریق استفاده از شنونده رویداد به حل این مشکل کمک میکند. در ادامه فایل app/Providers/EventServiceProvider.php را طوری تغییر میدهیم که به صورت زیر درآید:
Illuminate\Auth\Events\Login رویدادی است که وقتی فردی وارد اپلیکیشن میشود، از سوی پلاگین Auth ایجاد میشود. ما این رویداد را به شنونده App\Listeners\SendEmailNotification متصل میکنیم به طوری که در زمان رویداد لاگین تحریک شود. البته باید کلاس شنونده App\Listeners\SendEmailNotification را نیز نوشته باشید. در این مورد هم لاراول از طریق استفاده از دستور آرتیزان زیر، امکان ایجاد یک کد قالب برای شنونده را فراهم میسازد:
php artisan event:generate
دستور فوق کلاسهای رویداد و شنونده را زیر مشخصه listen$ تولید میکند. در این حالت، رویداد Illuminate\Auth\Events\Login از قبل موجود است، به طوری که صرفاً کلاس شونده App\Listeners\SendEmailNotification ایجاد میشود. در واقع، در این وضعیت باید کلاس رویداد Illuminate\Auth\Events\Login نیز در صورتی که از قبل موجود نیست، ایجاد شود.
در ادامه شنوندهای که در مسیر app/Listeners/SendEmailNotification.php ایجاد شده را بررسی میکنیم:
این handle است که در زمان تحریک شدن شنونده به همراه وابستگیهای مناسب فراخوانی میشود. در این مثال، آرگومان event$ باید شامل اطلاعات زمینهای در مورد رویداد لاگین یعنی کاربر وارد شده به اپلیکیشن باشد.
همچنین میتوان از شیء event$ برای اجرای پردازش بیشتر در متد handle استفاده کرد. در این مثال، ما میخواهیم یک نوتیفیکیشن ایمیل به کاربر لاگین کرده ارسال کنیم. متد handle پس از بازبینی موارد فوق به صورت زیر درمیآید:
بنابراین استفاده از قابلیت رویداد در لاراول به این صورت است. در بخش بعدی پا را فراتر میگذاریم و یک رویداد سفارشی و کلاس شنونده متناظرش را در لاراول میسازیم.
در سناریوی مثال بخش قبل که در مثال این بخش نیز مورد استفاده میدهیم، قرار است کارهای زیر را انجام دهیم:
بنابراین در ادامه فایل app/Providers/EventServiceProvider.php را بازبینی میکنیم و رویداد سفارشی و نگاشتهای شنوندههای خود را در آن ثبت میکنیم:
چنان که میبینید، ما رویداد App\Events\ClearCache و کلاس شنوندههای مرتبط App\Listeners\WarmUpCache را زیر مشخصه listen$ تعریف میکنیم. سپس باید فایلهای کلاس مرتبط را ایجاد کنیم. به خاطر داشته باشید که همواره میتوانید از دستور artisan استفاده کنید و یک کد قالب مبنا تولید کنید.
php artisan event:generate
دستور فوق کلاس رویدادی را در فایل app/Events/ClearCache.php ایجاد کرده و کلاس شنونده را در فایل app/Listeners/WarmUpCache.php قرار میدهد. کلاس app/Events/ClearCache.php با چند تغییر به صورت زیر درمیآید:
چنان که احتمالاً متوجه شدهاید، ما مشخصه جدیدی به نام cache_keys$ اضافه کردهایم که از آن برای نگهداری اطلاعات ارسال شده به همراه یک رویداد استفاده خواهیم کرد. در این مثال، گروههای کش را که پاک شدهاند ارسال میکنیم. سپس نگاهی به کلاس شنوندهای خواهیم داشت که دارای یک متد handle بهروزرسانی شده در فایل app/Listeners/WarmUpCache.php است.
زمانی که شنونده فراخوانی میشود، متد handle به همراه وهلهای از رویداد مرتبط ارسال میشود. در این مثال، این مورد باید وهلهای از رویداد ClearCache باشد که به عنوان آرگومان اول متد handle ارسال میشود. سپس کافی است روی همه کلیدهای کش، حلقهای تعریف کنیم و کش های مرتبط را آمادهسازی کنیم.
اکنون همه چیز را آماده تست ساختهایم. در ادامه نگاهی به فایل کنترلر در مسیر app/Http/Controllers/EventController.php میاندازیم تا نشان دهیم که یک رویداد چگونه تحریک میشود.
قبل از هر چیز یک آرایه از کلیدهای کش در زمان ایجاد یک وهله از رویداد ClearCache به عنوان آرگومان نخست ارسال میشود. تابع کمکی رویداد برای تحریک یک رویداد از هر کجا درون یک اپلیکیشن مورد استفاده قرار میگیرد. زمانی که یک رویداد تحریک میشود، لاراول همه شنوندهها را فرامیخواند تا به آن رویداد خاص گوش دهند.
در مورد مثال خودمان، شنونده App\Listeners\WarmUpCache طوری تنظیم شده است که به رویداد App\Events\ClearCache گوش دهد. از این رو متد handle شنونده App\Listeners\WarmUpCache زمانی که یک رویداد از کنترلر تحریک میشود، فراخوانی خواهد شد. باقی کد برای آمادهسازی کش ها جهت پاکسازی استفاده میشود. بنابراین اینک شما با روش ایجاد رویدادهای سفارشی در اپلیکیشن خود آشنا شدهاید و میتوانید با آنها کار کنید.
«اشتراک رویداد» (Event Subscriber) امکان ثبت نام در چند شنونده رویداد را در یک مکان منفرد فراهم میسازد. چه بخواهید از نظر منطقی شنوندههای رویداد را گروهبندی کنید و چه بخواهید رویدادهای زیادی را در یک مکان منفرد گرد هم آورید، اشتراک رویداد گزینه مناسبی برای استفاده خواهد بود.
اگر بخواهیم مثالهایی را که تا به اینجا مورد بررسی قرار دادیم، با استفاده از اشتراک رویداد پیادهسازی کنیم، چیزی مانند زیر خواهد بود:
متد subscribe مسئول ثبت شنوندهها است. آرگومان اول متد subscribe وهلهای از کلاس Illuminate\Events\Dispatcher است که میتوان برای اتصال رویدادها به شنوندهها با استفاده از متد listen استفاده کرد. آرگومان اول متد listen رویدادی است که میخواهید به آن گوش دهید و آرگومان دوم شنوندهای است که هنگام تحریک رویداد فراخوانی خواهد شد.
به این ترتیب میتوانید چندین رویداد و شنونده را در خود کلاس اشتراک تعریف کنید. کلاس اشتراک رویداد به صورت خودکار انتخاب نمیشود. شما باید آن را در کلاس EventServiceProvider.php زیر مشخصه subscriber$ چنان که در قطعه کد زیر میبینید ثبت کنید.
بنابراین کلاس اشتراک رویداد در اختیار شما قرار دارد و بدین ترتیب به پایان این مقاله میرسیم.
در این مقاله به بررسی چند قابلیت جالب لاراول پرداختیم که شامل رویدادها و شنوندهها است. این قابلیتها مبتنی بر الگوی طراحی مشاهدهگر هستند که امکان تحریک رویدادها در تمام نقاط اپلیکیشن را فراهم میسازد و به ماژولهای دیگر امکان میدهد که به این رویدادها گوش دهند و بر همین مبنا واکنش نشان دهند.