+ All Categories
Home > Technology > Extending Doctrine 2 for your Domain Model

Extending Doctrine 2 for your Domain Model

Date post: 10-May-2015
Category:
Upload: ross-tuck
View: 11,611 times
Download: 2 times
Share this document with a friend
Description:
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.
Popular Tags:
171
Ross Tuck Extending Doctrine 2 For Your Domain Model June 9th, DPC
Transcript
Page 1: Extending Doctrine 2 for your Domain Model

Ross Tuck

Extending Doctrine 2For Your Domain Model

June 9th, DPC

Page 2: Extending Doctrine 2 for your Domain Model
Page 3: Extending Doctrine 2 for your Domain Model

Who Am I?

Page 4: Extending Doctrine 2 for your Domain Model

Ross Tuck

Page 5: Extending Doctrine 2 for your Domain Model

Team Lead at IbuildingsCodemonkeyREST nutHat guyToken Foreigner

America, &@*! Yeah

Page 7: Extending Doctrine 2 for your Domain Model

Quick But Necessary

Page 8: Extending Doctrine 2 for your Domain Model

Doctrine 101

Page 9: Extending Doctrine 2 for your Domain Model

Doctrine 102

Page 10: Extending Doctrine 2 for your Domain Model

Doctrine 102.5

Page 11: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

/** @Id @GeneratedValue

* @Column(type="integer") */

protected $id;

/** @Column(type="string") */

protected $title;

/** @Column(type="text") */

protected $content;

}

Page 12: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Story');

$em->flush();

Controller

Page 13: Extending Doctrine 2 for your Domain Model

Filters

Page 14: Extending Doctrine 2 for your Domain Model
Page 15: Extending Doctrine 2 for your Domain Model

We need a way to approve comments before they appear to all users.

TPS Request

Page 16: Extending Doctrine 2 for your Domain Model

$comments = $em->getRepository('Comment')->findAll();

foreach($comments as $comment) {

echo $comment->getContent()."\n";

}

Controller

Output:Doug isn't humanDoug is the best

Page 17: Extending Doctrine 2 for your Domain Model

$comments = $em->getRepository('Comment')->findAll();

foreach($comments as $comment) {

echo $comment->getContent()."\n";

}

Controller

Page 18: Extending Doctrine 2 for your Domain Model

$comments = $em->createQuery('SELECT c FROM Comment c');

foreach($comments->getResult() as $comment) {

echo $comment->getContent()."\n";

}

Controller

Page 19: Extending Doctrine 2 for your Domain Model

$comments = $em->find('Article', 1)->getComments();

foreach($comments as $comment) {

echo $comment->getContent()."\n";

}

Controller

Approx 100 places in your code!

Page 20: Extending Doctrine 2 for your Domain Model

FiltersNew in 2.2

Page 21: Extending Doctrine 2 for your Domain Model

use Doctrine\ORM\Query\Filter\SQLFilter;

class CommentFilter extends SQLFilter {

public function addFilterConstraint($entityInfo, $alias) {

if ($entityInfo->name !== 'Comment') {

return "";

}

return $alias.".approved = 1";

}

}

Filter

Page 22: Extending Doctrine 2 for your Domain Model

$em->getConfiguration()

->addFilter('approved_comments', 'CommentFilter');

Bootstrap

Handy key

Class name

Page 23: Extending Doctrine 2 for your Domain Model

$em->getConfiguration()

->addFilter('approved_comments', 'CommentFilter');

$em->getFilters()->enable('approved_comments');

Bootstrap

Page 24: Extending Doctrine 2 for your Domain Model

if ($this->isNormalUser()) {

$em->getConfiguration()

->addFilter('approved_comments', 'CommentFilter');

$em->getFilters()->enable('approved_comments');

}

Bootstrap

Page 25: Extending Doctrine 2 for your Domain Model

$comments = $em->getRepository('Comment')->findAll();

foreach($comments as $comment) {

echo $comment->getContent()."\n";

}

Controller

As Normal User

Output:Doug is the best

Page 26: Extending Doctrine 2 for your Domain Model

Controller

As the AdminOutput:

Doug isn't humanDoug is the best

$comments = $em->getRepository('Comment')->findAll();

foreach($comments as $comment) {

echo $comment->getContent()."\n";

}

