Вот как я лично реализую модели.Я буду использовать пример из реальной жизни: моя User
модель.
Всякий раз, когда я создаю модель, я использую два файла и два класса: сама модель (например, Application_Model_User
) и объект картографирования (например,Application_Model_UserMapper
).Очевидно, что сама модель содержит данные, методы для сохранения, удаления, изменения и т. Д. Объект mapper содержит методы для извлечения объектов модели, поиска объектов и т. Д.
Вот несколько первых строк модели User:
class Application_Model_User {
protected $_id;
protected $_name;
protected $_passHash;
protected $_role;
protected $_fullName;
protected $_email;
protected $_created;
protected $_salt;
// End protected properties
Для каждого свойства у меня есть метод получения и установки.Пример для id
:
/* id */
public function getId() {
return $this->_id;
}
public function setId($value) {
$this->_id = (int) $value;
return $this;
}
Я также использую некоторые стандартные «магические методы» для демонстрации открытых методов получения и установки (внизу каждой модели):
public function __set($name, $value) {
$method = 'set' . $name;
if (('mapper' == $name) || !method_exists($this, $method)) {
throw new Exception('Invalid user property');
}
$this->$method($value);
}
public function __get($name) {
$method = 'get' . $name;
if (('mapper' == $name) || !method_exists($this, $method)) {
throw new Exception('Invalid user property');
}
return $this->$method();
}
public function setOptions(array $options) {
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
Пример save
метод:
Я проверяю внутри метода save()
, используя исключения, когда информация не может быть проверена.
public function save() {
// Validate username
if (preg_match("/^[a-zA-Z](\w{6,15})$/", $this->_name) === 0) {
throw new Application_Exception_UserInfoInvalid();
}
// etc.
$db = Zend_Registry::get("db");
// Below, I would check if $this->_id is null. If it is, then we need to "insert" the data into the database. If it isn't, we need to "update" the data. Use $db->insert() or $db->update(). If $this->_id is null, I might also initialize some fields like 'created' or 'salt'.
}
Для объекта сопоставления у меня есть по крайней мере два метода:метод, который возвращает объект запроса для выбора объектов, и тот, который выполняет запрос, инициализирует и возвращает объекты.Я использую это, чтобы я мог манипулировать запросом в моем контроллере для сортировки и фильтрации.
РЕДАКТИРОВАТЬ
Как я уже говорил в моих комментариях, этот пост: http://weierophinney.net/matthew/archives/202-Model-Infrastructure.html послужило вдохновением для моей текущей реализации Модели.
Дополнительные параметры
Вы также можете использовать Zend_Form
для проверки вместо того, чтобы свернуть свою собственную: http://weierophinney.net/matthew/archives/200-Using-Zend_Form-in-Your-Models.html. Лично мне это не нравитсявариант, так как я думаю, что Zend_Form
неудобно использовать и трудно точно контролировать.
Когда большинство людей впервые изучают Zend Framework, они учатся создавать подклассы Zend_Db
связанных классов.Вот статья, которая демонстрирует это: http://akrabat.com/zend-framework/on-models-in-a-zend-framework-application/
Я упоминал, что мне не нравится это делать.Вот несколько причин, по которым:
- Трудно создавать модели, которые включают производные / вычисляемые поля (т.е. данные, заполненные из других таблиц)
- Я обнаружил, что невозможно включить контроль доступа (заполнено из моей базы данных)
- Мне нравится иметь полный контроль над моими моделями
РЕДАКТИРОВАТЬ 2
Для вашего второго примера: вы можете использовать Zend_Paginator для этого.Я упоминал, что в вашей оболочке вы создаете метод, который возвращает объект запроса к базе данных для выбора объектов.Вот мой упрощенный, но работающий пользовательский маппер:
class Application_Model_UserMapper {
public function generateSelect() {
$db = Zend_Registry::get("db");
$selectWhat = array(
"users_id",
"name",
"role",
"full_name",
"email",
"DATE_FORMAT(created, '%M %e, %Y at %l:%i:%s %p') as created",
"salt",
"passhash"
);
return $db->select()->from(array("u" => "users"), $selectWhat);
}
public function fetchFromSelect($select) {
$rows = $select->query()->fetchAll();
$results = array();
foreach ($rows as $row) {
$user = new Application_Model_User();
$user->setOptions(array(
"id" => $row["users_id"],
"name" => $row["name"],
"role" => $row["role"],
"fullName" => $row["full_name"],
"email" => $row["email"],
"created" => $row["created"],
"salt" => $row["salt"],
"passHash" => $row["passhash"]
));
$results[] = $user;
}
return $results;
}
}
Чтобы справиться со страницей, я пишу собственный плагин Paginator и сохраняю его в library/Application/Paginator/Adapter/Users.php
.Убедитесь, что у вас правильно настроены appnamespace
и autoloaderNamespaces[]
в application.ini.Вот плагин:
class Application_Paginator_Adapter_Users extends Zend_Paginator_Adapter_DbSelect {
public function getItems($offset, $itemCountPerPage) {
// Simply inject the limit clause and return the result set
$this->_select->limit($itemCountPerPage, $offset);
$userMapper = new Application_Model_UserMapper();
return $userMapper->fetchFromSelect($this->_select);
}
}
В моем контроллере:
// Get the base select statement
$userMapper = new Application_Model_UserMapper();
$select = $userMapper->generateSelect();
// Create our custom paginator instance
$paginator = new Zend_Paginator(new Application_Paginator_Adapter_Users($select));
// Set the current page of results and per page count
$paginator->setCurrentPageNumber($this->_request->getParam("page"));
$paginator->setItemCountPerPage(25);
$this->view->usersPaginator = $paginator;
Затем визуализируйте paginator в вашем скрипте вида.