|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace JiraRestApi\Issue; |
|
4
|
|
|
|
|
5
|
|
|
use JiraRestApi\JiraClient; |
|
6
|
|
|
use JiraRestApi\JiraClientResponse; |
|
7
|
|
|
use JiraRestApi\JiraException; |
|
8
|
|
|
use Symfony\Component\HttpFoundation\Request; |
|
9
|
|
|
|
|
10
|
|
|
class IssueService extends JiraClient |
|
11
|
|
|
{ |
|
12
|
|
|
private $uri = '/issue'; |
|
13
|
|
|
private $searchUri = '/search'; |
|
14
|
|
|
|
|
15
|
|
|
/** |
|
16
|
|
|
* Get issue |
|
17
|
|
|
* |
|
18
|
|
|
* @param $issueIdOrKey Issue id or key |
|
19
|
|
|
* |
|
20
|
|
|
* @return mixed |
|
21
|
|
|
*/ |
|
22
|
|
View Code Duplication |
public function get($issueIdOrKey) |
|
|
|
|
|
|
23
|
|
|
{ |
|
24
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey); |
|
25
|
|
|
|
|
26
|
|
|
return $this->extractErrors($result, [200], function () use ($result) { |
|
27
|
|
|
return $this->json_mapper->map( |
|
28
|
|
|
$result->getRawData(), new Issue() |
|
29
|
|
|
); |
|
30
|
|
|
}); |
|
31
|
|
|
} |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* Search issues. |
|
35
|
|
|
* |
|
36
|
|
|
* @param $jql |
|
37
|
|
|
* @param int $startAt |
|
38
|
|
|
* @param int $maxResults |
|
39
|
|
|
* @param array $fields |
|
40
|
|
|
* |
|
41
|
|
|
* @return mixed |
|
42
|
|
|
*/ |
|
43
|
|
|
public function search($jql, $startAt = 0, $maxResults = 15, $fields = []) |
|
44
|
|
|
{ |
|
45
|
|
|
$data = [ |
|
46
|
|
|
'jql' => $jql, |
|
47
|
|
|
'startAt' => $startAt, |
|
48
|
|
|
'maxResults' => $maxResults, |
|
49
|
|
|
'fields' => $fields, |
|
50
|
|
|
]; |
|
51
|
|
|
|
|
52
|
|
|
/** @var JiraClientResponse $result */ |
|
53
|
|
|
$result = $this->exec($this->searchUri, $data, Request::METHOD_POST); |
|
54
|
|
|
|
|
55
|
|
|
return $this->extractErrors($result, [200], function () use ($result) { |
|
56
|
|
|
return $this->json_mapper->map( |
|
57
|
|
|
$result->getRawData(), new IssueSearchResult() |
|
58
|
|
|
); |
|
59
|
|
|
}); |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* Create new issue. |
|
64
|
|
|
* |
|
65
|
|
|
* @param IssueField $issueField |
|
66
|
|
|
* |
|
67
|
|
|
* @return mixed |
|
68
|
|
|
*/ |
|
69
|
|
|
public function create(IssueField $issueField) |
|
70
|
|
|
{ |
|
71
|
|
|
$issue = new Issue(); |
|
72
|
|
|
$issue->fields = $issueField; |
|
73
|
|
|
$data = $this->filterNullVariable($issue); |
|
74
|
|
|
|
|
75
|
|
|
$result = $this->exec($this->uri, $data, Request::METHOD_POST); |
|
76
|
|
|
|
|
77
|
|
|
return $this->extractErrors($result, [201], function () use ($result) { |
|
78
|
|
|
return $this->json_mapper->map( |
|
79
|
|
|
$result->getRawData(), new Issue() |
|
80
|
|
|
); |
|
81
|
|
|
}); |
|
82
|
|
|
} |
|
83
|
|
|
|
|
84
|
|
|
/** |
|
85
|
|
|
* Update issue. |
|
86
|
|
|
* |
|
87
|
|
|
* @param $issueIdOrKey Issue id or key |
|
88
|
|
|
* @param IssueField $issueField |
|
89
|
|
|
* |
|
90
|
|
|
* @return string |
|
91
|
|
|
*/ |
|
92
|
|
|
public function update($issueIdOrKey, IssueField $issueField) |
|
93
|
|
|
{ |
|
94
|
|
|
$issue = new Issue(); |
|
95
|
|
|
$issue->fields = $issueField; |
|
96
|
|
|
|
|
97
|
|
|
// ToDO: Do we need to filter null variables? |
|
98
|
|
|
$data = $this->filterNullVariable($issue); |
|
99
|
|
|
|
|
100
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey, $data, Request::METHOD_PUT); |
|
101
|
|
|
|
|
102
|
|
|
return $this->extractErrors($result, [204], function () use ($result) { |
|
103
|
|
|
return $result; |
|
104
|
|
|
}); |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
/** |
|
108
|
|
|
* Add one or more file to an issue. |
|
109
|
|
|
* |
|
110
|
|
|
* @param $issueIdOrKey Issue id or key |
|
111
|
|
|
* @param array $filePathArray attachment file path. |
|
112
|
|
|
* |
|
113
|
|
|
* @return array |
|
114
|
|
|
*/ |
|
115
|
|
|
public function addAttachments($issueIdOrKey, array $filePathArray) |
|
116
|
|
|
{ |
|
117
|
|
|
$results = $this->upload($this->uri . '/' . $issueIdOrKey .'/attachments', $filePathArray); |
|
118
|
|
|
|
|
119
|
|
|
$resArr = []; |
|
120
|
|
|
foreach ($results as $result) { |
|
121
|
|
|
$extracted = $this->extractErrors($result, [200], function () use ($result) { |
|
122
|
|
|
return $this->json_mapper->mapArray( |
|
123
|
|
|
$result->getRawData(), new \ArrayObject(), '\JiraRestApi\Issue\Attachment' |
|
124
|
|
|
); |
|
125
|
|
|
}); |
|
126
|
|
|
|
|
127
|
|
|
array_push($resArr, $extracted); |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
return $resArr; |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
/** |
|
134
|
|
|
* @param $uri |
|
135
|
|
|
* @param null $toResource |
|
136
|
|
|
* |
|
137
|
|
|
* @return mixed |
|
138
|
|
|
*/ |
|
139
|
|
|
public function getAttachmentStream($uri, $toResource = null) |
|
140
|
|
|
{ |
|
141
|
|
|
return $this->download($uri, $toResource); |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
/** |
|
145
|
|
|
* Adds a new comment to an issue. |
|
146
|
|
|
* |
|
147
|
|
|
* @param $issueIdOrKey Issue id or key |
|
148
|
|
|
* @param Comment $comment |
|
149
|
|
|
* |
|
150
|
|
|
* @return mixed |
|
151
|
|
|
*/ |
|
152
|
|
|
public function addComment($issueIdOrKey, Comment $comment) |
|
153
|
|
|
{ |
|
154
|
|
|
$data = $this->filterNullVariable($comment); |
|
155
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey . '/comment', $data, Request::METHOD_POST); |
|
156
|
|
|
|
|
157
|
|
|
return $this->extractErrors($result, [201], function () use ($result) { |
|
158
|
|
|
return $this->json_mapper->map( |
|
159
|
|
|
$result->getRawData(), new Comment() |
|
160
|
|
|
); |
|
161
|
|
|
}); |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* Update comment to an issue. |
|
166
|
|
|
* |
|
167
|
|
|
* @param $issueIdOrKey Issue id or key |
|
168
|
|
|
* @param Comment $comment |
|
169
|
|
|
* |
|
170
|
|
|
* @return mixed |
|
171
|
|
|
* @throws JiraException |
|
172
|
|
|
*/ |
|
173
|
|
|
public function updateComment($issueIdOrKey, Comment $comment) |
|
174
|
|
|
{ |
|
175
|
|
|
$data = $this->filterNullVariable($comment); |
|
176
|
|
|
|
|
177
|
|
|
if (!isset($data['id'])) { |
|
178
|
|
|
throw new JiraException('CommentId not found in Comment object.'); |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
$commentId = $data['id']; |
|
182
|
|
|
unset($data['id']); |
|
183
|
|
|
|
|
184
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey . '/comment/' . $commentId, $data, Request::METHOD_PUT); |
|
185
|
|
|
|
|
186
|
|
|
return $this->extractErrors($result, [200], function () use ($result) { |
|
187
|
|
|
return $this->json_mapper->map( |
|
188
|
|
|
$result->getRawData(), new Comment() |
|
189
|
|
|
); |
|
190
|
|
|
}); |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
/** |
|
194
|
|
|
* Get a list of the transitions possible for this |
|
195
|
|
|
* issue by the current user, along with fields that |
|
196
|
|
|
* are required and their types. |
|
197
|
|
|
* |
|
198
|
|
|
* @param $issueIdOrKey |
|
199
|
|
|
* |
|
200
|
|
|
* @return mixed|string |
|
201
|
|
|
*/ |
|
202
|
|
|
public function getTransition($issueIdOrKey) |
|
203
|
|
|
{ |
|
204
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey . '/transitions'); |
|
205
|
|
|
|
|
206
|
|
|
return $this->extractErrors($result, [200], function () use ($result) { |
|
207
|
|
|
$data = $result->getRawData(); |
|
208
|
|
|
return $this->json_mapper->mapArray( |
|
209
|
|
|
$data['transitions'], new \ArrayObject(), '\JiraRestApi\Issue\Transition' |
|
210
|
|
|
); |
|
211
|
|
|
}); |
|
212
|
|
|
} |
|
213
|
|
|
|
|
214
|
|
|
/** |
|
215
|
|
|
* Find transition id by transition's to field name(aka 'Resolved'). |
|
216
|
|
|
* |
|
217
|
|
|
* @param $issueIdOrKey |
|
218
|
|
|
* @param $transitionToName |
|
219
|
|
|
* |
|
220
|
|
|
* @return mixed |
|
221
|
|
|
* @throws JiraException |
|
222
|
|
|
*/ |
|
223
|
|
|
public function findTransitionId($issueIdOrKey, $transitionToName) |
|
224
|
|
|
{ |
|
225
|
|
|
$ret = $this->getTransition($issueIdOrKey); |
|
226
|
|
|
|
|
227
|
|
|
foreach ($ret as $trans) { |
|
228
|
|
|
$toName = $trans->to->name; |
|
229
|
|
|
|
|
230
|
|
|
if (strcmp($toName, $transitionToName) == 0) { |
|
231
|
|
|
return $trans->id; |
|
232
|
|
|
} |
|
233
|
|
|
} |
|
234
|
|
|
|
|
235
|
|
|
// transition keyword not found |
|
236
|
|
|
throw new JiraException('Transition name \'' . $transitionToName . '\' not found on JIRA Server.'); |
|
237
|
|
|
} |
|
238
|
|
|
|
|
239
|
|
|
/** |
|
240
|
|
|
* Perform a transition on an issue. |
|
241
|
|
|
* |
|
242
|
|
|
* @param $issueIdOrKey Issue id or key |
|
243
|
|
|
* @param Transition $transition |
|
244
|
|
|
* |
|
245
|
|
|
* @return mixed - if transition was successful return http 204(no contents) |
|
246
|
|
|
* @throws JiraException |
|
247
|
|
|
*/ |
|
248
|
|
|
public function doTransition($issueIdOrKey, Transition $transition) |
|
249
|
|
|
{ |
|
250
|
|
|
if (!isset($transition->transition['id'])) { |
|
251
|
|
|
$transition->transition['id'] = $this->findTransitionId($issueIdOrKey, $transition->transition['name']); |
|
252
|
|
|
} |
|
253
|
|
|
|
|
254
|
|
|
$data = $this->filterNullVariable($transition); |
|
255
|
|
|
|
|
256
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey . '/transitions', $data, Request::METHOD_POST); |
|
257
|
|
|
|
|
258
|
|
|
return $this->extractErrors($result, [204], function () use ($result) { |
|
259
|
|
|
return $result; |
|
260
|
|
|
}); |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
/** |
|
264
|
|
|
* Get TimeTracking info. |
|
265
|
|
|
* |
|
266
|
|
|
* @param $issueIdOrKey |
|
267
|
|
|
* |
|
268
|
|
|
* @return bool|TimeTracking |
|
269
|
|
|
*/ |
|
270
|
|
|
public function getTimeTracking($issueIdOrKey) |
|
271
|
|
|
{ |
|
272
|
|
|
$result = $this->get($issueIdOrKey); |
|
273
|
|
|
|
|
274
|
|
|
if ($result instanceof Issue) { |
|
275
|
|
|
return $result->fields->timeTracking; |
|
276
|
|
|
} |
|
277
|
|
|
|
|
278
|
|
|
return false; |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
/** |
|
282
|
|
|
* TimeTracking issues. |
|
283
|
|
|
* |
|
284
|
|
|
* @param $issueIdOrKey |
|
285
|
|
|
* @param $timeTracking |
|
286
|
|
|
* |
|
287
|
|
|
* @return string |
|
288
|
|
|
*/ |
|
289
|
|
|
public function setTimeTracking($issueIdOrKey, TimeTracking $timeTracking) |
|
290
|
|
|
{ |
|
291
|
|
|
$data['update']['timetracking']['edit'] = $timeTracking; |
|
|
|
|
|
|
292
|
|
|
$data = $this->filterNullVariable($data); |
|
293
|
|
|
|
|
294
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey, $data, Request::METHOD_PUT); |
|
295
|
|
|
|
|
296
|
|
|
return $this->extractErrors($result, [204], function () use ($result) { |
|
297
|
|
|
return $result; |
|
298
|
|
|
}); |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
/** |
|
302
|
|
|
* Get getWorklog. |
|
303
|
|
|
* |
|
304
|
|
|
* @param mixed $issueIdOrKey |
|
305
|
|
|
* |
|
306
|
|
|
* @return Worklog Return Worklog object |
|
307
|
|
|
*/ |
|
308
|
|
View Code Duplication |
public function getWorklog($issueIdOrKey) |
|
|
|
|
|
|
309
|
|
|
{ |
|
310
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey . '/worklog'); |
|
311
|
|
|
|
|
312
|
|
|
return $this->extractErrors($result, [200], function () use ($result) { |
|
313
|
|
|
return $this->json_mapper->map( |
|
314
|
|
|
$result->getRawData(), new Worklog() |
|
315
|
|
|
); |
|
316
|
|
|
}); |
|
317
|
|
|
} |
|
318
|
|
|
|
|
319
|
|
|
/** |
|
320
|
|
|
* @param $issueIdOrKey |
|
321
|
|
|
* @param $label |
|
322
|
|
|
* |
|
323
|
|
|
* @return mixed |
|
324
|
|
|
*/ |
|
325
|
|
View Code Duplication |
public function setLabel($issueIdOrKey, $label) |
|
|
|
|
|
|
326
|
|
|
{ |
|
327
|
|
|
$labels = is_array($label) ? $label : [$label]; |
|
328
|
|
|
|
|
329
|
|
|
$data['update']['labels'][]['set'] = $labels; |
|
|
|
|
|
|
330
|
|
|
|
|
331
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey, $data, Request::METHOD_PUT); |
|
332
|
|
|
return $this->extractErrors($result, [204], function () use ($result) { |
|
333
|
|
|
return $result; |
|
334
|
|
|
}); |
|
335
|
|
|
} |
|
336
|
|
|
|
|
337
|
|
|
/** |
|
338
|
|
|
* @param $issueIdOrKey |
|
339
|
|
|
* @param $label |
|
340
|
|
|
* |
|
341
|
|
|
* @return mixed |
|
342
|
|
|
*/ |
|
343
|
|
View Code Duplication |
public function removeLabel($issueIdOrKey, $label) |
|
|
|
|
|
|
344
|
|
|
{ |
|
345
|
|
|
$labels = is_array($label) ? $label : [$label]; |
|
346
|
|
|
|
|
347
|
|
|
$data['update']['labels'][]['remove'] = $labels; |
|
|
|
|
|
|
348
|
|
|
|
|
349
|
|
|
$result = $this->exec($this->uri . '/' . $issueIdOrKey, $data, Request::METHOD_PUT); |
|
350
|
|
|
return $this->extractErrors($result, [204], function () use ($result) { |
|
351
|
|
|
return $result; |
|
352
|
|
|
}); |
|
353
|
|
|
} |
|
354
|
|
|
} |
|
355
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.