Page 27: Extending Doctrine 2 for your Domain Model

Parameters

Page 28: Extending Doctrine 2 for your Domain Model

$filter = $em->getFilters()->getFilter('approved_comments');

$filter->setParameter('level', $this->getUserLevel());

Bootstrap

Page 29: Extending Doctrine 2 for your Domain Model

use Doctrine\ORM\Query\Filter\SQLFilter;

class CommentFilter extends SQLFilter {

public function addFilterConstraint($entityInfo, $alias) {

if ($entityInfo->name !== 'Comment') {

return "";

}

$level = $this->getParameter('level');

return $alias.".approved = 1";

}

}

Filter

Page 30: Extending Doctrine 2 for your Domain Model

use Doctrine\ORM\Query\Filter\SQLFilter;

class CommentFilter extends SQLFilter {

public function addFilterConstraint($entityInfo, $alias) {

if ($entityInfo->name !== 'Comment') {

return "";

}

$level = $this->getParameter('level');

return $alias.".approved = ".$level;

}

}

Filter

Page 31: Extending Doctrine 2 for your Domain Model

use Doctrine\ORM\Query\Filter\SQLFilter;

class CommentFilter extends SQLFilter {

public function addFilterConstraint($entityInfo, $alias) {

if ($entityInfo->name !== 'Comment') {

return "";

}

$level = $this->getParameter('level');

return $alias.".approved = ".$level;

}

}

Filter

Already escaped

Page 32: Extending Doctrine 2 for your Domain Model

Limitations

Page 33: Extending Doctrine 2 for your Domain Model

Events

Page 34: Extending Doctrine 2 for your Domain Model

prePersistpostPersistpreUpdatepostUpdatepreRemovepostRemove

postLoadloadClassMetadatapreFlushonFlushpostFlushonClear

Insert

Page 35: Extending Doctrine 2 for your Domain Model

Callbacks Listeners

On the model External objects

Page 36: Extending Doctrine 2 for your Domain Model

Lifecycle Callbacks

Page 37: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

/** @Id @GeneratedValue

* @Column(type="integer") */

protected $id;

/** @Column(type="string") */

protected $title;

/** @Column(type="text") */

protected $content;

}

Page 38: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Story');

$em->flush();

Controller

Page 39: Extending Doctrine 2 for your Domain Model
Page 40: Extending Doctrine 2 for your Domain Model

Articles must record the last date they were modified in any way.

TPS Request

Page 41: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Story');

$article->setUpdatedAt(new DateTime('now'));

$em->flush();

Controller

+ 100 other files+ testing+ missed bugs

Page 42: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

/** @Id @GeneratedValue

* @Column(type="integer") */

protected $id;

/** @Column(type="string") */

protected $title;

}

Page 43: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

/** @Id @GeneratedValue

* @Column(type="integer") */

protected $id;

/** @Column(type="string") */

protected $title;

/** @Column(type="datetime") */

protected $updatedAt;

}

Page 44: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

// ...

public function markAsUpdated() {

$this->updatedAt = new \Datetime('now');

}

}

Page 45: Extending Doctrine 2 for your Domain Model

/** @Entity @HasLifecycleCallbacks */

class Article {

Model

// ...

/** @PreUpdate */

public function markAsUpdated() {

$this->updatedAt = new \Datetime('now');

}

}

Event mapping

Page 46: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Story');

$em->flush();

echo $article->getUpdatedAt()->format('c');

// 2012-05-29T10:48:00+02:00

Controller

NoChanges!

Page 47: Extending Doctrine 2 for your Domain Model

/** @Entity @HasLifecycleCallbacks */

class Article {

Model

// ...

/** @PreUpdate */

public function markAsUpdated() {

$this->updatedAt = new \Datetime('now');

}

}

Page 48: Extending Doctrine 2 for your Domain Model

What else can I do?

Page 49: Extending Doctrine 2 for your Domain Model

prePersistpostPersistpreUpdatepostUpdatepreRemovepostRemove

postLoadloadClassMetadatapreFlushonFlushpostFlushonClear

Page 50: Extending Doctrine 2 for your Domain Model

prePersistpostPersistpreUpdatepostUpdatepreRemovepostRemove

postLoadloadClassMetadatapreFlushonFlushpostFlushonClear

