Increase productivity with doctrine2 extensions

Preview:

Citation preview

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

SYMFONYCON WARSAW 2013

INCREASE PRODUCTIVITY WITHDOCTRINE2 BEHAVIORAL 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

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;

/**

HOW EXTENSIONS WORK?

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

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

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

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>

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;

SORTABLETracks sorting position on your entity

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

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

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;

//...}

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

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") */

How the tree looks in database:

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;

/*...*/}

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;}

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.

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

THANK YOU

Powered by: Revealjs

Recommended