From 5558f278ff411e6184e5cf2574841f7a195963ea Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 28 Mar 2014 18:34:22 -0700 Subject: [PATCH] CRM-14370 - TransactionSubscriber - Be more defensive --- Civi/API/Request.php | 3 ++ Civi/API/Subscriber/TransactionSubscriber.php | 39 ++++++++++++------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Civi/API/Request.php b/Civi/API/Request.php index 4c49eb4483..e4ffa282c1 100644 --- a/Civi/API/Request.php +++ b/Civi/API/Request.php @@ -27,6 +27,8 @@ namespace Civi\API; class Request { + private static $nextId = 1; + /** * Create a formatted/normalized request object. * @@ -47,6 +49,7 @@ class Request { */ public static function create($entity, $action, $params, $extra) { $apiRequest = array(); // new \Civi\API\Request(); + $apiRequest['id'] = self::$nextId++; $apiRequest['version'] = self::parseVersion($params); $apiRequest['params'] = $params; $apiRequest['extra'] = $extra; diff --git a/Civi/API/Subscriber/TransactionSubscriber.php b/Civi/API/Subscriber/TransactionSubscriber.php index 050058ef02..71c8439736 100644 --- a/Civi/API/Subscriber/TransactionSubscriber.php +++ b/Civi/API/Subscriber/TransactionSubscriber.php @@ -39,31 +39,39 @@ class TransactionSubscriber implements EventSubscriberInterface { } /** - * @var array<\CRM_Core_Transaction> + * @var array (scalar $apiRequestId => CRM_Core_Transaction $tx) */ - private $stack = array(); + private $transactions = array(); + + /** + * Determine if an API request should be treated as transactional + * + * @param \Civi\API\Provider\ProviderInterface $apiProvider + * @param array $apiRequest + * @return bool + */ + public function isTransactional($apiProvider, $apiRequest) { + return strtolower($apiRequest['action']) == 'create' || strtolower($apiRequest['action']) == 'delete' || strtolower($apiRequest['action']) == 'submit'; + } /** * Open a new transaction instance (if appropriate in the current policy) * - * @param \Civi\API\Event\Event $event + * @param \Civi\API\Event\PrepareEvent $event */ - function onApiPrepare(\Civi\API\Event\Event $event) { + function onApiPrepare(\Civi\API\Event\PrepareEvent $event) { $apiRequest = $event->getApiRequest(); - if (strtolower($apiRequest['action']) == 'create' || strtolower($apiRequest['action']) == 'delete' || strtolower($apiRequest['action']) == 'submit') { - $apiRequest['is_transactional'] = 1; - - $this->stack[] = new \CRM_Core_Transaction(); - } else { - $this->stack[] = NULL; + if ($this->isTransactional($event->getApiProvider(), $apiRequest)) { + $this->transactions[$apiRequest['id']] = new \CRM_Core_Transaction(); } } /** * Close any pending transactions */ - function onApiRespond() { - array_pop($this->stack); + function onApiRespond(\Civi\API\Event\RespondEvent $event) { + $apiRequest = $event->getApiRequest(); + unset($this->transactions[$apiRequest['id']]); } /** @@ -72,9 +80,10 @@ class TransactionSubscriber implements EventSubscriberInterface { * @param \Civi\API\Event\ExceptionEvent $event */ function onApiException(\Civi\API\Event\ExceptionEvent $event) { - $transaction = array_pop($this->stack); - if ($transaction !== NULL) { - $transaction->rollback(); + $apiRequest = $event->getApiRequest(); + if (isset($this->transactions[$apiRequest['id']])) { + $this->transactions[$apiRequest['id']]->rollback(); + unset($this->transactions[$apiRequest['id']]); } } } \ No newline at end of file -- 2.25.1