Page 51: Extending Doctrine 2 for your Domain Model

Protip:Only fires if you're dirty

Page 52: Extending Doctrine 2 for your Domain Model

new MudWrestling();

Page 53: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Story');

$em->flush();

// 2012-05-29T10:48:00+02:00

// 2012-05-29T10:48:00+02:00

Controller

2X

Page 54: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Story');

$em->flush();

Controller

'Awesome New Story' === 'Awesome New Story'

No update

Page 55: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Fantabulous Updated Story');

$em->flush();

Controller

'Awesome New Story' !== 'Fantabulous Updated Story'

Update, yeah!

Page 56: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Project'.uniqid());

$em->flush();

Controller

Page 57: Extending Doctrine 2 for your Domain Model

So, here's the thing.

Page 58: Extending Doctrine 2 for your Domain Model

The Thing

Page 59: Extending Doctrine 2 for your Domain Model

Events are cool.

Page 60: Extending Doctrine 2 for your Domain Model

Callbacks?

Page 61: Extending Doctrine 2 for your Domain Model

Eeeeeeeeeeeeeeeeeeh.

Page 62: Extending Doctrine 2 for your Domain Model

• Limited to model dependencies• Do you really need that function?• Protected function? Silent error• Repeated Code• Performance implications

Page 63: Extending Doctrine 2 for your Domain Model

Listeners

Page 64: Extending Doctrine 2 for your Domain Model

class UpdateTimeListener {

Listener

public function preUpdate($event) {

}

}

Page 65: Extending Doctrine 2 for your Domain Model

$em->getEventManager()->addEventListener(

array(Doctrine\ORM\Events::preUpdate),

new UpdateTimeListener()

);

Bootstrap

Page 66: Extending Doctrine 2 for your Domain Model

Invert

Page 67: Extending Doctrine 2 for your Domain Model

Invert

Page 68: Extending Doctrine 2 for your Domain Model

$em->getEventManager()->addEventListener(

array(Doctrine\ORM\Events::preUpdate),

new UpdateTimeListener()

);

Bootstrap

Page 69: Extending Doctrine 2 for your Domain Model

$em->getEventManager()->addEventSubscriber(

new UpdateTimeListener()

);

Bootstrap

Page 70: Extending Doctrine 2 for your Domain Model

class UpdateTimeListener {

Listener

public function preUpdate($event) {

}

public function getSubscribedEvents() {

return array(Events::preUpdate);

}

}

Page 71: Extending Doctrine 2 for your Domain Model

use Doctrine\Common\EventSubscriber;

class UpdateTimeListener implements EventSubscriber {

Listener

public function preUpdate($event) {

}

public function getSubscribedEvents() {

return array(Events::preUpdate);

}

}

Page 72: Extending Doctrine 2 for your Domain Model

Functionally?Design?

No differenceSubscriber

Page 73: Extending Doctrine 2 for your Domain Model

$em->getEventManager()->addEventSubscriber(

new ChangeMailListener()

);

Bootstrap

Page 74: Extending Doctrine 2 for your Domain Model

$em->getEventManager()->addEventSubscriber(

new ChangeMailListener($mailer)

);

Bootstrap

Page 75: Extending Doctrine 2 for your Domain Model

class UpdateTimeListener implements EventSubscriber {

Listener

public function getSubscribedEvents() {

return array(Events::preUpdate);

}

public function preUpdate($event) {

}

}

Page 76: Extending Doctrine 2 for your Domain Model

public function preUpdate($event) {

Listener

$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

);

}

Page 77: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

$article->setTitle('Awesome New Story');

$em->flush();

echo $article->getUpdatedAt()->format('c');

// 2012-05-29T10:48:00+02:00

Controller

Page 78: Extending Doctrine 2 for your Domain Model

Whoopity-doo

Page 79: Extending Doctrine 2 for your Domain Model

Theory Land

interface LastUpdatedInterface {

public function setUpdatedAt(\Datetime $date);

public function getUpdatedAt();

}

Page 80: Extending Doctrine 2 for your Domain Model

public function preUpdate($event) {

Listener

$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

);

}

Page 81: Extending Doctrine 2 for your Domain Model

