20
WHO'S TALKING? aka Gediminas Morkevi čius @l3pp4rd I code with - PHP, Go, JavaScript, C I'm an open-source geek - ViM, Arch Linux, DWM user And I share my stuff github.com/l3pp4rd

Increase productivity with doctrine2 extensions

Embed Size (px)

Citation preview

Page 1: Increase productivity with doctrine2 extensions

WHO'S TALKING? aka Gediminas Morkevičius @l3pp4rd

I code with - PHP, Go, JavaScript, CI'm an open-source geek - ViM, Arch Linux, DWM userAnd I share my stuff github.com/l3pp4rd

Page 2: Increase productivity with doctrine2 extensions

SYMFONYCON WARSAW 2013

INCREASE PRODUCTIVITY WITHDOCTRINE2 BEHAVIORAL EXTENSIONS

Page 3: Increase productivity with doctrine2 extensions

SOME HISTORYThe initial commit 2010-09-03 MIT licensedMaintained ever sincePurpose - provide common model behaviorsDerive metadata mapping and caching technicsBe a framework independent library

Page 4: Increase productivity with doctrine2 extensions

AN EXAMPLE<?phpnamespace Entity;

use Gedmo\Mapping\Annotation as Gedmo;use Doctrine\ORM\Mapping as ORM;

/** * @ORM\Entity * @Gedmo\SoftDeleteable(fieldName="deletedAt") */class Product{ /** * @Gedmo\Translatable * @ORM\Column(length=64) */ private $title;

/** * @Gedmo\Slug(fields={"title"}, updatable=false) * @ORM\Column(length=64, unique=true) */ private $slug;

/** * @Gedmo\Timestampable(on="create") * @ORM\Column(type="datetime") */ private $createdAt;

/**

Page 5: Increase productivity with doctrine2 extensions

HOW EXTENSIONS WORK?

Page 6: Increase productivity with doctrine2 extensions

SLUGGABLETransforms fields into an url friendly slug. Ensures

uniqueness if required./** * @Gedmo\Slug(fields={"code", "title"}, separator="-", style="camel") * @ORM\Column(length=64, unique=true) */private $slug;

Default transliterator transforms utf-8 characters to theirASCII equivalent

Page 7: Increase productivity with doctrine2 extensions

TRANSLATABLE/** * @Gedmo\Translatable * @ORM\Column(length=64) */private $title;

/** * @Gedmo\Translatable * @ORM\Column(type="text", nullable=true) */private $description;

Can link to a specific entity for translations. That would allowto use a direct foreign key constraint and optimize for better

performance

Page 8: Increase productivity with doctrine2 extensions

By default, puts all translations into a single translationtable. It is not performance wise. Uses locale from listener.

Page 9: Increase productivity with doctrine2 extensions

TRANSLATION QUERY HINTS$query = $em->createQuery("SELECT p FROM Entity\Product p ORDER BY p.title");

$query->setHint( Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\Translatable\Query\TreeWalker\TranslationWalker');$query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'de');

$deProducts = $query->getResult();array_walk($deProducts, function(Entity\Product $p) { echo "Got <{$p->getTitle()}> with description <{$p->getDescription()}>\n";});

// Got <Äpfel> with description <Früchte>// Got <Trauben> with description <Früchte>

Page 10: Increase productivity with doctrine2 extensions

TIMESTAMPABLESets timestamps for you. Derived extensions: IpTraceable,

Blameable/** * @Gedmo\Timestampable(on="create") * @ORM\Column(type="datetime") */private $createdAt;

/** * @Gedmo\Timestampable(on="update") * @ORM\Column(type="datetime") */private $updatedAt;

/** * @Gedmo\Timestampable(on="change", field="status.code", value=1) * @ORM\Column(type="datetime", nullable=true) */private $publishedAt;

Page 11: Increase productivity with doctrine2 extensions

SORTABLETracks sorting position on your entity

/** * @Gedmo\SortablePosition * @ORM\Column(type="integer") */private $position;

/** * @Gedmo\SortableGroup * @ORM\ManyToOne(targetEntity="Category") */private $category;

Page 12: Increase productivity with doctrine2 extensions

SOFTDELETEABLESoftly removes your entities, so they get filtered out

afterwards, but maintain in the database./** * @Gedmo\SoftDeleteable(fieldName="deletedAt") * @ORM\Entity */class Product{ /** * @ORM\Column(length=64) */ private $title;

/** * @ORM\Column(type="datetime", nullable=true) */ private $deletedAt;

//...}

Page 13: Increase productivity with doctrine2 extensions

Given the actions are performed:$p0 = new Entity\Product;$p0->setTitle('Will be softdeleted');

$p1 = new Entity\Product;$p1->setTitle('Trully successful product');

$em->persist($p0);$em->persist($p1);$em->flush();// at some point, product is removed$em->remove($p0);$em->flush();

echo count($em->getRepository('Entity\Product')->findAll());// result is: 1

Page 14: Increase productivity with doctrine2 extensions

NESTED-SET TREEManages your entity as Nested-Set strategy based tree.<?phpnamespace Entity;

use Gedmo\Mapping\Annotation as Gedmo;use Doctrine\ORM\Mapping as ORM;

/** * @Gedmo\Tree(type="nested") * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository") */class Category{ /** * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue */ private $id;

/** * @ORM\Column(length=64) */ private $title;

/** * @Gedmo\TreeLeft * @ORM\Column(type="integer") */

Page 15: Increase productivity with doctrine2 extensions

How the tree looks in database:

Page 16: Increase productivity with doctrine2 extensions

How to keep your tree records secure from gettingcompromised during concurrent requests?

Given we have entities:/** * @ORM\Entity */class Organisation {/*...*/}

/** * @Gedmo\Tree(type="nested") * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository") */class Project{ /** * @ORM\ManyToOne(targetEntity="Organisation") * @ORM\JoinColumn(referencedColumnName="id", nullable=false) */ private $organisation;

/*...*/}

Page 17: Increase productivity with doctrine2 extensions

On every request when you move, insert Project you have ahard relation Organisation. Meaning, you have to select the

specific organisation in order to update the tree.use Doctrine\DBAL\LockMode;

$conn = $em->getConnection();// start transaction$conn->beginTransaction();try { // selects organisation for update - locks it for any // read/write attempts until this transaction ends $org = $em->find("Entity\Organisation", $orgId, LockMode::PESSIMISTIC_WRITE);

// create a new category $subProject = new Project; $subProject->setTitle($_POST["title"]); $subProject->setOrganisation($org);

$parentProject = $em->find("Entity\Project", $_POST["parent_id"]);

// persist and flush $em->getRepository("Entity\Project") ->persistAsFirstChildOf($subProject, $parentProject); $em->flush();

$conn->commit();} catch (\Exception $e) { $conn->rollback(); throw $e;}

Page 18: Increase productivity with doctrine2 extensions

Read more about available locking mechanisms supportedby database you are using, some references:

on Doctrine2 website on MySQL 5.5 manual page

Transactions and concurrencyLocking reads

Any actions which does atomic operations needs to besecured including Sortable extension.

Page 19: Increase productivity with doctrine2 extensions

FUTURE PLANS:One next big version upgrade expected 2014

1. Simplify integration without any preconfiguration usingsensible defaults.

2. Improve extensions based on the issues learned.3. Make them less feature rich, but more customizable.4. Improve documentation, add helper commands to review

active listeners and watched entities.5. Maintain compatibility without changes to public

interface.6. Progress can be followed on pull request

Page 20: Increase productivity with doctrine2 extensions

THANK YOU

Powered by: Revealjs