Completed
Pull Request — master (#7)
by Sandro
02:21
created

TransactionalClient::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
1
<?php
2
/**
3
 * Sandro Keil (https://sandro-keil.de)
4
 *
5
 * @link      http://github.com/sandrokeil/arangodb-php-client for the canonical source repository
6
 * @copyright Copyright (c) 2018-2019 Sandro Keil
7
 * @license   http://github.com/sandrokeil/arangodb-php-client/blob/master/LICENSE.md New BSD License
8
 */
9
10
declare(strict_types=1);
11
12
namespace ArangoDb;
13
14
use ArangoDb\Type\Batch;
15
use ArangoDb\Type\GuardSupport;
16
use ArangoDb\Type\Transaction as TransactionType;
17
use ArangoDb\Type\Transactional;
18
use ArangoDb\Type\Type;
19
use Fig\Http\Message\StatusCodeInterface;
20
use Psr\Http\Client\ClientInterface;
21
use Psr\Http\Message\RequestFactoryInterface;
22
use Psr\Http\Message\RequestInterface;
23
use Psr\Http\Message\ResponseFactoryInterface;
24
use Psr\Http\Message\ResponseInterface;
25
26
final class TransactionalClient implements ClientInterface
27
{
28
    /**
29
     * @var ClientInterface
30
     */
31
    private $client;
32
33
    /**
34
     * @var RequestFactoryInterface
35
     */
36
    private $requestFactory;
37
38
    /**
39
     * @var ResponseFactoryInterface
40
     */
41
    private $responseFactory;
42
43
    /**
44
     * Types
45
     *
46
     * @var Type[]
47
     */
48
    private $types = [];
49
50
    /**
51
     * Types
52
     *
53
     * @var Transactional[]
54
     */
55
    private $transactionalTypes = [];
56
57 9
    public function __construct(
58
        ClientInterface $client,
59
        RequestFactoryInterface $requestFactory,
60
        ResponseFactoryInterface $responseFactory
61
    ) {
62 9
        $this->client = $client;
63 9
        $this->requestFactory = $requestFactory;
64 9
        $this->responseFactory = $responseFactory;
65 9
    }
66
67
    public function sendRequest(RequestInterface $request): ResponseInterface
68
    {
69
        return $this->client->sendRequest($request);
70
    }
71
72
    /**
73
     * Sends types and transactional types. Type responses and transaction response are validated via guards if provided
74
     * to a type. You can also manually validate the transaction response but not the non transaction response.
75
     *
76
     * @param array $params
77
     * @param bool $waitForSync
78
     * @return ResponseInterface
79
     * @throws \Psr\Http\Client\ClientExceptionInterface
80
     */
81 8
    public function send(array $params = [], bool $waitForSync = false): ResponseInterface
82
    {
83 8
        if (! empty($this->types)) {
84 2
            $batch = Batch::fromTypes(...$this->types);
85 2
            $responseBatch = $this->client->sendRequest($batch->toRequest($this->requestFactory));
86
87 2
            if ($guards = $batch->guards()) {
88 1
                BatchResult::fromResponse($responseBatch, $this->responseFactory)->validate(...$guards);
89
            }
90
        }
91
92 8
        $actions = '';
93 8
        $collectionsWrite = [[]];
94 8
        $collectionsRead = [[]];
95 8
        $return = [];
96 8
        $guards = [];
97
98 8
        if (empty($this->transactionalTypes)) {
99 1
            return $this->responseFactory->createResponse(StatusCodeInterface::STATUS_OK);
100
        }
101
102 7
        foreach ($this->transactionalTypes as $key => $type) {
103 7
            $collectionsWrite[] = $type->collectionsWrite();
104 7
            $collectionsRead[] = $type->collectionsRead();
105
106 7
            if ($type instanceof GuardSupport
107 7
                && ($guard = $type->guard()) !== null
108
            ) {
109 1
                $guards[] = $guard;
110 1
                $key = $guard->contentId();
111
            }
112 7
            $actions .= str_replace('var rId', 'var rId' . $key, $type->toJs());
113 7
            $return[] = 'rId' . $key;
114
        }
115 7
        $collectionsWrite = array_merge(...$collectionsWrite);
116 7
        $collectionsRead = array_merge(...$collectionsRead);
117
118 7
        $response = $this->client->sendRequest(
119 7
            TransactionType::with(
120 7
                sprintf(
121 7
                    'function () {var db = require("@arangodb").db;%s return {%s}}',
122
                    $actions,
123 7
                    implode(',', $return)
124
                ),
125 7
                array_unique($collectionsWrite),
126
                $params,
127 7
                array_unique($collectionsRead),
128
                $waitForSync
129 7
            )->toRequest($this->requestFactory)
130
        );
131
132 7
        if (! empty($guards)) {
133
            \array_walk($guards, function ($guard) use ($response) {
134 1
                $guard($response);
135 1
            });
136
        }
137
138 7
        $this->types = [];
139 7
        $this->transactionalTypes = [];
140
141 7
        return $response;
142
    }
143
144
    /**
145
     * Add type
146
     *
147
     * @param Type $type
148
     */
149 4
    public function add(Type $type): void
150
    {
151 4
        if ($type instanceof Transactional) {
152 4
            $this->transactionalTypes[] = $type;
153 4
            return;
154
        }
155 3
        $this->types[] = $type;
156 3
    }
157
158
    /**
159
     * Adds multiple types
160
     *
161
     * @param Type ...$types
162
     */
163 4
    public function addList(Type ...$types): void
164
    {
165 4
        foreach ($types as $type) {
166 4
            if ($type instanceof Transactional) {
167 4
                $this->transactionalTypes[] = $type;
168 4
                continue;
169
            }
170
            $this->types[] = $type;
171
        }
172 4
    }
173
174
    /**
175
     * Counts non transactional types
176
     *
177
     * @return int
178
     */
179 3
    public function countTypes(): int
180
    {
181 3
        return count($this->types);
182
    }
183
184
    /**
185
     * Counts transactional types
186
     *
187
     * @return int
188
     */
189 3
    public function countTransactionalTypes(): int
190
    {
191 3
        return count($this->transactionalTypes);
192
    }
193
194
    /**
195
     * Resets all types and transactional types
196
     */
197 1
    public function reset(): void
198
    {
199 1
        $this->types = [];
200 1
        $this->transactionalTypes = [];
201 1
    }
202
}
203