public function preUpdate($event) {

Listener

$em = $event->getEntityManager();

$model = $event->getEntity();

if (!$model instanceof LastUpdatedInterface) { return; }

$model->setUpdatedAt(new \Datetime('now'));

$uow = $event->getEntityManager()->getUnitOfWork();

$uow->recomputeSingleEntityChangeSet(

$em->getClassMetadata('Article'),

$model

);

}

Page 82: Extending Doctrine 2 for your Domain Model

public function preUpdate($event) {

Listener

$em = $event->getEntityManager();

$model = $event->getEntity();

if (!$model instanceof LastUpdatedInterface) { return; }

$model->setUpdatedAt(new \Datetime('now'));

$uow = $event->getEntityManager()->getUnitOfWork();

$uow->recomputeSingleEntityChangeSet(

$em->getClassMetadata(get_class($model)),

$model

);

}

Page 83: Extending Doctrine 2 for your Domain Model

The POWAH

Page 84: Extending Doctrine 2 for your Domain Model

Flushing And Multiple Events

Page 85: Extending Doctrine 2 for your Domain Model

OnFlush

Page 86: Extending Doctrine 2 for your Domain Model
Page 87: Extending Doctrine 2 for your Domain Model

After every update to an article, I want an email of the changes sent to me.

Also, bring me more lettuce.

TPS Request

Page 88: Extending Doctrine 2 for your Domain Model

Listener

class ChangeMailListener implements EventSubscriber {

protected $mailMessage;

public function getSubscribedEvents() {

return array(Events::onFlush, Events::postFlush);

}

}

Page 89: Extending Doctrine 2 for your Domain Model

Listener

public function onFlush($event) {

$uow = $event->getEntityManager()->getUnitOfWork();

foreach($uow->getScheduledEntityUpdates() as $model) {

$changeset = $uow->getEntityChangeSet($model);

}

}

Page 90: Extending Doctrine 2 for your Domain Model

array(1) {

["title"]=>

array(2) {

[0]=> string(16) "Boring Old Title"

[1]=> string(16) "Great New Title!"

}

}

Page 91: Extending Doctrine 2 for your Domain Model

Listener

public function onFlush($event) {

$uow = $event->getEntityManager()->getUnitOfWork();

foreach($uow->getScheduledEntityUpdates() as $model) {

$changeset = $uow->getEntityChangeSet($model);

$this->formatAllPrettyInMail($model, $changeset);

}

}

Page 92: Extending Doctrine 2 for your Domain Model

Listener

public function onFlush($event) {

$uow = $event->getEntityManager()->getUnitOfWork();

foreach($uow->getScheduledEntityUpdates() as $model) {

$changeset = $uow->getEntityChangeSet($model);

$this->formatAllPrettyInMail($model, $changeset);

}

}

public function postFlush($event) {

if (!$this->hasMessage()) { return; }

$this->mailTheBoss($this->message);

}

Page 93: Extending Doctrine 2 for your Domain Model

That's really all there is to it.

Page 94: Extending Doctrine 2 for your Domain Model

Listener

public function formatAllPrettyInMail($model, $changes) {

if (!$model instanceof Article) {

return;

}

$msg = "";

foreach($changes as $field => $values) {

$msg .= "{$field} ----- \n".

"old: {$values[0]} \n".

"new: {$values[1]} \n\n";

}

$this->mailMessage .= $msg;

}

Page 95: Extending Doctrine 2 for your Domain Model

Advice:Treat your listeners like controllers

Page 96: Extending Doctrine 2 for your Domain Model

Keep it thin

Page 97: Extending Doctrine 2 for your Domain Model

Crazy Town

Page 98: Extending Doctrine 2 for your Domain Model
Page 99: Extending Doctrine 2 for your Domain Model

Write the change messages to the database instead of emailing them.

TPS Request

Page 100: Extending Doctrine 2 for your Domain Model

Model

/** @Entity */

class ChangeLog {

/** @Id @GeneratedValue

* @Column(type="integer") */

protected $id;

/** @Column(type="text") */

protected $description;

}

Page 101: Extending Doctrine 2 for your Domain Model

Listener

class ChangeLogger implements EventSubscriber {

public function getSubscribedEvents() {

return array(Events::onFlush);

}

public function onFlush($event) {

}

}

