UPDATE: My thoughts have changed a bit since I originally presented this talk. It's could still be a useful intro to some of Doctrine's intermediate features (although the docs continue to improve. However, I would recommend you take a look at a new talk I've done since then "Models & Service Layers; Hemoglobin & Hobgoblins" which I think does a better job of actually talking about architecture and domain models than this talk does. Thanks! http://www.slideshare.net/rosstuck/models-and-service-layers-hemoglobin-and-hobgoblins
As presented at the Dutch PHP Conference 2012.
Sure, it can save models and do relations but Doctrine 2 can do a whole lot more. This talk introduces features like Events and Filters that can keep your code clean and organized. If you like the idea of automatically updating your solr index or adding audit logs without changing any existing code, this is the talk for you.
The emphasis is on practical application of the lesser known but powerful features. The talk is geared toward people who are curious what Doctrine 2 can offer over a standard database layer or have used it previously.
15. TPS Request
We need a way to approve comments
before they appear to all users.
16. Controller
$comments = $em->getRepository('Comment')->findAll();
foreach($comments as $comment) {
echo $comment->getContent()."n";
}
Output:
Doug isn't human
Doug is the best
18. Controller
$comments = $em->createQuery('SELECT c FROM Comment c');
foreach($comments->getResult() as $comment) {
echo $comment->getContent()."n";
}
19. Controller
$comments = $em->find('Article', 1)->getComments();
foreach($comments as $comment) {
echo $comment->getContent()."n";
}
!
ce s in your code
Approx 100 pla
24. Bootstrap
if ($this->isNormalUser()) {
$em->getConfiguration()
->addFilter('approved_comments', 'CommentFilter');
$em->getFilters()->enable('approved_comments');
}
25. Controller
$comments = $em->getRepository('Comment')->findAll();
foreach($comments as $comment) {
echo $comment->getContent()."n";
}
al User
Output: A s Norm
Doug is the best
26. Controller
$comments = $em->getRepository('Comment')->findAll();
foreach($comments as $comment) {
echo $comment->getContent()."n";
}
in
Output:
As the Adm
Doug isn't human
Doug is the best
44. Model
/** @Entity */
class Article {
// ...
public function markAsUpdated() {
$this->updatedAt = new Datetime('now');
}
}
45. Model
/** @Entity @HasLifecycleCallbacks */
class Article {
// ...
Event mapping
/** @PreUpdate */
public function markAsUpdated() {
$this->updatedAt = new Datetime('now');
}
}
46. Controller
$article = $em->find('Article', 1);
$article->setTitle('Awesome New Story'); No
Changes!
$em->flush();
echo $article->getUpdatedAt()->format('c');
// 2012-05-29T10:48:00+02:00
47. Model
/** @Entity @HasLifecycleCallbacks */
class Article {
// ...
/** @PreUpdate */
public function markAsUpdated() {
$this->updatedAt = new Datetime('now');
}
}
54. Controller
$article = $em->find('Article', 1);
$article->setTitle('Awesome New Story');
$em->flush();
'Awesome New Story' === 'Awesome New Story'
No update
68. Bootstrap
$em->getEventManager()->addEventListener(
array(DoctrineORMEvents::preUpdate),
new UpdateTimeListener()
);
69. Bootstrap
$em->getEventManager()->addEventSubscriber(
new UpdateTimeListener()
);
70. Listener
class UpdateTimeListener {
public function preUpdate($event) {
}
public function getSubscribedEvents() {
return array(Events::preUpdate);
}
}
71. Listener
use DoctrineCommonEventSubscriber;
class UpdateTimeListener implements EventSubscriber {
public function preUpdate($event) {
}
public function getSubscribedEvents() {
return array(Events::preUpdate);
}
}
73. Bootstrap
$em->getEventManager()->addEventSubscriber(
new ChangeMailListener()
);
74. Bootstrap
$em->getEventManager()->addEventSubscriber(
new ChangeMailListener($mailer)
);
75. Listener
class UpdateTimeListener implements EventSubscriber {
public function getSubscribedEvents() {
return array(Events::preUpdate);
}
public function preUpdate($event) {
}
}
76. Listener
public function preUpdate($event) {
$em = $event->getEntityManager();
$model = $event->getEntity();
if (!$model instanceof Article) { return; }
$model->setUpdatedAt(new Datetime('now'));
$uow = $event->getEntityManager()->getUnitOfWork();
$uow->recomputeSingleEntityChangeSet(
$em->getClassMetadata('Article'),
$model
);
}
101. Listener
class ChangeLogger implements EventSubscriber {
public function getSubscribedEvents() {
return array(Events::onFlush);
}
public function onFlush($event) {
}
}
102. Listener::onFlush
public function onFlush($event) {
$em = $event->getEntityManager();
$uow = $em->getUnitOfWork();
foreach($uow->getScheduledEntityUpdates() as $model) {
if (!$model instanceof Article) { continue; }
$log = new ChangeLog();
$log->setDescription($this->meFormatPrettyOneDay());
$em->persist($log);
$uow->computeChangeSet(
$em->getClassMetadata('ChangeLog'), $log
);
}
136. Form in Symfony2
class ArticleType extends AbstractType {
public function buildForm($builder, array $options) {
$builder
->add('title')
->add('content');
}
}
137. Controller in Symfony2
$entity = new Article();
$form = $this->createForm(new ArticleType(), $entity);
138.
139. Form in Symfony2
class ArticleType extends AbstractType {
public function buildForm($builder, array $options) {
$builder
->add('title')
->add('content');
}
}
140.
141. Symfony Doctrine Bridge
switch ($metadata->getTypeOfField($property)) {
case 'string':
return new TypeGuess('text', ...);
case 'boolean':
return new TypeGuess('checkbox', ...);
case 'integer':
case 'bigint':
case 'smallint':
return new TypeGuess('integer', ...);
case 'text':
return new TypeGuess('textarea', ...);
default:
return new TypeGuess('text', ...);
}
146. Form in Symfony2
class ArticleType extends AbstractType {
public function buildForm($builder, array $options) {
$builder
->add('title')
->add('content')
->add('comments');
}
}
164. test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test
test test test test test test test test test test