View Helper ها در زند فریمورک ۲
یه
توضیح کوچولو
View helper ها
به زبون خودم، یه سری کد هستند که از طریق
تمپلیت و layout ها
قابل دسترسی هستند و می شه باهاشون مثل
متدی باهاشون رفتار کرد و از طریقشون یه
سری کارها رو داخل تمپلیت ها انجام داد.
به
تعریف دیگه ای، می شه گفت یه سری کد reusable
دارید که میخوایید
ازشون تو تمپلیت هاتون استفاده کنید و
نمی خوایید هربار از طریق کنترلرتون به
تمپلیت ٓتون تزریق کنیدکه در این صورت می
شه براش یه view helper یا
به نوعی کلاس مجزایی نوشت و ازش در هر
تمپلیت ای استفاده کرد.
خود
زند یه سری view helper ها
واسه راه انداختن سریع کارها تو خودش داره
مثل url و
escapehtml و …
.
اما
گاهی اوقات پیش می یاد که این view
helper های موجود به
کارمون نمی یاد و نیازه که خودمون یه سری
کد و منطق رو بتونیم از طریق تمپلیت هامون
بهشون دسترسی داشته باشیم و استفاده کنیم.
در
اینگونه موارد، می شه view helper
مخصوص کاری که لازم
داریم رو ایجاد کرد.
شروع
کار
برای
ایجاد view helper تو
zf2 چند راه
وجود داره که، یه سری شون رو که اکثراً به
کار می یان رو تو این مطلب می نویسم.
ابتدا
یه کلاسی ایجاد میکنیم و منطقمون یا
کدمون واسه کاری که می خواییم انجام بده
رو توش می نویسیم و خلاص :)
البته
یه چند تا نکته هست:
اولی
اینه که نیازه از کلاس
Zend\View\Helper\AbstractHelper ارثبری
کنین. در
حقیقت نیازه اینترفیس
Zend\View\Helper\HelperInterface رو
اعمال کنید که توصیه می شه همون کلاس
AbstractHelper رو
ازش ارثبری کنید که خودش همین اینترفیس
رو اعمال کرده و سریع کارتون راه می افته.
نکته
بعدی اینه که، به آبجکتی که تو تمپلیت
هاتون بهش دسترسی دارید در حقیقت آبجکت
کلاس PhpRenderer هست
و برای اینکه به کلاستون که همون view
helper هست مثل یه متد
خود PhpRenderer دسترسی
داشته باشید، نیازه که متد __invoke
رو هم تو کلاستون
اعمال کنید.
به
عنوان مثال برای دسترسی به helper
مثل url به
این صورت عمل می کنیم:
$this->url($input);
که
در حقیقت این $this به
آبجکت کلاس PhpRenderer اشاره
داره.
و
این url اسمی
هست که برای helper مون
در نظر گرفتیم، و مقدار داده شده بهش به
عنوان پارامتر به متد __invoke کلاسمون
پاس داده خواهد شد.
تعیین
کلاس به عنوان View Helper
خوب،
حالا که کلاسمون آماده هست، نیازه که این
helper نوشته
شده رو به سیستم معرفی کنیم که بشه ازش
استفاده کرد.
اینجا
بازم یه نکتهای هست و اون اینه که یه چند
تا راه برای معرفی helper مون
داریم، که بستگی به کلاسمون داره که از
کدومشون استفاده کنیم.
اولیش
اینه که یه factory بنویسم
و برای مواقعی هست که کلاس نوشته شده
وابستگی ای به کلاسهای دیگه ای داره که
نیازه بهش داده بشه، که در حقیقت این
factory یه
تابع بدون نام هست که باید داخلش از این
کلاس آبجکت ایجاد کرده و تنظیمش کنیم یا
همون وابستگی هاش رو بهش بدیم و در نهایت
آبجکت رو برگردونیم.
دومیش هم واسه وقتیه که کلاسمون وابستگی نداره راحت می شه
کلاس مون رو به عنوان helper به
سیستم معرفی کنیم و بهش به عنوان invokable
class اشاره می شه.
نمونه
کد
برای
نوع factory به
این شکل عمل میکنیم که در کلاس Module.php
مون اینترفیس
Zend\ModuleManager\Feature\ViewHelperProviderInterface
رو اعمال کرده و یا
بطور ساده متد getViewHelperConfig که
بصورت پابلیک هم خواهد بود رو ایجاد می
کنیم.
این
متد باید آرایه ای رو برگردونه که توش
آرایه دیگه ای قرار داره که به عنوان کلید
(key) کلمه
factories رو
خواهد داشت و مقدارش هم دوباره آرایه دیگه
ای خواهد بود که بصورت associative-array
خواهد بود.
الان
در این آرایه می تونیم اسمی واسه view
helper مون تعیین کنیم
که بشه با اون اسم صداش کرد و مقدارش هم
تابع بینامی خواهد بود که یک پارامتری
هم دریافت می کنه.
سپس
داخل تابع مربوطه آبجتی از کلاسی که قبلاً
ایجاد کردهایم رو ساخته و وابستگیهای
کلاس رو هم ایجاد و بهش می دیم، در نهایت
هم آبجکت کلاسمون رو برمی گردونیم.
به
عنوان مثال، کد زیر رو در نظر بگیرید:
public function
getViewHelperConfig()
{
return array(
'factories' =>
array(
'sidebarMenu' =>
function ($helpers){
$viewRenderer =
$helpers->getServiceLocator()->get('ZfcTwigRenderer');
return new
SidebarMenu($viewRenderer);
},
)
);
}
در
این تابع، آرایه ای برمی گردونیم که یک
عنصر به اسم factories داره
که مقدارش هم آرایه دیگه ای است.
در
حقیقت تمام view helper هامون
رو در این آرایه دومی تعیین خواهیم کرد.
در
این مثال، view helper ای
به اسم sidebarMenu ایجاد
شده و هدفش اینه که کلاس SidebarMenu
رو از طریق view
ها بهش دسترسی داشته
باشیم.
ولی
از اونجایی که این کلاس وابسته به کلاس
دیگه ای هست، نیاز بوده که براش به factory
ایجاد بشه و از طریق
Service Manager (که
از طریق تنها پارامتر مربوطه قابل دسترسی
است) آبجکتی
که کلاس اصلی مون بهش وابسته هست رو دریافت
و بهش می دیم.
(پارامتری
که به این تابع داده می شه از نوع
Zend\View\HelperPluginManager هست
و برای دسترسی به Service Manager می
شه از مد getServiceLocator() استفاده
کرد.)
در
نهایت هم آبجکت ایجاد شده از کلاس اصلی
مون یا همان SidebarMenu رو
برمی گردونیم.
واسه invokable class یا راه دوم هم واسه زمانی بود که کلاس مون
وابستگی نداره و می شه مستقیم به عنوان
view helper تعیین
کرد که برای این:
ابتدا
فایل module.config.php که
داخل پوشه config ماژولمون
هست و معمولاً آرایه ای برمی گردونه رو
باز می کنیم.
سپس
به آرایه اصلی یه عنصر جدید به اسم
view_helpers که
مقدارش هم آرایه دیگه ای خواهد بود اضافه
می کنیم.
در
آرایه ایجاد شده هم عنصر دیگه ای به اسم
invokables ایجاد
میکنیم و بازم مقدارش آرایه دیگری خواهد
بود.
کار
اصلی مون در این آرایه نهایی خواهد بود و
عنصر دیگه ای ایجاد می کنیم و نامی که براش
در نظر میگیریم نام view helper مون
خواهد بود و مقدارش رو هم برابر با اسم
کلاسی که ایجاد کردهایم (همراه
با namespace اش)
می زاریم.
به
عنوان مثال، کد زیر رو در نظر بگیرید:
return array(
'view_helpers' =>
array(
'invokables' =>
array(
'sidebarMenu' =>
'Dashboard\View\Helper\SidebarMenu',
),
),
)
که
المنت ای به اسم sidebarMenu است
(و از طریق
این اسم از داخل view هامون
می شه به کلاس مربوطه مون دسترسی داشته
باشیم) ایجاد
شده و مقدارش هم آدرس کلاس مربوطه است
(همراه
namespace کاملش).
سوال؟
یه سؤالی که ممکنه
واستون ایجاد شده باشه، که چرا تو یه روش،
view helper مون
رو تو فایل config تعیین
کردیم و در روش بعدی در کلاس Module
؟
دلیل این کار این
بود که می شه تعیین کرد فایلهای config
توسط زند کش بشن که
در این صورت هر سری فایلهای config
بخاطر performace
دیگه لود نمی شن و
از کش خونده می شن.
ولی مسأله اینجاست
که متأسفانه در حال حاضر PHP نمی
تونه آبجکتها و توابع بینام یا همون
Closure ها رو
serialize و
deserialize کنه
در نتیجه اگه تابع بی نام رو داخل فایل
config تعیین
میکردید مشکلاتی واسه کش کردن پیش می
اومد و دردسر ایجاد میکرد.
به همین خاطر چون
در روش دومی یا همون invokabale class که
مقدارهامون متن (String ) هست
می شه در فایل config تعیین
کرد و در نهایت کش کرد که هر بار فایلها
دوباره خونده نشن.
ولی در رابطه با
getViewHelperConfig که
در کلاس Module تعیین
می شه، چه کش فعال باشه یا نه، این متد در
صورتی که تعیین بشه، هر بار صدا زده می
شه.
نحوه
استفاده
برای
استفاده یا صدا کردن کلاس مربوطه در
تمپلتها مون، به این صورت عمل کنیم:
$this->sidebarMenu();
توجه
کنید که راههای دیگه ای هم به غیر از این
موارد برای ایجاد view helper هست،
که اگه این مطلب نیازتون رو برآورده نمی
کنه توصیه میکنم مستندات موجود در خود
سایت زند فریمورک رو مطالعه کنید که وارد
جزئیات بیشتری می شه. ولی
با این حال، این دو روش اکثراً جوابگو
خواهد بود.
نکته:
تو این مطلب در نظر
گرفته شده که شما از zend-skeleton-application
استفاده می کنید.
منابع
امیدوارم
مفید بوده باشه. :)