Вы можеть быть даже слышали о шаблонах проектирования и даже листали эти прекрасные книги:
Представленная статья будет полезна в первую очередь новичкам. Во всяком случае, я надеюсь что за пару часов вы сможете получить представление о реализации MVC паттерна, который лежит в основе всех современных веб-фреймворков, а также получить «пищу» для дальнейших размышлений над тем - «как стоит делать». В конце статьи приводится подборка полезных ссылок, которые также помогут разобраться из чего состоят веб-фреймворки (помимо MVC) и как они работают.
Прожженные PHP-программисты вряд ли найдут в данной статье что-то новое для себя, но их замечания и комментарии к основному тексту были бы очень кстати! Т.к. без теории практика невозможна, а без практики теория бесполезна, то сначала будет чуть-чуть теории, а потом перейдем к практике. Если вы уже знакомы с концепцией MVC, можете пропустить раздел с теорией и сразу перейти к практике.
1. Теория Шаблон MVC описывает простой способ построения структуры приложения, целью которого является отделение бизнес-логики от пользовательского интерфейса. В результате, приложение легче масштабируется, тестируется, сопровождается и конечно же реализуется.Рассмотрим концептуальную схему шаблона MVC (на мой взгляд - это наиболее удачная схема из тех, что я видел):
В архитектуре MVC модель предоставляет данные и правила бизнес-логики, представление отвечает за пользовательский интерфейс, а контроллер обеспечивает взаимодействие между моделью и представлением.
Типичную последовательность работы MVC-приложения можно описать следующим образом:
Вид
- используется для задания внешнего отображения данных, полученных из контроллера и модели.
Виды cодержат HTML-разметку и небольшие вставки PHP-кода для обхода, форматирования и отображения данных.
Не должны напрямую обращаться к базе данных. Этим должны заниматься модели.
Не должны работать с данными, полученными из запроса пользователя. Эту задачу должен выполнять контроллер.
Может напрямую обращаться к свойствам и методам контроллера или моделей, для получения готовых к выводу данных.
Виды обычно разделяют на общий шаблон, содержащий разметку, общую для всех страниц (например, шапку и подвал) и части шаблона, которые используют для отображения данных выводимых из модели или отображения форм ввода данных.
Контроллер
- связующее звено, соединяющее модели, виды и другие компоненты в рабочее приложение. Контроллер отвечает за обработку запросов пользователя. Контроллер не должен содержать SQL-запросов. Их лучше держать в моделях. Контроллер не должен содержать HTML и другой разметки. Её стоит выносить в виды.
В хорошо спроектированном MVC-приложении контроллеры обычно очень тонкие и содержат только несколько десятков строк кода. Чего, не скажешь о Stupid Fat Controllers (SFC) в CMS Joomla. Логика контроллера довольно типична и большая ее часть выносится в базовые классы.
Модели, наоборот, очень толстые и содержат большую часть кода, связанную с обработкой данных, т.к. структура данных и бизнес-логика, содержащаяся в них, обычно довольно специфична для конкретного приложения.
Надеюсь, вы уже успели заметить, что у разных сайтов могут быть совершенные разные форматы построения адресной строки. Каждый формат может отображать архитектуру web-приложения. Хотя это и не всегда так, но в большинстве случаев это явный факт.
Рассмотрим два варианта адресной строки, по которым показывается какой-то текст и профиль пользователя.
Приблизительный код обработки в таком случае:
switch($_GET["action"])
{
case "about" :
require_once("about.php"); // страница "О Нас"
break;
case "contacts" :
require_once("contacts.php"); // страница "Контакты"
break;
case "feedback" :
require_once("feedback.php"); // страница "Обратная связь"
break;
default:
require_once("page404.php"); // страница "404"
break;
}
Думаю, почти все так раньше делали.
С использованием движка маршрутизации URL вы сможете для отображения той же информации настроить приложение на прием таких запросов:
http://www.example.com/contacts/feedback
Здесь contacts представляет собой контроллер, а feedback - это метод контроллера contacts, отображающий форму обратной связи и т.д. Мы еще вернемся к этому вопросу в практической части.
Также стоит знать, что маршрутизаторы многих веб-фреймворков позволяют создавать произвольные маршруты URL (указать, что означает каждая часть URL) и правила их обработки.
Теперь мы обладаем достаточными теоретическими знаниями, чтобы перейти к практике.
Забегая вперед, скажу, что в папке core будут храниться базовые классы Model, View и Controller.
Их потомки будут храниться в директориях controllers, models и views. Файл index.php
это точка в хода в приложение. Файл bootstrap.php
инициирует загрузку приложения, подключая все необходимые модули и пр.
Будем идти последовательно; откроем файл index.php и наполним его следующим кодом:
ini_set("display_errors", 1);
require_once "application/bootstrap.php";
Тут вопросов возникнуть не должно.
Следом, сразу же перейдем к фалу bootstrap.php
:
require_once "core/model.php";
require_once "core/view.php";
require_once "core/controller.php";
require_once "core/route.php";
Route::start(); // запускаем маршрутизатор
Первые три строки будут подключать пока что несуществующие файлы ядра. Последние строки подключают файл с классом маршрутизатора и запускают его на выполнение вызовом статического метода start.
Маршрутизацию мы поместим в отдельный файл route.php в директорию core. В этом файле опишем класс Route, который будет запускать методы контроллеров, которые в свою очередь будут генерировать вид страниц.
Содержимое файла route.php
class Route
{
static function start()
{
// контроллер и действие по умолчанию
$controller_name = "Main";
$action_name = "index";
$routes = explode("/", $_SERVER["REQUEST_URI"]);
// получаем имя контроллера
if (!empty($routes))
{
$controller_name = $routes;
}
// получаем имя экшена
if (!empty($routes))
{
$action_name = $routes;
}
// добавляем префиксы
$model_name = "Model_".$controller_name;
$controller_name = "Controller_".$controller_name;
$action_name = "action_".$action_name;
// подцепляем файл с классом модели (файла модели может и не быть)
$model_file = strtolower($model_name).".php";
$model_path = "application/models/".$model_file;
if(file_exists($model_path))
{
include "application/models/".$model_file;
}
// подцепляем файл с классом контроллера
$controller_file = strtolower($controller_name).".php";
$controller_path = "application/controllers/".$controller_file;
if(file_exists($controller_path))
{
include "application/controllers/".$controller_file;
}
else
{
/*
правильно было бы кинуть здесь исключение,
но для упрощения сразу сделаем редирект на страницу 404
*/
Route::ErrorPage404();
}
// создаем контроллер
$controller = new $controller_name;
$action = $action_name;
if(method_exists($controller, $action))
{
// вызываем действие контроллера
$controller->$action();
}
else
{
// здесь также разумнее было бы кинуть исключение
Route::ErrorPage404();
}
}
function ErrorPage404()
{
$host = "http://".$_SERVER["HTTP_HOST"]."/";
header("HTTP/1.1 404 Not Found");
header("Status: 404 Not Found");
header("Location:".$host."404");
}
}
В элементе глобального массива $_SERVER["REQUEST_URI"] содержится полный адрес по которому обратился пользователь.
Например: example.ru/contacts/feedback
С помощью функции explode производится разделение адреса на составлющие. В результате мы получаем имя контроллера, для приведенного примера, это контроллер contacts и имя действия, в нашем случае - feedback .
Далее подключается файл модели (модель может отсутствовать) и файл контроллера, если таковые имеются и наконец, создается экземпляр контроллера и вызывается действие, опять же, если оно было описано в классе контроллера.
Таким образом, при переходе, к примеру, по адресу:
example.com/portfolio
или
example.com/portfolio/index
роутер выполнит следующие действия:
Напомню, что они будут содержать базовые классы, к написанию которых мы сейчас и приступим.
Содержимое файла model.php
class Model
{
public function get_data()
{
}
}
Класс модели содержит единственный пустой метод выборки данных, который будет перекрываться в классах потомках. Когда мы будем создавать классы потомки все станет понятней.
Содержимое файла view.php
class View
{
//public $template_view; // здесь можно указать общий вид по умолчанию.
function generate($content_view, $template_view, $data = null)
{
/*
if(is_array($data)) {
// преобразуем элементы массива в переменные
extract($data);
}
*/
include "application/views/".$template_view;
}
}
Не трудно догадаться, что метод generate
предназначен для формирования вида. В него передаются следующие параметры:
В нашем случае общий шаблон будет содержать header, menu, sidebar и footer, а контент страниц будет содержаться в отдельном виде. Опять же это сделано для упрощения.
Содержимое файла controller.php
class Controller {
public $model;
public $view;
function __construct()
{
$this->view = new View();
}
function action_index()
{
}
}
Метод action_index
- это действие, вызываемое по умолчанию, его мы перекроем при реализации классов потомков.
На предыдущем рисунке отдельно выделен файл template_view.php
- это шаблон, содержащий общую для всех страниц разметку. В простейшем случае он мог бы выглядеть так:
Главная
Для придания сайту презентабельного вида сверстаем CSS шаблон и интегририруем его в наш сайт путем изменения структуры HTML-разметки и подключения CSS и JavaScript файлов:
В конце статьи, в разделе «Результат», приводится ссылка на GitHub-репозиторий с проектом, в котором проделаны действия по интеграции простенького шаблона.
Файл с общим видом мы рассмотрели ранее. Рассмотрим файл контента main_view.php
:
Добро пожаловать!
ОЛОЛОША TEAM - команда первоклассных специалистов в области разработки веб-сайтов с многолетним опытом коллекционирования мексиканских масок, бронзовых и каменных статуй из Индии и Цейлона, барельефов и изваяний, созданных мастерами Экваториальной Африки пять-шесть веков назад...
Класс контроллера модели содержится в файле controller_portfolio.php
, вот его код:
class Controller_Portfolio extends Controller
{
function __construct()
{
$this->model = new Model_Portfolio();
$this->view = new View();
}
function action_index()
{
$data = $this->model->get_data();
$this->view->generate("portfolio_view.php", "template_view.php", $data);
}
}
В переменную data
записывается массив, возвращаемый методом get_data
, который мы рассматривали ранее.
Далее эта переменная передается в качестве параметра метода generate
, в который также передаются: имя файла с общим шаблон и имя файла, содержащего вид c контентом страницы.
Вид содержащий контент страницы находится в файле portfolio_view.php
.
Портфолио
Год | Проект | Описание |
Скриншот получившегося сайта-визитки
А вот в этой версии я набросал следующие классы (и соответствующие им виды):
Но, использование веб-фреймворков, типа Yii или Kohana, состоящих из нескольких сотен файлов, при разработке простых веб-приложений (например, сайтов-визиткок) не всегда целесообразно. Теперь мы умеем создавать красивую MVC модель, чтобы не перемешивать Php, Html, CSS и JavaScript код в одном файле.
Данная статья является скорее отправной точкой для изучения CMF, чем примером чего-то истинно правильного, что можно взять за основу своего веб-приложения. Возможно она даже вдохновила Вас и вы уже подумываете написать свой микрофреймворк или CMS, основанные на MVC. Но, прежде чем изобретать очередной велосипед с «блекджеком и шлюхами», еще раз подумайте, может ваши усилия разумнее направить на развитие и в помощь сообществу уже существующего проекта?!
P.S.: Статья была переписана с учетом некоторых замечаний, оставленных в комментариях. Критика оказалась очень полезной. Судя по отклику: комментариям, обращениям в личку и количеству юзеров добавивших пост в избранное затея написать этот пост оказалось не такой уж плохой. К сожалению, не возможно учесть все пожелания и написать больше и подробнее по причине нехватки времени… но возможно это сделают те таинственные личности, кто минусовал первоначальный вариант. Удачи в проектах!
5. Подборка полезных ссылок по сабжу В статье очень часто затрагивается тема веб-фреймворков - это очень обширная тема, потому что даже микрофреймворки состоят из многих компонентов хитро увязанных между собой и потребовалась бы не одна статья, чтобы рассказать об этих компонентах. Тем не менее, я решил привести здесь небольшую подборку ссылок (по которым я ходил при написаниие этой статьи), которые так или иначе касаются темы фреймворков.Теги: Добавить метки
Я ощущаю безнадёжность, когда кажется, что все бессмысленно и ни к чему не приведёт, крах жизни. Это чувство, когда руки опускаются и любые мысли или действия, призванные обнадёжить или изменить что-то, отбрасываются как бесполезные. Сопровождается у меня чувством одиночества, когда кажется, что никому я не нужен со своими проблемами и заморочками.
Раньше вообще ничего не делал, чтобы стало легче, а, наоборот, начинаю жалеть себя, потому что мне плохо, ничего не хочется и ничего не радует.
Сегодня занимаю себя какими-то действиями: например, уборка по дому, игра в компьютер.
Самому любопытно, как проживаются чувства, потому что я их проживать, наверное, не умею.
В своей жизни лишь однажды испытывал подобное чувство!
Мне было лет 15.
В очередное посещение одного из тренигов, меня переполняла стойкая уверенность в своих силах, я достигал успеха из раза в раз...
И вот она, ситуация, задание с тремя действующими лицами, разыгрывается ситуация..банальная, как мне тогда казалось.
Для меня безнадежность - это отсутствие желания что-либо делать, полная подавленность и безразличие ко всему, депрессия.Не хочу проживать это чувство, потому что в таком состоянии для меня все перестает быть важным и опускаются руки. Я не убегаю и не глушу его.
Раньше я просто жил с ним и употреблял, а сейчас я знаю, что из любой ситуации есть выход и ВС мне поможет его найти. Не обращал внимания, склонен ли я проговаривать ощущение безнадежности другим людям, но себе точно признаюсь не всегда, хотя со временем это становится очевидным. Я хочу научиться видеть выход из ситуаций, чтобы даже мысли не появлялись о том, что выхода нет.
Безнадежность - это когда я не вижу выхода и опускаются руки, не хочется что-либо предпринимать, потому что не вижу в этом смысла, когда нет надежды, которая, по идее, должна умирать последней.Однозначно не хочу проживать это чувство, но выход всегда есть, также как и в наркомании, выхода из которой я не видел, но благодаря ВС и людям, которые мне его показали, я сегодня трезвый, с Богом, с Вами. Безнадежность - тяжелое чувство, стараюсь перепоручать и нахожу выход, ведь безнадежных ситуаций не бывает. Вера очень помогает. Теперь я знаю, что признать ситуацию безнадежной - это значит сдаться и ничего не делать, так что не надо быть пессимистом. В любом негативе можно найти позитив - из любой безнадежной ситуации есть выход.
22.05.06 83.2KВы когда-нибудь хотели установить на свой сайт форму обратной связи? Наверняка Вы встречались с подобными скриптами. Как ни странно, готовые скрипты отправки формы на email пользуются большой популярностью (Вы можете убедиться в этом в любом архиве скриптов), причем их существует великое множество. Есть простые, в которых ничего не меняется, а есть сложные и большие системы, которые функционируют на mysql, позволяют динамически изменять любые поля, содержат кучу настроек… Но так ли они нужны? На мой взгляд необходимость в подобных системах очень сомнительна.
Тестировать отправку почты на домашнем компьютере не получиться. Для этого Вам необходим хостинг с поддержкой php и функциями отправки почты. Я рекомендую Вам хостинг-провайдера runweb.ru. Этот провайдер предлагает отличные тарифы, высочайшую скорость доступа и отличное обслуживание.
Методы отправки почтыОтправлять почту с сервера с помощью php можно двумя основными способами.
Я хочу рассмотреть оба этих способа по порядку.
Первый и самый простой — это использование php функции mail(). Функция очень простая и понятная, хотя отправка почты с использованием mail() имеет и ряд недостатков. Самый главный — письмо отправляется не напрямую, а через php. Одновременно программа php подставляет в письмо некоторые свои поля. Например, у Вас не получится корректно указать отправителя. В поле "from" (то есть от кого пришло письмо) в большинстве случаев будет стоять имя сервера. Все дело в том, что php подставляет свои заголовки в служебную строку письмо "from".
Тем не менее отправка почты с помощью функции mail() остается самым простым
способом отправить письмо с сервера. Давайте рассмотрим этот способ подробнее.
Функция mail() имеет следующий синтаксис:
mail($to, $subject, $body, $headers);
$to - это адрес получателя. Например, "[email protected]". $subject - тема письма. Например, "Вам пришло письмо". $body - текст сообщения. $headers - любые заголовки письма. Например, адрес отправителя будет выглядеть так: "from: [email protected]".
Вот полный пример отправки почты с помощью mail():
mail("[email protected]", "Тема письма", "Здравствуйте!nВам пришло письмо.", "from: site_name");
Обратите внимание, что при использовании этой функции на домашнем компьютере она может выдавать ошибку, так как не может отправить письмо без почтового сервера.
Теперь давайте посмотрим, как можно отправить письмо с помощью sendmail.
sendmail — это стандартная программа операционной системы unix, которая отправляет почту.
php может запускать unix-программы путем использования средства pipes (дословно "трубопроводы"). Это средство unix позволяет направлять данные из одной программы в другую, наподобие того, как мы пишем в файл. Только файлом в этом случае выступает программа (в частности, sendmail), которая и получает данные.
sendmail программа имеет множество параметров, мы будем использовать некоторые из них. Чтобы использовать sendmail, нужно открыть к нему поток (pipe). В php это делается использованием команды popen(), которая по синтаксису идентична команде fopen(). Путем использования popen() мы открывает поток к sendmail
для записи в него (помните, параметр режима "w"?), после чего можно отправлять в него данные обычной командой fputs(). Посмотрим, как полностью выглядит процедура отправки письма через sendmail:
В этой программе первое, что мы делаем — описываем rfc заголовки. rfc — это службные поля, которые содержат всю информацию о письме. Увидеть пример rfc Вы можете, например, в программе the bat!, щелкнув правой кнопкой мыши на тексте письмо и выбрав "rfc-822 headers" (название пункта может отличаться). Чтобы убрать их, повторите действия. В заголовке мы описываем поля "content-type", которые указывают что письмо текстовое и в кодировке windows-1251 (стандартная кодировка windows). В качестве кодировки также может быть использовано "koi8-r", это стандартная кодировка unix. В этой статье мы не будем рассматривать возможные rfc заголовки подробно. Мы сделаем это чуть позже,
когда будем ближе работать с почтой. Итак, после того, как мы описали служебные переменные и заголовки письма, мы открываем sendmail. Обратите внимание на путь к программе "/usr/sbin/sendmail". На разных серверах он может отличаться!
Если эта строка не работает, спросите у Вашего провайдера, где расположен sendmail. Далее указываются параметры: "-i -f$from — $recipients". Это стандартные параметры для отправки письма и в них подставляется два поля: $from — от кого, $recipients — адреса получателей. В нашем случае переменная $recipients содержит всего один адрес. На самом деле можно использовать несколько адресов, указывая их через пробел:
$recipients = "[email protected] [email protected] [email protected]";
Далее мы записываем в поток сначала заголовки письма (переменная $text_headers), потом отделяем их символом переноса строки и записываем текст сообщения. Последний шаг — закрытие потока и проверка на ошибку. При правильном выполеннии в переменную $result помещается ноль, а если возникла ошибка, в нее записывается номер ошибки.
Теперь давайте рассмотрим пример использования возможностей отправки почты. Для этого мы сделаем форму обратной связи, которую Вы сможете установить на свой сайт. В качестве метода отправки письма мы будем использовать sendmail.
Создаем форму обратной связиНаша форма обратной связи будет представлять собой один скрипт. Этот скрипт будет выводить форму и отправлять письмо.
contact.php:
Обратная связь
Прямая связь | ||
Ваше имя: * | ||
Ваш email: * | ||
Ваш сайт: | ||
|
||
Поля, отмеченные звездочкой (*) должны быть заполнены.
Теперь давате рассмотрим, как работает эта программа. Выполнение начинается со строки "if (!$a) show_form();", так как до этого указана функция, которая, естественно, не выполняется. В этой строке мы проверяем, была ли попытка заполнения формы (из формы, как Вы видите, передается переменная $a, которая и проверяется в этой строке). Если такой попытки не было, вызывается функция show_form(), которая выводит форму.
В последнее время мне все чаще приходится сталкиваться с бездарность в IT. Друзья обращаются за консультациями, и когда начинаешь разбираться в предмете вопроса, волосы начинают вставать дыбом на всех возможных местах. Узнав, сколько друзья заплатили за подобные услуги, испытываешь приступ шока.
Десятки тысяч рублей выбрасываются просто на ветер и вместо упрощения владельцы бизнесов получают дополнительные проблемы. Возможно, кто-то увидит в заметке проблемы своей организации и сможет сделать соответствующие выводы.
Есть такие люди, которые любят ругать всех и превозносить свои знания. Такие «левши» есть в каждой сфере. Возможно, они прошли за свою практику огонь, воду и медные трубы и имеют полное право так рассуждать. В сфере информационных технологий, людей подпадающих под это описание встретить тяжело. Технологий слишком много и быть экспертом абсолютно во всех – невозможно.
Человек может быть экспертом в нескольких областях, но только не во всех. Например, моя работа большую часть времени связана с разработкой ПО. В этой сфере я чувствую себя намного уверенней, чем в системном администрировании. Я никогда не стану спорить с крутым админом о нюансах маршрутизации пакетов, т.к. сам обладаю поверхностными знаниями.
Мне не составит труда настроить серверные компоненты, поднять FireWall или интернет-шлюз, но я не стараюсь потратить время на детальное изучение уровней модели OSI. Я этого ни капли не стыжусь, т.к. мне больше интересна другая область.
Сегодня довелось поговорить с подобным всезнайкой в области БД. Человек, гордо величавший себя профессионалом, полностью загубил базу КИС и даже не подумал признать свою вину. Он просто делал обновление и что-то пошло не так. Резервную копию перед установкой апдейтов ему делать не захотелось (действительно, а зачем?) и при возникновении проблемы особо голову ломать не стал. Просто залил копию месячной давности и отрапортовал о проделанной работе.
Круто? Я чуть со стула не упал от такого профессионализма. Мало то, что не была создана политика резервного копирования, так этот умелец не удосужился сделать копию перед такой важной операцией как обновление структуры БД. Оказалось, что забывчивость – не главная его проблема.
Я взял телефон этого специалиста и решил лично созвониться. Мало ли, вдруг у человека были веские причины принять это решение. Лучше бы не созванивался. Причин никаких не было, а вот некомпетентности и отсутствие элементарных знаний - целый вал.
Он тупо пытался оправдать себя, и мои вопросы вызвали лишь удивление. Представляете, он заявил мне, что никаких таблиц программа не использует. Все хранится в одном единственном файле. Эти слова окончательно убили во мне частички веры, на положительный исход. Это он мне рассказывал о FireBird.
Раз все хранится в одном файле и программа не может этот файл «прочитать», то надо просто вернуться к старой копии. Зачем пытаться разобраться в проблеме и хотя бы вытащить важную информацию напрямую из таблиц? Дальнейший разговор было продолжать бессмысленно. Специалист просто одним махом убил работу людей за полмесяца и получил вознаграждение.
Если ваша организация не готова содержать штатного IT-специалиста, то настоятельно рекомендую позаботиться о документировании стратегии взаимодействия с приходящим человеком. Нужно на бумаге закреплять его обязанности, и иметь список объектов инфраструктуры, за которые он несет ответственность.
Это не спасет от проблем, но даст четкое понимание, что делает человек и какие участки его работы требуют повышенного внимания. Например, если вы не разбираетесь в ИТ, и в вашей компании есть базы данных, от которых зависит жизнь организации, то не поскупитесь приобрести профессиональную программу для резервного копирования. Пусть приходящий специалист ее настроит, и вы будите получить ежедневные отчеты на email о результатах резервного копирования.
Я не случайно заговорил о программном обеспечении, т.к. на практике прочувствовал, что не все ИТ-специалисты готовы автоматизировать процесс резервного копирования. Они либо берут обязанность за создания копий на себя, либо просто играют в русскую рулетку. В итоге от этой ситуации проигрываете только вы – руководитель компании.