کلاس های Extension و Dispatcher

کلاس‌های Extension و Dispatcher به حوزه توسعه‌دهندگان برنامه‌های افزودنی در جوملا 4 معرفی شدند، که اکنون باید بفهمند که چه هستند.

در بررسی کلاس‌های Extension و Dispatcher، ابتدا روی افزونه های کامپوننت ها تمرکز می‌کنیم. بعداً خواهیم دید که چگونه این مفهوم به ماژول ها و پلاگین ها تعمیم می یابد.

شاید برای شما مفید باشد که به این ویدیو در Component Extension Class و بخشی از این ویدیو Component Dispatcher and MVC Factory classes نگاه کنید.

کلاس افزونه برای کامپوننت ها

برای مثال، مواردی وجود دارد که کدهای دیگر جوملا می خواهند با کامپوننت ما تعامل داشته باشند.

  • روتر ممکن است بخواهد از روتر سفارشی کامپوننت ما برای تجزیه و ساخت مسیرهای SEF استفاده کند .
  • اگر کامپوننت ما از دسته‌ها پشتیبانی می‌کند، com_categories می‌خواهد در دسته‌ها خلاصه‌ای را بر اساس دسته‌بندی نشان دهد که شامل تعداد موارد با آن دسته است، تقسیم بر وضعیت منتشر شده .
  • اگر مؤلفه ما از فیلدهای سفارشی پشتیبانی می کند، com_fields می خواهد getContexts() را فراخوانی کند تا انواع آیتم هایی را که می توانند فیلدهای سفارشی مرتبط با آنها داشته باشند را دریافت کند.
  • اگر مؤلفه ما از انجمن‌های چندزبانه پشتیبانی می‌کند، com_associations می‌خواهد انواع آیتم‌هایی را که می‌توانند ارتباط داشته باشند، بدانند.
  • و البته جوملا می خواهد کامپوننت ما را برای گرفتن خروجی صفحه وب اجرا کند.

دلایل معرفی کلاس افزونه با بررسی نحوه تعامل سایر کدهای جوملا با برنامه افزودنی ما در جوملا 3 واضح تر می شود.

Joomla 3 component access

 

در جوملا 3 همه این بیت‌های کد دیگر به شکلی نسبتاً تصادفی در پایه کد کامپوننت ما فرو می‌روند – فراخوانی توابع در فایل‌های کمکی مختلف. در جوملا 4 این کار ساده شده است:

Joomla 4 component access

از کامپوننت‌های جوملا 4، با فراخوانی، یک دسته بر روی کامپوننت com_example ما دریافت کنید:

$extension = $app->bootComponent("com_example");

سپس می توانند تابع مورد نیاز خود را در این نمونه Extension فراخوانی کنند.

بلافاصله پس از نمونه سازی کلاس افزونه کامپوننت، کد کتابخانه جوملا تابع بوت افزونه شما را فراخوانی می کند و نمونه Dependency Injection Container را ارسال می کند:

$extension->boot($container);

این فقط فرصتی است تا به شما اجازه دهیم، خوب، واقعاً، هر کاری که دوست دارید انجام دهید. گاهی اوقات برای تنظیم کلاس های خاص برای استفاده با فراخوانی های HtmlHelper::_() استفاده می شود. یا می توانید از آن برای ذخیره یک مرجع به DIC فرزند خود استفاده کنید (که در غیر این صورت می تواند سخت باشد).

پس از اولین نمونه سازی از کامپوننت شما، جوملا نمونه را ذخیره می کند، و اگر فراخوانی دیگری وجود داشته باشد:

$extension = $app->bootComponent("com_example");

فقط نمونه برنامه افزودنی شما را بر می گرداند، نه اینکه نمونه سازی کلاس و فراخوانی مجدد ()boot را انجام دهد. حتی می‌توانید bootComponent را که کامپوننت خود را ارسال می‌کند، فراخوانی کنید، اگر نیاز به ارجاع به شیء Extension خود دارید.

کلاس Dispatcher برای کامپوننت ها

