Chaincode::extractTransactionOptions()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
ccs 8
cts 8
cp 1
crap 3
1
<?php
2
3
/**
4
 * Copyright 2017 American Express Travel Related Services Company, Inc.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
15
 * or implied. See the License for the specific language governing
16
 * permissions and limitations under the License.
17
 */
18
19
declare(strict_types=1);
20
21
namespace AmericanExpress\HyperledgerFabricClient\Chaincode;
22
23
use AmericanExpress\HyperledgerFabricClient\Exception\InvalidArgumentException;
24
use AmericanExpress\HyperledgerFabricClient\Proposal\ResponseCollection;
25
use AmericanExpress\HyperledgerFabricClient\ProtoFactory\ChaincodeHeaderExtensionFactory;
26
use AmericanExpress\HyperledgerFabricClient\ProtoFactory\ChaincodeIdFactory;
27
use AmericanExpress\HyperledgerFabricClient\ProtoFactory\ChaincodeProposalPayloadFactory;
28
use AmericanExpress\HyperledgerFabricClient\Transaction\TransactionOptions;
29
30
/**
31
 * #### Example Usage
32
 *
33
 * ```php
34
 * $client = ClientFactory::fromConfig(new ClientConfig([]));
35
 *
36
 * $responseCollection = $client->getChannel('foo')->getChaincode('bar')->invoke('query', 'foobar');
37
 * ```
38
 */
39
class Chaincode
40
{
41
    /**
42
     * @var string $name
43
     */
44
    private $name;
45
46
    /**
47
     * @var string $version
48
     */
49
    private $version;
50
51
    /**
52
     * @var string $path
53
     */
54
    private $path;
55
56
    /**
57
     * @var ChaincodeProposalProcessorInterface $channel
58
     */
59
    private $channel;
60
61
    /**
62
     * Chaincode constructor.
63
     * @param string | array $nameOrDetails
64
     * @param ChaincodeProposalProcessorInterface $channel
65
     * @throws InvalidArgumentException
66
     */
67 14
    public function __construct($nameOrDetails, ChaincodeProposalProcessorInterface $channel)
68
    {
69 14
        $details = $this->normalizeName($nameOrDetails);
70
71 14
        if (empty($details['name'])) {
72 2
            throw new InvalidArgumentException('A string name parameter must be provided');
73
        }
74
75 14
        $this->name = $details['name'];
76 14
        $this->version = $details['version'];
77 14
        $this->path = $details['path'];
78 14
        $this->channel = $channel;
79 14
    }
80
81
    /**
82
     * @return string
83
     */
84 7
    public function getName(): string
85
    {
86 7
        return $this->name;
87
    }
88
89
    /**
90
     * @return string
91
     */
92 2
    public function getVersion(): string
93
    {
94 2
        return $this->version;
95
    }
96
97
    /**
98
     * @return string
99
     */
100 2
    public function getPath(): string
101
    {
102 2
        return $this->path;
103
    }
104
105
    /**
106
     * @param string | array $nameOrDetails
107
     * @return string[]
108
     * @throws InvalidArgumentException
109
     */
110 14
    private function normalizeName($nameOrDetails): array
111
    {
112 14
        if (\is_string($nameOrDetails)) {
113 14
            return ['name' => $nameOrDetails, 'version' => '', 'path' => ''];
114
        }
115
116 4
        if (!\is_array($nameOrDetails)) {
117 1
            throw new InvalidArgumentException('name must be a string or an array');
118
        }
119
120 3
        return \array_merge(['name' => '', 'version' => '', 'path' => ''], $nameOrDetails);
121
    }
122
123
    /**
124
     * @param mixed $value
125
     * @param mixed[] $array
126
     * @return mixed[]
127
     */
128 7
    private function prependValueToArray($value, array $array): array
129
    {
130 7
        array_unshift($array, $value);
131 7
        return $array;
132
    }
133
134
    /**
135
     * @param string $name
136
     * @param mixed[] $args
137
     * @param TransactionOptions|null $options
138
     * @return ResponseCollection
139
     */
140 7
    private function executeCommand(
141
        string $name,
142
        array $args = [],
143
        TransactionOptions $options = null
144
    ): ResponseCollection {
145 7
        $chaincodeId = ChaincodeIdFactory::create(
146 7
            $this->path,
147 7
            $this->name,
148 7
            $this->version
149
        );
150
151 7
        $chaincodeHeaderExtension = ChaincodeHeaderExtensionFactory::fromChaincodeId($chaincodeId);
152
153 7
        $nameAndArguments = $this->prependValueToArray($name, $args);
154 7
        $chaincodeProposalPayload = ChaincodeProposalPayloadFactory::fromChaincodeInvocationSpecArgs(
155 7
            $nameAndArguments
156
        );
157
158 7
        return $this->channel->processChaincodeProposal(
159 7
            $chaincodeProposalPayload,
160 7
            $chaincodeHeaderExtension,
161 7
            $options
162
        );
163
    }
164
165
    /**
166
     * @param mixed[] $arguments
167
     * @return TransactionOptions|null
168
     */
169 7
    private function extractTransactionOptions(array $arguments): ?TransactionOptions
170
    {
171 7
        $transactionRequest = null;
172 7
        if (count($arguments) > 0) {
173 6
            $lastArgumentIndex = count($arguments) - 1;
174 6
            $lastArgument = $arguments[$lastArgumentIndex];
175
176 6
            if ($lastArgument instanceof TransactionOptions) {
177 3
                $transactionRequest = $lastArgument;
178
            }
179
        }
180
181 7
        return $transactionRequest;
182
    }
183
184
    /**
185
     *
186
     * Execute a proposal against a Chaincode. Because Chaincodes have variable methods, __call allows for dynamic
187
     * function submission
188
     *
189
     * @param string $name
190
     * @param array $arguments
191
     * @return ResponseCollection
192
     */
193 7
    public function __call(string $name, array $arguments = []): ResponseCollection
194
    {
195 7
        $options = $this->extractTransactionOptions($arguments);
196 7
        if ($options !== null) {
197 3
            array_pop($arguments);
198
        }
199
200 7
        return $this->executeCommand($name, $arguments, $options);
201
    }
202
203
    /**
204
     *
205
     * Typing the default call to a Chaincode (invoke)
206
     *
207
     * @param array ...$args
208
     * @return ResponseCollection
209
     */
210 2
    public function invoke(...$args): ResponseCollection
211
    {
212 2
        return $this->__call('invoke', $args);
213
    }
214
}
215