w3c/W3CLifecycleEventsBundle

Name: W3CLifecycleEventsBundle

Owner: World Wide Web Consortium

Description: A Symfony 3 bundle to dispatch usable entity lifecycle events (create, update, delete)

Created: 2017-02-28 14:12:23.0

Updated: 2017-12-17 00:56:59.0

Pushed: 2017-11-16 14:08:04.0

Homepage:

Size: 103

Language: PHP

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

Build Status Coverage Status SensioLabsInsight

lifecycle-events-bundle

This Symfony bundle is meant to capture and dispatch events that happen throughout the lifecycle of entities:

Doctrine already provides such events, but using them directly has a few shortcomings:

This bundle aims at circumventing these issues by providing means to fire entity creation, deletion and update events after a successful flush or whenever needed.

It also provides a set of annotation to configure what events should be sent and when.

This bundle was partially inspired by @kriswallsmith's talk “Matters of State”.

Installation

Simply run assuming you have installed composer.phar or composer binary:

p composer.phar require w3c/lifecycle-events-bundle 1.0.*

Finally, enable the bundle in the kernel:

p
pp/AppKernel.php

ic function registerBundles()

$bundles = array(
    // ...
    new W3C\LifecycleEventsBundle\W3CLifecycleEventsBundle(),
);

That's it!

Usage
Annotations

For this bundle to do anything interesting, it is necessary to annotate entities you want to monitor. There are five annotations. Three of them apply to classes (@Create, @Delete and @Update) and the remaining two to properties (@Change, @IgnoreClassUpdates).

All annotations live in the namespace W3C\LifecycleEventsBundle\Annotation, so it is recommended to import it:

p
W3C\LifecycleEventsBundle\Annotation as On;
@On\Create

Monitors the creation of new entities. It accepts the following parameters:

p

param mixed $entity the entity being created

ic function __construct($entity)
@On\Delete

Monitors the deletion (or soft deletion, if you use Doctrine Extensions) of entities. It accepts the following parameters:

p

param mixed $entity the entity being deleted
param array $identifier identifier of the entity being deleted

ic function __construct($entity, $identifier)
@On\Update

Monitors updates to entities. It accepts the following parameters:

p

param object $entity the entity being modified
param array $propertiesChangeSet list of changes to properties
param array $collectionsChangeSet list of changes to collections

ic function __construct($entity, array $propertiesChangeSet = null, array $collectionsChangeSet = null)
@On\Change

Monitors whenever an entity field (property or collection) changes. It accepts the following parameters:

p

param object $entity entity being modified
param string $property property being modified
param array $oldValue property's old value
param array $newValue property's new value

ic function __construct($entity, $property, $oldValue = null, $newValue = null)

and for collections:

p

param object $entity entity being modified
param string $property collection being modified
param array $deletedElements elements being deleted from the collection
param array $insertedElements elements being inserted to the collection

ic function __construct($entity, $property, $deletedElements = null, $insertedElements = null)
@On\IgnoreClassUpdates

This annotation is a bit different. When placed on a field (property or collection), it prevents @On\Update from firing events related to this field. @On\Change ones will still work. This annotation does not allow any parameters.

Example class
p

erson

ORM\Table(name="person")
ORM\Entity(repositoryClass="AppBundle\Repository\PersonRepository")
On\Create(
   PersonEvents::CREATED,
   class=PersonEvent::class

On\Delete(
   PersonEvents::DELETED,
   class=PersonEvent::class

On\Update(PersonEvents::UPDATED)

s Person

/**
 * @var int
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255, unique=true)
 * @On\Change(PersonEvents::PROPERTY_CHANGED)
 */
private $name;

/**
 * @var Person[]|Collection
 *
 * @ORM\ManyToMany(targetEntity="Person")
 * @ORM\JoinTable(name="friendships",
 *      joinColumns={@ORM\JoinColumn(name="person_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="friend_id", referencedColumnName="id")}
 *      )
 * @On\Change()
 * @On\IgnoreClassUpdates()
 */
private $friends;

[...]   

With such a class, the following events will be fired:

Disabling automatic dispatching of events

Lifecycle events are dispatched by default after a successful flush. If needed, this can be disabled:

p
patcher = $this->container->get("w3c_lifecycle_events.dispatcher");
patcher->setAutoDispatch(false);

Events can then be dispatched manually using the following:

p
patcher->dispatchEvents(); // manually dispatch all events
Special case: inheritance

If you use inheritance in your entities, make sure to set fields of the parent class(es) protected (or public) so that changes to those can be monitored as belonging to subclasses.

Failing to do so may lead to \ReflectionException exceptions such as:

erty W3CGroup::$updated does not exist. Could this be a private field of a parent class?

Even if those fields are not monitored!


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.