کلاس Dispatcher هر زمان که جوملا بخواهد کامپوننتی را اجرا کند تا خروجی را برای نمایش در صفحه وب بگیرد، وارد عمل می شود. کلاس یک تابع اصلی دارد: dispatch()که کامپوننت را اجرا می کند.

بنابراین برای اجرای یک کامپوننت ابتدا کلاس Extension آن را دریافت می کنید سپس:

$extension->getDispatcher()->dispatch();

اینکه چگونه کلاس Extension نمونه کلاس Dispatcher را از طریق فراخوانی getDispatcher() دریافت می کند در مستندات Dependency Injection پوشش داده شده است. کد getDispatcher() را در libraries/src/Extension/Component.php پیدا خواهید کرد - کلاس Component در این فایل در زنجیره ارث بردن نمونه Extension قرار دارد.

(شاید تعجب کنید که چرا به جای داشتن این کلاس Dispatcher اضافی، فقط یک تابع dispatch() در کلاس Extension وجود ندارد. من فکر می کنم به این دلیل است که طراحان جوملا یک الگوی Extension/Dispatcher مشترک در بین کامپوننت ها، ماژول ها و افزونه ها می خواستند، و کلاس Dispatcher برای پلاگین ها بسیار پیچیده تر است.)

برای کامپوننت ها، هدف اصلی تابع dispatch() از کلاسDispatcher این است که:

  1. بررسی کنید که از کدام کامپوننت کنترلر استفاده کنید و سپس از آن نمونه سازی کنید.
  2. متد execute() آن را فراخوانی کنید - اساساً کامپوننت MVC را اجرا می کند و با کنترلر شروع می شود.
  3. فراخوانی متد redirect() آن (برای رسیدگی به جاهایی که نیاز به تغییر مسیر HTTP است).

این کنترلر را با بررسی پارامترهای پرس و جوی HTTP، به ویژه پارامتر task، کار می کند. این وظیفه را با در نظر گرفتن قسمت‌های آن به‌عنوان <نوع کنترلر> استفاده می‌کند. سپس خواهد شد

یک نمونه از کلاس <Controller type>Controller ایجاد کنید.

تابع آن را <method> صدا کنید.

اگر پارامتر task از دست رفته باشد، DisplayController را نمونه‌سازی کرده و متد display() آن را فراخوانی می‌کند.

کنترلر با پیشوند سایت یا فضای نام مدیر پیشوند می شود تا نام کلاس کاملاً واجد شرایط را تشکیل دهد.

اگر با کامپوننت‌های جوملا ۳ آشنایی دارید، احتمالاً الان متوجه شده‌اید که این اساساً همان چیزی است که در فایل نقطه ورود (entry point) خود داشتید، همانطور که در مدل-نما-کنترلر جوملا ۳ توضیح داده شده است. پارامتر task به روشی تقریباً مشابه در جوملا ۴ نیز پردازش می‌شود، با این تفاوت که DisplayController اکنون هماهنگ‌تر با سایر کنترلرها جای گرفته است. ضمناً ممکن است در برخی کامپوننت‌های جوملا فایل AjaxController.php را ببینید. جوملا به دلیل درخواست XHR به طور خودکار به AjaxController هدایت نمی‌کند، بلکه به این دلیل است که جاوااسکریپت کلاینت، مقدار 'ajax.something' را در پارامتر task درخواست HTTP از نوع Ajax تنظیم کرده است.

اگر کامپوننت شما از پارامتر task به همان شکلی که در بالا توضیح داده شد برای هدایت به کنترلر و متد مناسب استفاده می‌کند، احتمالاً نیازی به تعریف کلاس Dispatcher مخصوص به خود نخواهید داشت و می‌توانید از کلاس استاندارد ComponentDispatcher که توسط جوملا در مسیر زیر ارائه شده است استفاده کنید.

 libraries/src/Dispatcher/ComponentDispatcher.php

کلاس‌های Extension و Dispatcher برای ماژول‌ها

