Редко какое веб-приложение обходится без работы с базой данных. Компонент Zend_Db предоставляет удобный интерфейс доступа к SQL базам данных. Он использует ряд адаптеров для соединения с различными

базами данных. На полноценную ORM рассчитывать не приходится, да это и не нужно в большинстве случаев, Zend_Db является своего рода конструктором запросов. Разводить холивара на тему того, использовать

ли plain sql или ORM, не буду. Лично я сложные запросы предпочитаю записывать в явном виде, а простые можно генерировать, используя тот же самый Zend_Db.

Итак, вспомним наш каталог книг, который мы делали при помощи компонента Zend_Session_Namespace. Сессии – это, конечно, хорошо, но все-таки хочется иметь возможность сохранить информацию, чтобы потом

в любой момент иметь к ней доступ, а не только во время текущего сеанса 😉

Сначала нам необходимо настроить соединение с базой данных. Идем в application/configs/application.ini и прописываем такие строчки:

[code language=”php”]

;DB settings
resources.db.adapter = “pdo_mysql”
resources.db.params.host = “localhost”
resources.db.params.username = “zf”
resources.db.params.password = “s3cr3t”
resources.db.params.dbname = “books”
resources.db.isDefaultTableAdapter = true
resources.db.params.driver_options.1002 = “SET NAMES utf8”

[/code]

В качестве адаптера я выбрал pdo_mysql, имя пользователя – zf, пароль – s3cr3t, имя базы данных – books.

Далее необходимо создать базу данных books и выставить привилегии

[code language=”bash”]

mysqladmin create books -uroot -p

mysql -uroot -p -e “grant all privileges on books.* to [email protected] identified by ‘s3cr3t'”

[/code]

Создаем таблицу

[code language=”sql”]
CREATE  TABLE  `books`.`books` (
`id` INT NOT  NULL  AUTO_INCREMENT  PRIMARY  KEY ,
`name` VARCHAR( 255  )  NOT  NULL ,
`author` VARCHAR( 100  )  NOT  NULL ,
`description` VARCHAR( 255  )  NOT  NULL
) ENGINE  = InnoDB;

[/code]

Опишем модель books, которая будет манипулировать книгами.

[code language=”php”]

class Model_Book
{

protected $name;
protected $author;
protected $description;
protected $mapper;

public function getName()
{
return $this->name;
}

public function setName($name)
{
$this->name = $name;
return $this;
}

public function getAuthor()
{
return $this->author;
}

public function setAuthor($author)
{
$this->author = $author;
return $this;
}

public function getDescription()
{
return $this->description;
}

public function setDescription($desc)
{
$this->description = $desc;
return $this;
}

public function getMapper()
{
if( null === $this->mapper) {
$this->mapper = new Model_BookMapper();
}
return $this->mapper;
}
public function save()
{
$this->getMapper()->save($this);
}

public function find($id)
{
return $this->getMapper()->find($id, $this);
}

}

[/code]

Для книг имеется три свойства – это название книги (name), автор книги (author) и описание (description). Для них мы определили свои сетеры и гетеры. Еще есть два метода – save и find, которые используют класс маппера для доступа к данным. Используя шаблон Data Mapper, мы как бы абстрагируемся от работы с базой данных и скрываем от модели все взаимодействие с БД. В случае же изменения структуры таблицы, нам просто необходимо будет создать соответствующие свойства в модели и указать для них get и set методы доступа. Класс BookMapper определим пока следующим образом:

[code language=”php”]

class Model_BookMapper
{

public function save(Model_Book $book)
{

}

public function find($id, Model_Book $book)
{

}

}

[/code]

Перейдем пока в контроллер BookController.php

[code language=”php”]

class BookController extends Zend_Controller_Action
{

public function createAction()
{
$frmBook = new Form_Book();
$frmBook->setMethod(‘post’);
if($this->_request->isPost()) {
if($frmBook->isValid($this->_request->getPost())) {
$mdlBook = new Model_Book($frmBook->getValues());
$mdlBook->save();
}
}
$this->view->form = $frmBook;
}

}

[/code]

Мы получаем данные из формы и передаем их в конструктор объекта Книга, затем просто сохраняем объект. Красиво получается и совсем мало кода, не правда ли?) Но теперь нам нужно определить конструктор объекта, чтобы двумя строчками кода создавать новый объект.

