Doctrine2 / Symfony Cheat Sheet
Helpers / Make
- php bin/console make:entity
- php bin/console make:migration
- php bin/console doctrine:schema:validate
Schema
Column Types
Date
- https://php-de.github.io/jumpto/datetime/
- https://stackoverflow.com/questions/10836123/how-to-set-a-date-in-doctrine-2
Many to One / One to Many
One state has many towns. Town is the owning part with the native "state_id" column.
- State.php
-
/** * @ORM\Entity(repositoryClass=StateRepository::class) */ class State { /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private $id; /** * @ORM\OneToMany(targetEntity=Town::class, mappedBy="State") * This is the foreign "one" part of the relation. One state can * have many towns. */ private $towns; public function __construct() { $this->towns = new ArrayCollection(); } /** * @return Collection<int, Town> */ public function getTowns(): Collection { return $this->towns; } public function addTown(Town $town): self { if (!$this->towns->contains($town)) { $this->towns[] = $town; $town->setState($this); } return $this; } public function removeTown(Town $town): self { if ($this->towns->removeElement($town)) { // set the owning side to null (unless already changed) if ($town->getState() === $this) { $town->setState(null); } } return $this; } }
-
-
Town.php
-
/** * @ORM\Entity(repositoryClass=TownRepository::class) * Giving the table name ("town") is optional with '@ORM\Table(name="studiengang")' */ class Town { /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private $id; /** * @ORM\ManyToOne(targetEntity=State::class, inversedBy="towns") * @ORM\JoinColumn(nullable=false) * This is the owning "many" part of the relation as many towns can have one state * Native column: "state_id" * Seems like column name "state_id" is guessed from the relation * Other optional "@JoinColumn" options are: name="state_id", referencedColumnName="id" * Note that $State is upper case (Entity?) and "towns" collection is lowercase */ private $State; public function getState(): ?State { return $this->State; } public function setState(?State $State): self { $this->State = $State; return $this; } }
-
Associations
Trigger Lazy Loading
-
$entity = ... get entity $towns = $entity->getTowns(); // is empty because of lazy loading. // Load relation data: $entity->getTowns()->initialize();
Create and persist
-
// In a symfony controller inject the entity manager: public function test(EntityManagerInterface $em) {
-
$country = new Country(); $country->setName('Foo'); $em->persist($country); $em->flush();
Query Builder
Queries should be mainly in a repository.
-
// ExampleRepository.php public function findOneByFoo($foo) { // automatically knows e = "example" entity because we are in this repository $qb = $this->createQueryBuilder('e') ->where('s.bar LIKE :foo') ->setParameter('foo', "%$foo%") ; return $qb->getQuery()->getOneOrNullResult(); }
count
-
$qb = $this->createQueryBuilder('standort') ->select('count(standort.id)') ->where('standort.town=:town') ->setParameter('town', $town) ; $count = $qb->getQuery()->getSingleScalarResult();
where In
-
$qb->andWhere('user.name IN (:names)'); $qb->setParameter('names', ['Karen', 'Kevin', 'Kim']);
offset / limit
-
$qb->setMaxResults($limit) $qb->setFirstResult($offset)
index by
-
$this->createQueryBuilder('c') ->indexBy('c', 'c.slug') ->getQuery() ->getArrayResult()
Use another repository in a repository
-
// in UserRepository.php $locations = $this->getEntityManager()->getRepository(Location::class) // without ...Repository! ->findDistinctLocations()
Migrations
Use PDO
-
$pdo = $this->connection->getNativeConnection(); // Or in a repository: $pdo = $this->getEntityManager()->getConnection()->getNativeConnection();
Livecycle Events (preUpdate, postPersist, ...)
https://symfony.com/doc/5.4/doctrine/events.html
PostPersist = OnCreate
Use Listeners
- src/EventListener/FooInvalidateCacheListener.php
-
<?php namespace App\EventListener; use App\Entity\Foo; use App\Service\HttpCacheUtils; use Doctrine\Persistence\Event\LifecycleEventArgs; class FooInvalidateCacheListener { private $httpCacheUtils; public function __construct(HttpCacheUtils $httpCacheUtils) { $this->httpCacheUtils = $httpCacheUtils; } public function postUpdate(Foo $Foo, LifecycleEventArgs $args) { $tag = 'b' . $Foo->getId(); $this->httpCacheUtils->invalidateCacheByTags([$tag], get_class(), 'Update'); } }
-
-
config/services.yaml
-
services: App\EventListener\BerufInvalidateCacheListener: tags: - { name: doctrine.orm.entity_listener, entity: App\Entity\Beruf, event: postUpdate }
-
Save changed values to the database (not done automatically)
-
// src/Entity/Foo.php * @ORM\HasLifecycleCallbacks() */ class Foo { ... /** * @ORM\PostPersist() * @return void */ public function myPostPersistFunction(LifecycleEventArgs $args): void { $this->setBar('Baz'); $args->getEntityManager()->flush(); } }
Auditable / Versionable
https://github.com/DamienHarper/auditor-bundle
Installation:
- composer require damienharper/auditor-bundle
- config/packages/dh_auditor.yaml
-
# Full configuration reference available at: # https://damienharper.github.io/auditor-docs/docs/auditor-bundle/configuration/reference.html dh_auditor: enabled: true timezone: 'Europe/Vienna' providers: doctrine: table_prefix: null table_suffix: '_audit' viewer: true entities: App\Entity\Example: ~
-
- bin/console doctrine:schema:update --dump-sql
- Take line for "example_audit" table and put it into migration
- php bin/console doctrine:migrations:generate
- $this->addSql("CREATE TABLE example_audit (id INT UNSIG....");
- bin/console doctrine:migrations:migrate --no-interaction -vvv
Caching
$query->setResultCacheId('my_custom_id'); // or shorter notation with lifetime option $query->useResultCache(true, 3600, 'my_custom_id'); // to delete cache $cacheDriver = $entityManager->getConfiguration()->getResultCacheImpl(); $cacheDriver->delete('my_custom_id'); // to delete all cache entries $cacheDriver->deleteAll();