Completed
Pull Request — master (#303)
by Andrejs
02:25
created

IssueService::getEditMeta()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
cc 1
eloc 11
c 2
b 2
f 0
nc 1
nop 3
dl 0
loc 21
rs 9.9
1
<?php
2
3
namespace JiraRestApi\Issue;
4
5
use JiraRestApi\JiraException;
6
7
class IssueService extends \JiraRestApi\JiraClient
8
{
9
    private $uri = '/issue';
10
11
    /**
12
     * @param $json
13
     *
14
     * @throws \JsonMapper_Exception
15
     *
16
     * @return Issue|object
17
     */
18
    public function getIssueFromJSON($json)
19
    {
20
        $issue = $this->json_mapper->map(
21
            $json, new Issue()
22
        );
23
24
        return $issue;
25
    }
26
27
    /**
28
     *  get all project list.
29
     *
30
     * @param string|int $issueIdOrKey
31
     * @param array      $paramArray   Query Parameter key-value Array.
32
     * @param Issue      $issueObject
33
     *
34
     * @throws JiraException
35
     * @throws \JsonMapper_Exception
36
     *
37
     * @return Issue|object class
38
     */
39
    public function get($issueIdOrKey, $paramArray = [], $issueObject = null)
40
    {
41
        // for REST API V3
42
        if ($this->isRestApiV3()) {
43
            $issueObject = ($issueObject) ? $issueObject : new IssueV3();
44
        } else {
45
            $issueObject = ($issueObject) ? $issueObject : new Issue();
46
        }
47
48
        $ret = $this->exec($this->uri.'/'.$issueIdOrKey.$this->toHttpQueryParameter($paramArray), null);
49
50
        $this->log->info("Result=\n".$ret);
51
52
        return $issue = $this->json_mapper->map(
0 ignored issues
show
Unused Code introduced by
The assignment to $issue is dead and can be removed.
Loading history...
53
            json_decode($ret), $issueObject
54
        );
55
    }
56
57
    /**
58
     * create new issue.
59
     *
60
     * @param IssueField $issueField
61
     *
62
     * @throws JiraException
63
     * @throws \JsonMapper_Exception
64
     *
65
     * @return Issue|object created issue key
66
     */
67
    public function create($issueField)
68
    {
69
        $issue = new Issue();
70
71
        // serilize only not null field.
72
        $issue->fields = $issueField;
73
74
        $data = json_encode($issue);
75
76
        $this->log->info("Create Issue=\n".$data);
77
78
        $ret = $this->exec($this->uri, $data, 'POST');
79
80
        return $this->getIssueFromJSON(json_decode($ret));
81
    }
82
83
    /**
84
     * Create multiple issues using bulk insert.
85
     *
86
     * @param IssueField[] $issueFields Array of IssueField objects
87
     * @param int          $batchSize   Maximum number of issues to send in each request
88
     *
89
     * @throws JiraException
90
     * @throws \JsonMapper_Exception
91
     *
92
     * @return array Array of results, where each result represents one batch of insertions
93
     */
94
    public function createMultiple($issueFields, $batchSize = 50)
95
    {
96
        $issues = [];
97
98
        foreach ($issueFields as $issueField) {
99
            $issue = new Issue();
100
            $issue->fields = $issueField;
101
            $issues[] = $issue;
102
        }
103
104
        $batches = array_chunk($issues, $batchSize);
105
106
        $results = [];
107
        foreach ($batches as $batch) {
108
            $results = array_merge($results, $this->bulkInsert($batch));
109
        }
110
111
        return $results;
112
    }
113
114
    /**
115
     * Makes API call to bulk insert issues.
116
     *
117
     * @param Issue[] $issues Array of issue arrays that are sent to Jira one by one in single create
118
     *
119
     * @throws JiraException
120
     * @throws \JsonMapper_Exception
121
     *
122
     * @return Issue[] Result of API call to insert many issues
123
     */
124
    private function bulkInsert($issues)
125
    {
126
        $data = json_encode(['issueUpdates' => $issues]);
127
128
        $this->log->info("Create Issues=\n".$data);
129
        $results = $this->exec($this->uri.'/bulk', $data, 'POST');
130
131
        $issues = [];
132
        foreach (json_decode($results)->issues as $result) {
133
            $issues[] = $this->getIssueFromJSON($result);
134
        }
135
136
        return $issues;
137
    }
138
139
    /**
140
     * Add one or more file to an issue.
141
     *
142
     * @param string|int   $issueIdOrKey  Issue id or key
143
     * @param array|string $filePathArray attachment file path.
144
     *
145
     * @throws JiraException
146
     * @throws \JsonMapper_Exception
147
     *
148
     * @return Attachment[]
149
     */
150
    public function addAttachments($issueIdOrKey, $filePathArray)
151
    {
152
        if (is_array($filePathArray) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
153
            $filePathArray = [$filePathArray];
154
        }
155
156
        $results = $this->upload($this->uri."/$issueIdOrKey/attachments", $filePathArray);
0 ignored issues
show
Bug introduced by
It seems like $filePathArray can also be of type string; however, parameter $filePathArray of JiraRestApi\JiraClient::upload() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

156
        $results = $this->upload($this->uri."/$issueIdOrKey/attachments", /** @scrutinizer ignore-type */ $filePathArray);
Loading history...
157
158
        $this->log->info('addAttachments result='.var_export($results, true));
159
160
        $attachArr = [];
161
        foreach ($results as $ret) {
162
            $ret = json_decode($ret);
163
            if (is_array($ret)) {
164
                $tmpArr = $this->json_mapper->mapArray(
165
                    $ret, new \ArrayObject(), '\JiraRestApi\Issue\Attachment'
166
                );
167
168
                foreach ($tmpArr as $t) {
169
                    array_push($attachArr, $t);
170
                }
171
            } elseif (is_object($ret)) {
172
                array_push($attachArr, $this->json_mapper->map(
173
                    $ret, new Attachment()
174
                    )
175
                );
176
            }
177
        }
178
179
        return $attachArr;
180
    }
181
182
    /**
183
     * update issue.
184
     *
185
     * @param string|int $issueIdOrKey Issue Key
186
     * @param IssueField $issueField   object of Issue class
187
     * @param array      $paramArray   Query Parameter key-value Array.
188
     *
189
     * @throws JiraException
190
     *
191
     * @return string created issue key
192
     */
193
    public function update($issueIdOrKey, $issueField, $paramArray = [])
194
    {
195
        $issue = new Issue();
196
197
        // serilize only not null field.
198
        $issue->fields = $issueField;
199
200
        //$issue = $this->filterNullVariable((array)$issue);
201
202
        $data = json_encode($issue);
203
204
        $this->log->info("Update Issue=\n".$data);
205
206
        $queryParam = '?'.http_build_query($paramArray);
207
208
        $ret = $this->exec($this->uri."/$issueIdOrKey".$queryParam, $data, 'PUT');
209
210
        return $ret;
211
    }
212
213
    /**
214
     * Adds a new comment to an issue.
215
     *
216
     * @param string|int $issueIdOrKey Issue id or key
217
     * @param Comment    $comment
218
     *
219
     * @throws JiraException
220
     * @throws \JsonMapper_Exception
221
     *
222
     * @return Comment|object Comment class
223
     */
224
    public function addComment($issueIdOrKey, $comment)
225
    {
226
        $this->log->info("addComment=\n");
227
228
        if (!($comment instanceof Comment) || empty($comment->body)) {
0 ignored issues
show
introduced by
$comment is always a sub-type of JiraRestApi\Issue\Comment.
Loading history...
229
            throw new JiraException('comment param must instance of Comment and have to body text.!');
230
        }
231
232
        $data = json_encode($comment);
233
234
        $ret = $this->exec($this->uri."/$issueIdOrKey/comment", $data);
235
236
        $this->log->debug('add comment result='.var_export($ret, true));
237
        $comment = $this->json_mapper->map(
238
           json_decode($ret), new Comment()
239
        );
240
241
        return $comment;
242
    }
243
244
    /**
245
     * Update a comment in issue.
246
     *
247
     * @param string|int $issueIdOrKey Issue id or key
248
     * @param string|int $id           Comment id
249
     * @param Comment    $comment
250
     *
251
     * @throws JiraException
252
     * @throws \JsonMapper_Exception
253
     *
254
     * @return Comment|object Comment class
255
     */
256
    public function updateComment($issueIdOrKey, $id, $comment)
257
    {
258
        $this->log->info("updateComment=\n");
259
260
        if (!($comment instanceof Comment) || empty($comment->body)) {
0 ignored issues
show
introduced by
$comment is always a sub-type of JiraRestApi\Issue\Comment.
Loading history...
261
            throw new JiraException('comment param must instance of Comment and have to body text.!');
262
        }
263
264
        $data = json_encode($comment);
265
266
        $ret = $this->exec($this->uri."/$issueIdOrKey/comment/$id", $data, 'PUT');
267
268
        $this->log->debug('update comment result='.var_export($ret, true));
269
        $comment = $this->json_mapper->map(
270
            json_decode($ret), new Comment()
271
        );
272
273
        return $comment;
274
    }
275
276
    /**
277
     * Get a comment on an issue.
278
     *
279
     * @param string|int $issueIdOrKey Issue id or key
280
     * @param string|int $id           Comment id
281
     *
282
     * @throws JiraException
283
     * @throws \JsonMapper_Exception
284
     *
285
     * @return Comment|object Comment class
286
     */
287
    public function getComment($issueIdOrKey, $id)
288
    {
289
        $this->log->info("getComment=\n");
290
291
        $ret = $this->exec($this->uri."/$issueIdOrKey/comment/$id");
292
293
        $this->log->debug('get comment result='.var_export($ret, true));
294
        $comment = $this->json_mapper->map(
295
                json_decode($ret), new Comment()
296
                );
297
298
        return $comment;
299
    }
300
301
    /**
302
     * Get all comments on an issue.
303
     *
304
     * @param string|int $issueIdOrKey Issue id or key
305
     *
306
     * @throws JiraException
307
     * @throws \JsonMapper_Exception
308
     *
309
     * @return Comment|object Comment class
310
     */
311
    public function getComments($issueIdOrKey)
312
    {
313
        $this->log->info("getComments=\n");
314
315
        $ret = $this->exec($this->uri."/$issueIdOrKey/comment");
316
317
        $this->log->debug('get comments result='.var_export($ret, true));
318
        $comment = $this->json_mapper->map(
319
                json_decode($ret), new Comment()
320
                );
321
322
        return $comment;
323
    }
324
325
    /**
326
     * Delete a comment on an issue.
327
     *
328
     * @param string|int $issueIdOrKey Issue id or key
329
     * @param string|int $id           Comment id
330
     *
331
     * @throws JiraException
332
     *
333
     * @return string|bool
334
     */
335
    public function deleteComment($issueIdOrKey, $id)
336
    {
337
        $this->log->info("deleteComment=\n");
338
339
        $ret = $this->exec($this->uri."/$issueIdOrKey/comment/$id", '', 'DELETE');
340
341
        $this->log->info('delete comment '.$issueIdOrKey.' '.$id.' result='.var_export($ret, true));
342
343
        return $ret;
344
    }
345
346
    /**
347
     * Change a issue assignee.
348
     *
349
     * @param string|int  $issueIdOrKey
350
     * @param string|null $assigneeName Assigns an issue to a user.
351
     *                                  If the assigneeName is "-1" automatic assignee is used.
352
     *                                  A null name will remove the assignee.
353
     *
354
     * @throws JiraException
355
     *
356
     * @return string|bool
357
     */
358
    public function changeAssignee($issueIdOrKey, $assigneeName)
359
    {
360
        $this->log->info("changeAssignee=\n");
361
362
        $ar = ['name' => $assigneeName];
363
364
        $data = json_encode($ar);
365
366
        $ret = $this->exec($this->uri."/$issueIdOrKey/assignee", $data, 'PUT');
367
368
        $this->log->info('change assignee of '.$issueIdOrKey.' to '.$assigneeName.' result='.var_export($ret, true));
369
370
        return $ret;
371
    }
372
373
    /**
374
     * Change a issue assignee for REST API V3.
375
     *
376
     * @param string|int  $issueIdOrKey
377
     * @param string|null $accountId    Assigns an issue to a user.
378
     *
379
     * @throws JiraException
380
     *
381
     * @return string
382
     */
383
    public function changeAssigneeByAccountId($issueIdOrKey, $accountId)
384
    {
385
        $this->log->info("changeAssigneeByAccountId=\n");
386
387
        $ar = ['accountId' => $accountId];
388
389
        $data = json_encode($ar);
390
391
        $ret = $this->exec($this->uri."/$issueIdOrKey/assignee", $data, 'PUT');
392
393
        $this->log->info('change assignee of '.$issueIdOrKey.' to '.$accountId.' result='.var_export($ret, true));
394
395
        return $ret;
396
    }
397
398
    /**
399
     * Delete a issue.
400
     *
401
     * @param string|int $issueIdOrKey Issue id or key
402
     * @param array      $paramArray   Query Parameter key-value Array.
403
     *
404
     * @throws JiraException
405
     *
406
     * @return string|bool
407
     */
408
    public function deleteIssue($issueIdOrKey, $paramArray = [])
409
    {
410
        $this->log->info("deleteIssue=\n");
411
412
        $queryParam = '?'.http_build_query($paramArray);
413
414
        $ret = $this->exec($this->uri."/$issueIdOrKey".$queryParam, '', 'DELETE');
415
416
        $this->log->info('delete issue '.$issueIdOrKey.' result='.var_export($ret, true));
417
418
        return $ret;
419
    }
420
421
    /**
422
     * Get a list of the transitions possible for this issue by the current user, along with fields that are required and their types.
423
     *
424
     * @param string|int $issueIdOrKey Issue id or key
425
     * @param array      $paramArray   Query Parameter key-value Array.
426
     *
427
     * @throws JiraException
428
     *
429
     * @return Transition[] array of Transition class
430
     */
431
    public function getTransition($issueIdOrKey, $paramArray = [])
432
    {
433
        $queryParam = '?'.http_build_query($paramArray);
434
435
        $ret = $this->exec($this->uri."/$issueIdOrKey/transitions".$queryParam);
436
437
        $this->log->debug('getTransitions result='.var_export($ret, true));
438
439
        $data = json_encode(json_decode($ret)->transitions);
440
441
        $transitions = $this->json_mapper->mapArray(
442
           json_decode($data), new \ArrayObject(), '\JiraRestApi\Issue\Transition'
443
        );
444
445
        return $transitions;
446
    }
447
448
    /**
449
     * find transition id by transition's to field name(aka 'Resolved').
450
     *
451
     * @param string|int $issueIdOrKey
452
     * @param string     $transitionToName
453
     *
454
     * @throws JiraException
455
     *
456
     * @return string
457
     */
458
    public function findTransitonId($issueIdOrKey, $transitionToName)
459
    {
460
        $this->log->debug('findTransitonId=');
461
462
        $ret = $this->getTransition($issueIdOrKey);
463
464
        foreach ($ret as $trans) {
465
            $toName = $trans->to->name;
466
467
            $this->log->debug('getTransitions result='.var_export($ret, true));
468
469
            if (strcmp($toName, $transitionToName) == 0) {
470
                return $trans->id;
471
            }
472
        }
473
474
        // transition keyword not found
475
        throw new JiraException("Transition name '$transitionToName' not found on JIRA Server.");
476
    }
477
478
    /**
479
     * Perform a transition on an issue.
480
     *
481
     * @param string|int $issueIdOrKey Issue id or key
482
     * @param Transition $transition
483
     *
484
     * @throws JiraException
485
     *
486
     * @return string|null nothing - if transition was successful return http 204(no contents)
487
     */
488
    public function transition($issueIdOrKey, $transition)
489
    {
490
        $this->log->debug('transition='.var_export($transition, true));
491
492
        if (!isset($transition->transition['id'])) {
493
            $transition->transition['id'] = $this->findTransitonId($issueIdOrKey, $transition->transition['name']);
494
        }
495
496
        $data = json_encode($transition);
497
498
        $this->log->debug("transition req=$data\n");
499
500
        $ret = $this->exec($this->uri."/$issueIdOrKey/transitions", $data, 'POST');
501
502
        $this->log->debug('getTransitions result='.var_export($ret, true));
503
504
        return $ret;
505
    }
506
507
    /**
508
     * Search issues.
509
     *
510
     * @param string $jql
511
     * @param int    $startAt
512
     * @param int    $maxResults
513
     * @param array  $fields
514
     * @param array  $expand
515
     * @param bool   $validateQuery
516
     *
517
     * @throws JiraException
518
     * @throws \JsonMapper_Exception
519
     *
520
     * @return IssueSearchResult|object
521
     */
522
    public function search($jql, $startAt = 0, $maxResults = 15, $fields = [], $expand = [], $validateQuery = true)
523
    {
524
        $data = json_encode([
525
            'jql'           => $jql,
526
            'startAt'       => $startAt,
527
            'maxResults'    => $maxResults,
528
            'fields'        => $fields,
529
            'expand'        => $expand,
530
            'validateQuery' => $validateQuery,
531
        ]);
532
533
        $ret = $this->exec('search', $data, 'POST');
534
        $json = json_decode($ret);
535
536
        $result = null;
537
        if ($this->isRestApiV3()) {
538
            $result = $this->json_mapper->map(
539
                $json, new IssueSearchResultV3()
540
            );
541
        } else {
542
            $result = $this->json_mapper->map(
543
                $json, new IssueSearchResult()
544
            );
545
        }
546
547
        return $result;
548
    }
549
550
    /**
551
     * get TimeTracking info.
552
     *
553
     * @param string|int $issueIdOrKey
554
     *
555
     * @throws JiraException
556
     * @throws \JsonMapper_Exception
557
     *
558
     * @return TimeTracking
559
     */
560
    public function getTimeTracking($issueIdOrKey)
561
    {
562
        $ret = $this->exec($this->uri."/$issueIdOrKey", null);
563
        $this->log->debug("getTimeTracking res=$ret\n");
564
565
        $issue = $this->json_mapper->map(
566
             json_decode($ret), new Issue()
567
        );
568
569
        return $issue->fields->timeTracking;
570
    }
571
572
    /**
573
     * TimeTracking issues.
574
     *
575
     * @param string|int   $issueIdOrKey Issue id or key
576
     * @param TimeTracking $timeTracking
577
     *
578
     * @throws JiraException
579
     *
580
     * @return string
581
     */
582
    public function timeTracking($issueIdOrKey, $timeTracking)
583
    {
584
        $array = [
585
            'update' => [
586
                'timetracking' => [
587
                    ['edit' => $timeTracking],
588
                ],
589
            ],
590
        ];
591
592
        $data = json_encode($array);
593
594
        $this->log->debug("TimeTracking req=$data\n");
595
596
        // if success, just return HTTP 201.
597
        $ret = $this->exec($this->uri."/$issueIdOrKey", $data, 'PUT');
598
599
        return $ret;
600
    }
601
602
    /**
603
     * get getWorklog.
604
     *
605
     * @param string|int $issueIdOrKey
606
     *
607
     * @throws JiraException
608
     * @throws \JsonMapper_Exception
609
     *
610
     * @return PaginatedWorklog|object
611
     */
612
    public function getWorklog($issueIdOrKey)
613
    {
614
        $ret = $this->exec($this->uri."/$issueIdOrKey/worklog");
615
        $this->log->debug("getWorklog res=$ret\n");
616
        $worklog = $this->json_mapper->map(
617
            json_decode($ret), new PaginatedWorklog()
618
        );
619
620
        return $worklog;
621
    }
622
623
    /**
624
     * get getWorklog by Id.
625
     *
626
     * @param string|int $issueIdOrKey
627
     * @param int        $workLogId
628
     *
629
     * @throws JiraException
630
     * @throws \JsonMapper_Exception
631
     *
632
     * @return Worklog|object PaginatedWorklog object
633
     */
634
    public function getWorklogById($issueIdOrKey, $workLogId)
635
    {
636
        $ret = $this->exec($this->uri."/$issueIdOrKey/worklog/$workLogId");
637
        $this->log->debug("getWorklogById res=$ret\n");
638
        $worklog = $this->json_mapper->map(
639
            json_decode($ret), new Worklog()
640
        );
641
642
        return $worklog;
643
    }
644
645
    /**
646
     * add work log to issue.
647
     *
648
     * @param string|int     $issueIdOrKey
649
     * @param Worklog|object $worklog
650
     *
651
     * @throws JiraException
652
     * @throws \JsonMapper_Exception
653
     *
654
     * @return Worklog|object Worklog Object
655
     */
656
    public function addWorklog($issueIdOrKey, $worklog)
657
    {
658
        $this->log->info("addWorklog=\n");
659
660
        $data = json_encode($worklog);
661
        $url = $this->uri."/$issueIdOrKey/worklog";
662
        $type = 'POST';
663
664
        $ret = $this->exec($url, $data, $type);
665
666
        $ret_worklog = $this->json_mapper->map(
667
           json_decode($ret), new Worklog()
668
        );
669
670
        return $ret_worklog;
671
    }
672
673
    /**
674
     * edit the worklog.
675
     *
676
     * @param string|int     $issueIdOrKey
677
     * @param Worklog|object $worklog
678
     * @param string|int     $worklogId
679
     *
680
     * @throws JiraException
681
     * @throws \JsonMapper_Exception
682
     *
683
     * @return Worklog|object
684
     */
685
    public function editWorklog($issueIdOrKey, $worklog, $worklogId)
686
    {
687
        $this->log->info("editWorklog=\n");
688
689
        $data = json_encode($worklog);
690
        $url = $this->uri."/$issueIdOrKey/worklog/$worklogId";
691
        $type = 'PUT';
692
693
        $ret = $this->exec($url, $data, $type);
694
695
        $ret_worklog = $this->json_mapper->map(
696
            json_decode($ret), new Worklog()
697
        );
698
699
        return $ret_worklog;
700
    }
701
702
    /**
703
     * delete worklog.
704
     *
705
     * @param string|int $issueIdOrKey
706
     * @param string|int $worklogId
707
     *
708
     * @throws JiraException
709
     *
710
     * @return bool
711
     */
712
    public function deleteWorklog($issueIdOrKey, $worklogId)
713
    {
714
        $this->log->info("deleteWorklog=\n");
715
716
        $url = $this->uri."/$issueIdOrKey/worklog/$worklogId";
717
        $type = 'DELETE';
718
719
        $ret = $this->exec($url, null, $type);
720
721
        return (bool)$ret;
722
    }
723
724
    /**
725
     * Get all priorities.
726
     *
727
     * @throws JiraException
728
     *
729
     * @return Priority[] array of priority class
730
     */
731
    public function getAllPriorities()
732
    {
733
        $ret = $this->exec('priority', null);
734
735
        $priorities = $this->json_mapper->mapArray(
736
             json_decode($ret, false), new \ArrayObject(), '\JiraRestApi\Issue\Priority'
737
        );
738
739
        return $priorities;
740
    }
741
742
    /**
743
     * Get priority by id.
744
     * throws  HTTPException if the priority is not found, or the calling user does not have permission or view it.
745
     *
746
     * @param string|int $priorityId Id of priority.
747
     *
748
     * @throws JiraException
749
     * @throws \JsonMapper_Exception
750
     *
751
     * @return Priority|object priority
752
     */
753
    public function getPriority($priorityId)
754
    {
755
        $ret = $this->exec("priority/$priorityId", null);
756
757
        $this->log->info('Result='.$ret);
758
759
        $prio = $this->json_mapper->map(
760
             json_decode($ret), new Priority()
761
        );
762
763
        return $prio;
764
    }
765
766
    /**
767
     * Get priority by id.
768
     * throws HTTPException if the priority is not found, or the calling user does not have permission or view it.
769
     *
770
     * @param string|int $priorityId Id of priority.
771
     *
772
     * @throws JiraException
773
     * @throws \JsonMapper_Exception
774
     *
775
     * @return Priority|object priority
776
     */
777
    public function getCustomFields($priorityId)
778
    {
779
        $ret = $this->exec("priority/$priorityId", null);
780
781
        $this->log->info('Result='.$ret);
782
783
        $prio = $this->json_mapper->map(
784
            json_decode($ret), new Priority()
785
        );
786
787
        return $prio;
788
    }
789
790
    /**
791
     * get watchers.
792
     *
793
     * @param $issueIdOrKey
794
     *
795
     * @throws JiraException
796
     *
797
     * @return Reporter[]
798
     */
799
    public function getWatchers($issueIdOrKey)
800
    {
801
        $this->log->info("getWatchers=\n");
802
803
        $url = $this->uri."/$issueIdOrKey/watchers";
804
805
        $ret = $this->exec($url, null);
806
807
        $watchers = $this->json_mapper->mapArray(
808
            json_decode($ret, false)->watchers, new \ArrayObject(), '\JiraRestApi\Issue\Reporter'
809
        );
810
811
        return $watchers;
812
    }
813
814
    /**
815
     * add watcher to issue.
816
     *
817
     * @param string|int $issueIdOrKey
818
     * @param string     $watcher      watcher id
819
     *
820
     * @throws JiraException
821
     *
822
     * @return bool
823
     */
824
    public function addWatcher($issueIdOrKey, $watcher)
825
    {
826
        $this->log->info("addWatcher=\n");
827
828
        $data = json_encode($watcher);
829
        $url = $this->uri."/$issueIdOrKey/watchers";
830
        $type = 'POST';
831
832
        $this->exec($url, $data, $type);
833
834
        return $this->http_response == 204 ? true : false;
835
    }
836
837
    /**
838
     * remove watcher from issue.
839
     *
840
     * @param string|int $issueIdOrKey
841
     * @param string     $watcher      watcher id
842
     *
843
     * @throws JiraException
844
     *
845
     * @return bool
846
     */
847
    public function removeWatcher($issueIdOrKey, $watcher)
848
    {
849
        $this->log->addInfo("removeWatcher=\n");
850
851
        $ret = $this->exec($this->uri."/$issueIdOrKey/watchers/?username=$watcher", '', 'DELETE');
852
853
        $this->log->addInfo('remove watcher '.$issueIdOrKey.' result='.var_export($ret, true));
854
855
        return $this->http_response == 204 ? true : false;
856
    }
857
858
    /**
859
     * remove watcher from issue by watcher account id.
860
     *
861
     * @param string|int $issueIdOrKey
862
     * @param string     $accountId    Watcher account id.
863
     *
864
     * @throws JiraException
865
     *
866
     * @return bool
867
     */
868
    public function removeWatcherByAccountId($issueIdOrKey, $accountId)
869
    {
870
        $this->log->info("removeWatcher=\n");
871
872
        $ret = $this->exec($this->uri."/$issueIdOrKey/watchers/?accountId=$accountId", '', 'DELETE');
873
874
        $this->log->info('remove watcher '.$issueIdOrKey.' result='.var_export($ret, true));
875
876
        return $this->http_response == 204 ? true : false;
877
    }
878
879
    /**
880
     * Get the meta data for creating issues.
881
     *
882
     * @param array $paramArray Possible keys for $paramArray: 'projectIds', 'projectKeys', 'issuetypeIds', 'issuetypeNames'.
883
     * @param bool  $expand     Retrieve all issue fields and values
884
     *
885
     * @throws JiraException
886
     *
887
     * @return object array of meta data for creating issues.
888
     */
889
    public function getCreateMeta($paramArray = [], $expand = true)
890
    {
891
        $paramArray['expand'] = ($expand) ? 'projects.issuetypes.fields' : null;
892
        $paramArray = array_filter($paramArray);
893
894
        $queryParam = '?'.http_build_query($paramArray);
895
896
        $ret = $this->exec($this->uri.'/createmeta'.$queryParam, null);
897
898
        return json_decode($ret);
899
    }
900
901
    /**
902
     * returns the metadata(include custom field) for an issue.
903
     *
904
     * @param string $idOrKey                issue id or key
905
     * @param bool   $overrideEditableFlag   Allows retrieving edit metadata for fields in non-editable status
906
     * @param bool   $overrideScreenSecurity Allows retrieving edit metadata for the fields hidden on Edit screen.
907
     *
908
     * @throws JiraException
909
     *
910
     * @return array of custom fields
911
     *
912
     * @see https://confluence.atlassian.com/jirakb/how-to-retrieve-available-options-for-a-multi-select-customfield-via-jira-rest-api-815566715.html How to retrieve available options for a multi-select customfield via JIRA REST API
913
     * @see https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-issue-issueIdOrKey-editmeta-get
914
     */
915
    public function getEditMeta($idOrKey, $overrideEditableFlag = false, $overrideScreenSecurity = false)
916
    {
917
        $queryParam = '?'.http_build_query([
918
            'overrideEditableFlag'   => $overrideEditableFlag,
919
            'overrideScreenSecurity' => $overrideScreenSecurity,
920
        ]);
921
922
        $uri = sprintf('%s/%s/editmeta', $this->uri, $idOrKey).$queryParam;
923
924
        $ret = $this->exec($uri, null);
925
926
        $metas = json_decode($ret, true);
927
928
        // extract only custom field(startWith customefield_XXXXX)
929
        $cfs = array_filter($metas['fields'], function ($key) {
930
            $pos = strpos($key, 'customfield');
931
932
            return $pos !== false;
933
        }, ARRAY_FILTER_USE_KEY);
934
935
        return $cfs;
936
    }
937
938
    /**
939
     * Sends a notification (email) to the list or recipients defined in the request.
940
     *
941
     * @param string|int $issueIdOrKey Issue id Or Key
942
     * @param Notify     $notify
943
     *
944
     * @throws JiraException
945
     *
946
     * @see https://docs.atlassian.com/software/jira/docs/api/REST/latest/#api/2/issue-notify
947
     */
948
    public function notify($issueIdOrKey, $notify)
949
    {
950
        $full_uri = $this->uri."/$issueIdOrKey/notify";
951
952
        // set self value
953
        foreach ($notify->to['groups'] as &$g) {
954
            $g['self'] = $this->getConfiguration()->getJiraHost().'/rest/api/2/group?groupname='.$g['name'];
955
        }
956
        foreach ($notify->restrict['groups'] as &$g) {
957
            $g['self'] = $this->getConfiguration()->getJiraHost().'/rest/api/2/group?groupname='.$g['name'];
958
        }
959
960
        $data = json_encode($notify, JSON_UNESCAPED_SLASHES);
961
962
        $this->log->debug("notify=$data\n");
963
964
        $ret = $this->exec($full_uri, $data, 'POST');
965
966
        if ($ret !== true) {
0 ignored issues
show
introduced by
The condition $ret !== true is always true.
Loading history...
967
            throw new JiraException('notify failed: response code='.$ret);
968
        }
969
    }
970
971
    /**
972
     * Get a remote issue links on the issue.
973
     *
974
     * @param string|int $issueIdOrKey Issue id Or Key
975
     *
976
     * @throws JiraException
977
     *
978
     * @return array array os RemoteIssueLink class
979
     *
980
     * @see https://developer.atlassian.com/server/jira/platform/jira-rest-api-for-remote-issue-links/
981
     * @see https://docs.atlassian.com/software/jira/docs/api/REST/latest/#api/2/issue-getRemoteIssueLinks
982
     */
983
    public function getRemoteIssueLink($issueIdOrKey)
984
    {
985
        $full_uri = $this->uri."/$issueIdOrKey/remotelink";
986
987
        $ret = $this->exec($full_uri, null);
988
989
        $rils = $this->json_mapper->mapArray(
990
            json_decode($ret, false), new \ArrayObject(), RemoteIssueLink::class
991
        );
992
993
        return $rils;
994
    }
995
996
    /**
997
     * @param string|int      $issueIdOrKey
998
     * @param RemoteIssueLink $ril
999
     *
1000
     * @throws JiraException
1001
     * @throws \JsonMapper_Exception
1002
     *
1003
     * @return object
1004
     */
1005
    public function createOrUpdateRemoteIssueLink($issueIdOrKey, RemoteIssueLink $ril)
1006
    {
1007
        $full_uri = $this->uri."/$issueIdOrKey/remotelink";
1008
1009
        $data = json_encode($ril, JSON_UNESCAPED_SLASHES);
1010
1011
        $this->log->debug("create remoteIssueLink=$data\n");
1012
1013
        $ret = $this->exec($full_uri, $data, 'POST');
1014
1015
        $res = $this->json_mapper->map(
1016
            json_decode($ret), new RemoteIssueLink()
1017
        );
1018
1019
        return $res;
1020
    }
1021
1022
    /**
1023
     * @param string|int $issueIdOrKey
1024
     * @param string|int $globalId
1025
     *
1026
     * @throws JiraException
1027
     *
1028
     * @return string|bool
1029
     */
1030
    public function removeRemoteIssueLink($issueIdOrKey, $globalId)
1031
    {
1032
        $query = http_build_query(['globalId' => $globalId]);
1033
1034
        $full_uri = sprintf('%s/%s/remotelink?%s', $this->uri, $issueIdOrKey, $query);
1035
1036
        $ret = $this->exec($full_uri, '', 'DELETE');
1037
1038
        $this->log->info(
1039
            sprintf(
1040
                'delete remote issue link for issue "%s" with globalId "%s". Result=%s',
1041
                $issueIdOrKey,
1042
                $globalId,
1043
                var_export($ret, true)
1044
            )
1045
        );
1046
1047
        return $ret;
1048
    }
1049
1050
    /**
1051
     * get all issue security schemes.
1052
     *
1053
     * @throws JiraException
1054
     * @throws \JsonMapper_Exception
1055
     *
1056
     * @return SecurityScheme[] array of SecurityScheme class
1057
     */
1058
    public function getAllIssueSecuritySchemes()
1059
    {
1060
        $url = '/issuesecurityschemes';
1061
1062
        $ret = $this->exec($url);
1063
1064
        $data = json_decode($ret, true);
1065
1066
        // extract schem field
1067
        $schemes = json_decode(json_encode($data['issueSecuritySchemes']), false);
1068
1069
        $res = $this->json_mapper->mapArray(
1070
            $schemes, new \ArrayObject(), '\JiraRestApi\Issue\SecurityScheme'
1071
        );
1072
1073
        return $res;
1074
    }
1075
1076
    /**
1077
     *  get issue security scheme.
1078
     *
1079
     * @param int $securityId security scheme id
1080
     *
1081
     * @throws JiraException
1082
     * @throws \JsonMapper_Exception
1083
     *
1084
     * @return SecurityScheme SecurityScheme
1085
     */
1086
    public function getIssueSecuritySchemes($securityId)
1087
    {
1088
        $url = '/issuesecurityschemes/'.$securityId;
1089
1090
        $ret = $this->exec($url);
1091
1092
        $res = $this->json_mapper->map(
1093
            json_decode($ret), new SecurityScheme()
1094
        );
1095
1096
        return $res;
1097
    }
1098
1099
    /**
1100
     * convenient wrapper function for add or remove labels.
1101
     *
1102
     * @param string|int $issueIdOrKey
1103
     * @param array|null $addLablesParam
1104
     * @param array|null $removeLabelsParam
1105
     * @param bool       $notifyUsers
1106
     *
1107
     * @throws JiraException
1108
     *
1109
     * @return Issue|object class
1110
     */
1111
    public function updateLabels($issueIdOrKey, $addLablesParam, $removeLabelsParam, $notifyUsers = true)
1112
    {
1113
        $labels = [];
1114
        foreach ($addLablesParam as $a) {
1115
            array_push($labels, ['add' => $a]);
1116
        }
1117
1118
        foreach ($removeLabelsParam as $r) {
1119
            array_push($labels, ['remove' => $r]);
1120
        }
1121
1122
        $postData = json_encode([
1123
            'update' => [
1124
                'labels' => $labels,
1125
            ],
1126
        ], JSON_UNESCAPED_UNICODE);
1127
1128
        $this->log->info("Update labels=\n".$postData);
1129
1130
        $queryParam = '?'.http_build_query(['notifyUsers' => $notifyUsers]);
1131
1132
        $ret = $this->exec($this->uri."/$issueIdOrKey".$queryParam, $postData, 'PUT');
1133
1134
        return $ret;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $ret returns the type string which is incompatible with the documented return type JiraRestApi\Issue\Issue|object.
Loading history...
1135
    }
1136
1137
    /**
1138
     * convenient wrapper function for add or remove fix versions.
1139
     *
1140
     * @param string|int $issueIdOrKey
1141
     * @param array|null $addFixVersionsParam
1142
     * @param array|null $removeFixVersionsParam
1143
     * @param bool       $notifyUsers
1144
     *
1145
     * @throws JiraException
1146
     *
1147
     * @return Issue|object class
1148
     */
1149
    public function updateFixVersions($issueIdOrKey, $addFixVersionsParam, $removeFixVersionsParam, $notifyUsers = true)
1150
    {
1151
        $fixVersions = [];
1152
        foreach ($addFixVersionsParam as $a) {
1153
            array_push($fixVersions, ['add' => ['name' => $a]]);
1154
        }
1155
1156
        foreach ($removeFixVersionsParam as $r) {
1157
            array_push($fixVersions, ['remove' => ['name' => $r]]);
1158
        }
1159
1160
        $postData = json_encode([
1161
            'update' => [
1162
                'fixVersions' => $fixVersions,
1163
            ],
1164
        ], JSON_UNESCAPED_UNICODE);
1165
1166
        $this->log->info("Update fixVersions=\n".$postData);
1167
1168
        $queryParam = '?'.http_build_query(['notifyUsers' => $notifyUsers]);
1169
1170
        $ret = $this->exec($this->uri."/$issueIdOrKey".$queryParam, $postData, 'PUT');
1171
1172
        return $ret;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $ret returns the type string which is incompatible with the documented return type JiraRestApi\Issue\Issue|object.
Loading history...
1173
    }
1174
}
1175