Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Commit

Permalink
Added $data to the DoctrineResourceEvent allowing access to original …
Browse files Browse the repository at this point in the history
…data submitted to the resource method. Implemented an Event Listener to handled embedded toMany collections submitted to the Resource.
  • Loading branch information
Phillip McCaffrey authored and TomHAnderson committed Jun 6, 2015
1 parent f7965f8 commit 29c23d1
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 43 deletions.
64 changes: 49 additions & 15 deletions src/Server/Event/DoctrineResourceEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace ZF\Apigility\Doctrine\Server\Event;

use Doctrine\Common\Persistence\ObjectManager;
use Zend\EventManager\Event;
use ZF\Rest\ResourceEvent;

Expand Down Expand Up @@ -43,32 +44,42 @@ class DoctrineResourceEvent extends Event
*/
protected $collection;

/**
* @var array|mixed Should be the original data that was supplied the resource
*/
protected $data;

/**
* @var object
* @var ObjectManager
*/
protected $objectManager;

/**
* @param object
*/
public function setObjectManager($objectManager)
/**
* @param ObjectManager $objectManager
*
* @return $this
*/
public function setObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;

return $this;
}

/**
* @return object
* @return ObjectManager
*/
public function getObjectManager()
{
return $this->objectManager;
}

/**
* @param mixed $collection
*/
/**
* @param mixed $collection
*
* @deprecated Callers have been removed in Commit b1cf74e
* @return $this
*/
public function setCollection($collection)
{
$this->collection = $collection;
Expand All @@ -78,15 +89,18 @@ public function setCollection($collection)

/**
* @return mixed
* @deprecated Should almost certainly be null at all times as of commit b1cf74e
*/
public function getCollection()
{
return $this->collection;
}

/**
* @param mixed $entity
*/
/**
* @param mixed $entity
*
* @return $this
*/
public function setEntity($entity)
{
$this->entity = $entity;
Expand All @@ -102,9 +116,29 @@ public function getEntity()
return $this->entity;
}

/**
* @param \ZF\Rest\ResourceEvent $resourceEvent
*/
/**
* @return mixed
*/
public function getData() {
return $this->data;
}

/**
* @param mixed $data The Original Data supplied to the Resource Method
*
* @return $this
*/
public function setData( $data ) {
$this->data = $data;

return $this;
}

/**
* @param \ZF\Rest\ResourceEvent $resourceEvent
*
* @return $this
*/
public function setResourceEvent($resourceEvent)
{
$this->resourceEvent = $resourceEvent;
Expand Down
102 changes: 102 additions & 0 deletions src/Server/Event/Listener/CollectionListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace ZF\Apigility\Doctrine\Server\Event\Listener;

use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\EventManagerInterface;
use ZF\Apigility\Doctrine\Server\Event\DoctrineResourceEvent;
use Zend\Stdlib\Response;
use ZF\Apigility\Doctrine\Server\Resource\DoctrineResource;
use Zend\Stdlib\Hydrator\HydratorAwareInterface;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject;

/**
* Class CollectionListener
*
* @package ZF\Apigility\Doctrine\Server\Event\Listener
*/
class CollectionListener implements ListenerAggregateInterface {
protected $listeners = array();

public function attach( EventManagerInterface $events ) {
$this->listeners[] = $events->attach(
DoctrineResourceEvent::EVENT_UPDATE_PRE,
array( $this, 'handleCollections' )
);

$this->listeners[] = $events->attach(
DoctrineResourceEvent::EVENT_CREATE_PRE,
array( $this, 'handleCollections' )
);
}

public function handleCollections( DoctrineResourceEvent $event ) {
$objectManager = $event->getObjectManager();
$entity = $event->getEntity();
$originalData = (array) $event->getData();

$metadata = $objectManager->getClassMetadata( get_class( $entity ) );

$associations = $metadata->getAssociationNames();

foreach ( $associations as $association ) {
// Skip handling associations that arent in the data
if ( $metadata->isCollectionValuedAssociation( $association ) ) {
if ( array_key_exists( $association, $originalData )
&& ! empty( $originalData[ $association ] )
&& ( is_array( $originalData[ $association ] ) || $originalData[ $association ] instanceof \Traversable )
) {
foreach ( $originalData[ $association ] as &$subEntityData ) {
$target = $metadata->getAssociationTargetClass( $association );
$identifierNames = $metadata->getIdentifierFieldNames( $target );
if ( empty( $identifierNames ) ) {
continue; // TODO Investigate what we should do here, throw exception? for now handle downstream
}

$identifierValues = [ ];
foreach ( $identifierNames as $identifierName ) {
if ( ! isset( $subEntityData[ $identifierName ] ) || empty( $subEntityData[ $identifierName ] ) ) {
continue;
}
$identifierValues[ $identifierName ] = $subEntityData[ $identifierName ];
}

$subEntity = false;
if ( count( $identifierValues ) === count( $identifierNames ) ) {
$subEntity = $objectManager->find( $target, $identifierValues );
}

if(!$subEntity){
$subEntity = new $target;
}

// TODO This could cause a catastrophe as it wouldnt have the appropriate strategies/listeners
// probably should fetch from "hydrator-manager" if possible
$hydrator = new DoctrineObject( $objectManager );
$hydrator->hydrate($subEntityData,$subEntity);
$objectManager->persist($subEntity);
$objectManager->flush();

$subEntityData = $hydrator->extract($subEntity);

foreach ( $identifierNames as $identifierName ) {
$identifierValues[ $identifierName ] = $subEntityData[ $identifierName ];
}
$subEntityData = $identifierValues;
}
}
}
}

$event->setData($originalData);
return $originalData;
}

public function detach( EventManagerInterface $events ) {
foreach ( $this->listeners as $index => $listener ) {
if ( $events->detach( $listener ) ) {
unset( $this->listeners[ $index ] );
}
}
}
}
Loading

0 comments on commit 29c23d1

Please sign in to comment.