Skip to content

Instantly share code, notes, and snippets.

@koemeet
Last active August 29, 2016 17:13
Show Gist options
  • Save koemeet/237e54f51c59e7b793a8 to your computer and use it in GitHub Desktop.
Save koemeet/237e54f51c59e7b793a8 to your computer and use it in GitHub Desktop.
<?php
/**
* (c) Steffen Brem <steffenbrem@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Mango\Bundle\ContentBundle\EventListener\PHPCR;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\Common\Persistence\Event\ManagerEventArgs;
use Doctrine\ODM\PHPCR\DocumentManager;
use Doctrine\ODM\PHPCR\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManager;
use Gedmo\References\LazyCollection;
/**
* AbstractReferenceListener
*
* @author Steffen Brem <steffenbrem@gmail.com>
*/
abstract class AbstractReferenceListener implements EventSubscriber
{
protected $em;
private $_scheduledInserts = [];
private $_scheduledUpdates = [];
/**
* @param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* Returns an array of events this subscriber wants to listen to.
*
* @return array
*/
public function getSubscribedEvents()
{
return [
'prePersist',
'preUpdate',
'postLoad',
'onFlush',
'postFlush',
];
}
/**
* @param LifecycleEventArgs $event
*/
public function prePersist(LifecycleEventArgs $event)
{
$object = $event->getObject();
if (!$this->supports($object)) {
return;
}
/** @var ClassMetadata $metadata */
$metadata = $event->getObjectManager()->getClassMetadata(get_class($object));
$value = $this->getReferenceId($object);
if (!$metadata->hasField($this->getFieldName())) {
throw new \RuntimeException(sprintf(
'Class "%s" doesn\'t have the property "%s" mapped, add this field mapping to your doctrine mapping.',
get_class($object),
$this->getFieldName()
));
}
$metadata->setFieldValue($object, $this->getFieldName(), $value);
}
/**
* @param LifecycleEventArgs $event
*/
public function preUpdate(LifecycleEventArgs $event)
{
$this->prePersist($event);
}
/**
* @param LifecycleEventArgs $event
*/
public function postLoad(LifecycleEventArgs $event)
{
$object = $event->getObject();
if (!$this->supports($object)) {
return;
}
/** @var ClassMetadata $metadata */
$metadata = $event->getObjectManager()->getClassMetadata(get_class($object));
$id = $metadata->getFieldValue($object, $this->getFieldName());
$prop = $metadata->getReflectionClass()->getProperty($this->getFieldName());
$prop->setAccessible(true);
if (is_array($id)) {
$prop->setValue($object, new LazyCollection(
function () use ($id) {
if (count($id) > 0) {
$results = $this->em
->getRepository($this->getClassName())
->findBy([
'id' => $id,
])
;
} else {
$results = [];
}
return new ArrayCollection((is_array($results) ? $results : $results->toArray()));
}
));
} else {
$prop->setValue($object, $this->em->getReference(
$this->getClassName(),
$id
));
}
}
/**
* Keep track of what documents where updated or inserted, whe need to refresh those later.
*
* @param ManagerEventArgs $event
*/
public function onFlush(ManagerEventArgs $event)
{
$manager = $event->getObjectManager();
if ($manager instanceof DocumentManager) {
$uow = $manager->getUnitOfWork();
$this->_scheduledInserts = $uow->getScheduledInserts();
$this->_scheduledUpdates = $uow->getScheduledUpdates();
}
}
/**
* Refresh document after insert and update.
*
* @param ManagerEventArgs $event
*/
public function postFlush(ManagerEventArgs $event)
{
$manager = $event->getObjectManager();
if ($manager instanceof DocumentManager) {
foreach ($this->_scheduledInserts as $document) {
if ($this->supports($document)) {
$manager->refresh($document);
}
}
foreach ($this->_scheduledUpdates as $document) {
if ($this->supports($document)) {
$manager->refresh($document);
}
}
}
}
/**
* @return string
*/
abstract protected function getClassName();
/**
* @return mixed
*/
abstract protected function getFieldName();
/**
* @param $object
*
* @return mixed
*/
abstract protected function getReferenceId($object);
/**
* @param $object
*
* @return bool
*/
abstract protected function supports($object);
}
<?php
/**
* (c) Steffen Brem <steffenbrem@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Mango\Bundle\ContentBundle\EventListener\PHPCR;
use Mango\Component\Core\Model\Channel;
use Sylius\Component\Channel\Model\ChannelsAwareInterface;
/**
* ChannelsReferenceListener
*
* @author Steffen Brem <steffenbrem@gmail.com>
*/
class ChannelsReferenceListener extends AbstractReferenceListener
{
protected $fieldName = 'channels';
/**
* @return string
*/
protected function getClassName()
{
return Channel::class;
}
/**
* The field name on the PHPCR document that holds the id(s) of the reference.
*
* @return mixed
*/
protected function getFieldName()
{
return $this->fieldName;
}
/**
* Returns the ids of all channels on a `ChannelAware` document.
*
* @param ChannelsAwareInterface $object
*
* @return mixed
*/
protected function getReferenceId($object)
{
$ids = [];
foreach ($object->getChannels() as $channel) {
$ids[] = $channel->getId();
}
return $ids;
}
/**
* Check if the current PHPCR document ($object) is supported by this listener.
*
* @param $object
*
* @return bool
*/
protected function supports($object)
{
return $object instanceof ChannelsAwareInterface;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment