Skip to content

Commit 7e048ac

Browse files
committed
Implement transaction service
1 parent cd7d066 commit 7e048ac

9 files changed

Lines changed: 285 additions & 2 deletions

File tree

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
"license": "MIT",
1111
"require": {
1212
"php": ">=7.0.0",
13+
"ext-soap": "*",
1314
"nesbot/carbon": "^1.20",
1415
"doctrine/inflector": "~1.0"
1516
},
1617
"require-dev": {
1718
"phpunit/phpunit": "^5.2",
18-
"mockery/mockery": "^0.9.4"
19+
"mockery/mockery": "^0.9.4",
20+
"symfony/var-dumper": "^5.0"
1921
},
2022
"autoload": {
2123
"psr-4": {

src/Client.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Pace;
44

5+
use Closure;
56
use InvalidArgumentException;
67
use Pace\Soap\DateTimeMapping;
78
use Pace\Contracts\Soap\Factory as SoapFactory;
@@ -172,6 +173,42 @@ public function service($name)
172173
return $this->services[$name] ?? $this->services[$name] = $this->makeService($name);
173174
}
174175

176+
/**
177+
* Wrap the specified closure in a transaction.
178+
*
179+
* @param Closure $callback
180+
*/
181+
public function transaction(Closure $callback)
182+
{
183+
$this->service('TransactionService')->transaction($callback);
184+
}
185+
186+
/**
187+
* Start a transaction.
188+
*
189+
* @param int $timeout
190+
*/
191+
public function startTransaction(int $timeout = 60)
192+
{
193+
$this->service('TransactionService')->startTransaction($timeout);
194+
}
195+
196+
/**
197+
* Rollback the transaction.
198+
*/
199+
public function rollbackTransaction()
200+
{
201+
$this->service('TransactionService')->rollback();
202+
}
203+
204+
/**
205+
* Commit the transaction.
206+
*/
207+
public function commitTransaction()
208+
{
209+
$this->service('TransactionService')->commit();
210+
}
211+
175212
/**
176213
* Update an object.
177214
*
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace Pace\Services;
4+
5+
use Closure;
6+
use SoapFault;
7+
use Throwable;
8+
use Pace\Service;
9+
use Pace\Soap\SoapClient;
10+
use Pace\Soap\Middleware\Transaction;
11+
use Pace\Soap\Middleware\StartTransaction;
12+
use Pace\Soap\Middleware\CommitTransaction;
13+
use Pace\Soap\Middleware\RollbackTransaction;
14+
15+
class TransactionService extends Service
16+
{
17+
/**
18+
* Wrap the specified closure in a transaction.
19+
*
20+
* @param Closure $callback
21+
*/
22+
public function transaction(Closure $callback)
23+
{
24+
$this->startTransaction();
25+
26+
try {
27+
$callback();
28+
} catch (SoapFault $exception) {
29+
// Pace has already rolled the transaction back.
30+
SoapClient::removeMiddleware('transaction');
31+
throw $exception;
32+
} catch (Throwable $exception) {
33+
$this->rollback();
34+
throw $exception;
35+
}
36+
37+
$this->commit();
38+
}
39+
40+
/**
41+
* Start a new transaction.
42+
*
43+
* @param int $timeout
44+
*/
45+
public function startTransaction(int $timeout = 60)
46+
{
47+
SoapClient::addMiddleware('startTransaction', new StartTransaction);
48+
49+
$response = $this->soap->startTransaction(['in0' => $timeout]);
50+
51+
SoapClient::removeMiddleware('startTransaction');
52+
SoapClient::addMiddleware('transaction', new Transaction($response->out));
53+
}
54+
55+
/**
56+
* Rollback the transaction.
57+
*/
58+
public function rollback()
59+
{
60+
SoapClient::addMiddleware('rollback', new RollbackTransaction);
61+
62+
$this->soap->rollback();
63+
64+
SoapClient::removeMiddleware('rollback');
65+
SoapClient::removeMiddleware('transaction');
66+
}
67+
68+
/**
69+
* Commit the transaction.
70+
*/
71+
public function commit()
72+
{
73+
SoapClient::addMiddleware('commit', new CommitTransaction);
74+
75+
$this->soap->commit();
76+
77+
SoapClient::removeMiddleware('commit');
78+
SoapClient::removeMiddleware('transaction');
79+
}
80+
}

