Doctrine

Doctrine #

Entity #

use Doctrine\ORM\Mapping AS ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="acme_user")
 */
class Event
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", unique=true, length=64, nullable=false)
     */
    private $name;
}

Relations #

@OneToOne #

  • target­Entity (string)
  • cascade (array­|ca­scades actions)
  • fetch (choice: LAZY, EAGER)
  • orphan­Removal (boolean)
  • inversedBy (string)

@ManyToOne #

  • target­Entity (string)
  • cascade (array­|ca­scades actions)
  • fetch (choice: LAZY, EAGER)
  • inversedBy (string)

@OneToMany #

  • target­Entity (string)
  • cascade (array­|ca­scades actions)
  • orphan­Removal (boolean)
  • mappedBy (string)
  • fetch (choice: LAZY, EXTRA_­LAZY, EAGER)
  • indexBy (string)

@ManyT­oMany #

  • target­Entity (string)
  • mappedBy (string)
  • inversedBy (string)
  • cascade (array­|ca­scades actions)
  • fetch (choice: LAZY, EXTRA_­LAZY, EAGER)
  • indexBy (string)

@OrderBy #

/**
 * @ManyToMany(targetEntity="Group")
 * @OrderBy({"name" = "ASC"})
 */
private $groups;

@JoinC­olumn #

  • name (string)
  • refere­nce­dCo­lum­nName (string)
  • unique (boolean)
  • nullable (bool)
  • onDelete (array­|ca­scades actions)
  • column­Def­inition (string : DQL definition)

@JoinTable #

  • name (string)
  • joinCo­lumns (array­|@J­oin­Column)
  • invers­eJo­inC­olumns (array­|@J­oin­Column)

@JoinC­olumns #

  • Array of @JoinC­olumn.

Inheritance mapping strategy #

Mapped superclasses #

  • Just a regular non-mapped class
  • Not an entity
  • Non-persistent
  • Unidirectional (one-to-many not possible)
/** @MappedSuperclass */
class Animal
{
    /** @Column(type="integer") */
    protected $mapped1;
    /** @Column(type="string") */
    protected $mapped2;
}

/** @Entity */
class Person extends Animal
{
    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="string") */
    private $name;
}

/** @Entity */
class Elephant extends Animal
{
    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="float") */
    private $size;
}

Single table inheritance #

Inheritance mapping strategy where all classes of a hierarchy are mapped to a single database table. In order to distinguish which row represents which type in the hierarchy a so-called discriminator column is used

/**
 * @Entity
 * @InheritanceType("SINGLE_TABLE")
 * @DiscriminatorColumn(name="discr", type="string")
 * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
 */
class Person
{
    // ...
}

/**
 * @Entity
 */
class Employee extends Person
{
    // ...
}

QueryBuilder #

Provides an API that is designed for conditionally constructing a DQL query in several steps.

$qb = $em->createQueryBuilder();

$qb->select('u')
   ->from('User', 'u')
   ->where('u.id = :identifier')
   ->orderBy('u.name', 'ASC')
   ->setParameter('identifier', 100);

The $qb->expr()->* methods can help you build conditional expressions dynamically.

$qb->select(array('u')) // string 'u' is converted to array internally
   ->from('User', 'u')
   ->where($qb->expr()->orX(
       $qb->expr()->eq('u.id', '?1'),
       $qb->expr()->like('u.nickname', '?2')
   ))
   ->orderBy('u.surname', 'ASC');

The Expr class #

// "SELECT u FROM User u WHERE u.id = ? OR u.nickname LIKE ? ORDER BY u.name ASC" using Expr class
$qb->add('select', new Expr\Select(array('u')))
   ->add('from', new Expr\From('User', 'u'))
   ->add('where', $qb->expr()->orX(
       $qb->expr()->eq('u.id', '?1'),
       $qb->expr()->like('u.nickname', '?2')
   ))
   ->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));

Loading type #

Eager #

Loads the full entity object and all its relation in one query

Lazy (default behavior) #

Loads the relations only when they are called explicitely

Extra lazy #

  • For Many-to-Many and One-to-Many relations
  • Loads a collection but tries to avoid loading them fully in memory
  • Used with the following methods : contains($entity), containsKey($key), count(), get($key), slice($offset, $length = null), add($entity) et offsetSet($key, $entity)
  • $user->getParticipations()->count() will only do SELECT COUNT(*).
  • Useful for counting and paginate

Changeset #

  • Doctrine\ORM\UnitOfWork::computeChangeSets() to compute all the changes that have been done to entities and collections and store these changes;
  • Doctrine\ORM\UnitOfWork::getEntityChangeSet($entity) to retrieve all changes to our entity object;
  • Doctrine\ORM\UnitOfWork::getOriginalEntityData($entity) to retrieve the original data of an entity before introduced changes.

  • Doctrine\ORM\PersistentCollection::getSnapshot to return the last snapshot of the elements in the collection;
  • Doctrine\ORM\PersistentCollection::getDeleteDiff to return removed entities from the collection;
  • Doctrine\ORM\PersistentCollection::getInsertDiff to return new entities thast have been added to the collection;
  • Doctrine\ORM\PersistentCollection::isDirty to check whether this collection is dirty which means its state needs to be synchronized with the database.

Security #

https://www.doctrine-project.org/projects/doctrine-orm/en/2.11/reference/security.html

You can consider the following APIs to be safe from SQL injection:

  • \Doctrine\ORM\EntityManager#find() and getReference().
  • All values on Objects inserted and updated through Doctrine\ORM\EntityManager#persist()
  • All find methods on Doctrine\ORM\EntityRepository.
  • User Input set to DQL Queries or QueryBuilder methods through
    • setParameter() or variants
    • setMaxResults()
    • setFirstResult()
  • Queries through the Criteria API on Doctrine\ORM\PersistentCollection and |Doctrine\ORM\EntityRepository.

You are NOT safe from SQL injection when using user input with:

  • Expression API of Doctrine\ORM\QueryBuilder
  • Concatenating user input into DQL SELECT, UPDATE or DELETE statements or Native SQL.