Page 102: Extending Doctrine 2 for your Domain Model

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

);

}

Page 103: Extending Doctrine 2 for your Domain Model

Shiny

Page 104: Extending Doctrine 2 for your Domain Model

Yes, I really used PHPMyAdmin there

Page 105: Extending Doctrine 2 for your Domain Model

Shiny

Page 106: Extending Doctrine 2 for your Domain Model

Also, wow, it worked!

Page 107: Extending Doctrine 2 for your Domain Model
Page 108: Extending Doctrine 2 for your Domain Model

UnitOfWork API

$uow->getScheduledEntityInsertions();

$uow->getScheduledEntityUpdates();

$uow->getScheduledEntityDeletions();

$uow->getScheduledCollectionUpdates();

$uow->getScheduledCollectionDeletions();

Page 109: Extending Doctrine 2 for your Domain Model

UnitOfWork API

$uow->scheduleForInsert();

$uow->scheduleForUpdate();

$uow->scheduleExtraUpdate();

$uow->scheduleForDelete();

Page 110: Extending Doctrine 2 for your Domain Model

UnitOfWork API

And many more...

Page 111: Extending Doctrine 2 for your Domain Model

postLoad

Page 112: Extending Doctrine 2 for your Domain Model
Page 113: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

//...

/** @Column(type="integer") */

protected $viewCount;

}

Page 114: Extending Doctrine 2 for your Domain Model
Page 115: Extending Doctrine 2 for your Domain Model

MySQL Redis

+

Page 116: Extending Doctrine 2 for your Domain Model

Move view counts out of the database into a faster system.

And don't break everything.

TPS Request

Page 117: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

echo $article->getViewCount();

Controller

Page 118: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

//...

/** @Column(type="integer") */

protected $viewCount;

}

Page 119: Extending Doctrine 2 for your Domain Model

Listener

class ViewCountListener implements EventSubscriber {

public function getSubscribedEvents() {

return \Doctrine\ORM\Events::postLoad;

}

public function postLoad($event) {

$model = $event->getEntity();

if (!$model instanceof Article) {

return;

}

$currentRank = $this->getCountFromRedis($model);

$model->setViewCount($currentRank);

}

}

Page 120: Extending Doctrine 2 for your Domain Model

$article = $em->find('Article', 1);

echo $article->getViewCount();

Controller

Page 121: Extending Doctrine 2 for your Domain Model

Many, many other uses.

Page 122: Extending Doctrine 2 for your Domain Model

Class Metadata

Page 123: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

/** @Id @GeneratedValue

* @Column(type="integer") */

protected $id;

/** @Column(type="string") */

protected $title;

/** @Column(type="datetime") */

protected $updatedAt;

}

Where dothey go?

Page 124: Extending Doctrine 2 for your Domain Model

/** @Entity */

class Article {

Model

/** @Id @GeneratedValue

* @Column(type="integer") */

protected $id;

/** @Column(type="string") */

protected $title;

/** @Column(type="datetime") */

protected $updatedAt;

}

Page 125: Extending Doctrine 2 for your Domain Model

Doctrine\ORM\Mapping\ClassMetadata

Page 126: Extending Doctrine 2 for your Domain Model

???

$metadata = $em->getClassMetadata('Article');

Page 127: Extending Doctrine 2 for your Domain Model

???

$metadata = $em->getClassMetadata('Article');

echo $metadata->getTableName();

Output:Article

Page 128: Extending Doctrine 2 for your Domain Model

???

$metadata = $em->getClassMetadata('Article');

echo $metadata->getTableName();

Output:articles

Page 129: Extending Doctrine 2 for your Domain Model

Doctrine 2.3 will bring NamingStrategy

Page 130: Extending Doctrine 2 for your Domain Model

???

$conn = $em->getConnection();

$tableName = $metadata->getQuotedTableName($conn);

$results = $conn->query('SELECT * FROM '.$tableName);

Page 131: Extending Doctrine 2 for your Domain Model

Tip of the Iceberg

Page 132: Extending Doctrine 2 for your Domain Model

???

array(8) { fieldName => "title" type => "string" length => NULL precision => 0 scale => 0 nullable => false unique => false columnName => "title"}

$metadata->getFieldMapping('title');

Page 133: Extending Doctrine 2 for your Domain Model

