
Въпреки че шаблона за дизайн Model-View-Controller се използва от почти всеки уеб програмист, много хора още не са наясно как да пишат качествено MVC за реални проекти. Реших да напиша тази статия, в която да ви споделя моя скромен опит и да събера мненията на компетентни хора на едно място.
Главната идея около MVC е да се постигне преизползваемост на код и разделянето на логиката на приложението. За целта на тази статия ще считаме че разполагаме с уеб приложение, което се състой от няколко неща – фронтенд, бекенд, конзолни административни команди и уеб API. Може да разглеждате тези неща като модули на нашето приложение.
1. Модел класовете
Моделите представят структурите от данни в които се пази информацията в едно уеб приложение. Моделите се ползват от различни части на приложението. Например ако имаме една форма за вход, тя може да бъде ползвана както от фронтенд модула, така и от бекенд модула на приложението. Или ако имаме Модел клас за новини, той може да се използва от фронтенд модула или от API модула. Затова Модел класа трябва да:
Понякога ако се възползваме и от трите правила едновременно, може да направим модел класа ни много голям, съдържащ твърде много код за един клас. Това ще направи Модел класа труден за поддръжка и ще доведе до редица други недостатъци. Например ако имаме един Модел клас за новини. В него може да име метод getLatestNews, който да се използва само от фронтенд модула или метод getDeletedNews, който се използва само от бекенд модула. Това може да е приемливо в малки фирмени сайтове. За по-големи проекти може да следваме седната стратегия с която да направим Модел класовете ни по-структурирани:
Ако ползваме тази стратегия в горния пример, ще добавим нов News Mодел клас във фронтенда на приложението, който ще съдържа само метода getLatestNews и ще наследява базовия клас за новини.
Като цяло, Mодел класовете не трябва да съдържат логика, която се занимава директно с потребителската заявка. По-точно в Модел класовете, не трябва да има неща като $_GET, $_POST или други подобни променливи, които са директно свързани със заявката на крайния потребител. Винаги помнете, че Модел класа може да бъде използван от различни части на приложението, които може да не използват данни от заявката на потребителя. Всичко свързано с потребителските заявки трябва да се случва в Контролер класовете. В Модел класовете не трябва да има статичен код(HTML, CSS, JavaScript и т.н.).
2. Изгледи
Изгледите са отговорни за представяне на данните от Модел класовете в формат, който ще се хареса на крайния потребител. Като цяло, в тях трябва да има само статичен код като HTML и много малко и то проста логика за извеждане, форматиране и рендване на данните. В изгледите не трябва да има по-сложна логика или изпълнение на SQL заявки. Подобен код може да намери мястото си в Модел класовете. Трябва да се избегне използването на $_GET, $_POST в изгледите, защото това е работа на Контролер класовете. Изглед файла трябва да е фокусиран върху представянето и форматирането на информацията, предадена до него от Контролер или Модел класовете. Той може да извиква методи на Модел класове, но не и да достъпва директно базата от данни. Извикването на методи на Контролер и Модел класовете, трябва да се ограничава само до задачи свързани със самото представяне на информацията в тези файлове.
Принципно има два вида MVC. Едното се казва Push MVC а другото е Pull MVC. При Push MVC, контролерите взимат някакви данни от Модел класовете и ги предават на Изглед файловете. При Pull MVC самите Изглед файлове, могат да извикват методи от различни Контролер и Модел класове и по този начин да събират нужната им информация.
Изглед файловете могат да бъдат разширени по следните начини:
Лейаут: Това е основната структура на нашият сайт(може да включва head частта на ХТML страницата, хеадъра и фуутера на сайта и други елементи, които се повтарят на всички страници).
Непълни изгледи: това са изгледи, които не са декорирани от лейаут. Може да си ги представяте като файлове в които има само парчета HTML. Например може да имате един файл _form.php, които да съдържа форма за новини. Тази форма е разположена в един файл, които се използва в метода за добавяне на новина и още веднъж в метода за редактиране на новина. Така ако искаме да променим формата, не редактираме всички файлове, в които има форма за новини, ами редактираме само един.
Уйджети: ако се изисква повече логика за да представим някаква информация, е удобно да обособим нов функционален компонент на нашето приложение – уйджети. При него имаме един файл с репрезентационно предназначение(тоест само с HTML) и един клас, който да обработи сложната логика и да я изплюе в изглед файла.
Помощни класове: Често във изглед файловете ни се налага да решаваме някакви малки задачки, като да форматираме дата, час, валута. Добра идея е, да не добавяме функциите за това в Изглед файла, а да си обособим нов клас, който ще наречем помощен. Така например, за да форматираме часа в Изглед файловете ни, може да си направим помощен клас, който се грижи за това според настройките на потребителя. Може да си направим и помощен клас за писане на HTML. Ползата е голяма.
3. Контролери(Контролер класове)
Контролерите са междинната връзка или лепилото между Модел класовете, Изгледите и останалите части на нашето приложение. Контролерите са директно отговорни за обработването на заявките, идващи от потребителя. В Контролерите има отделни функционални блокове, които се наричат действия. Всяко действие отговаря на определена страница поискана от потребителя. Те работят с данните, идващи от GET и POST завки. Също така, те създават инстанции на Модел класовете и се грижат за техния живот(метафорично казано). Например, ако имаме едно действие за добавяне на нова новини, когато започне да се изпълнява конкретното действие, се създава инстанция на Модел класа отговарящ за новините. След това, Контролер класа изпраща данните, събрани от POST заявката, към Модел класа. След като Контролера каже на Модел класа да запише данните, които е получил, Контролера пренасочва потребителя към определена страница. Обърнете внимание, че реалното записване на данни се случа в самият Модел клас, а не извън него. Трябва да избягвате писането на SQL код в Контролера. Трябва да избягвате и писането на HTML в контролера.
Има няколко мнения относно доброто проектиране на MVC. При единия подход се препоръчва, контролерите да бъдат много малки, а Модел класовете да са по-големи, като изместим повечето логика за манипулиране на данните в Модел класовете. Обосновката за това е, че структурите от данни и бизнес логиката, съдържани в Модел класовете, често са тясно свързани и са уникални за конкретната ситуация и са специално писани за нея. Докато логиката на контролерите често следва един и същи шаблон в приложението и може да бъде обобщена от класа, който наследяват всички контролери.
Ами не съм ползвал CI, но след бърз преглед на кратката документация, която имаше за моделите разбрах, че те не могат да правят много неща. Предполагам, че няма да е проблем просто да направиш подмодела да наследява главния модел вместо базовия ти клас за модели.
17:49
Здравей, имам един въпрос свързан с Codeigniter Framework.Да речем, че имам един главен модел и искам той да притежава методите на друг подмодел.Би ли ми обяснил как може да се реализира.