این کلاس ها نقش مشابهی در ماژول ها مانند کامپوننت‌ها دارند، با این تفاوت که ساده‌تر هستند زیرا جوملا این کلاس‌ها را فقط برای اجرای ماژول و گرفتن خروجی (یعنی رندر کردن ماژول) نمونه‌سازی می‌کند.

نمونه کلاس Extension به روشی مشابه به شکل زیر بازیابی می‌شود:

$module = $app->bootModule($moduleName, $applicationName);

که در آن متغیر $moduleName نام ماژول مثلاً 'mod_example' و متغیر $applicationName برابر با 'site' یا 'administrator' است.

کلاس Extension پیش‌فرض برای ماژول‌ها در مسیر libraries/src/Extension/Module.php تعریف شده و اساساً مکانیزمی فراهم می‌کند برای دسترسی به:

  • کلاس Dispatcher (از طریق یک شیء DispatcherFactory)
  • کلاس Helper مخصوص ماژول (از طریق یک شیء HelperFactory)

مشابه کامپوننت‌ها، کلاس Dispatcher ماژول شامل تابع dispatch() است که برای اجرای کد ماژول استفاده می‌شود:

$module->getDispatcher($mod, $app)->dispatch();

در اینجا $mod یک شیء stdClass در PHP است که اطلاعات مربوط به ماژول مانند نام ماژول، شناسه، عنوان، موقعیت در قالب و غیره را دارد و $app نیز نمونه‌ای از Application است.

کلاس Dispatcher پیش‌فرض ماژول در مسیر زیر تعریف شده است:

 libraries/src/Dispatcher/ModuleDispatcher.php

کدی که در کلاس Dispatcher نوشته شده به ماژول نسخه‌هایی از چند داده کلیدی را می‌دهد که ممکن است ماژول به آن‌ها نیاز داشته باشد:

  • شیء stdClass ماژول که پیش‌تر توضیح داده شد
  • نمونه  Application
  • داده‌های ورودی (Input) – پارامترهای کوئری مربوط به URL مانند  option، view و غیره
  • پارامترهای ماژول (params)
  • نام قالب (template)

بر خلاف جوملا ۳، از جوملا ۴ به بعد این داده‌ها نسخه‌هایی کپی شده هستند، بنابراین اگر آن‌ها را تغییر دهید، داده‌های اصلی تغییر نمی‌کنند.

در کل، احتمالاً می‌توانید از کلاس‌های Extension و Dispatcher پیش‌فرض ماژول استفاده کنید و کافیست موارد زیر را ارائه دهید مثلاً برای (mod_example):

  • فایل XML مانیفست ماژول – mod_example.xml
  • فایل نقطه ورود ماژول – mod_example.php که فقط شامل کد PHP است و کلاس نیست
  • فایل Helper ماژول (که کد لازم برای دریافت داده‌ها را دارد) – یک کلاس دارای namespace در مسیر src/Helper/
  • یک فایل tmpl شامل کد HTML خروجی – در پوشه tmpl/ مثلاً tmpl/default.php

کلاس‌های Extension و Dispatcher برای پلاگین‌ها

کلاس‌های Extension و Dispatcher برای پلاگین‌ها کمی متفاوت هستند. برای پلاگین‌ها، کلاس Extension همان کد پلاگین شماست که در آن رویدادهایی که می‌خواهید به آن‌ها گوش دهید (subscribe کنید) را مشخص می‌کنید و کدی که باید هنگام فعال شدن آن رویداد اجرا شود را تعریف می‌کنید. برای جزئیات بیشتر به مستندات پلاگین جوملا مراجعه کنید.

کلاس Dispatcher پلاگین یک کلاس داخلی در جوملا است و شما نیازی به پیاده‌سازی یا بازنویسی آن در کد پلاگین خود ندارید. وقتی قرار است یک رویداد فعال (trigger) شود، جوملا با فراخوانی متد dispatch(...) روی نمونه Dispatcher، نام رویداد پلاگین و داده‌های مرتبط را ارسال می‌کند. سپس تابع dispatch() توابع مرتبط با همه پلاگین‌هایی که به آن نوع رویداد اشتراک دارند را اجرا می‌کند.