آموزش کامل MVC در PHP – از صفر تا صد و به زبان ساده
در این مقاله، با ایجاد یک فریمورک کامل MVC در PHP از صفر، توسعه وب با استفاده از چارچوب الگوی معماری MVC و فناوری PHP آموزش داده شده است. آموزش کامل MVC در PHP با هدف کسب مهارت برای شروع ساخت اپلیکیشن به این شیوه ارائه شده است. با مطالعه این مقاله میتوان درک بهتری از نحوه کارکرد الگوی MVC در PHP به دست آورد و به دنبال آن، میتوان فریمورکهای MVC محور رایج PHP نظیر Phalcon و CodeIgniter را با درک، دانش و مهارت بیشتری به کار گرفت. در این آموزش، مباحث به صورت پروژه محور، گامبهگام و با بیانی ساده ارائه شدهاند.
پیشنیازهای آموزش کامل MVC در PHP
پیش از شروع آموزش کامل MVC در PHP باید آشنایی کافی با زبانهای پیاچپی، HTML و CSS وجود داشته باشد. برای یک برنامهنویس مبتدی، منابع و دورههای آموزشی بسیاری جهت شروع یادگیری و آموزش زبانهای HTML ،PHP و CSS در دسترس است.
آموزش کامل MVC در PHP در سطح پیچیدگی متوسط قرار میگیرد. با یادگیری MVC در PHP، یک برنامهنویس مبتدی که پروژه کاملی را انجام داده و آشنایی کافی با زبانهای HTML ،PHP و CSS دارد، میتواند گام بعدی را برداشته و سطح دانش و مهارتهای خود را در توسعه کاربردهای وب با فناوری PHP ارتقا دهد.
بدون شک توسعه دهندگان ارشد در این حوزه مهارت لازم را دارند و آموزش کامل MVC در PHP را فرا گرفتهاند. آموزش MVC در PHP برای افرادی مناسب است که مراحل مقدماتی آموزش توسعه وب با PHP را گذراندهاند، تعدادی پروژه ساده با PHP انجام دادهاند، درکی از HTML و CSS دارند و اکنون قصد دارند به صورت حرفهای وارد بازار کار شوند.
برنامهنویسی شیگرا یکی دیگر از مهارتهای مورد نیاز پیش از شروع آموزش کامل MVC در PHP است. ممکن است یادگیری مفاهیم شیگرایی در ابتدا کمی دشوار به نظر برسد، اما با تمرین و تکرار میتوان تسلط کافی را در این زمینه به دست آورد. بنابراین، میتوان مهارتهای مورد نیاز برای آموزش کامل MVC در PHP را به صورت زیر فهرست کرد:
در ادامه این بخش، چند نکته پیرامون آموزش MVC در PHP بیان شده است.
نکاتی پیش از شروع آموزش کامل MVC در PHP
اولین نکتهای که پیش از شروع آموزش کامل MVC در PHP میتوان به آن اشاره کرد، این است که یادگیری نحوه خطایابی (دیباگ کردن) کدها به اندازه یادگیری نحو (سینتکس) اهمیت دارد. حتی میتوان مدعی شد که خطایابی مهمتر است و بخش زیادی از مهارت برنامهنویسی را در بر میگیرد. یک برنامهنویس باید شناختی از پیامهای خطا داشته باشد. یکی از روشهای موثر در خطایابی به موقع، گرفتن خروجی آزمایشی به صورت مقطعی و در مراحل مختلف است. مثلاً، بهتر است بلافاصله پس از پایان کدنویسی یک کلاس یا تابع، از برنامه خروجی گرفته شود. در صورت بروز خطا میتوان به روشهای مختلف درخواست کمک کرد، اما بهتر است پیش از کمک گرفتن، فرد خودش سعی کند مشکل را برطرف سازد.
مطالعه و جستجو برای رفع خطا در روند آموزش کامل MVC در PHP میتواند بسیار موثر باشد. حتی یک توسعهدهنده ارشد هم در اکثر مواقع نیاز به جستجو دارد و نمیتواند همه چیز را به خاطر بسپارد. بنابراین، جستجو در اینترنت یا مراجعه به مستندات PHP برای یادآوری اینکه مثلاً اول چه پارامتری باید در یک تابع استفاده شود، امری کاملاً معمول و رایج است. در PHP این کار را میتوان با استفاده از توابع داخلی مانند var_dump ،echo یا die و dnd انجام داد. برای آموزش MVC در PHP یا یادگیری هر فناوری دیگر، کسب مهارت حل مسئله بسیار اهمیت دارد. آنچه ارزش دارد، تفکر منطقی درباره یک مسئله و یافتن راهحلی برای آن است. در آغاز آموزش کامل MVC در PHP ، لازم است شرح مختصری پیرامون برخی مفاهیم پایه ارائه شود. بنابراین، در ادامه، ابتدا توضیحاتی پیرامون چیستی یک فریمورک به زبان ساده ارائه شده است.
فریم ورک چیست ؟
یک برنامهنویس میتواند کدنویسی را از صفر و از یک صفحه خالی (مثلاً index.php یا index.htm) شروع کند. اما در صورتی که برنامهنویسان حرفهای و متخصص کدهایی را نوشته باشند که بتوان بارها در پروژههای مختلف از آنها استفاده کرد و این کدها ایمن باشند و به خوبی کار کنند، میتوان به جای شروع از نقطه صفر از کدهای آماده استفاده کرد. این دقیقاً همان چیزی است که به آن فریمورک یا چارچوب گفته میشود. ممکن است در ابتدا استفاده از فریمورکها پیچیده و دشوار به نظر برسد. یک فریمورک میتواند روند کار را برای تیم توسعه تسریع کند.
میتوان MVC را نیز نوعی فریمورک یا چارچوب در نظر گرفت. زیرا میتوان برخی از کدهایی را که برای برپایی ساختار MVC استفاده میشوند، در سایر پروژهها نیز به کار گرفت. به بیان دقیقتر، MVC الگویی است که پیادهسازی و ایجاد یک فریمورک را میتوان بر اساس آن انجام داد. فریمورکهای CSS نظیر بوتاسترپ یا فریمورکهای PHP مثل CodeIgniter، سوئیفت و سایر فریمورکها، نمونهای از مجموعه کدهای آماده هستند که برای استفاده در توسعه اپلیکیشن به کار گرفته میشوند. برای درک و آموزش کامل MVC در PHP باید چنین چارچوبی را از پایه بنا کرد و یک فریمورک MVC را توسعه داد. این کار در این مقاله انجام شده است. برای آموزش کامل MVC در PHP باید ابتدا درکی از چیستی الگوی معماری MVC حاصل شود. این کار در ادامه انجام شده است.
MVC چیست ؟
MVC سرنامی برای «Model, View, Controller» (مدل، نما، کنترلر) و یک الگوی توسعه اپلیکیشن یا یک روش برنامهنویسی است که امکان جداسازی نماها را از مدلها فراهم میکند. مدلها برای بهروزرسانی و کار با دادهها در پایگاه داده استفاده میشوند و نماها به تعامل با کاربر میپردازند. کنترلرها دادهها را از مدلها دریافت کرده و نماها را بهروزرسانی میکنند. ممکن است مفهوم MVC در ابتدا کمی پیچیده به نظر برسد اما روشی بسیار کاربردی و رایج است و به طور گستردهای از این ساختار استفاده میشود.
به بیان ساده، MVC روشی برای سازماندهی کدها به حساب میآید. این سازماندهی به گونهای انجام میشود که سایر توسعهدهندگان بتوانند درکی از کار انجام شده داشته باشند. در واقع MVC یک روش از پیش تعیین شده برای ساختاردهی به کدها محسوب میشود. استفاده از MVC در پروژههای گروهی اهمیت دارد و کار تیمی را بسیار سادهتر میکند. زیرا محل نوشتن کدهای مربوط به یک بخش خاص با استفاده از MVC مشخص است و اعضای تیم میدانند که کدهای مربوطه در کجا قرار دارد. بنابراین خطایابی و از بین بردن باگها با استفاده از الگوی MVC بسیار سادهتر میشود. میتوان از MVC به عنوان ساختاری برای تفکیک دغدغهها (Separation of Concerns) نام برد.
نما در MVC چیست ؟
لایه نما (View) در MVC شامل تمام عناصر نشانهگذاری (Markup) است. به آنچه که کاربر نهایی قرار است ببیند، نما گفته میشود. با استفاده از الگوی MVC میتوان طراحی و ساخت فرانتاند و تجربه کاربری را بدون تغییر منطق یا ایجاد اختلال در بکاند انجام داد و مسئولیت آن را به یک تیم مجزا سپرد. بنابراین، اگر به جای اینکه تمام کدها در یک فایل طولانی نوشته شوند، کدهای HTML و CSS در یک فایل جداگانه قرار بگیرند و تنها توسعه دهندگان فرانتاند مسئولیت آن فایلها را برعهده داشته باشند، یک لایه نما ایجاد شده است.
مدل در MVC چه کاری انجام میدهد؟
لایه مدل در MVC با دادهها سر و کار دارد. مدل مسئولیت مدیریت دادهها را در پایگاه داده برعهده دارد. روش اتصال به پایگاه داده، نحوه تعامل با دادهها در پایگاه داده، شیوه بهروزرسانی، ایجاد، حذف و درج دادهها در پایگاه داده همگی در لایه مدل انجام میشوند. بنابراین هر متد و تابعی که به دستکاری دادهها مربوط میشود، در لایه مدل جای میگیرد.
کنترلر در MVC چگونه عمل میکند؟
آنچه که منطق را مدیریت میکند، کنترلر نامیده میشود. به بیان ساده، کنترلر وظیفه برقراری ارتباط میان مدل و نما را برعهده دارد. بنابراین، اتفاقی که در یک چارچوب MVC رخ میدهد به این صورت است که اطلاعات از URL دریافت میشوند. سپس، اولین پارامتر در URL مشخص خواهد کرد که باید از کدام کنترلر استفاده شود. بدین ترتیب میتوان با استفاده از آن کنترلر، هر نوع منطق لازم را پیادهسازی کرد. بنابراین کنترلر، هر دادهای را که مورد نیاز باشد، برای نمایش دادن به کاربر از مدل دریافت میکند. در واقع، منطق لازم توسط کنترلر روی دادههای دریافت شده اعمال میشود و نتیجه حاصل برای نمایش به لایه نما ارسال میشود. به این ترتیب، با استفاده از MVC تمام کدها در سه قسمت توزیع شدهاند. در ادامه توضیحات بیشتری پیرامون نحوه عملکرد الگوی MVC ارائه شده است.
کارکرد اپلیکیشن MVC چگونه است؟
در این بخش، چگونگی تعامل کاربر با یک اپلیکیشن MVC شرح داده شده است. نحوه عملکرد یک اپلیکیشن MVC مطابق تصویر زیر به این صورت است که ابتدا کاربر با کنترلر ارتباط برقرار میکند. در واقع، وقتی کاربر دکمهای را فشار میدهد، از یک لینک بازدید یا یک فرم را ارسال میکند، کنترلر مسئولیت مدیریت این عملیات (Actions) را بر عهده دارد. در واقع به همین دلیل است که به متُدهای نوشته شده در کلاسهای کنترلر Action گفته میشود. در واقع، آنچه را که کاربر با آن در تعامل است، اکشن مینامند.
در مرحله بعد، کنترلر یک درخواست یا بهروزرسانی را به مدل ارسال میکند و در صورت درخواست داده، مدل دادهها را به کنترلر میفرستد. کنترلر دادهها را بهروزرسانی کرده، آنها را باز گردانده یا حذف میکند. در این مرحله، کنترلر ممکن است پردازشهای بیشتری را روی دادهها انجام دهد و بر اساس نیاز، یک نما را تولید یا بهروزرسانی کند. آنچه که کاربر میبیند، همان نمای تولیدی یا بهروزرسانی شده است. بنابراین، کاربر از کنترلر استفاده میکند و نما را میبینید. در توسعه اکثر وب اپلیکیشنها از الگوی MVC استفاده میشود.
همچنین، در مورد جریان کارکردی در MVC رویکرد دیگری هم به این صورت وجود دارد که مدل پس از دریافت درخواست از کنترلر به طور مستقیم با نما در ارتباط است و کنترلر در بهروزرسانی یا تولید نماها نقشی ندارد. میتوان از این رویکرد نیز استفاده کرد. اگرچه، ماهیت کنترلر، همانطور که از نامش پیداست، در مدیریت جریان دادهها و منطق مورد نیاز اپلیکیشن شکل میگیرد. بنابراین، رویکردی که در ابتدا شرح داده شد، منطقیتر به نظر میرسد. به این ترتیب الگوی معماری MVC تعریف و به بیان ساده شرح داده شد. پیش از شروع آموزش کامل MVC در PHP باید نرمافزارهای مورد استفاده در این آموزش معرفی شوند. این کار در ادامه انجام شده است.
نرمافزارهای مورد نیاز برای آموزش MVC در PHP چه هستند ؟
برای کدنویسی میتوان از هر ویرایشگری استفاده کرد، اما سایر نرمافزارها باید یکسان باشند. در این مقاله برای آموزش کامل MVC در PHP از محیط توسعه XAMPP استفاده شده است. همچنین برای کدنویسی و ویرایش کدها میتوان از ویرایشگر Atom استفاده کرد. برای ذخیره کدها و کنترل نسخه نیز میتوان از Bitbucket و گیت استفاده کرد.
Atom توسط گیتهاب ساخته شده است و به همین دلیل با گیت هماهنگی زیادی دارد و ویرایشگری کاربردی به حساب میآید. Atom رایگان و برای مک او اس یا ویندوز در دسترس است. به این ترتیب، پس از نصب و راهاندازی نرمافزارهای مورد نیاز، زمان آن فرا رسیده است تا آموزش کامل MVC در PHP را آغاز کرد.
آموزش کامل MVC در PHP
در این بخش، آموزش کامل MVC در PHP ارائه شده است. ساختار URL یکی از مهمترین مباحث در آموزش کامل MVC در PHP به حساب میآید. URL سرنامی برای عبارت «Uniform Resource Locator» و به معنی «موقعیتیاب منابع یکپارچه» است.
همانطور که از نامش پیداست، URL یک نشانی است که برای دسترسی به منابعی خاص مورد استفاده قرار میگیرد. دسترسی به منابع با استفاده از URL در MVC دارای ساختار مشخصی است. در ادامه توضیحات لازم پیرامون این ساختار ارائه شده است.
ساختار URL در MVC
پس از نصب و راهاندازی نرمافزارهای لازم، در این بخش از آموزش کامل MVC در PHP نحوه سازماندهی و ساختار URL بر اساس معماری MVC شرح داده شده است. در صورتی که پروژهای به نام ruah وجود داشته باشد، آدرس ریشه اپلیکیشن یا Root به صورت زیر خواهد بود:
1localhost/ruah
در این ریشه، همه چیز از یک فایل عبور میکند و این فایل index.php خواهد بود که آدرس آن به صورت زیر است:
1localhost/ruah/index.php
اما در این پروژه از افزونهای استفاده نخواهد شد، بنابراین URL چیزی شبیه به آدرس زیر خواهد بود:
1localhost/ruah/users/registration
به این ترتیب، اولین بخش URL فوق، یعنی «users» برای اپلیکیشن تعیین میکند که از چه کنترلری باید استفاده شود. بنابراین، در اینجا users به عنوان کنترلر در نظر گرفته میشود. در URL فوق، بخش بعدی پس از users که «Registration» است، همان اکشن یا فراخوانی متُدی خواهد بود که در کنترلر users تعریف میشود. پس از تعیین اکشن در URL، باید پارامترهای مورد نیاز آن اکشن را ارجاع داد. به عنوان مثال، اگر قصد دسترسی به جدول کاربران یا جزئیات اطلاعات آنها وجود داشته باشد، میتوان از URL زیر استفاده کرد:
1localhost/ruah/users/detail/658
آدرس URL فوق، به وسیله کنترلر users، متد details را فراخوانی میکند و شناسه 658 را به عنوان یک پارامتر به این متد ارجاع میدهد. همانطور که ملاحظه میشود، شفافیت و سادگی بیشتری با استفاده از MVC در ساختار URL ایجاد میشود. در حالت عادی و بدون استفاده از MVC، آدرسدهی مشابه URL زیر است:
1localhost/ruah/users_details.php?id=658
در ادامه آموزش کامل MVC در PHP ، ساختار پوشهها با الگوی MVC در PHP شرح داده شده است.
ساختار پوشهها با الگوی MVC در PHP
برای ایجاد و سازماندهی ساختار پوشهها بر اساس الگوی MVC، میتوان از خط فرمان یا کاوشگر فایل در سیستم عامل استفاده کرد. در این آموزش از ترمینال و سیستم عامل مک OS استفاده شده است. ابتدا باید در آدرس فضای کاری (Working Directory) قرار گرفت. آدرس فضای کاری، «Applications/XAMPP/htdocs» است. باید در محل فعلی یک دایرکتوری جدید با نام ruah ایجاد شود:
1mkdir ruah
پس از ایجاد دایرکتوری ruah، پوشه فعلی باید با دستور cd به ruah تغییر داده شود:
1cd ruah
بعد از قرار گرفتن در پوشه کاری پروژه (ruah)، نوبت به اجرای ویرایشگر Atom میرسد. این کار را میتوان با دستور زیر انجام داد:
1atom .
با اجرای Atom، یک پروژه خالی آماده برای شروع کار است. باید با راست کلیک کردن روی دایرکتوری ruah، پوشههای (دایرکتوری | فولدر) مورد نیاز پروژه را ایجاد کرد. این پوشهها شامل موارد زیر است:
- app
- config
- core
- css
- fonts
- js
همچنین، یک فایل به نام «index.php» نیز باید ایجاد شود. میتوان در این فایل عبارت «Welcome to ruah MVC» را نوشت. در ادامه ایجاد ساختار فایلهای پروژه، باید پوشههای داخل دایرکتوری app را ایجاد کرد. پوشههای ایجاد شده در داخل پوشه app بر اساس الگوی MVC ایجاد میشوند و در اینجا الگوی MVC تاثیر خود را در ساختار پوشهها نشان میدهد. پوشههایی که باید ایجاد شوند، در ادامه فهرست شدهاند:
- controllers
- models
- views
یک فولدر دیگر به نام lib نیز باید در دایرکتوری app ایجاد شود. در داخل پوشه lib فولدر دیگری به نام «helpers» ایجاد میشود. در ادامه آموزش کامل MVC در PHP ، یک جمعبندی و توضیح کلی پیرامون پوشههای ایجاد شده ارائه شده است. تصویر ساختار پوشههای پروژه PHP بر اساس الگوی MVC در ادامه آمده است:
جمعبندی ساختار فایل در پروژه ایجاد فریمورک MVC در PHP
برای پیادهسازی فریمورک MVC در PHP ، یک پوشه یا دایرکتوری اصلی وجود دارد که به آن پوشه ریشه (Root Folder) گفته میشود. اولین پوشه در داخل پوشه ریشه، app نام دارد. پوشه app محلی است که فرانتاند و فایلهای اپلیکیشن در داخل آن قرار میگیرند. فولدر بعدی در پوشه ریشه، config نام دارد که برای پیکربندی فریمورک استفاده میشود.
کلاسهای هستهای (Core Class) که برای ساخت فریمورک استفاده میشوند، در پوشه core قرار میگیرند. علاوه بر آن، برخی کلاسهای دیگر نیز در پوشه core ایجاد خواهند شد. فایلهای CSS، جاوا اسکریپت و فایلهای فونت نیز به ترتیب در پوشههای js ،css و fonts قرار داده میشوند. برای پیادهسازی یک پروژه MVC در PHP، پس از ایجاد فریمورک، کار عمدهای که برای توسعه یک وباپلیکیشن انجام میشود، ایجاد کنترلرها، مدلها و نماها خواهد بود.
پیکربندی آپاچی با .htaccess
همانطور که در بخش تشریح ساختار URL بیان شد، در پیادهسازی فریمورک MVC PHP ، برای آدرسدهی از الگوی MVC استفاده خواهد شد. همچنین بیان شد که هر آنچه که وارد اپلیکیشن میشود، فارق از آنچه در URL به کار رفته، از مسیر index.php عبور خواهد کرد. بنابراین به بیان ساده، در این بخش باید سرور را به گونهای تنظیم کرد تا این کار را انجام دهد.
یعنی سرور همه چیز را از طریق فایل index.php عبور دهد. برای انجام این کار میتوان سرور و آپاچی را با یک فایل htaccess بازنویسی کرد. بنابراین، باید یک فایل در پوشه ریشه با نام «.htaccess» ایجاد شود. در این فایل باید کدهای زیر را وارد کرد:
1RewriteEngine On
2
3RewriteCond %{REQUEST_FILENAME} !-d
4RewriteCond %{REQUEST_FILENAME} !-f
5RewriteCond $1 !^(config|core|css|js|fonts|robots\.txt)
6
7RewriteRule ^(.+)$ index.php/$1 [L]
در کدهای فوق، یک قانون (RewriteRule) نوشته شده است تا همه چیز در URLها، به غیر از آنچه در برخی از پوشهها قرار دارد، از مسیر index.php عبور کند. یعنی دیگر نیازی نباشد که این کار (یعنی عبور همه چیز از طریق index.php) هر بار در URL ذکر شود. برای انجام این کار، ابتدا باید RewriteEngine را در آپاچی فعال کرد. سپس، در خطهای ۳ تا ۵ شرطهای قانون بازنویسی URL تعیین شدهاند. دو شرط اول تعیین میکنند که آنچه در URL استفاده میشود از نوع فایل یا پوشه نباشد.
پس از آن، از اعمال شرایط تغییر مسیر و عبور از index.php برای پوشههای fonts ،js ، css ،core ،config و فایل robots.txt صرف نظر میشود. این کار در خط پنجم انجام شده است. در صورتی که تغییر مسیر به index.php روی همه پوشهها اعمال شود، مرورگر امکان بیرون کشیدن و دریافت فایلهای CSS و جاوا اسکریپت را از پوشههای css و js نخواهد داشت. بنابراین، در خط پنجم، به نرمافزار وبسرور آپاچی اعلام میشود که قانون بازنویسی URL را برای پوشههای fonts ،js ، css ،core ،config و فایل robots.txt انجام ندهد. یعنی اگر نیاز به دسترسی به پوشههای ذکر شده وجود داشت، از این قانون بازنویسی استفاده نشود. در ادامه آموزش کامل MVC در PHP، ساختار فایل index.php و کدنویسی آن شرح داده شده است.
پیکربندی فایل index.php
با توجه به اینکه همه چیز از طریق index.php مسیریابی میشود، باید اطمینان حاصل کرد نقطه شروع اپلیکیشن از این فایل باشد. کدهای مربوط به پیکربندی فایل index.php در ادامه آمده است:
1<?php
2 sessions_start();
3define('DS', DIRECTORY_SEPARATOR);
4define('ROOT', dirname(__FILE__));
5$url = isset($_SERVER['PATH_INFO']) ? explode('/', ltrim($_SERVER['PATH'], '/')) : [];
6require_once(ROOT . DS . 'core' . DS . 'bootstrap.php');
توضیحات کدهای فایل index.php
در کدهای فوق، ابتدا تگ PHP باز میشود. در خط بعد، یک جلسه با دستور sessions_start() آغاز میشود. در دو خط بعدی، دو مقدار ثابت تعریف میشود. در سیستم عاملهای لینوکس، مک و ویندوز جدا کننده دایرکتوری متفاوت است. به همین دلیل، با استفاده از امکانی که PHP ارائه میدهد، میتوان جدا کننده را تعریف کرد. بنابراین در خط سوم یک جداکننده دایرکتوری با نام DS تعریف شده است. در خط چهارم نیز یک مقدار ثابت با نام ROOT تعریف میشود و آدرس دایرکتوری ریشه در آن قرار میگیرد. بنابراین، اگر دستور echo ROOT اجرا شود، آدرس URL پوشه ریشه در خروجی نمایش داده خواهد شد. در خط پنجم، یک آرایه از URL ایجاد میشود.
در واقع یک مسیر با «/» از هم جدا شده و به یک آرایه تبدیل میشود. با استفاده از دستور var_dump($url) میتوان آنچه در متغیر $url در خط پنجم تولید میشود را مشاهده کرد. به عنوان مثال اگر مسیر به صورت «users/register/568» باشد، users به عنوان اولین عنصر آرایه و به ترتیب register و عدد ۵۶۸ نیز به عنوان عناصر بعدی آرایه در متغیر $url ذخیره خواهند شد. در خط پایانی هم الزام به استفاده از فایل bootstrap.php در پوشه core تعریف میشود. فایل bootstrap.php ارتباطی با فریمورک CSS ندارد بلکه فایل خودگردانسازی است که مدیریت اپلیکیشن را انجام خواهد داد. پس از ملزم کردن index.php به استفاده از فایل bootstrap.php، باید این فایل را در پوشه core ایجاد کرد. به این ترتیب، ادامه آموزش کامل MVC در PHP به آمادهسازی فایل bootstrap.php اختصاص دارد.
برپایی فایل bootstrap.php
فایل bootstrap.php کار بارگذاری خودکار برخی از کلاسها را انجام میدهد. کاری که اساساً در دایرکتوری core انجام میشود، ایجاد تعدادی کلاس است. همانطور که بیان شد، باید آشنایی کافی با برنامهنویسی شیگرا پیش از شروع آموزش کامل MVC در PHP وجود داشته باشد. اما، به طور کلی میتوان یک کلاس را مانند نقشه ساختی برای یک شی در نظر گرفت. در PHP نیز از شیگرایی برای امکان استفاده مجدد از کدها استفاده میشود. کدهای فایل bootstrap.php به صورت زیر نوشته میشوند:
1<?php
2 // Load Configuration and helper functions
3 require_once(ROOT . DS . 'config' . DS . 'config.php');
4 require_once(ROOT . DS . 'app' . DS . 'helpers' . DS . 'functions.php');
5
6 // Autoload classes
7 function__autoload($className) {
8 if(file_exists(ROOT . DS . 'core' . DS . $classname . '.php')) {
9 require_once((ROOT . DS . 'core' . DS . $classname . '.php');
10 } elseif (ile_exists(ROOT . DS . 'app' . DS . 'controllers'. DS . $classname . '.php')) {
11 require_once(ROOT . DS . 'app' . DS . 'controllers'. DS . $classname . '.php');
12 } elseif (ile_exists(ROOT . DS . 'app' . DS . 'models'. DS . $classname . '.php')) {
13 require_once(ROOT . DS . 'app' . DS . 'models' . DS . $classname . '.php');
14 }
15}
16
17//Route the request
18Router::route($url);
در بخش اول کدهای فایل bootstrap.php، از فایلهای config.php در پوشه config و فایل functions.php در پوشه helpers برای بارگذاری توابع Helper استفاده میشود. بنابراین، باید این فایلها را در پوشههای مربوطه ایجاد کرد. همچنین، یک فایل به نام helpers.php نیز باید در پوشه helpers ایجاد شود. فایل functions.php، فایل helpers.php را در بر خواهد داشت. به بیان ساده، فایل functions.php حاوی فهرستی از توابع Helper و فایلهای ایستایی است که بارگذاری خواهند شد. در فایل helpers.php نیز توابع helper مورد نیاز، تعریف خواهند شد. همچنین، باید فایل config.php را نیز در پوشه config ایجاد کرد.
بخش دوم کدهای فایل bootstrap.php مربوط به بارگذاری خودکار کلاسها است. در این بخش، یک تابع به نام autoload تعریف میشود. باید پارامتری به نام className به این تابع ارجاع داد. در تابع autoload، از گزارههای if و else برای بررسی وجود داشتن برخی فایلها استفاده میشود تا در صورتی که فایل مربوطه وجود داشت، از این فایل استفاده شود و در غیر اینصورت به گزاره if بعدی مراجعه خواهد شد. در اولین گزاره if، بررسی موجود بودن className در پوشه core انجام میشود. در گزاره if بعدی، بررسی موجود بودن فایل در پوشه app/controllers انجام خواهد شد. به این ترتیب، کلاسهایی که در کنترلر، در مدلها و در پوشه core موجود هستند در زمان استفاده به صورت خودکار بارگذاری خواهند شد. این کار منجر به صرفهجویی در زمان میشود. زیرا هر بار که کلاس جدیدی اضافه میشود، نیازی به استفاده از دستور require_once نخواهد بود.
کار بعدی که در فایل bootstrap باید انجام شود، مسیریابی URL است. برای این کار از کلاسی به نام Router استفاده میشود. یک متد ایستا به نام route ایجاد میشود. این متد یک پارامتر را به نام $url میپذیرد. حال باید در پوشه core فایل مربوط به مسیریابی URL را ایجاد کرد. نام این فایل باید دقیقاً به صورت «Router.php» باشد. متغیر $url در فایل index.php تعریف شده است. همانطور که بیان شد، این متغیر حاوی مسیر در قالب آرایه است. در ادامه آموزش کامل MVC در PHP ، کدنویسی متد مسیریابی در Router.php انجام شده است.
مسیریابی
کدهای مربوط به متد مسیریابی برای پیادهسازی فریمورک MVC در PHP به صورت زیر است:
1<?php
2
3 class Router {
4
5 public static function route($url) {
6
7 //controller
8 $controller = (isset($url[0]) && $url[0] != '') ? ucwords($url[0]): DEFAULT_CONTROLLER;
9 $controller_name = $controller;
10 array_shift($url);
11
12 //action
13 $action = (isset($url[0]) && $url[0] != '') ? $url[0] . 'Action': 'indexAction';
14 $action_name = $action;
15 array_shift($url);
16
17 //params
18 $queryParams = $url
19
20 $dispatch = new $controller($controller_name, $action);
21
22 if(method_exists($controller, $action)) {
23 call_user_func_array([$dispatch, $action], $queryParams);
24 } else {
25 die('That method does not exist in the controller \"' . $controller_name . '\"\);
26 }
27 }
28 }
برای خوانایی بیشتر، کدهای مسیریابی در فایل Router.php، به بخشهای مختلفی تقسیم شدهاند. در ادامه هر یک از این بخشها شرح داده شدهاند.
استخراج متد کنترلر از URL
اولین کاری که باید انجام شود، استخراج کنترلرها از آرایه URL است. همانطور که پیشتر بیان شد، اولین بخش یک URL مربوط به کنترلر است. به عنوان مثال، کنترلر در URL زیر، user خواهد بود:
1localhost/ruah/users/register/568
به بیان ساده، کنترلر از URL استخراج میشود و در متغیر controller قرار داده میشود. با توجه به اینکه کنترلرها از نوع کلاس هستند، نام آنها باید با حرف بزرگ شروع شود. به همین دلیل در کدهای فوق از تابع پیشساخته php به نام ucwords استفاده شده است. اگر در آدرس URL وارد شده هیچ کنترلری وجود نداشته باشد و مثلاً آدرس URL به صورت «localhost/ruah» باشد، چه اتفاقی میافتد؟ برای چنین مواقعی، در کدهای بالا یک مقدار ثابت به نام «DEFAULT_CONTROLLER» در نظر گرفته شده است. این مقدار ثابت را باید در فایل config.php (در پوشه config) تعریف کرد:
1<?php
2
3 //Default controller if there isn't one defined in the URL:
4 define ('DEAFULT_CONTROLLER' , "HOME');
بخش بعدی کلاس روتر مربوط به دریافت متد اکشن است که در ادامه پیرامون کدهای این بخش توضیحاتی ارائه شده است.
استخراج متد اکشن از URL
در بخش «action» از کلاس مسیریابی، قسمت بعدی URL (قسمت بعد از کنترلر) به عنوان متد اکشن در نظر گرفته میشود و یک کلمه «Action» نیز به آخر نام آن اضافه شده است. سپس، این قسمت به وسیله تابع array_shift از آرایه $url حذف میشود.
دریافت پارامتر از URL
همانطور که پیشتر بیان شد، در الگوی MVC، قسمت آخر آدرس URL به عنوان پارامترهای ورودی متد اکشن در نظر گرفته میشوند. بنابراین در بخش سوم کلاس روتر، که با کامنت «params» مشخص شده، هر آنچه که از آرایه $url باقی مانده در متغیر $queryParams قرار داده میشود.
تعریف شی کنترلر
برای تعریف شی کنترلر در خط بیستم کدهای مربوط به کلاس Router، یک شی به نام «dispatch» تعریف میشود. یک کنترلر جدید با نام controller_name و یک action به عنوان متد شی کنترلر تعریف میشود. سپس، شرط if، وجود داشتن شی کنترلر و متد اکشن را بررسی میکند. در صورت برقرار بودن شرط، تابعی به نام call_user-func_array اجرا میشود. این تابع، پارامترهای دریافت شده از URL (یعنی queryParams)، شی کلاس و متدش را به صورت یک آرایه دریافت میکند.
در واقع کاری که انجام میشود به این صورت است که یک شی جدید ایجاد و یک متد در داخل آن شی فراخوانی میشود. همچنین، پارامترهای queryParams به آن متد ارجاع داده میشوند و در صورتی که متد فراخوانی شده در کنترلر مربوطه وجود نداشته باشد، یک پیام خطا ارسال میشود. اما کلاس users هنوز ایجاد نشده و در نتیجه با اجرای کلاس Router در خروجی خطا چاپ میشود. کلاس users در ادامه ایجاد خواهد شد. پیش از آن، ایجاد کلاس والدی که تمام کنترلرها از آن گسترش داده میشوند، در ادامه، آموزش کامل MVC در PHP انجام شده است.
ایجاد کلاس والد Application
در این بخش از آموزش کامل MVC در PHP ، کلاسی به نام Application ایجاد میشود. Application کلاس والد تمام کنترلرها در فریمورک MVC خواهد بود. بنابراین، باید در پوشه core یک فایل جدید به نام «application.php» ایجاد شود. کدهای مربوط به کلاس Application در ادامه آمده است.
1<?php
2 namespace Core;
3
4 class Application {
5 public function __construct() {
6 $this->_set_reporting();
7 $this->_unregister_globals();
8 }
9
10 private function _set_reporting() {
11 if(DEBUG) {
12 error_reporting(E_ALL);
13 ini_set('display_errors', 1);
14 } else {
15 error_reporting(0);
16 ini_set('display_errors', 0);
17 ini_set('log_errors', 1);
18 ini_set('error_log', ROOT . DS .'tmp' . DS . 'logs' . DS . 'errors.log');
19 }
20 }
21
22 private function _unregister_globals() {
23 if(ini_get('register_globals')) {
24 $globalsAry = ['_SESSION', '_COOKIE', '_POST', '_GET', '_REQUEST', '_SERVER', '_ENV', '_FILES'];
25 foreach( $globalsAry as $g) {
26 foreach($GLOBALS[$g] as $k => $v) {
27 if($GLOBALS[$k] === $v) {
28 unset($GLOBALS[$k]);
29 }
30 }
31 }
32 }
33 }
34
35
36 }
در ابتدای کلاس Application، تابع construct تعریف شده است. این تابع وقتی اجرا خواهد شد که شی ایجاد میشود. در واقع، هر بار که یک شی ایجاد میشود، میتوان با تابع construct عملیاتی را انجام داد. تابع construct برای عبور دادن پارامترها در ابتدای ایجاد یک شی مورد استفاده قرار میگیرد.
دو متد در داخل کلاس Application باید ایجاد شوند و برای دسترسی به آنها از this در تابع construct استفاده شده است. این دو متد «set_reporting» و «unregister_globals» نام دارند. پس از تعریف تابع construct، هر یک از متدهای set_reporting و unregister_globals تعریف شدهاند. در متد set_reporting عملیات مربوط به گزارش خطا انجام میشود. باید متغیر DEBUG که در متد set_reporting به کار گرفته شده است را در فایل config.php به صورت زیر تعریف کرد:
1 define('DEBUG', true);
دومین متدی که در کلاس Application تعریف میشود، متد unregister_globals است که در ادامه پیرامون آن توضیحاتی ارائه شده است.
متد unregister_globals
در توسعه وباپلیکیشن با PHP، قابلیتی به نام «Register Globals» ارائه شده است. ایده قابل تحسینی در پس Register Globals نهفته است، اما این قابلیت خطرات امنیتی با خود به همراه دارد. در این قابلیت، برای کوکیها، جلسات، پستها و تمام آرایههای سراسری متغیرهایی در داخل اپلیکیشن PHP ایجاد میشود تا توسعهدهنده بتواند از آنها استفاده کند. اما ممکن است از این امکان سوءاستفاده شود و مثلاً با جا زدن یک متغیر به جای متغیر دیگر، به اطلاعات پایگاه داده دسترسی پیدا کرد.
بنابراین، متد unregister_globals برای حذف این قابلیت تعریف شده است. اگرچه، همچنان از آرایههای سراسری مثل Session ،Cookie ،Post و سایر موارد استفاده خواهد شد. اما، با unregister_globals اطمینان حاصل میشود که قابلیت Register Globals به کار گرفته نخواهد شد. ایجاد کلاس کنترلر در ادامه آموزش کامل MVC در PHP انجام شده است. کلاس کنترلر کلاس اپلیکیشن را بسط خواهد داد.
ایجاد کلاس Controller
در این بخش از آموزش کامل MVC در PHP ، نحوه ایجاد کلاس کنترلر پایه (هستهای) شرح داده شده است. فایل کلاس کنترلر با نام Controller.php در پوشه core ایجاد میشود. کدهای مربوط به این فایل در ادامه آمده است:
1<?php
2 namespace Core;
3 use Core\Application;
4
5 class Controller extends Application {
6 protected $_controller, $_action;
7 public $view, $request;
8
9 public function __construct($controller, $action) {
10 parent::__construct();
11 $this->_controller = $controller;
12 $this->_action = $action;
13 $this->request = new Input();
14 $this->view = new View();
15 }
16
17 protected function load_model($model) {
18 $modelPath = 'App\Models\\' . $model;
19 if(class_exists($modelPath)) {
20 $this->{$model.'Model'} = new $modelPath();
21 }
22 }
23
24 public function jsonResponse($resp){
25 header("Access-Control-Allow-Origin: *");
26 header("Content-Type: applicaton/json; charset=UTF-8");
27 http_response_code(200);
28 echo json_encode($resp);
29 exit;
30 }
31
32 }
همانطور که بیان شد، کلاس کنترلر زیرکلاس Application است و آن را بسط میدهد. این مسئله در تعریف کلاس کنترلر در خط سوم مشخص شده است. وقتی یک کلاس از کلاس والد خود بسط داده میشود، به تمام متدهای کلاس والد دسترسی خواهد داشت. اولین کاری که پس از تعریف کلاس کنترلر انجام میشود، ایجاد تعدادی خصیصه (Property) است. دو خصیصه محافظت شده (Protected Property) به نامهای $_controller و $_action به همراه یک خصیصه عمومی (Public Property) به نام $view تعریف شده است.
در خط نهم، تابع construct تعریف میشود که به دو پارامتر ورودی نیاز دارد. اولین پارامتر، کنترلر و دومین پارامتر، یک اکشن است. در خط دهم، تابع construct از کلاس والد (Application) فراخوانی میشود تا بتوان دو متد set_reporting و unregister_globals را از کلاس کنترلر اجرا کرد. از خصیصههای تعریف شده برای راهاندازی کنترلر و متد مربوط به آن و همچنین ایجاد یک کلاس نما در تابع construct استفاده میشود. در ادامه، کدنویسی کلاس نما یا View شرح داده شده است.
ایجاد کلاس View
کلاس View نیز مانند کلاس کنترلر در پوشه core با نام «View.php» ایجاد میشود. باید به یاد داشت که نام همه کلاسها باید با حرف بزرگ نوشته شود. کدهای کلاس View به صورت زیر است:
1<?php
2namespace Core;
3
4 class View {
5 protected $_head, $_body, $_siteTitle = SITE_TITLE, $_outputBuffer, $_layout = DEFAULT_LAYOUT;
6
7 public function __construct() {
8
9 }
10
11 public function render($viewName) {
12 $viewAry = explode('/', $viewName);
13 $viewString = implode(DS, $viewAry);
14 if(file_exists(ROOT . DS . 'app' . DS . 'views' . DS . $viewString . '.php')) {
15 include(ROOT . DS . 'app' . DS . 'views' . DS . $viewString . '.php');
16 include(ROOT . DS . 'app' . DS . 'views' . DS . 'layouts' . DS . $this->_layout . '.php');
17 } else {
18 die('The view \"' . $viewName . '\" does not exist.');
19 }
20 }
21
22 public function content($type) {
23 if($type == 'head') {
24 return $this->_head;
25 } elseif($type == 'body') {
26 return $this->_body;
27 }
28 return false;
29 }
30
31 public function start($type) {
32 $this->_outputBuffer = $type;
33 ob_start();
34 }
35
36 public function end() {
37 if($this->_outputBuffer == 'head') {
38 $this->_head = ob_get_clean();
39 } elseif($this->_outputBuffer == 'body') {
40 $this->_body = ob_get_clean();
41 } else {
42 die('You must first run the start method.');
43 }
44 }
45
46 public function siteTitle() {
47 return $this->_siteTitle;
48 }
49
50 public function setSiteTitle($title) {
51 $this->_siteTitle = $title;
52 }
53
54 public function setLayout($path) {
55 $this->_layout = $path;
56 }
57
58 public function insert($path){
59 include ROOT . DS . 'app' . DS . 'views' . DS . $path . '.php';
60 }
61
62 public function partial($group, $partial){
63 include ROOT . DS . 'app' . DS . 'views' . DS . $group . DS . 'partials' . DS . $partial . '.php';
64 }
65
66 }
در کلاس View نیز مانند کلاس کنترلر، تعدادی Property تعریف شده است. در اینجا باید DEFAULT_LAYOUT را در فایل config تعریف کرد.
1 define('DEFAULT_LAYOUT', 'default');
پس از ایجاد متد constructor، باید تعدادی متد دیگر نیز در کلاس View ایجاد شود. اولین متد «render» خواهد بود. این متد یک پارامتر به نام «viewName» (نام نما) را دریافت میکند. در خط 13، اجزای viewName در یک آرایه جداسازی میشوند. در خط بعدی، اطمینان حاصل میشود که از جدا کننده دایرکتوری سیستم مربوطه استفاده خواهد شد.
به همین دلیل آرایه viewAry دوباره به یک رشته تبدیل میشود. این کار برای این انجام میشود که در سیستم عاملهای مختلف جدا کننده متفاوت است. مثلاً در ویندوز جدا کننده بکاسلش (\) است، اما در مک OS از فوروارداسلش (/) به عنوان جدا کننده استفاده میشود. در ادامه آموزش کامل MVC در PHP و توضیح کدهای کلاس View، کارکرد تابع render شرح داده شده است.
تابع render در کلاس View
تابع render پوشه view در دایرکتوری app را بررسی میکند و در صورتی که فایل view در آن وجود داشته باشد، آن را به همراه قالب (layouts) مربوطه در پوشه layouts در بر میگیرد. بنابراین، تابع render تنها فایلهای مربوط به نما در الگوی MVC را include میکند. «content» متد بعدی است که در کلاس View تعریف میشود، در ادامه توضیحاتی راجع به آن ارائه شده است.
تابع content در کلاس View
به بیان ساده، به وسیله تابع content در داخل نماهای ایجاد شده، محتوا اضافه میشود. این محتوا میتواند از نوع head یا body باشد. همچنین، میتوان انواع دیگری را هم ایجاد کرد. برای اینکه منطق و کارکرد این تابع بهتر مشخص شود، باید تعدادی فایل در برخی پوشههای پروژه ایجاد کرد. ابتدا باید در پوشه views یک پوشه جدید به نام home ایجاد شود. سپس، در پوشه home یک فایل به نام index.php ایجاد میشود. همچنین، در داخل پوشه controllers باید یک فایل کلاس جدید به نام Home.php ایجاد کرد.
نحوه عملکرد یک فریمورک MVC در PHP به این صورت است که به تعداد کنترلر مورد نیاز در پوشه controllers کلاسهایی از نوع کنترلر ایجاد میشود. کلاس Controller هستهای که در پوشه core ایجاد شد، به عنوان والد این کنترلرها عمل میکند. متناظر با هر کنترلر، یک پوشه در دایرکتوری views ایجاد میشود. به عنوان مثال برای کنترلر Home.php یک پوشه home در views ساخته شده است که در داخل آن تعداد زیادی فایل view وجود خواهد داشت. بنابراین، کنترلر Home، نمای index.php و کلاس View.php با هم در ارتباط هستند. به عنوان مثال، ساختار یک فایل نما مثل index.php (در پوشه home) به صورت زیر است:
1<?php $this->setSiteTitle('home'); ?>
2<?php $this->start('head'); ?>
3
4<?php $this->end(); ?>
5
6<?php $this->start('body'); ?>
7
8<?php $this->end(); ?>
متدهای فوق در داخل نماها قرار داده میشوند و سپس اسکریپتهای JavaScript و استایلهای CSS در head سند HTML قرار میگیرند:
1<?php $this->setSiteTitle('home'); ?>
2<?php $this->start('head'); ?>
3<script></script>
4<style></style>
5
6<?php $this->end(); ?>
7
8<?php $this->start('body'); ?>
9
10<?php $this->end(); ?>
و هر چیزی که در داخل body قرار بگیرد، در بدنه HTML درج خواهد شد:
1<?php $this->setSiteTitle('home'); ?>
2<?php $this->start('head'); ?>
3<script></script>
4<style></style>
5
6<?php $this->end(); ?>
7
8<?php $this->start('body'); ?>
9<h1>Welcome to ruah MVC Framework</h1>
10<?php $this->end(); ?>
در کدهای فوق، هر آنچه که بین <?php $this->start('body'); ?> و <?php $this->end(); ?> قرار بگیرد، در بدنه HTML درج خواهد شد. بنابراین، فایلهای view تنها حاوی نشانهگذاریهای مورد نیاز برای بدنه هستند و اسکریپتها و استایلهای مورد نیاز هم در head قرار داده میشوند. متدهای setSiteTitle ،start و end در کلاس هستهای View در پوشه core تعریف شدهاند. حال باید کدنویسی کنترلر Home.php را انجام داد. این کار در ادامه انجام شده است.
کنترلر Home.php
برای بررسی کارکرد صحیح اجزا و بررسی عدم وجود خطا، میتوان کدنویسی کلاس Home را به صورت زیر انجام داد:
1<?php
2
3 class Home extends Controller {
4
5 public function __construct($controller, $action) {
6 parent:: __construct($controller, @action);
7 }
8
9 public function indexAction() {
10 die('Welcome to the home controller this is the index action')
11 }
12 }
در متد indexAction تنها کاری که انجام میشود، چاپ کردن پیامی در خروجی است. این کار تنها برای آزمایش و خطایابی انجام شده است. مشاهده پیام خوشامدگویی به این معناست که همه چیز به خوبی کار میکند و خطایی وجود ندارد. در ادامه آموزش کامل MVC در PHP ، قالب پیشفرض ایجاد با استفاده از Bootstrap و jQuery ایجاد میشود. همچنین، از کارکرد صحیح نماها اطمینان حاصل خواهد شد. سپس ایجاد کلاس پایگاه داده و اتصال PHP به پایگاه داده مورد بررسی قرار خواهد گرفت.
ایجاد قالب پیشفرض
برای ایجاد قالب پیشفرض پروژه، باید Bootstrap و jQuery را دانلود کرد. تنها فایل CSS مورد نیاز از بوتاسترپ، فایل «bootstrap.min.css» است که باید آن را در پوشه css پروژه ruah کپی کرد. همچنین، میتوان فونتهای بوتاسترپ را هم در پوشه fonts قرار داد. باید فایل «bootstrap.min.js» را نیز در پوشه js کپی کرد. سپس باید در پوشه js یک فایل به نام «jQuery-2.2.4.min.js» ایجاد کرد.
در ادامه باید به آدرس [+] مراجعه و تمام محتویات صفحه را در فایل jQuery-2.2.4.min.js کپی کرد. پس از آن، باید در دایرکتوری views یک پوشه به نام «layouts» ایجاد کرد. سپس در داخل پوشه layouts، باید یک فایل جدید به نام default.php ایجاد شود. کدهای default.php در ادامه آمده است:
1<?php
2use Core\Session;
3?>
4<!DOCTYPE html>
5<html lang="en">
6 <head>
7 <meta charset="utf-8">
8 <meta http-equiv="X-UA-Compatible" content="IE=edge">
9 <meta name="viewport" content="width=device-width, initial-scale=1">
10 <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
11 <title><?=$this->siteTitle(); ?></title>
12 <link rel="stylesheet" href="<?=PROOT?>css/bootstrap.min.css" media="screen" title="no title" charset="utf-8">
13 <link rel="stylesheet" href="<?=PROOT?>css/custom.css" media="screen" title="no title" charset="utf-8">
14 <script src="<?=PROOT?>js/jQuery-2.2.4.min.js"></script>
15 <script src="<?=PROOT?>js/bootstrap.min.js"></script>
16
17 <?= $this->content('head'); ?>
18
19 </head>
20 <body>
21 <?php include 'main_menu.php' ?>
22 <div class="container-fluid" style="min-height:cal(100% - 125px);">
23 <?= Session::displayMsg() ?>
24 <?= $this->content('body'); ?>
25 </div>
26 </body>
27</html>
کدهای فوق از سایت بوتاسترپ در بخش «Basic Template» کپی و سپس تغییراتی روی آنها اعمال شده است. در خط دوازدهم فایلهای CSS بارگذاری شدهاند. فایل custom.css نیز باید در پوشه css پروژه ایجاد شود. همچنین در کدنویسی قالب، بارگذاری jQuery و بوتاسترپ انجام شده است.
مروری بر پیادهسازی فریمورک MVC PHP
همانطور که بیان شد، ایده استفاده از الگوی MVC ایجاد یک وباپلیکیشن بسیار منظم و ساختاریافته است. پس از توسعه فریمورک MVC PHP، اکثر فایلها برای توسعه وباپلیکیشن در پوشه app قرار خواهند گرفت. همچنین، در داخل پوشه app نیز اکثر فایلها در پوشههای models ،controllers و views قرار خواهند گرفت.
مثلاً برای آزمایش کارکرد MVC در PHP برای پروژه ruah و نمایش آنچه اتفاق میافتد، میتوان یک فایل در پوشه controllers ایجاد کرد و آن را Tools.php نامید. کدهای فایل Tools.php را میتوان به صورت زیر نوشت:
1<?php
2 class Tools extends Controller {
3 public function __construct() {
4 parent::__construct($controller, $action)
5 $this->view->setLayout('default');
6 }
7
8 public function indexAction() {
9 $this->view->render('tools/index');
10 }
11 public function firstAction() {
12 $this->view->render('tools/first');
13 }
14 public function secondAction() {
15 $this->view->render('tools/second');
16 }
17 public function thirdAction() {
18 $this->view->render('tools/third');
19 }
20}
کدهای فوق برای ایجاد یک کنترلر استفاده میشوند. در داخل هر یک از اکشنها، منطق مورد نیاز پیادهسازی میشود. همچنین هر نوع اطلاعاتی از مدلها یا ارسال اطلاعات به مدلها در کنترلرها انجام میشود. حال برای ایجاد نما، یک پوشه جدید به نام tools در دایرکتوری views ایجاد میشود. حال باید در داخل پوشه tools یک فایل جدید به index.php ایجاد کرد. همچنین فایلهای دیگری هم به نامهای second.php ،first.php و third.php در پوشه tools ایجاد میشوند. کدهای فایل index.php در پوشه tools به صورت زیر است:
1<?php $this->setSiteTitle
2<?php $this->start('body'); ?>
3<h1 class='text-center red'>This is the tools index page.</h1>
4<?php $this->end(); ?>
کدهای فایل first.php نیز به صورت زیر نوشته میشوند:
1<?php $this->setSiteTitle('First Tools'); ?>
2<?php $this->start('body'); ?>
3<h1 class='text-center red'>This is the FIRST tools page.</h1>
4<?php $this->end(); ?>
کدهای فایل second.php نیز به صورت زیر نوشته میشوند:
1<?php $this->setSiteTitle('Second Tools'); ?>
2<?php $this->start('body'); ?>
3<h1 class='text-center red'>This is the SECOND tools page.</h1>
4<?php $this->end(); ?>
کدهای فایل third.php نیز به صورت زیر نوشته میشوند:
1<?php $this->setSiteTitle('Third Tools'); ?>
2<?php $this->start('body'); ?>
3<h1 class='text-center red'>This is the THIRD tools page.</h1>
4<?php $this->end(); ?>
به این ترتیب، مثلاً با وارد کردن URL مربوط به صفحه اول، یعنی «localhost/ruah/tools/first» خروجی به صورت زیر خواهد بود:
به این ترتیب، همانطور که ملاحظه میشود، فریمورک MVC پیادهسازی شده است و به درستی عمل میکند. همانطور که بیان شد، همه چیز از طریق صفحه index.php در دایرکتوری ریشه عبور میکند. در فایل Router.php، بخشهای آدرس URL در یک آرایه جداسازی میشوند. کنترلر از اولین عنصر آرایه استخراج میشود. سپس، اولین عنصر آرایه با متد array_shift حذف میشود. سپس، اکشن از آرایه دریافت و کلمه Action به انتهای آن اضافه میشود. بعد از آن، هر آنچه از URL باقی میماند به عنوان پارامتر در نظر گرفته میشود. یک شی به نام dispatch ایجاد و با یک کنترلر نمونهسازی (Instantiate) میشود. مثلاً در مورد Home، از یک کنترلر Home استفاده میشود و نام کنترلر به همراه اکشن عبور داده میشود. به عنوان مثال، در کلاس کنترلر Home، دو پارامتر در Construct وجود دارد.
بنابراین اولین پارامتر شی dispatch به اولین پارامتر Construct عبور داده میشود و دومین پارامتر هم به همین شکل به پارامتر دوم Construct عبور داده میشود. در داخل Constuct نیز این پارامترها به کلاس والد عبور داده میشوند. کلاس والد، Controller.php در پوشه core است. کلاس Controller.php پارامترها را دریافت میکند و کنترلر و اکشن مربوطه را ایجاد میکند. همچنین، Controller شی View را نیز نمونهسازی میکند. در ادامه، اکشن Index در Router فراخوانی میشود و پارامترهای کوئری به آن ارجاع داده میشود. در واقع، در این مرحله پارامترها به اکشنها ارجاع داده میشوند و میتوان از آنها در داخل کنترلر و اکشنها استفاده کرد. در ادامه آموزش کامل MVC در PHP ، اتصال به پایگاه داده و ساخت پوششدهنده پایگاه داده (DB Wrapper) انجام خواهد شد تا بتوان یک وباپلیکیشن واقعی را بر اساس فریمورک MVC PHP توسعه داد.
ایجاد پوشش دهنده پایگاه داده
در این بخش بر کلاس پایگاه داده و همچنین کلاس مدل تمرکز شده است. برای ساخت کلاس پایگاه داده، باید در داخل پوشه core یک فایل جدید به نام DB.php ایجاد شود. کدهای مربوط به فایل DB.php به صورت زیر است:
1<?php
2namespace Core;
3use \PDO;
4use \PDOException;
5
6class DB {
7 private static $_instance = null;
8 private $_pdo, $_query, $_error = false, $_result, $_count = 0, $_lastInsertID = null;
9
10 private function __construct() {
11 try {
12 $this->_pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASSWORD);
13 $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
14 $this->_pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
15 } catch(PDOException $e) {
16 die($e->getMessage());
17 }
18 }
19
20 public static function getInstance() {
21 if(!isset(self::$_instance)) {
22 self::$_instance = new self();
23 }
24 return self::$_instance;
25 }
26
27 public function query($sql, $params = [],$class = false) {
28 $this->_error = false;
29 if($this->_query = $this->_pdo->prepare($sql)) {
30 $x = 1;
31 if(count($params)) {
32 foreach($params as $param) {
33 $this->_query->bindValue($x, $param);
34 $x++;
35 }
36 }
37 if($this->_query->execute()) {
38 if($class){
39 $this->_result = $this->_query->fetchAll(PDO::FETCH_CLASS,$class);
40 } else {
41 $this->_result = $this->_query->fetchALL(PDO::FETCH_OBJ);
42 }
43 $this->_count = $this->_query->rowCount();
44 $this->_lastInsertID = $this->_pdo->lastInsertId();
45 } else {
46 $this->_error = true;
47 }
48 }
49 return $this;
50 }
51
52 protected function _read($table, $params=[],$class) {
53 $conditionString = '';
54 $bind = [];
55 $order = '';
56 $limit = '';
57
58 // conditions
59 if(isset($params['conditions'])) {
60 if(is_array($params['conditions'])) {
61 foreach($params['conditions'] as $condition) {
62 $conditionString .= ' ' . $condition . ' AND';
63 }
64 $conditionString = trim($conditionString);
65 $conditionString = rtrim($conditionString, ' AND');
66 } else {
67 $conditionString = $params['conditions'];
68 }
69 if($conditionString != '') {
70 $conditionString = ' Where ' . $conditionString;
71 }
72 }
73
74 // bind
75 if(array_key_exists('bind', $params)) {
76 $bind = $params['bind'];
77 }
78
79 // order
80 if(array_key_exists('order', $params)) {
81 $order = ' ORDER BY ' . $params['order'];
82 }
83
84 // limit
85 if(array_key_exists('limit', $params)) {
86 $limit = ' LIMIT ' . $params['limit'];
87 }
88 $sql = "SELECT * FROM {$table}{$conditionString}{$order}{$limit}";
89 if($this->query($sql, $bind,$class)) {
90 if(!count($this->_result)) return false;
91 return true;
92 }
93 return false;
94 }
95
96 public function find($table, $params=[],$class=false) {
97 if($this->_read($table, $params,$class)) {
98 return $this->results();
99 }
100 return false;
101 }
102
103 public function findFirst($table, $params=[],$class=false) {
104 if($this->_read($table, $params,$class)) {
105 return $this->first();
106 }
107 return false;
108 }
109
110 public function insert($table, $fields = []) {
111 $fieldString = '';
112 $valueString = '';
113 $values = [];
114
115 foreach($fields as $field => $value) {
116 $fieldString .= '`' . $field . '`,';
117 $valueString .= '?,';
118 $values[] = $value;
119 }
120 $fieldString = rtrim($fieldString, ',');
121 $valueString = rtrim($valueString, ',');
122 $sql = "INSERT INTO {$table} ({$fieldString}) VALUES ({$valueString})";
123 if(!$this->query($sql, $values)->error()) {
124 return true;
125 }
126 return false;
127 }
128
129 public function update($table, $id, $fields = []) {
130 $fieldString = '';
131 $values = [];
132 foreach($fields as $field => $value) {
133 $fieldString .= ' ' . $field . ' = ?,';
134 $values[] = $value;
135 }
136 $fieldString = trim($fieldString);
137 $fieldString = rtrim($fieldString, ',');
138 $sql = "UPDATE {$table} SET {$fieldString} WHERE id = {$id}";
139 if(!$this->query($sql, $values)->error()) {
140 return true;
141 }
142 return false;
143 }
144
145 public function delete($table, $id) {
146 $sql = "DELETE FROM {$table} WHERE id = {$id}";
147 if(!$this->query($sql)->error()) {
148 return true;
149 }
150 return false;
151 }
152
153 public function results() {
154 return $this->_result;
155 }
156
157 public function first() {
158 return (!empty($this->_result))? $this->_result[0] : [];
159 }
160
161 public function count() {
162 return $this->_count;
163 }
164
165 public function lastID() {
166 return $this->_lastInsertID;
167 }
168
169 public function get_columns($table) {
170 return $this->query("SHOW COLUMNS FROM {$table}")->results();
171 }
172
173 public function error() {
174 return $this->_error;
175 }
176}
نکتهای که در مورد این کلاس وجود دارد این است که این کلاس هیچگاه به طور مستقیم نمونهسازی نخواهد شد، بلکه از الگوی یگانه (Singleton Pattern) استفاده شده است. کاری که انجام خواهد شد به این صورت است که بررسی میشود آیا کلاس نمونهسازی شده است و در صورتی که نمونهسازی شده باشد، شی در یک خصیصه ذخیره خواهد شد. در اینجا، نام این خصیصه instance گذاشته شده است. خصیصه instance یک خصیصه ایستا خواهد بود. خصیصه ایستا تغییر نمیکند و تمام اشیایی که از یک کلاس ایجاد شدهاند را بسط میدهد.
باید اطمینان حاصل شود که اپلیکیشن هیچگاه بیش از یک پایگاه داده را نمونهسازی و ایجاد نخواهد کرد. در کدهای فوق، ابتدا خصیصه ایستای instance و چند خصیصه دیگر تعریف شدهاند. سپس، شی PDO جدید نمونهسازی شده است. PDO یک افزونه PHP است. این افزونه در اکثر سرورهای PHP به طور پیشفرض نصب شده است. همچنین، در کدهای فوق یک شی PDO ایجاد شده است. این شی سه پارامتر را دریافت میکند. موتور پایگاه داده (در اینجا MySQL)، میزبان و نام پایگاه داده همگی در پارامتر اول ارجاع داده میشوند. پارامترهای دوم و سوم مربوط به نام کاربری و رمز عبور هستند.
ایجاد پایگاه داده
برای ایجاد پایگاه داده باید به آدرس زیر مراجعه شود:
1localhost:/phpmyadmin
باید با کلیک کردن «New» یک پایگاه داده جدید با نام دلخواه ایجاد شود. سپس یک جدول باید در پایگاه داده ایجاد کرد. در ادامه، باید ستونهای جدول و نوع داده آنها را تعریف کرد. در صورت null بودن مقدار instance، تابع getInstance شی پایگاه داده را نمونهسازی خواهد کرد. میتوان به جای مقداردهی به پارامترهای شی PDO در فایل DB.php، متغیرهایی را در فایل config.php ایجاد و آنها را مقداردهی کرد:
1define('DB_NAME', 'ruah');
2define('DB_USER', 'root');
3define('DB_PASSWORD', '');
4define('DB_HOST', '127.0.0.1');
به این ترتیب، اتصال پایگاه داده برقرار شده است. در ادامه باید متدهای مربوط به DB Wrapper ایجاد شوند. در ادامه، کدهای کلاس پایگاه داده، متد query برای اجرای یک کوئری SQL ایجاد شده است. پس از اجرای کوئری، نتایج در result ذخیره میشوند. این نتایج با استفاده از افزونه PDO از پایگاه داده بیرون کشیده میشود. برای آزمایش صحت عملکرد کدها میتوان در سطرهایی را به جدول ایجاد شده در پایگاه داده اضافه کرد. سپس در کلاس کنترلر Home.php، کدهای ارتباط با پایگاه داده را اضافه کرد:
1<?php
2
3 class Home extends Controller {
4
5 public function __construct($controller, $action) {
6 parent:: __construct($controller, @action);
7 }
8
9 public function indexAction() {
10 $db = DB::getInstance();
11 $sql = "SELECT * FROM contacts";
12 $contactsQ = $db->query($sql);
13 dnd($contactsQ)
14 $this->view->render('home/index');
15 }
16 }
با اجرای مجدد اپلیکیشن، شی پایگاه داده در خروجی نمایش داده میشود. در result یک آرایه به همراه یک شی در آن وجود دارد که اطلاعات وارد شده در پایگاه داده را نمایش میدهد. به این ترتیب، آموزش کامل MVC در PHP ارائه شده است. برای دسترسی به همه کدهای منبع و پروژه کامل میتوان به اینجا [+] مراجعه کرد.
جمعبندی
در این مقاله آموزش کامل MVC در PHP ارائه شد. برای درک کامل کارکرد و استفاده از الگوی MVC در PHP یک فریمورک MVC از ابتدا توسعه داده شد. در ابتدا برخی مقدمات مورد نیاز برای آموزش کامل MVC در PHP بیان شد و سپس مراحل توسعه فریمورک MVC در PHP به ترتیب آموزش داده شدند.
ساختار آدرسدهی با الگوی MVC، ساختار پوشهها، پیکربندی آپاچی با .htaccess، پیکربندی فایل index.php و مسیریابی تنها بخشهایی از روند آموزش کامل MVC در PHP هستند که در این مقاله به آنها پرداخته شده است. در پایان نیز دورههای آموزشی مرتبط با توسعه وب به روش MVC PHP معرفی شدند.
سلام وقت بخیر حس میکنم یذره زیادی کد هاتون پیچیده کردید میشد خیلی کمتر کد نویسی کرد و در قالب ام وی سی نیازی ب تعریف این همه کلاس و متد اضافه نبود
با سلام و عرض ادب
من دقیقا همانند روشی که ارائه دادین جلو رفتم اما به چندین ارور منطقی برخوردم چندین مورد رو تونستم خودم حل کنم ولی چند تا هم هستن که نتونستم حلشون کنم اگر امکان داره یه کمکی به من بکنید.
ارور ها هم بیشترشون فتال ارورن یعنی باید رفع بشن
Fatal error: Class ‘Core\Application’ not found in C:\wamp64\www\MCV\core\Controller.php on line 5
مطلب با ارزشی بود، دست شما درد نکنه