Zend Framework и MVCРеализация Модели
27 марта 2010 г.Санкт-Петербург
Докладчик
Стешенко Александр• Ведущий разработчик компании Norada• Более 7-и лет разработки и проектирования
программного обеспечения• Более 2-х лет использования Zend Framework
Содержание доклада
• Что такое MVC?• MVC в Zend Framework• Реализация модели
Что такое MVC?
Model View Controller
• Модель (Model)- отвечает за данные и поведение бизнес логики приложения
• Представление (View)- отвечает за логику связанную с отображением информации
• Контроллер (Controller)- обрабатывает пользовательский ввод- оперирует моделью для изменения её состояния и
получения необходимых данных- передает данные представлению
Схема отношений в MVC
Модель
Представление
Контроллер
MVC в Zend Framework
Zend_Controller_Front
• Шаблон проектирования Фронт Контроллер (Front Controller)
• Является так называемым «Одиночкой» (Singleton)
• Централизованная точка входа для всех запросов
• Делегирование запроса к специализированному обработчику (Zend_Controller_Action)
Инициализация приложения
Файл /public/index.php
<?php
Zend_Controller_Front::run('../application/controllers');
Диспетчеризация
• Zend_Controller_Front координирует весь процесс жизни приложения
• Объект запроса (Request)- POST, GET, SESSION, COOKIES
• Маршрутизатор (Router)• Диспетчер (Dispatcher)• Объект ответа (Response)
- буферизация вывода
Zend_Controller_Action
• Абстрактный класс для реализации MVC в Zend Framework
• Наследование Zend_Controller_Action классами - контроллерами
• Класс – контроллер группирует наборы обработчиков в виде публичных методов – действий.
Zend_Controller_ActionФайл ../application/controllers/GuestBookController.php
<?phpclass GuestBookController extends Zend_Controller_Action{ public function listCommentsAction() { //[...] } public function addCommentAction() { //[...] }}
Zend_View• Реализация Представления в Zend Framework• Интерпретация «скриптов вида»• Поддержка любых обработчиков шаблонов
public function listAction(){ $guestBookModel = new GuestBook(); $comments = $guestBookModel->getComments(); $view = new Zend_View(); $view->comments = $comments; echo $view->render('guest-book.php');}
Скрипт вида guest-book.phpФайл ../application/views/scripts/guest-book.php
<html> <head> <title>Comments</title> </head> <body> <div>Comments:</div> <?php foreach($this->comments as $comment): ?> <div class = "comment"> <?php echo $this->trim($comment); ?> </div> <?php endforeach; ?> </body></html>
Помощники вида• Механизм для расширения функциональности Вида
- повторяемая логика представления- форматированние данных- доступ к Модели
Файл ../application/views/helpers/Trim.php<?phpclass My_View_Helper_Trim{ public function trim($value) { return trim($value); }}
Помощник действия ViewRenderer
• Помощники действия:- Способ расширить функциональность контроллеров- Перехватчики событий
• Автоматизация настройки объекта Вида• Автоматизация рендеринга шаблонов
Помощник действия ViewRenderer
Файл ../application/controllers/GuestBookController.phpclass GuestBookController extends Zend_Controller_Action{ public function listComments() { $guestBookModel = new GuestBook(); $comments = $guestBookModel->getComments(); $this->view->comments = $comments; } }
Файл ../application/views/scripts/guest-book/list.phtml<?php foreach ($this->comments as $comment): ?> <div class=“comment”><?php echo $comment ?></div><?php endforeach; ?>
Модель
Zend_Model… ?
• Zend Framework предоставляет набор вспомогательных компонент для реализации модели
• Модель – результат процесса моделирования прикладной системы
«Тонкая» модель
• Контроллер выполняет все функции модели- бизнес логика- чтение и запись данных- проверка входящей информации
• Роль модели заключается в доступе к данным
«Тонкая» модель
Файл ../application/models/GuestBook.php
<?php class GuestBook extends Zend_Db_Table_Abstract{ protected $_name = "comments";}
«Толстый» контроллерclass CommentsController extends Zend_Controller_Action{ public function listComments() { $postId = $this->_request->getParam("postid"); $isUser = $this->_request->getCookie("user"); $guestBook = new GuestBook(); $rows = $guestBook->fetchAll("post_id = ?", $postId); $commentsNumber = count($rows); $comments = array(); $hiddenComments = array(); foreach($rows as $row) { if ($row["visible"] == 1) { $comments[] = $row["text"]; } else { if ($isUser) { $hiddenComments[] = $row["text"]; } } } $this->view->comments = $comments; $this->view->hiddenComments = $hiddenComments; }}
«Толстая» модель
Файл ../application/models/GuestBook.php
<?php class GuestBook{ protected $dbTableGateway;
public function getVisibleCommentsByPostId() { }
public function getHiddenCommentsByPostId() { }}
«Тонкий» контроллерpublic function listComments(){ $postId = $this->_request->getParam("post"); $isUser = $this->_request->getCookie("user");
$guestBook = new GuestBook(); $comments = $guestBook ->getVisibleCommentsByPostId($postId, $isUser); $hiddenComments = $guestBook ->getHiddenCommentsByPostId($postId, $isUser);
$this->view->comments = $comments; $this->view->hiddenComments = $hiddenComments;}
Слои (Layers)
Сервисный
слой
Данные
Сервисный слой
• Шаблон проектирования Фасад• Скрывает реализацию объектов бизнес
логики и их взаимодействие- Валидация пользовательского ввода- Авторизация и проверка прав доступа
GuestBookServiceФайл ../application/models/GuestBookService.php
<?phpclass GuestBookService{ //[...] public function addComment($commentData) { $validator = $this->getCommentValidator(); if ($validator->isValid($commentData)) { $this->getCommentTable()->insert($commentData);
} }}
Доменная модель
• Слой инкапсулирующий объекты бизнес логики и взаимодействие между ними
• Отделяет бизнес логику системы от доступа к данным и сервисного слоя
Пользователь (User)Файл ../application/models/User.php
<?phpclass User{ protected $_name; protected $_comments; public function isAdmin(){/*[...]*/} public function authenticate(){/*[...]*/} public function getName(){/*[...]*/} public function getComments(){/*[...]*/}}
Комментарий (Comment)Файл ../application/models/Comment.php
<?phpclass Comment{ protected $_text; /** * Returns comment’s author * * @return User */ public function getAuthor() { return $this->_user; }}
Слой доступа к данным
• Реляционные базы данных- Zend_Db
• Файловая система • Веб сервисы
- Zend_Feed- Zend_Service
• Кеш- Zend_Cache
Table Data Gateway<?php$usersGateway = new UsersGateway();// Добавление нового пользователя$usersGateway->insert($userData);// Обновление данных пользователя$usersGateway->update($userId, $userData);// Удаление пользователя$usersGateway->delete($userId);// Чтение данных$rows = $usersGateway->findAllByAddress($address);// Преобразование в доменные объекты$users = array();foreach ($rows as $row) { $users[] = new User($row);}
Zend_Db_Table<?php class UsersGateway extends Zend_Db_Table_Abstract{ protected $_name = 'users';
public function findAllByAddress($address) { $where = $this->getAdapter() ->quoteInto('adress = ?',
$address); $rows = $this->fetchAll($where); return $rows; }}
Active Record / ORM// Добавление нового пользователя$user = new User($userData);$user->save();// Обновление данных$user->setName($newUserName);$user->save();// Удаление записи о пользователе$user->delete();
// Чтение данных$users = $userFinder->findAllByAddress($address);// или$users = User::findAllByAddress($address);
Zend ORMclass User extends Zend_Db_Table_Row_Abstract{ public function authorize(){/*[...]*/}}
class Users extends Zend_Db_Table_Abstract{ protected $_name = 'users'; protected $_rowClass = 'User'; public function findAllByAddress($address){/*[...]*/}}
$users = new Users;$user = $users->findAllByAddress($address);
Data Mapper
// Добавление нового пользователя$user = new User($userData);$usersMapper->save($user);// Обновление данных$user->setName($newUserName);$usersMapper->save($user);// Удаление записи о пользователе$usersMapper->delete($user);
// Чтение данных$users = $usersMapper-
>findAllByAddress($address);
Data Mapper Поиск объекта по параметру
class UsersMapper{ protected $_db; public function findAllByAddress($address) { $rows = $this->_db->fetchAll( 'Select * From users Where address = ?',
array($address)); $users = array(); foreach ($rows as $row) { $user = new User(); $user->setName($row); $user->setAddress($address); $users[] = $user; } return $users; }
Data Mapper Добавление объекта
public function insert(User $user) { $data = array( 'name' => $user->getName(), 'address' => $user->getAddress() ); $this->_db->insert('users', $data); }
Преимущества Data Mapper
• Доменные объекты инкапсулируют только бизнес логику и не зависят от реализации их хранения- преимущества ORM без зависимости от
реляционных баз данных• Наилучшее разбиение на слои
- рефакторинг- при изменении одной компоненты, остальные не
изменяются- тестирование
Реализация Data Mapper
• Zend_Entity… ?• Doctrine 2• phpDataMapper ORM