Как работать с базами данных или знакомство с компонентом Zend_Db

Как работать с базами данных или знакомство с компонентом Zend_Db

Редко какое веб-приложение обходится без работы с базой данных. Компонент 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 оставлю вам в качестве упражнения 😉 Если не получится, задавайте вопросы, с радостью отвечу.

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

Ссылки:

miholeus

Related Posts

Кастомный элемент формы или Plugin by name xxx was not found in the registry

Как настроить xgettext для перевода phtml файлов

Как настроить xgettext для перевода phtml файлов

Метки вида

Метки вида

Zend Layout и ajax приложение просмотра погоды

Zend Layout и ajax приложение просмотра погоды

Leave a Reply

1 Comment

  1. Кто и где отредактировать этим летом в отпуск , поделитесь информацией.

Leave a Reply

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