[code language=”php”]

// application/models/Book.php

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;
}

public function __construct(array $options = null)
{
if (is_array($options)) {
$this->setOptions($options);
}
}

public function __set($name, $value)
{
$method = ‘set’ . $name;
if ((‘mapper’ == $name) || !method_exists($this, $method)) {
throw new Exception(‘Invalid book property’);
}
$this->$method($value);
}

public function __get($name)
{
$method = ‘get’ . $name;
if ((‘mapper’ == $name) || !method_exists($this, $method)) {
throw new Exception(‘Invalid book property’);
}
return $this->$method();
}

[/code]

Теперь осталось реализовать методы в mapper классе.

[code language=”php”]

// application/models/BookMapper.php

protected $_dbTable;

public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception(‘Invalid table data gateway provided’);
}
$this->_dbTable = $dbTable;
return $this;
}

public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable(‘Model_DbTable_Book’);
}
return $this->_dbTable;
}

public function save(Model_Book $book)
{
$data = array(
‘name’   => $book->getName(),
‘author’ => $book->getAuthor(),
‘description’ => $book->getDescription()
);

if (null === ($id = $book->getId())) {
unset($data[‘id’]);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array(‘id = ?’ => $id));
}
}

public function find($id, Model_Book $book)
{
$result = $this->getDbTable()->find($id);
if (0 == count($result)) {
return;
}
$row = $result->current();
$book->setId($row->id)
->setName($row->name)
->setAuthor($row->author)
->setDescription($row->description);
}

[/code]

Ах да, я забыл про идентификатор записи. Так что в модели Book необходимо добавить:

[code language=”php”]

protected $id;

public function getId()
{
return $this->id;
}

public function setId($id)
{
$this->id = $id;
return $this;
}

[/code]

В маппер классе мы используем шлюз Model_DbTable_Book для манипуляции с данными таблицы. В папке models необходимо создать папку DbTable, внутри которой  – файл Book.php.

[code language=”php”]
class Model_DbTable_Book extends Zend_Db_Table_Abstract
{
protected $_name = ‘books’;
}
[/code]

Класс Model_DbTable_Book является наследником класса Zend_Db_Table_Abstract, так что методы типа find, insert, update, которые используются в маппер классе уже реализованы.

Можно теперь попробовать добавить книгу в базу данных, должно получиться =). Настало время для отображения всех книг, откроем indexAction контроллера Книги.

[code language=”php”]

public function indexAction()
{
$mdlBook = new Model_BookMapper();
$this->view->books = $mdlBook->fetchAll();
}

[/code]

Добавим метод fetchAll в mapper класс

[code language=”php”]

public function fetchAll()
{
$resultSet = $this->getDbTable()->fetchAll();
$entries   = array();
foreach ($resultSet as $row) {
$book = new Model_Book();
$book->setId($row->id)
->setName($row->name)
->setAuthor($row->author)
->setDescription($row->description);
$entries[] = $book;
}
return $entries;
}

[/code]

Создадим view для отображения всех книг

[code language=”html”]

<!– application/views/scripts/book/index.phtml –>

<h2>List of all books</h2>
<?php
if(count($this->books)) {
?>
<dl>
<?php
foreach($this->books as $book) {
?>
<dt>
<?=$book->name?> | <small>author: <?=$book->author?></small> |
<a href=”/book/update/id/<?=$book->id?>”>update</a>&nbsp;
<a href=”/book/delete/id/<?=$book->id?>”>delete</a>
</dt>
<dd>
<?=$book->description?>
</dd>
<?php
}
?>
</dl>
<?php
}

[/code]

Можно насладиться результатом, открыв страницу /book. На этом, пожалуй, я сегодня закончу.

Реализацию методов update и delete оставлю вам в качестве упражнения 😉 Если не получится, задавайте вопросы, с радостью отвечу.

На всякий случай прикрепил исходники проекта.

Ссылки:

Leave a Reply

One thought on “Как работать с базами данных или знакомство с компонентом Zend_Db”
  1. Кто и где отредактировать этим летом в отпуск , поделитесь информацией.

Leave a Reply

Your email address will not be published. Required fields are marked *