src/Soap/Factory.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace Pace\Soap;
44

5-
use SoapClient;
65
use Pace\Contracts\Soap\TypeMapping;
76
use Pace\Contracts\Soap\Factory as FactoryContract;
87

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Pace\Soap\Middleware;
4+
5+
use SoapHeader;
6+
7+
class CommitTransaction
8+
{
9+
/**
10+
* Add the commit transaction SOAP header.
11+
*
12+
* @param array $headers
13+
* @return array
14+
*/
15+
public function __invoke(array $headers): array
16+
{
17+
$headers[] = new SoapHeader('transaction', 'process', 'commit');
18+
19+
return $headers;
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Pace\Soap\Middleware;
4+
5+
use SoapHeader;
6+
7+
class RollbackTransaction
8+
{
9+
/**
10+
* Add the rollback transaction SOAP header.
11+
*
12+
* @param array $headers
13+
* @return array
14+
*/
15+
public function __invoke(array $headers): array
16+
{
17+
$headers[] = new SoapHeader('transaction', 'process', 'rollback');
18+
19+
return $headers;
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Pace\Soap\Middleware;
4+
5+
use SoapHeader;
6+
7+
class StartTransaction
8+
{
9+
/**
10+
* Add the start transaction SOAP header.
11+
*
12+
* @param array $headers
13+
* @return array
14+
*/
15+
public function __invoke(array $headers): array
16+
{
17+
$headers[] = new SoapHeader('transaction', 'process', 'startTransaction');
18+
19+
return $headers;
20+
}
21+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Pace\Soap\Middleware;
4+
5+
use SoapHeader;
6+
7+
class Transaction
8+
{
9+
/**
10+
* The transaction ID.
11+
*
12+
* @var string
13+
*/
14+
protected $id;
15+
16+
/**
17+
* Create a new middleware instance.
18+
*
19+
* @param string $id
20+
*/
21+
public function __construct(string $id)
22+
{
23+
$this->id = $id;
24+
}
25+
26+
/**
27+
* Add the transaction ID SOAP header.
28+
*
29+
* @param array $headers
30+
* @return array
31+
*/
32+
public function __invoke(array $headers): array
33+
{
34+
$headers[] = new SoapHeader('transaction', 'txnId', $this->id);
35+
36+
return $headers;
37+
}
38+
}

src/Soap/SoapClient.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace Pace\Soap;
4+
5+
use SoapClient as PhpSoapClient;
6+
7+
class SoapClient extends PhpSoapClient
8+
{
9+
/**
10+
* The middleware.
11+
*
12+
* @var array
13+
*/
14+
protected static $middleware = [];
15+
16+
/**
17+
* Add the specified middleware.
18+
*
19+
* @param string $name
20+
* @param callable $callable
21+
*/
22+
public static function addMiddleware(string $name, callable $callable)
23+
{
24+
static::$middleware[$name] = $callable;
25+
}
26+
27+
/**
28+
* Remove the specified middleware.
29+
*
30+
* @param string $name
31+
*/
32+
public static function removeMiddleware(string $name)
33+
{
34+
unset(static::$middleware[$name]);
35+
}
36+
37+
/**
38+
* Apply middleware before calling the specified SOAP function.
39+
*
40+
* @param string $function
41+
* @param array $arguments
42+
* @return mixed
43+
*/
44+
public function __call($function, $arguments)
45+
{
46+
$this->applyMiddleware();
47+
48+
return parent::__call($function, $arguments);
49+
}
50+
51+
/**
52+
* Apply the middleware.
53+
*/
54+
protected function applyMiddleware()
55+
{
56+
$headers = [];
57+
58+
foreach(static::$middleware as $middleware) {
59+
$headers = $middleware($headers);
60+
}
61+
62+
$this->__setSoapHeaders($headers);
63+
}
64+
}

0 commit comments

Comments
 (0)