???

$metadata->getFieldMapping('title');

$metadata->getFieldNames();

$metadata->getReflectionClass();

$metadata->getReflectionProperty('title');

$metadata->getColumnName('title');

$metadata->getTypeOfField('title');

Page 134: Extending Doctrine 2 for your Domain Model

Simple Example

Page 135: Extending Doctrine 2 for your Domain Model

Symple Example

Page 136: Extending Doctrine 2 for your Domain Model

class ArticleType extends AbstractType {

public function buildForm($builder, array $options) {

$builder

->add('title')

->add('content');

}

}

Form in Symfony2

Page 137: Extending Doctrine 2 for your Domain Model

$entity = new Article();

$form = $this->createForm(new ArticleType(), $entity);

Controller in Symfony2

Page 138: Extending Doctrine 2 for your Domain Model
Page 139: Extending Doctrine 2 for your Domain Model

class ArticleType extends AbstractType {

public function buildForm($builder, array $options) {

$builder

->add('title')

->add('content');

}

}

Form in Symfony2

Page 140: Extending Doctrine 2 for your Domain Model
Page 141: Extending Doctrine 2 for your Domain Model

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', ...);

}

Page 142: Extending Doctrine 2 for your Domain Model

Cool, huh?

Page 143: Extending Doctrine 2 for your Domain Model

Cool, huh?

Page 144: Extending Doctrine 2 for your Domain Model

???

array(15) { fieldName => "comments" mappedBy => "article" targetEntity => "Comment" cascade => array(0) {} fetch => 2 type => 4 isOwningSide => false sourceEntity => "Article" ...

$metadata->getAssociationMapping('comments');

Page 145: Extending Doctrine 2 for your Domain Model

???

$metadata->getAssociationMapping('comments');

$metadata->getAssociationMappings();

$metadata->isSingleValuedAssociation('comments');

$metadata->isCollectionValuedAssociation('comments');

$metadata->getAssociationTargetClass('comments');

Page 146: Extending Doctrine 2 for your Domain Model

class ArticleType extends AbstractType {

public function buildForm($builder, array $options) {

$builder

->add('title')

->add('content')

->add('comments');

}

}

Form in Symfony2

Page 147: Extending Doctrine 2 for your Domain Model
Page 148: Extending Doctrine 2 for your Domain Model

Oh yeah.

Page 149: Extending Doctrine 2 for your Domain Model

You can set all of this stuff.

Page 150: Extending Doctrine 2 for your Domain Model

100~ public functions

Page 151: Extending Doctrine 2 for your Domain Model

But is there a good reason?Unless you're writing a driver, probably not.

Page 152: Extending Doctrine 2 for your Domain Model

Listener

class MyListener {

public function loadClassMetadata($event) {

echo $event->getClassMetadata()->getName();

}

}

Page 153: Extending Doctrine 2 for your Domain Model

Where's the manatee?

Page 154: Extending Doctrine 2 for your Domain Model

You're the manatee.

Page 155: Extending Doctrine 2 for your Domain Model

Epilogue & Service Layers

Page 156: Extending Doctrine 2 for your Domain Model

Model

Controller

View

Page 157: Extending Doctrine 2 for your Domain Model

Model

Service Layer

Controller

View

Page 158: Extending Doctrine 2 for your Domain Model

Be smart.

Page 159: Extending Doctrine 2 for your Domain Model

Be smart.

Page 160: Extending Doctrine 2 for your Domain Model

Be simple

Page 161: Extending Doctrine 2 for your Domain Model

Don't overuse this.

Page 162: Extending Doctrine 2 for your Domain Model

Test

Page 163: Extending Doctrine 2 for your Domain Model

Test test test

Page 164: Extending Doctrine 2 for your Domain Model

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

Page 165: Extending Doctrine 2 for your Domain Model

RTFM.

Page 166: Extending Doctrine 2 for your Domain Model

Go forth and rock.

Page 167: Extending Doctrine 2 for your Domain Model
Page 168: Extending Doctrine 2 for your Domain Model

You're the manatee.

Page 169: Extending Doctrine 2 for your Domain Model

Thanks to:

@boekkooi#doctrine (freenode)

Page 171: Extending Doctrine 2 for your Domain Model

https://joind.in/6251


Recommended