1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Guzzle\Service\Description; |
4
|
|
|
|
5
|
|
|
use Guzzle\Common\Exception\InvalidArgumentException; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Data object holding the information of an API command |
9
|
|
|
*/ |
10
|
|
|
class Operation implements OperationInterface |
11
|
|
|
{ |
12
|
|
|
/** @var string Default command class to use when none is specified */ |
13
|
|
|
const DEFAULT_COMMAND_CLASS = 'Guzzle\\Service\\Command\\OperationCommand'; |
14
|
|
|
|
15
|
|
|
/** @var array Hashmap of properties that can be specified. Represented as a hash to speed up constructor. */ |
16
|
|
|
protected static $properties = array( |
17
|
|
|
'name' => true, 'httpMethod' => true, 'uri' => true, 'class' => true, 'responseClass' => true, |
18
|
|
|
'responseType' => true, 'responseNotes' => true, 'notes' => true, 'summary' => true, 'documentationUrl' => true, |
19
|
|
|
'deprecated' => true, 'data' => true, 'parameters' => true, 'additionalParameters' => true, |
20
|
|
|
'errorResponses' => true |
21
|
|
|
); |
22
|
|
|
|
23
|
|
|
/** @var array Parameters */ |
24
|
|
|
protected $parameters = array(); |
25
|
|
|
|
26
|
|
|
/** @var Parameter Additional parameters schema */ |
27
|
|
|
protected $additionalParameters; |
28
|
|
|
|
29
|
|
|
/** @var string Name of the command */ |
30
|
|
|
protected $name; |
31
|
|
|
|
32
|
|
|
/** @var string HTTP method */ |
33
|
|
|
protected $httpMethod; |
34
|
|
|
|
35
|
|
|
/** @var string This is a short summary of what the operation does */ |
36
|
|
|
protected $summary; |
37
|
|
|
|
38
|
|
|
/** @var string A longer text field to explain the behavior of the operation. */ |
39
|
|
|
protected $notes; |
40
|
|
|
|
41
|
|
|
/** @var string Reference URL providing more information about the operation */ |
42
|
|
|
protected $documentationUrl; |
43
|
|
|
|
44
|
|
|
/** @var string HTTP URI of the command */ |
45
|
|
|
protected $uri; |
46
|
|
|
|
47
|
|
|
/** @var string Class of the command object */ |
48
|
|
|
protected $class; |
49
|
|
|
|
50
|
|
|
/** @var string This is what is returned from the method */ |
51
|
|
|
protected $responseClass; |
52
|
|
|
|
53
|
|
|
/** @var string Type information about the response */ |
54
|
|
|
protected $responseType; |
55
|
|
|
|
56
|
|
|
/** @var string Information about the response returned by the operation */ |
57
|
|
|
protected $responseNotes; |
58
|
|
|
|
59
|
|
|
/** @var bool Whether or not the command is deprecated */ |
60
|
|
|
protected $deprecated; |
61
|
|
|
|
62
|
|
|
/** @var array Array of errors that could occur when running the command */ |
63
|
|
|
protected $errorResponses; |
64
|
|
|
|
65
|
|
|
/** @var ServiceDescriptionInterface */ |
66
|
|
|
protected $description; |
67
|
|
|
|
68
|
|
|
/** @var array Extra operation information */ |
69
|
|
|
protected $data; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Builds an Operation object using an array of configuration data: |
73
|
|
|
* - name: (string) Name of the command |
74
|
|
|
* - httpMethod: (string) HTTP method of the operation |
75
|
|
|
* - uri: (string) URI template that can create a relative or absolute URL |
76
|
|
|
* - class: (string) Concrete class that implements this command |
77
|
|
|
* - parameters: (array) Associative array of parameters for the command. {@see Parameter} for information. |
78
|
|
|
* - summary: (string) This is a short summary of what the operation does |
79
|
|
|
* - notes: (string) A longer text field to explain the behavior of the operation. |
80
|
|
|
* - documentationUrl: (string) Reference URL providing more information about the operation |
81
|
|
|
* - responseClass: (string) This is what is returned from the method. Can be a primitive, PSR-0 compliant |
82
|
|
|
* class name, or model. |
83
|
|
|
* - responseNotes: (string) Information about the response returned by the operation |
84
|
|
|
* - responseType: (string) One of 'primitive', 'class', 'model', or 'documentation'. If not specified, this |
85
|
|
|
* value will be automatically inferred based on whether or not there is a model matching the |
86
|
|
|
* name, if a matching PSR-0 compliant class name is found, or set to 'primitive' by default. |
87
|
|
|
* - deprecated: (bool) Set to true if this is a deprecated command |
88
|
|
|
* - errorResponses: (array) Errors that could occur when executing the command. Array of hashes, each with a |
89
|
|
|
* 'code' (the HTTP response code), 'reason' (response reason phrase or description of the |
90
|
|
|
* error), and 'class' (a custom exception class that would be thrown if the error is |
91
|
|
|
* encountered). |
92
|
|
|
* - data: (array) Any extra data that might be used to help build or serialize the operation |
93
|
|
|
* - additionalParameters: (null|array) Parameter schema to use when an option is passed to the operation that is |
94
|
|
|
* not in the schema |
95
|
|
|
* |
96
|
|
|
* @param array $config Array of configuration data |
97
|
|
|
* @param ServiceDescriptionInterface $description Service description used to resolve models if $ref tags are found |
98
|
|
|
*/ |
99
|
|
|
public function __construct(array $config = array(), ServiceDescriptionInterface $description = null) |
100
|
|
|
{ |
101
|
|
|
$this->description = $description; |
102
|
|
|
|
103
|
|
|
// Get the intersection of the available properties and properties set on the operation |
104
|
|
|
foreach (array_intersect_key($config, self::$properties) as $key => $value) { |
105
|
|
|
$this->{$key} = $value; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
$this->class = $this->class ?: self::DEFAULT_COMMAND_CLASS; |
109
|
|
|
$this->deprecated = (bool) $this->deprecated; |
110
|
|
|
$this->errorResponses = $this->errorResponses ?: array(); |
111
|
|
|
$this->data = $this->data ?: array(); |
112
|
|
|
|
113
|
|
|
if (!$this->responseClass) { |
114
|
|
|
$this->responseClass = 'array'; |
115
|
|
|
$this->responseType = 'primitive'; |
116
|
|
|
} elseif ($this->responseType) { |
117
|
|
|
// Set the response type to perform validation |
118
|
|
|
$this->setResponseType($this->responseType); |
119
|
|
|
} else { |
120
|
|
|
// A response class was set and no response type was set, so guess what the type is |
121
|
|
|
$this->inferResponseType(); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
// Parameters need special handling when adding |
125
|
|
|
if ($this->parameters) { |
|
|
|
|
126
|
|
|
foreach ($this->parameters as $name => $param) { |
127
|
|
|
if ($param instanceof Parameter) { |
128
|
|
|
$param->setName($name)->setParent($this); |
129
|
|
|
} elseif (is_array($param)) { |
130
|
|
|
$param['name'] = $name; |
131
|
|
|
$this->addParam(new Parameter($param, $this->description)); |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
if ($this->additionalParameters) { |
137
|
|
|
if ($this->additionalParameters instanceof Parameter) { |
138
|
|
|
$this->additionalParameters->setParent($this); |
139
|
|
|
} elseif (is_array($this->additionalParameters)) { |
140
|
|
|
$this->setadditionalParameters(new Parameter($this->additionalParameters, $this->description)); |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
public function toArray() |
146
|
|
|
{ |
147
|
|
|
$result = array(); |
148
|
|
|
// Grab valid properties and filter out values that weren't set |
149
|
|
|
foreach (array_keys(self::$properties) as $check) { |
150
|
|
|
if ($value = $this->{$check}) { |
151
|
|
|
$result[$check] = $value; |
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
// Remove the name property |
155
|
|
|
unset($result['name']); |
156
|
|
|
// Parameters need to be converted to arrays |
157
|
|
|
$result['parameters'] = array(); |
158
|
|
|
foreach ($this->parameters as $key => $param) { |
159
|
|
|
$result['parameters'][$key] = $param->toArray(); |
160
|
|
|
} |
161
|
|
|
// Additional parameters need to be cast to an array |
162
|
|
|
if ($this->additionalParameters instanceof Parameter) { |
163
|
|
|
$result['additionalParameters'] = $this->additionalParameters->toArray(); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
return $result; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
public function getServiceDescription() |
170
|
|
|
{ |
171
|
|
|
return $this->description; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
public function setServiceDescription(ServiceDescriptionInterface $description) |
175
|
|
|
{ |
176
|
|
|
$this->description = $description; |
177
|
|
|
|
178
|
|
|
return $this; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
public function getParams() |
182
|
|
|
{ |
183
|
|
|
return $this->parameters; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
public function getParamNames() |
187
|
|
|
{ |
188
|
|
|
return array_keys($this->parameters); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
public function hasParam($name) |
192
|
|
|
{ |
193
|
|
|
return isset($this->parameters[$name]); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
public function getParam($param) |
197
|
|
|
{ |
198
|
|
|
return isset($this->parameters[$param]) ? $this->parameters[$param] : null; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Add a parameter to the command |
203
|
|
|
* |
204
|
|
|
* @param Parameter $param Parameter to add |
205
|
|
|
* |
206
|
|
|
* @return self |
207
|
|
|
*/ |
208
|
|
|
public function addParam(Parameter $param) |
209
|
|
|
{ |
210
|
|
|
$this->parameters[$param->getName()] = $param; |
211
|
|
|
$param->setParent($this); |
212
|
|
|
|
213
|
|
|
return $this; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Remove a parameter from the command |
218
|
|
|
* |
219
|
|
|
* @param string $name Name of the parameter to remove |
220
|
|
|
* |
221
|
|
|
* @return self |
222
|
|
|
*/ |
223
|
|
|
public function removeParam($name) |
224
|
|
|
{ |
225
|
|
|
unset($this->parameters[$name]); |
226
|
|
|
|
227
|
|
|
return $this; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
public function getHttpMethod() |
231
|
|
|
{ |
232
|
|
|
return $this->httpMethod; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Set the HTTP method of the command |
237
|
|
|
* |
238
|
|
|
* @param string $httpMethod Method to set |
239
|
|
|
* |
240
|
|
|
* @return self |
241
|
|
|
*/ |
242
|
|
|
public function setHttpMethod($httpMethod) |
243
|
|
|
{ |
244
|
|
|
$this->httpMethod = $httpMethod; |
245
|
|
|
|
246
|
|
|
return $this; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
public function getClass() |
250
|
|
|
{ |
251
|
|
|
return $this->class; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Set the concrete class of the command |
256
|
|
|
* |
257
|
|
|
* @param string $className Concrete class name |
258
|
|
|
* |
259
|
|
|
* @return self |
260
|
|
|
*/ |
261
|
|
|
public function setClass($className) |
262
|
|
|
{ |
263
|
|
|
$this->class = $className; |
264
|
|
|
|
265
|
|
|
return $this; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
public function getName() |
269
|
|
|
{ |
270
|
|
|
return $this->name; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Set the name of the command |
275
|
|
|
* |
276
|
|
|
* @param string $name Name of the command |
277
|
|
|
* |
278
|
|
|
* @return self |
279
|
|
|
*/ |
280
|
|
|
public function setName($name) |
281
|
|
|
{ |
282
|
|
|
$this->name = $name; |
283
|
|
|
|
284
|
|
|
return $this; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
public function getSummary() |
288
|
|
|
{ |
289
|
|
|
return $this->summary; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Set a short summary of what the operation does |
294
|
|
|
* |
295
|
|
|
* @param string $summary Short summary of the operation |
296
|
|
|
* |
297
|
|
|
* @return self |
298
|
|
|
*/ |
299
|
|
|
public function setSummary($summary) |
300
|
|
|
{ |
301
|
|
|
$this->summary = $summary; |
302
|
|
|
|
303
|
|
|
return $this; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
public function getNotes() |
307
|
|
|
{ |
308
|
|
|
return $this->notes; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* Set a longer text field to explain the behavior of the operation. |
313
|
|
|
* |
314
|
|
|
* @param string $notes Notes on the operation |
315
|
|
|
* |
316
|
|
|
* @return self |
317
|
|
|
*/ |
318
|
|
|
public function setNotes($notes) |
319
|
|
|
{ |
320
|
|
|
$this->notes = $notes; |
321
|
|
|
|
322
|
|
|
return $this; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
public function getDocumentationUrl() |
326
|
|
|
{ |
327
|
|
|
return $this->documentationUrl; |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Set the URL pointing to additional documentation on the command |
332
|
|
|
* |
333
|
|
|
* @param string $docUrl Documentation URL |
334
|
|
|
* |
335
|
|
|
* @return self |
336
|
|
|
*/ |
337
|
|
|
public function setDocumentationUrl($docUrl) |
338
|
|
|
{ |
339
|
|
|
$this->documentationUrl = $docUrl; |
340
|
|
|
|
341
|
|
|
return $this; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
public function getResponseClass() |
345
|
|
|
{ |
346
|
|
|
return $this->responseClass; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Set what is returned from the method. Can be a primitive, class name, or model. For example: 'array', |
351
|
|
|
* 'Guzzle\\Foo\\Baz', or 'MyModelName' (to reference a model by ID). |
352
|
|
|
* |
353
|
|
|
* @param string $responseClass Type of response |
354
|
|
|
* |
355
|
|
|
* @return self |
356
|
|
|
*/ |
357
|
|
|
public function setResponseClass($responseClass) |
358
|
|
|
{ |
359
|
|
|
$this->responseClass = $responseClass; |
360
|
|
|
$this->inferResponseType(); |
361
|
|
|
|
362
|
|
|
return $this; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
public function getResponseType() |
366
|
|
|
{ |
367
|
|
|
return $this->responseType; |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
/** |
371
|
|
|
* Set qualifying information about the responseClass. One of 'primitive', 'class', 'model', or 'documentation' |
372
|
|
|
* |
373
|
|
|
* @param string $responseType Response type information |
374
|
|
|
* |
375
|
|
|
* @return self |
376
|
|
|
* @throws InvalidArgumentException |
377
|
|
|
*/ |
378
|
|
|
public function setResponseType($responseType) |
379
|
|
|
{ |
380
|
|
|
static $types = array( |
381
|
|
|
self::TYPE_PRIMITIVE => true, |
382
|
|
|
self::TYPE_CLASS => true, |
383
|
|
|
self::TYPE_MODEL => true, |
384
|
|
|
self::TYPE_DOCUMENTATION => true |
385
|
|
|
); |
386
|
|
|
if (!isset($types[$responseType])) { |
387
|
|
|
throw new InvalidArgumentException('responseType must be one of ' . implode(', ', array_keys($types))); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
$this->responseType = $responseType; |
391
|
|
|
|
392
|
|
|
return $this; |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
public function getResponseNotes() |
396
|
|
|
{ |
397
|
|
|
return $this->responseNotes; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* Set notes about the response of the operation |
402
|
|
|
* |
403
|
|
|
* @param string $notes Response notes |
404
|
|
|
* |
405
|
|
|
* @return self |
406
|
|
|
*/ |
407
|
|
|
public function setResponseNotes($notes) |
408
|
|
|
{ |
409
|
|
|
$this->responseNotes = $notes; |
410
|
|
|
|
411
|
|
|
return $this; |
412
|
|
|
} |
413
|
|
|
|
414
|
|
|
public function getDeprecated() |
415
|
|
|
{ |
416
|
|
|
return $this->deprecated; |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
/** |
420
|
|
|
* Set whether or not the command is deprecated |
421
|
|
|
* |
422
|
|
|
* @param bool $isDeprecated Set to true to mark as deprecated |
423
|
|
|
* |
424
|
|
|
* @return self |
425
|
|
|
*/ |
426
|
|
|
public function setDeprecated($isDeprecated) |
427
|
|
|
{ |
428
|
|
|
$this->deprecated = $isDeprecated; |
429
|
|
|
|
430
|
|
|
return $this; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
public function getUri() |
434
|
|
|
{ |
435
|
|
|
return $this->uri; |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* Set the URI template of the command |
440
|
|
|
* |
441
|
|
|
* @param string $uri URI template to set |
442
|
|
|
* |
443
|
|
|
* @return self |
444
|
|
|
*/ |
445
|
|
|
public function setUri($uri) |
446
|
|
|
{ |
447
|
|
|
$this->uri = $uri; |
448
|
|
|
|
449
|
|
|
return $this; |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
public function getErrorResponses() |
453
|
|
|
{ |
454
|
|
|
return $this->errorResponses; |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
/** |
458
|
|
|
* Add an error to the command |
459
|
|
|
* |
460
|
|
|
* @param string $code HTTP response code |
461
|
|
|
* @param string $reason HTTP response reason phrase or information about the error |
462
|
|
|
* @param string $class Exception class associated with the error |
463
|
|
|
* |
464
|
|
|
* @return self |
465
|
|
|
*/ |
466
|
|
|
public function addErrorResponse($code, $reason, $class) |
467
|
|
|
{ |
468
|
|
|
$this->errorResponses[] = array('code' => $code, 'reason' => $reason, 'class' => $class); |
469
|
|
|
|
470
|
|
|
return $this; |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* Set all of the error responses of the operation |
475
|
|
|
* |
476
|
|
|
* @param array $errorResponses Hash of error name to a hash containing a code, reason, class |
477
|
|
|
* |
478
|
|
|
* @return self |
479
|
|
|
*/ |
480
|
|
|
public function setErrorResponses(array $errorResponses) |
481
|
|
|
{ |
482
|
|
|
$this->errorResponses = $errorResponses; |
483
|
|
|
|
484
|
|
|
return $this; |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
public function getData($name) |
488
|
|
|
{ |
489
|
|
|
return isset($this->data[$name]) ? $this->data[$name] : null; |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
/** |
493
|
|
|
* Set a particular data point on the operation |
494
|
|
|
* |
495
|
|
|
* @param string $name Name of the data value |
496
|
|
|
* @param mixed $value Value to set |
497
|
|
|
* |
498
|
|
|
* @return self |
499
|
|
|
*/ |
500
|
|
|
public function setData($name, $value) |
501
|
|
|
{ |
502
|
|
|
$this->data[$name] = $value; |
503
|
|
|
|
504
|
|
|
return $this; |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
/** |
508
|
|
|
* Get the additionalParameters of the operation |
509
|
|
|
* |
510
|
|
|
* @return Parameter|null |
511
|
|
|
*/ |
512
|
|
|
public function getAdditionalParameters() |
513
|
|
|
{ |
514
|
|
|
return $this->additionalParameters; |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Set the additionalParameters of the operation |
519
|
|
|
* |
520
|
|
|
* @param Parameter|null $parameter Parameter to set |
521
|
|
|
* |
522
|
|
|
* @return self |
523
|
|
|
*/ |
524
|
|
|
public function setAdditionalParameters($parameter) |
525
|
|
|
{ |
526
|
|
|
if ($this->additionalParameters = $parameter) { |
527
|
|
|
$this->additionalParameters->setParent($this); |
528
|
|
|
} |
529
|
|
|
|
530
|
|
|
return $this; |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
/** |
534
|
|
|
* Infer the response type from the responseClass value |
535
|
|
|
*/ |
536
|
|
|
protected function inferResponseType() |
537
|
|
|
{ |
538
|
|
|
static $primitives = array('array' => 1, 'boolean' => 1, 'string' => 1, 'integer' => 1, '' => 1); |
539
|
|
|
if (isset($primitives[$this->responseClass])) { |
540
|
|
|
$this->responseType = self::TYPE_PRIMITIVE; |
541
|
|
|
} elseif ($this->description && $this->description->hasModel($this->responseClass)) { |
542
|
|
|
$this->responseType = self::TYPE_MODEL; |
543
|
|
|
} else { |
544
|
|
|
$this->responseType = self::TYPE_CLASS; |
545
|
|
|
} |
546
|
|
|
} |
547
|
|
|
} |
548
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.