Обзор
Doctrine 2 представляет собой хороший пример механизма объектно-реляционного отображения (ORM) для PHP 5.3+, позволяющий работать с базой данных максимально прозрачно, где в качестве промежуточного слоя используются обычные объекты PHP. В качестве основы используется весьма мощный слой абстракции от базы данных (DBAL). Основная задача ORM — связать две концепции: объекты PHP и записи в реляционной базе данных. Одна из ключевых особенностей Doctrine — возможность написания запросов на собственном объектно-ориентированном языке, чем-то напоминающим SQL, называемым Doctrine Query Language (DQL). Помимо небольших отличий от SQL, он позволяет значительно усилить степень абстракции между объектами и строками базы данных, что позволяет создавать мощные и гибкие запросы, при этом сохраняя целостность.
В дополнение к Doctrine 2, мы также ознакомимся с концепцией Фикстур данных. Фикстуры данных представляют собой механизм для заполнения баз данных для разработки и тестирования подходящими тестовыми данными. В конце этой главы вы определите модель блога, обновите базу данных, чтобы отразить новую модель, и создадите несколько фикстур данных.
Проект на Github
Узнать как установить нужную вам часть руководства, можно в описании к репозиторию по ссылке. (Например, если вы хотите начать с это урока не проходя предыдущий)
Doctrine 2: Модель
Чтобы наш блог функционировал нам нужно подумать о том, как мы будем хранить данные. Doctrine 2 предоставляет библиотеку ОRМ, предназначенную именно для этой цели. Она позволяет использовать различные СУБД включая MySQL, PostgreSQL и SQLite. Мы будем использовать MySQL, но ее можно легко заменить другой СУБД.
Заметка
Если вы не знакомы с ORM мы раскроем базовые принципы. Определение от Wikipedia гласит:
ORM (англ. Object-Relational Mapping, рус. объектно-реляционное отображение) — технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая «виртуальную объектную базу данных».ОRМ облегчает перевод данных из реляционной базы данных, такие как MySQL в PHP объекты, которыми мы можем манипулировать. Это позволяет нам инкапсулировать нужную функциональность, которая нам необходима в таблице, через класс. Представьте таблицу пользователя, она вероятно имеет поля: username, password, first_name, last_name, email и job. С помощью ОRМ это становится классом с свойствами username, password, first_name и т.д., что позволяет нам вызывать такие методы, как getUsername() и setPassword(). ORM пошло гораздо дальше, оно также позволяет получить связанные таблицы, в то время как мы извлекаем объект пользователя или позже. Теперь предположим, что наш пользователь имеет несколько друзей, связанных с ним. Это будет таблица друзей, с первичным ключом для таблицы пользователя. Теперь с помощью ORM мы можем вызвать метод $user->getFriends() чтобы вернуть объекты из таблицы друзей. ORM также занимается сохранением данных, так что мы можем создавать объекты в PHP, вызывать метод save() и ORM займется сохранением данных в базу. Так как мы используем Doctrine 2 ORM библиотеку, вы гораздо лучше узнаете о её возможностях по ходу прохождения руководства.
Примечание
В то время как, это руководство будет использовать библиотеку Doctrine 2 ORM, вы можете выбрать библиотеку Doctrine 2 ODM. Существует несколько вариаций этой библиотеки, включая реализации для MongoDB и CouchDB. Смотрите страницу Doctrine Projects для получения дополнительной информации.
Так же вы можете посмотреть эту статью, которая объясняет, как установить ODM с Symfony 2.
База данных
Создание Базы данных
Если вы проходите руководство с первой части, у вас уже должны быть прописаны параметры базы данных. Если вы пропустили первую часть, то обновите значения database_ * в файле параметров, расположенного в app/config/parameters.yml
Создадим базу данных с помощью команды Doctrine 2. Эта команда лишь создаёт базу данных и не создаёт никаких таблиц в базе. Если база данных с таким же именем уже существует будет выведено сообщение об ошибке, а существующая база данных будет оставлена без изменений.
$ php app/console doctrine:database:create
Сущность Blog
Мы начнём с создания класса сущности Blog. Мы уже говорили о сущностях в предыдущей части, когда создавали сущность Enquiry. Поскольку сущность предназначена для хранения данных, имеет смысл использовать одну сущность для представления записи в блоге. Когда мы определяем сущность мы не говорим этим чтобы данные автоматически были сопоставлены с базой. Мы видели это в нашей сущности Enquiry (Запрос) где данные, хранящиеся в сущности были лишь только отправлены по электронной почте веб-мастеру.
Создайте новый файл src/Blogger/BlogBundle/Entity/Blog.php
и вставьте следующее:
<?php
// src/Blogger/BlogBundle/Entity/Blog.php
namespace BloggerBlogBundleEntity;
class Blog
{
protected $title;
protected $author;
protected $blog;
protected $image;
protected $tags;
protected $comments;
protected $created;
protected $updated;
}
Как вы видите это простой PHP класс. Он не расширяет родительский и не имеет методов доступа. Каждое свойство заявлено как protected таким образом, мы не в состоянии получить доступ к ним при работе с объектом этого класса. Мы могли бы прописать геттеры и сеттеры для этих свойств, но в Doctrine 2 есть команда, которая выполняет эту задачу за нас.
Перед тем как запустить эту команду, мы должны сообщить Doctrine 2 каким образом сущность Blog должна быть отображена в базе данных. Информация указана в качестве метаданных, используя Doctrine 2 сопоставления. Метаданные могут быть определены в разных форматах включая: YAML, PHP, XML и Аннотации. В этом руководстве мы будем использовать аннотации. Важно отметить, что не все свойства в объекте должны быть сохранены, так что мы не будем предоставлять метаданные для них. Это дает нам возможность выбрать только те элементы, которые нам требуются, чтобы Doctrine 2 сопоставило их с базой данных. Замените содержимое класса сущности Blog, расположенной src/Blogger/BlogBundle/Entity/Blog.php
<?php
// src/Blogger/BlogBundle/Entity/Blog.php
namespace BloggerBlogBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity
* @ORMTable(name="blog")
*/
class Blog
{
/**
* @ORMId
* @ORMColumn(type="integer")
* @ORMGeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORMColumn(type="string")
*/
protected $title;
/**
* @ORMColumn(type="string", length=100)
*/
protected $author;
/**
* @ORMColumn(type="text")
*/
protected $blog;
/**
* @ORMColumn(type="string", length=20)
*/
protected $image;
/**
* @ORMColumn(type="text")
*/
protected $tags;
protected $comments;
/**
* @ORMColumn(type="datetime")
*/
protected $created;
/**
* @ORMColumn(type="datetime")
*/
protected $updated;
}
Во-первых, мы импортируем и определяем пространство имен Doctrine 2 ОRМ Mappings. Это позволяет нам использовать аннотации для описания метаданных сущности. Метаданные содержат информацию о том, как свойства должны быть отображены в базе данных.
Заметка
Мы использовали только небольшую часть предоставляемых Doctrine 2 типов сопоставления. Полный список типов сопоставлений можно найти на веб-сайте Doctrine 2. Другие типы сопоставлений будут рассмотрены позже в этом руководстве.
Посмотрев внимательнее, вы возможно, заметили, что для свойства $comments не описаны метаданные. Это произошло потому, что мы не нуждаемся в сохранении, оно будет просто предоставлять набор комментариев, относящихся к сообщению в блоге. Подумайте об этом абстрагируясь от базы данных. Следующий код покажет более наглядно.
// Create a blog object.
$blog = new Blog();
$blog->setTitle("symblog - A Symfony2 Tutorial");
$blog->setAuthor("dsyph3r");
$blog->setBlog("symblog is a fully featured blogging website ...");
// Create a comment and add it to our blog
$comment = new Comment();
$comment->setComment("Symfony2 rocks!");
$blog->addComment($comment);
Приведенный выше фрагмент кода демонстрирует нормальное поведение, которого вы ожидаете от блога и комментариев класса. Внутренний метод $blog->addComment() может быть реализован следующим образом.
class Blog
{
protected $comments = array();
public function addComment(Comment $comment)
{
$this->comments[] = $comment;
}
}
Метод addComment просто добавляет новый объект комментария свойства блога $comments. Получение комментариев тоже реализуется довольно просто.
class Blog
{
protected $comments = array();
public function getComments()
{
return $this->comments;
}
}
Как вы можете видеть свойство $comments это просто список объектов Comment. Doctrine 2 не меняет, то как это работает. Doctrine 2 будет иметь возможность автоматически заполнять $comments свойство объектами, связанных с объектом blog.
Теперь, когда мы поговорили как сопоставить свойства сущности в Doctrine 2, мы можем сгенерировать методы доступа, используя следующую команду в консоли.
$ php app/console doctrine:generate:entities Blogger
Вы будете уведомлены, что сущность Blog была обновлена с методами доступа. Каждый раз, когда мы делаем изменения в метаданных ORM классов наших сущностей мы можем запустить эту команду, чтобы сгенерировать какие-либо дополнительные методы доступа. Эта команда не будет делать изменения в методах доступа, уже имеющихся в сущности, так что ваши существующие доступы, никогда не будут переопределены этой командой. Это важно, поскольку впоследствии вы можете изменить некоторые методы.
Заметка
В то время как мы используем аннотации в нашей сущности, можно преобразовать информацию сопоставления в другие поддерживаемые форматы сопоставления используя команду doctrine:mapping:convert. Например, следующая команда, преобразует сопоставления сущности выше в yml формат.
$ php app/console doctrine:mapping:convert --namespace="BloggerBlogBundleEntityBlog" yaml src/Blogger/BlogBundle/Resources/config/doctrine
И создаст файл в
src/Blogger/BlogBundle/Resources/config/doctrine/Blogger.BlogBundle.Entity.Blog.orm.yml
который будет содержать сопоставления сущности blog в yml формате.
Теперь мы готовы создать представление сущности Blog в базе данных. Есть 2 способа с помощью которых мы можем достичь этого. Мы можем использовать Doctrine 2 schema команды для обновления базы данных или более мощные, миграции Doctrine 2. Сейчас мы будем использовать schema команды. Миграции Doctrine буду рассмотрены в следующей части руководства.
Создание таблицы blog
Для создания таблицы blog мы можем воспользоваться следующей командой.
$ php app/console doctrine:schema:create
Это вызовет действия для генерации схемы базы данных для сущности blog. Вы можете также передать --dump-sql опцию, чтобы сделать дамп SQL. Если вы посмотрите на базу данных, то вы увидите, что таблица blog была создана с полями, к которым мы сделали сопоставление.
Совет
Мы использовали ряд консольных команд Symfony2. Вы можете получить помощь по любой команде введя опцию --help. Например, чтобы увидеть помощь по команде doctrine:schema:create введите:
$ php app/console doctrine:schema:create --help
Справочная информация выведет методы использования, а также доступные опции. Большинство команд выполняются с несколькими опциями, которые могут расширить её.
Модель и отображение. Вывод записи блога.
Сейчас у нас есть сущность Blog и обновлённая база данных для её представления, мы можем начать интегрировать модель в отображение. Мы начнем с создания страницы show нашего блога.
Маршрут Show Blog
Мы начнём с создания маршрута для blog show action. Блог будет идентифицировать запись по уникальному ID, таким образом этот ID должен быть представлен в URL. Обновите BloggerBlogBundle маршрут, расположенный src/Blogger/BlogBundle/Resources/config/routing.yml
следующим:
# src/Blogger/BlogBundle/Resources/config/routing.yml
BloggerBlogBundle_blog_show:
path: /{id}
defaults: { _controller: BloggerBlogBundle:Blog:show }
requirements:
methods: GET
id: d+
Так как ID записи должен быть представлен в URL, мы определили id placeholder. Это означает что URL вида http://localhost:8000/1 и http://localhost:8000/my-blog будут соответствовать этому маршруту. Однако, мы знаем, что id блога должно быть целым числом, (он определён таким образом в сопоставлении сущности) поэтому мы можем добавить ограничение, определяющее что этот маршрут будет соответствовать только тогда, когда параметр id содержит целое число. Это достигается с помощью id: d+ требованием маршрута. Теперь только первый пример URL будет соответствовать, а http://localhost:8000/my-blog уже нет. Вы также можете увидеть, как соответствующий маршрут выполнит showAction, метод контроллера BloggerBlogBundleBlog. Этот контроллер ещё должен быть создан.
Метод showAction
Клей связывающий Модель и отображение — это контроллер, это то место где мы начнём создание страницы. Мы могли бы добавить метод showAction к нашему существующему контроллеру Page, но так как эта страница посвящена отображению сущностей blog, будет лучше добавить их в свой собственный контроллер Blog.
Создайте новый файл, расположенный в src/Blogger/BlogBundle/Controller/BlogController.php
и вставьте следующее.
<?php
// src/Blogger/BlogBundle/Controller/BlogController.php
namespace BloggerBlogBundleController;
use SymfonyBundleFrameworkBundleControllerController;
/**
* Blog controller.
*/
class BlogController extends Controller
{
/**
* Show a blog entry
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$blog = $em->getRepository('BloggerBlogBundle:Blog')->find($id);
if (!$blog) {
throw $this->createNotFoundException('Unable to find Blog post.');
}
return $this->render('BloggerBlogBundle:Blog:show.html.twig', array(
'blog' => $blog,
));
}
}
Мы создали новый контроллер для сущности Blog и определили метод showAction, а также задали id параметр в BloggerBlogBundle_blog_show правиле маршрута, он будет вставлен в качестве аргумента в метод showAction. Если бы мы определили больше параметров в правиле маршрута, они бы так же были бы вставлены в качестве аргументов, через запятую.
Далее нам нужно получить сущность Blog из базы данных. Мы впервые используем другой вспомогательный метод класса SymfonyBundleFrameworkBundleControllerController, чтобы получить Doctrine2 Manager. Работой Manager является обрабатывание, извлечение и сохранение объектов в базу данных и из неё. Далее мы используем объект Manager для получения Doctrine 2 Репозитория для сущности BloggerBlogBundle:Blog. Синтаксис, указанный здесь, просто сокращения, которые могут быть использованы в Doctrine 2 вместо указания полного названия сущности BloggerBlogBundleEntityBlog. Вместе с объектом репозитория мы вызываем метод find() и передаём в аргументе $id. Этот метод будет получать объект по его первичному ключу.
И в конце мы проверяем, что сущность была найдена и передаём её в отображение. Если сущности не будет найдено, то вернётся createNotFoundException. Это сформирует ответ 404 Not Found.
Заметка
Объект репозитория предоставляет доступ к ряду полезных вспомогательных методов, включая
// Return entities where 'author' matches 'dsyph3r' $em->getRepository('BloggerBlogBundle:Blog')->findBy(array('author' => 'dsyph3r')); // Return one entity where 'slug' matches 'symblog-tutorial' $em->getRepository('BloggerBlogBundle:Blog')->findOneBySlug('symblog-tutorial');
Мы будем создавать свои собственные пользовательские классы в Репозитории в следующей части, когда нам потребуются более сложные запросы к базе данных.
Отображение
Мы создали метод showAction для контроллера Blog и можем сфокусироваться на отображении сущности Blog. Как указано в методе showAction будет выведен шаблон BloggerBlogBundle:Blog:show.html.twig. Давайте создадим этот шаблон src/Blogger/BlogBundle/Resouces/views/Blog/show.html.twig
и вставим следующее.
{# src/Blogger/BlogBundle/Resouces/views/Blog/show.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}
{% block title %}{{ blog.title }}{% endblock %}
{% block body %}
<article class="blog">
<header>
<div class="date"><time datetime="{{ blog.created|date('c') }}">{{ blog.created|date('l, F j, Y') }}</time></div>
<h2>{{ blog.title }}</h2>
</header>
<img src="{{ asset(['images/', blog.image]|join) }}" alt="{{ blog.title }} image not found" class="large" />
<div>
<p>{{ blog.blog }}</p>
</div>
</article>
{% endblock %}
Как и следовало ожидать, мы начнем с расширения основного шаблона Blogger BlogBundle. Далее мы переопределим заголовок страницы заголовком для нашего блога. Это будет полезно для SEO, так как заголовок страницы блога является более описательным, чем заголовок по умолчанию. Наконец, мы переопределим блок body для вывода контента сущности Blog. Мы используем функцию asset снова, чтобы вывести изображение в блоге. Изображения блога должны быть помещены в директорию web/images. Скачать изображения можно по ссылке.
CSS
Для того сделать визуальное оформление, нам нужно добавить некоторый стили. Добавьте стили ниже в src/Blogger/BlogBundle/Resouces/public/css/blog.css.
.date { margin-bottom: 20px; border-bottom: 1px solid #ccc; font-size: 24px; color: #666; line-height: 30px }
.blog { margin-bottom: 20px; }
.blog img { width: 190px; float: left; padding: 5px; border: 1px solid #ccc; margin: 0 10px 10px 0; }
.blog .meta { clear: left; margin-bottom: 20px; }
.blog .snippet p.continue { margin-bottom: 0; text-align: right; }
.blog .meta { font-style: italic; font-size: 12px; color: #666; }
.blog .meta p { margin-bottom: 5px; line-height: 1.2em; }
.blog img.large { width: 300px; min-height: 165px; }
Заметка
Если вы не используете метод символических ссылок для обращения к assets бандла в папке web, вы должны повторно запустить команду установки assets.
$ php app/console assets:install web
Так как мы создали контроллер и отображение для метода showAction давайте взглянем на страницу. Введите в ваш браузер http://localhost:8000/1. Это не та страница, которую вы ожидали увидеть?
Symfony сгенерировал ответ 404 Not Found. Это произошло потому что у нас нет данных в базе, т.е. сущность с id равным 1 не может быть найдена. Можно просто вставить строку в таблицу blog вашей базы данных, но мы будем использовать метод значительно лучше: Фикстуры данных.
Фикстуры данных
Мы можем использовать фикстуры для заполнения базы данных некоторыми простыми тестовыми данными. Для этого мы используем doctrine-fixtures-bundle и data-fixtures. Расширение Doctrine Fixtures не поставляется с Symfony2, мы должны вручную его установить. К счастью это простая задача. Откройте файл composer.json расположенный в корне проекта и вставьте следующее:
"require": {
// ...
"doctrine/doctrine-fixtures-bundle": "dev-master",
"doctrine/data-fixtures" : "dev-master"
}
Далее обновите библиотеки командой.
$ composer update
Это обновит все библиотеки с Github и установит их в необходимые директории.
Теперь давайте зарегистрируем DoctrineFixturesBundle в kernel расположенного в
app/AppKernel.php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new DoctrineBundleFixturesBundleDoctrineFixturesBundle(),
// ...
);
// ...
}
Фикстуры Блога
Теперь мы готовы определить фикстуры для нашего блога. Создайте файл фикстур src/Blogger/BlogBundle/DataFixtures/ORM/BlogFixtures.php
и вставьте
<?php
// src/Blogger/BlogBundle/DataFixtures/ORM/BlogFixtures.php
namespace BloggerBlogBundleDataFixturesORM;
use DoctrineCommonDataFixturesFixtureInterface;
use DoctrineCommonPersistenceObjectManager;
use BloggerBlogBundleEntityBlog;
class BlogFixtures implements FixtureInterface
{
public function load(ObjectManager $manager)
{
$blog1 = new Blog();
$blog1->setTitle('A day with Symfony2');
$blog1->setBlog('Lorem ipsum dolor sit amet, consectetur adipiscing eletra electrify denim vel ports.nLorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ut velocity magna. Etiam vehicula nunc non leo hendrerit commodo. Vestibulum vulputate mauris eget erat congue dapibus imperdiet justo scelerisque. Nulla consectetur tempus nisl vitae viverra. Cras el mauris eget erat congue dapibus imperdiet justo scelerisque. Nulla consectetur tempus nisl vitae viverra. Cras elementum molestie vestibulum. Morbi id quam nisl. Praesent hendrerit, orci sed elementum lobortis, justo mauris lacinia libero, non facilisis purus ipsum non mi. Aliquam sollicitudin, augue id vestibulum iaculis, sem lectus convallis nunc, vel scelerisque lorem tortor ac nunc. Donec pharetra eleifend enim vel porta.');
$blog1->setImage('beach.jpg');
$blog1->setAuthor('dsyph3r');
$blog1->setTags('symfony2, php, paradise, symblog');
$blog1->setCreated(new DateTime());
$blog1->setUpdated($blog1->getCreated());
$manager->persist($blog1);
$blog2 = new Blog();
$blog2->setTitle('The pool on the roof must have a leak');
$blog2->setBlog('Vestibulum vulputate mauris eget erat congue dapibus imperdiet justo scelerisque. Na. Cras elementum molestie vestibulum. Morbi id quam nisl. Praesent hendrerit, orci sed elementum lobortis.');
$blog2->setImage('pool_leak.jpg');
$blog2->setAuthor('Zero Cool');
$blog2->setTags('pool, leaky, hacked, movie, hacking, symblog');
$blog2->setCreated(new DateTime("2011-07-23 06:12:33"));
$blog2->setUpdated($blog2->getCreated());
$manager->persist($blog2);
$blog3 = new Blog();
$blog3->setTitle('Misdirection. What the eyes see and the ears hear, the mind believes');
$blog3->setBlog('Lorem ipsumvehicula nunc non leo hendrerit commodo. Vestibulum vulputate mauris eget erat congue dapibus imperdiet justo scelerisque.');
$blog3->setImage('misdirection.jpg');
$blog3->setAuthor('Gabriel');
$blog3->setTags('misdirection, magic, movie, hacking, symblog');
$blog3->setCreated(new DateTime("2011-07-16 16:14:06"));
$blog3->setUpdated($blog3->getCreated());
$manager->persist($blog3);
$blog4 = new Blog();
$blog4->setTitle('The grid - A digital frontier');
$blog4->setBlog('Lorem commodo. Vestibulum vulputate mauris eget erat congue dapibus imperdiet justo scelerisque. Nulla consectetur tempus nisl vitae viverra.');
$blog4->setImage('the_grid.jpg');
$blog4->setAuthor('Kevin Flynn');
$blog4->setTags('grid, daftpunk, movie, symblog');
$blog4->setCreated(new DateTime("2011-06-02 18:54:12"));
$blog4->setUpdated($blog4->getCreated());
$manager->persist($blog4);
$blog5 = new Blog();
$blog5->setTitle('You're either a one or a zero. Alive or dead');
$blog5->setBlog('Lorem ipsum dolor sit amet, consectetur adipiscing elittibulum vulputate mauris eget erat congue dapibus imperdiet justo scelerisque.');
$blog5->setImage('one_or_zero.jpg');
$blog5->setAuthor('Gary Winston');
$blog5->setTags('binary, one, zero, alive, dead, !trusting, movie, symblog');
$blog5->setCreated(new DateTime("2011-04-25 15:34:18"));
$blog5->setUpdated($blog5->getCreated());
$manager->persist($blog5);
$manager->flush();
}
}
Файл фикстур демонстрирует ряд важных особенностей при использовании Doctrine 2, в том числе, как сохранять объекты в базу данных.
Давайте посмотрим, как мы создаем одну запись в блоге.
$blog1 = new Blog();
$blog1->setTitle('A day in paradise - A day with Symfony2');
$blog1->setBlog('Lorem ipsum dolor sit d us imperdiet justo scelerisque. Nulla consectetur...');
$blog1->setImage('beach.jpg');
$blog1->setAuthor('dsyph3r');
$blog1->setTags('symfony2, php, paradise, symblog');
$blog1->setCreated(new DateTime());
$blog1->setUpdated($this->getCreated());
$manager->persist($blog1);
// ..
$manager->flush();
Мы начинаем с создания объекта Blog и определения значений его свойств. На данный момент Doctrine 2 ничего не знает об объекте сущности. Это произойдёт только тогда, когда мы вызываем $manager->persist($blog1), этим мы поручаем Doctrine 2, приступить к управлению этого объекта сущности. Объект $manager здесь является экземпляром объекта Manager который мы видели ранее при получении объектов из базы данных. Важно отметить, что в то время как Doctrine 2 в настоящее время известно об объекте сущности, она до сих пор не сохраняется в базе данных. Для этого необходим вызов $manager->flush() Метод flush заставляет Doctrine 2, начать взаимодействовать с базой данных и задействовать все сущности, которыми она управляет. Для лучшей производительности следует группировать команды Doctrine 2 и выполнять все действия за один раз. Мы создали каждый объект, попросили Doctrine 2, начать управлять ими, а затем выполнили необходимые операции.
Загрузка фикстур
Теперь мы готовы загрузить фикстуры в базу данных
$ php app/console doctrine:fixtures:load
На вопрос продолжать ли выполнение команды отвечаем: yes
Если мы взглянем на страницу http://localhost:8000/1 мы увидим запись в блоге.
Попробуйте поменять id в URL на 2. Вы должны увидеть следующую запись.
Если вы перейдете по URL http://localhost:8000/100 вы увидите ошибку 404 Not Found. Это произошло, как и ожидалось так как нет сущности Blog с id равным 100. Теперь попробуйте ввести http://localhost:8000/symfony2-blog Почему нет ошибки 404 Not Found? Это связано с тем что метод showAction не был вызван. URL-адрес не соответствует ни одному маршруту в приложении в связи с d+ требованием, которое мы установили в BloggerBlogBundle_blog_show маршруте. Вот почему вы видите не найден маршрут для исключения «GET /symfony2-blog».
Метка времени
Наконец, в этой части мы посмотрим на 2 свойства меток времени в сущности Blog: created и updated. Функциональные возможности для этих 2-х членов, обычно называют как поведение Timestampable. Эти свойства содержат время, когда была создана запись и время её последнего обновления. Поскольку мы не хотим, вручную устанавливать эти поля каждый раз, когда мы создаем или обновляем запись, мы можем использовать Doctrine 2 для этих целей.
Doctrine 2 поставляется с Event System, которая обеспечивает Lifecycle Callbacks. Мы можем использовать эти события обратного вызова, чтобы зарегистрировать наши сущности, получать уведомления о событиях в течение всего срока жизни объекта. Несколько примеров событий, о которых мы можем быть уведомлены, прежде чем произойдет обновление, после сохранения и удаления. Чтобы использовать Lifecycle Callbacks в нашей сущности, нам нужно зарегистрировать сущность для них. Это делается с помощью метаданных, в сущности. Обновите сущность Blog src/Blogger/BlogBundle/Entity/Blog.php
<?php
// src/Blogger/BlogBundle/Entity/Blog.php
// ..
/**
* @ORMEntity
* @ORMTable(name="blog")
* @ORMHasLifecycleCallbacks
*/
class Blog
{
// ..
}
Теперь давайте добавим метод в сущности Blog который регистрирует событие PreUpdate. Мы также добавим конструктор, чтобы установить значения по умолчанию для свойств created и updated.
<?php
// src/Blogger/BlogBundle/Entity/Blog.php
// ..
/**
* @ORMEntity
* @ORMTable(name="blog")
* @ORMHasLifecycleCallbacks
*/
class Blog
{
// ..
public function __construct()
{
$this->setCreated(new DateTime());
$this->setUpdated(new DateTime());
}
/**
* @ORMPreUpdate
*/
public function setUpdatedValue()
{
$this->setUpdated(new DateTime());
}
// ..
}
Мы зарегистрировали сущность Blog которая будет уведомлена о событии preUpdate, чтобы установить updated значение свойства. Теперь, когда вы удалите фикстуры из таблицы, а также удалите из каждого объекта
setCreated();
setUpdated();
в файле
src/Blogger/BlogBundle/DataFixtures/ORM/BlogFixtures.php
и повторно запустите задачу загрузки фикстур вы увидите, что created и updated свойства установлены автоматически.
Заметка
Так как свойства timestampable являются очень распространенной потребностью, есть бандл который их поддерживает. StofDoctrineExtensionsBundle предоставляет ряд полезных Doctrine 2 расширений, включая Timestampable, Sluggable и Sortable.
Мы рассмотрим интеграцию этого бандла позже. Кому не терпится посмотреть перейдите по ссылке.
Вывод
Мы рассмотрели ряд концепций для работы с моделями, в Doctrine 2. Рассмотрели Фикстуры данных, которые предоставили нам простой способ, получения тестовых данных для разработки и тестирования нашего приложения.
Далее мы рассмотрим расширение модели, добавив сущность для комментариев. Мы начнем создавать домашнюю страницу и применим для этого пользовательский репозиторий. Мы также введем понятие Миграций Doctrine и как формы взаимодействуют с Doctrine 2, для того чтобы мы могли размещать комментарии в блоге.
Источники и вспомогательные материалы:
https://symfony.com/
http://tutorial.symblog.co.uk/
http://twig.sensiolabs.org/
http://www.doctrine-project.org/
http://odiszapc.ru/doctrine/
Всем спасибо за внимание и замечания сделанные по проекту, если у вас возникли сложности или вопросы, отписывайтесь в комментарии или личные сообщения, добавляйтесь в друзья.
Часть 1 — Конфигурация Symfony2 и шаблонов
Часть 2 — Страница с контактной информацией: валидаторы, формы и электронная почта
Автор: antoscenco-vladimir