Passed
Push — master ( c4b978...6342bd )
by Brian
01:32 queued 14s
created

JiraProject::extractJiraError()   B

Complexity

Conditions 11
Paths 7

Size

Total Lines 36
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 11.0099

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 22
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 36
ccs 22
cts 23
cp 0.9565
crap 11.0099
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * JiraProjectReader
6
 */
7
8
namespace Fr3nch13\Jira\Lib;
9
10
use Cake\Core\Configure;
11
use Fr3nch13\Jira\Exception\IssueSubmissionException;
12
use Fr3nch13\Jira\Exception\MissingAllowedTypeException;
13
use Fr3nch13\Jira\Exception\MissingConfigException;
14
use Fr3nch13\Jira\Exception\MissingDataException;
15
use Fr3nch13\Jira\Exception\MissingIssueException;
16
use Fr3nch13\Jira\Exception\MissingIssueFieldException;
17
use Fr3nch13\Jira\Exception\MissingProjectException;
18
use JiraRestApi\Configuration\ArrayConfiguration;
19
use JiraRestApi\Issue\Issue;
20
use JiraRestApi\Issue\IssueField;
21
use JiraRestApi\Issue\IssueService;
22
use JiraRestApi\Issue\JqlQuery;
23
use JiraRestApi\JiraException;
24
use JiraRestApi\Project\ProjectService;
25
26
/**
27
 * Jira Project class
28
 */
29
class JiraProject
30
{
31
    /**
32
     * @var \JiraRestApi\Configuration\ArrayConfiguration Config Object.
33
     */
34
    public $ConfigObj;
35
36
    /**
37
     * @var null|string The key for the project.
38
     */
39
    public $projectKey = null;
40
41
    /**
42
     * @var \JiraRestApi\Project\ProjectService The project service object.
43
     */
44
    public $ProjectService;
45
46
    /**
47
     * @var \JiraRestApi\Project\Project The project object.
48
     */
49
    protected $Project;
50
51
    /**
52
     * @var array<\JiraRestApi\Issue\Version> The list of a Project's Versions.
53
     */
54
    protected $Versions;
55
56
    /**
57
     * @var \JiraRestApi\Issue\IssueService The project service object.
58
     */
59
    public $IssueService;
60
61
    /**
62
     * @var array<string, mixed> The Cached list of issues.
63
     */
64
    protected $Issues = [];
65
66
    /**
67
     * @var array<string, mixed> The cached list of returned issue info from the below getIssue() method.
68
     */
69
    protected $issuesCache = [];
70
71
    /**
72
     * Valid Types.
73
     * Used to ensure we're getting a valid type when filtering.
74
     * Currently only support Jira Core and Software.
75
     *
76
     * @see https://confluence.atlassian.com/adminjiracloud/issue-types-844500742.html
77
     * @var array<int, string>
78
     */
79
    protected $validTypes = [
80
        'Bug',
81
        'Epic',
82
        'Story',
83
        'Subtask',
84
        'Task',
85
    ];
86
87
    /**
88
     * @var array<string, array<mixed>> Types of issues allowed to be submitted.
89
     */
90
    protected $allowedTypes = [
91
        'Task' => [
92
            'jiraType' => 'Task', // Must be one of the types in the $this->validTypes.
93
            'jiraLabels' => 'task-submitted', // The label used to tag user submitted bugs.
94
            // The form's field information.
95
            'formData' => [
96
                'fields' => [
97
                    'summary' => [
98
                        'type' => 'text',
99
                        'required' => true,
100
                    ],
101
                    'details' => [
102
                        'type' => 'textarea',
103
                        'required' => true,
104
                    ],
105
                ],
106
            ],
107
        ],
108
        'Bug' => [
109
            'jiraType' => 'Bug', // Must be one of the types in the $this->validTypes.
110
            'jiraLabels' => 'bug-submitted', // The label used to tag user submitted bugs.
111
            // The form's field information.
112
            'formData' => [
113
                'fields' => [
114
                    'summary' => [
115
                        'type' => 'text',
116
                        'required' => true,
117
                    ],
118
                    'details' => [
119
                        'type' => 'textarea',
120
                        'required' => true,
121
                    ],
122
                ],
123
            ],
124
        ],
125
        'FeatureRequest' => [
126
            'jiraType' => 'Story', // Must be one of the types in the $this->validTypes.
127
            'jiraLabels' => 'feature-request', // The label used to tag feature requests.
128
            // The form's field information.
129
            'formData' => [
130
                'fields' => [
131
                    'summary' => [
132
                        'type' => 'text',
133
                        'required' => true,
134
                    ],
135
                    'details' => [
136
                        'type' => 'textarea',
137
                        'required' => true,
138
                    ],
139
                ],
140
            ],
141
        ],
142
    ];
143
144
    /**
145
     * This is here for the Form object (or any other object) to use.
146
     * It tacks all errors, even if an exception is thrown.
147
     *
148
     * @var array<int|string, string>
149
     */
150
    protected $errors = [];
151
152
    /**
153
     * Constructor
154
     *
155
     * Reads the configuration, and crdate a config object to be passed to the other objects.
156
     *
157
     * @throws \Fr3nch13\Jira\Exception\MissingProjectException When the project can't be found.
158
     * @return void
159
     */
160 66
    public function __construct()
161
    {
162 66
        $this->configure();
163
164
        // setup the objects
165 66
        $this->ProjectService = new ProjectService($this->ConfigObj);
166
        try {
167 66
            $this->Project = $this->ProjectService->get($this->projectKey);
168
        } catch (JiraException $e) {
169
            $msg = $e->getMessage();
170
            if ($msg) {
171
                $msg = $this->extractJiraError($msg);
172
            }
173
            $msg = __('{0}: {1}', [
174
                $this->projectKey,
175
                $msg,
176
            ]);
177
            $this->setJiraError($msg, 'MissingProjectException');
178
            throw new MissingProjectException($msg);
179
        }
180
181 66
        $this->Versions = (array)$this->ProjectService->getVersions($this->projectKey);
182 66
        $this->IssueService = new IssueService($this->ConfigObj);
183
    }
184
185
    /**
186
     * Configures the object.
187
     * Broken out of construct.
188
     *
189
     * @throws \Fr3nch13\Jira\Exception\MissingConfigException When a config setting isn't set.
190
     * @return void
191
     */
192 66
    public function configure(): void
193
    {
194 66
        $schema = Configure::read('Jira.schema');
195 66
        if (!$schema) {
196 1
            $this->setJiraError('schema', 'MissingConfigException');
197 1
            throw new MissingConfigException('schema');
198
        }
199 66
        $host = Configure::read('Jira.host');
200 66
        if (!$host) {
201 1
            $this->setJiraError('host', 'MissingConfigException');
202 1
            throw new MissingConfigException('host');
203
        }
204 66
        $username = Configure::read('Jira.username');
205 66
        if (!$username) {
206 1
            $this->setJiraError('username', 'MissingConfigException');
207 1
            throw new MissingConfigException('username');
208
        }
209 66
        $apiKey = Configure::read('Jira.apiKey');
210 66
        if (!$apiKey) {
211 1
            $this->setJiraError('apiKey', 'MissingConfigException');
212 1
            throw new MissingConfigException('apiKey');
213
        }
214 66
        $projectKey = Configure::read('Jira.projectKey');
215 66
        if (!$projectKey) {
216 1
            $this->setJiraError('projectKey', 'MissingConfigException');
217 1
            throw new MissingConfigException('projectKey');
218
        }
219 66
        $useV3RestApi = Configure::read('Jira.useV3RestApi');
220 66
        if (!$useV3RestApi) {
221 1
            $this->setJiraError('useV3RestApi', 'MissingConfigException');
222 1
            throw new MissingConfigException('useV3RestApi');
223
        }
224 66
        $jiraLogFile = Configure::read('Jira.jiraLogFile');
225 66
        if (!$jiraLogFile) {
226 1
            $this->setJiraError('jiraLogFile', 'MissingConfigException');
227 1
            throw new MissingConfigException('jiraLogFile');
228
        }
229 66
        $this->ConfigObj = new ArrayConfiguration([
230 66
            'jiraHost' => $schema . '://' . $host,
231 66
            'jiraUser' => $username,
232 66
            'jiraPassword' => $apiKey,
233 66
            'useV3RestApi' => $useV3RestApi,
234 66
            'jiraLogFile' => $jiraLogFile,
235 66
        ]);
236
237 66
        $this->projectKey = $projectKey;
238
    }
239
240
    /**
241
     * Get the Project's Info.
242
     *
243
     * @return \JiraRestApi\Project\Project The information about the project.
244
     * @throws \Fr3nch13\Jira\Exception\MissingProjectException If the project can't be found.
245
     */
246 9
    public function getInfo(): \JiraRestApi\Project\Project
247
    {
248 9
        return $this->Project;
249
    }
250
251
    /**
252
     * Get the Project's Versions.
253
     *
254
     * @return array<\JiraRestApi\Issue\Version> A list of version objects.
255
     */
256 2
    public function getVersions(): array
257
    {
258 2
        return $this->Versions;
259
    }
260
261
    /**
262
     * Get the Project's Issues.
263
     *
264
     * @param string|null $type Filter the Issues by type.
265
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
266
     */
267 4
    public function getIssues(?string $type = null): \JiraRestApi\Issue\IssueSearchResult
268
    {
269 4
        $cacheKey = 'all';
270 4
        if ($type) {
271 2
            $cacheKey .= '-' . $type;
272
        }
273 4
        if (!isset($this->Issues[$cacheKey])) {
274 4
            $jql = new JqlQuery();
275
276 4
            $jql->setProject($this->projectKey);
277 4
            if ($type && in_array($type, $this->validTypes)) {
278 2
                $jql->setType($type);
279
            }
280 4
            $jql->addAnyExpression('ORDER BY key DESC');
281
282 4
            $this->Issues[$cacheKey] = $this->IssueService->search($jql->getQuery(), 0, 1000);
283
        }
284
285 4
        return $this->Issues[$cacheKey];
286
    }
287
288
    /**
289
     * Get the Project's Open Issues.
290
     *
291
     * @param string|null $type Filter the Issues by type.
292
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
293
     */
294 4
    public function getOpenIssues(?string $type = null): \JiraRestApi\Issue\IssueSearchResult
295
    {
296 4
        $cacheKey = 'open';
297 4
        if ($type) {
298 2
            $cacheKey .= '-' . $type;
299
        }
300 4
        if (!isset($this->Issues[$cacheKey])) {
301 4
            $jql = new JqlQuery();
302
303 4
            $jql->setProject($this->projectKey);
304 4
            if ($type && in_array($type, $this->validTypes)) {
305 2
                $jql->setType($type);
306
            }
307 4
            $jql->addAnyExpression('AND resolution is EMPTY');
308 4
            $jql->addAnyExpression('ORDER BY key DESC');
309
310 4
            $this->Issues[$cacheKey] = $this->IssueService->search($jql->getQuery(), 0, 1000);
311
        }
312
313 4
        return $this->Issues[$cacheKey];
314
    }
315
316
    /**
317
     * Gets info on a particular issue within your project.
318
     *
319
     * @param int|null $id The issue id. The integer part without the project key.
320
     * @throws \Fr3nch13\Jira\Exception\MissingDataException If the issue's id isn't given.
321
     * @throws \Fr3nch13\Jira\Exception\MissingIssueException If the project's issue can't be found.
322
     * @return \JiraRestApi\Issue\Issue|\JiraRestApi\Issue\IssueV3 the object that has the info of that issue.
323
     */
324 4
    public function getIssue(?int $id = null): Issue
325
    {
326 4
        if (!is_int($id)) {
327 1
            $this->setJiraError(__('Missing the Issue\'s ID.'), 'Exception');
328 1
            throw new MissingDataException(__('Missing the Issue\'s ID.'));
329
        }
330 3
        $key = $this->projectKey . '-' . $id;
331 3
        if (!isset($this->issuesCache[$key])) {
332
            try {
333 3
                $this->issuesCache[$key] = $this->IssueService->get($key);
334 1
            } catch (JiraException $e) {
335 1
                $msg = $e->getMessage();
336 1
                if ($msg) {
337 1
                    $msg = $this->extractJiraError($msg);
338
                }
339 1
                $msg = __('{0}: {1}', [
340 1
                    $key,
341 1
                    $msg,
342 1
                ]);
343 1
                $this->setJiraError($msg, 'MissingIssueException');
344 1
                throw new MissingIssueException($msg);
345
            }
346
        }
347
348 2
        return $this->issuesCache[$key];
349
    }
350
351
    /**
352
     * Gets a list of issues that are considered bugs.
353
     *
354
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
355
     */
356 2
    public function getBugs(): \JiraRestApi\Issue\IssueSearchResult
357
    {
358 2
        return $this->getIssues('Bug');
359
    }
360
361
    /**
362
     * Gets a list of open issues that are considered bugs.
363
     *
364
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
365
     */
366 2
    public function getOpenBugs(): \JiraRestApi\Issue\IssueSearchResult
367
    {
368 2
        return $this->getOpenIssues('Bug');
369
    }
370
371
    /**
372
     * Methods used to submit an Issue to Jira.
373
     */
374
375
    /**
376
     * Returns the allowed types and their settings
377
     *
378
     * @param string|null $type The type of issue you want to get.
379
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If a type is given, and that type is not configured.
380
     * @return array<string, mixed> the content of $this->allowedTypes.
381
     */
382 29
    public function getAllowedTypes(?string $type = null): array
383
    {
384 29
        if ($type) {
385 8
            if (!isset($this->allowedTypes[$type])) {
386 1
                $this->setJiraError($type, 'MissingAllowedTypeException');
387 1
                throw new MissingAllowedTypeException($type);
388
            }
389
390 7
            return $this->allowedTypes[$type];
391
        }
392
393 26
        return $this->allowedTypes;
394
    }
395
396
    /**
397
     * Allows you to modify the form allowdTypes to fir your situation.
398
     *
399
     * @param string $type The type of issue you want to add/modify.
400
     * @param array<string, mixed> $settings The settings for the type.
401
     * @throws \Fr3nch13\Jira\Exception\MissingIssueFieldException If we're adding a new issue type, and the summary field isn't defined.
402
     * @return void
403
     */
404 16
    public function modifyAllowedTypes(string $type, array $settings = []): void
405
    {
406 16
        if (!isset($this->allowedTypes[$type])) {
407 16
            $this->allowedTypes[$type] = [];
408 16
            if (!isset($settings['jiraType'])) {
409 1
                $this->setJiraError('jiraType', 'MissingIssueFieldException');
410 1
                throw new MissingIssueFieldException('jiraType');
411
            }
412 15
            if (!isset($settings['formData'])) {
413 1
                $this->setJiraError('formData', 'MissingIssueFieldException');
414 1
                throw new MissingIssueFieldException('formData');
415
            }
416 14
            if (!isset($settings['formData']['fields'])) {
417 1
                $this->setJiraError('formData.fields', 'MissingIssueFieldException');
418 1
                throw new MissingIssueFieldException('formData.fields');
419
            }
420 13
            if (!isset($settings['formData']['fields']['summary'])) {
421 1
                $this->setJiraError('formData.fields.summary', 'MissingIssueFieldException');
422 1
                throw new MissingIssueFieldException('formData.fields.summary');
423
            }
424
        }
425
426 12
        $this->allowedTypes[$type] += $settings;
427
    }
428
429
    /**
430
     * Checks to see if a type is allowed.
431
     *
432
     * @param string $type The type to check.
433
     * @return bool if it's allowed or not.
434
     */
435 32
    public function isAllowedType(string $type): bool
436
    {
437 32
        return isset($this->allowedTypes[$type]) ? true : false;
438
    }
439
440
    /**
441
     * Gets the array for the forms when submitting an issue to Jira.
442
     *
443
     * @param string|null $type The type of issue we're submitting.
444
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If that type is not configured.
445
     * @throws \Fr3nch13\Jira\Exception\MissingDataException If the form data for that type is missing.
446
     * @return array<string, mixed> The array of data to fill in the form with.
447
     */
448 27
    public function getFormData(?string $type = null): array
449
    {
450 27
        if (!$type) {
451 1
            $this->setJiraError('[$type is not set]', 'MissingAllowedTypeException');
452 1
            throw new MissingAllowedTypeException('[$type is not set]');
453
        }
454
455 26
        if (!$this->isAllowedType($type)) {
456 1
            $this->setJiraError($type, 'MissingAllowedTypeException');
457 1
            throw new MissingAllowedTypeException($type);
458
        }
459
460 25
        $allowedTypes = $this->getAllowedTypes();
461
462 25
        if (!isset($allowedTypes[$type]['formData'])) {
463
            $this->setJiraError('No form data is set.', 'MissingDataException');
464
            throw new MissingDataException(__('No form data is set.'));
465
        }
466
467 25
        if (!isset($allowedTypes[$type]['formData']['fields'])) {
468
            $this->setJiraError('No form data fields are set.', 'MissingDataException');
469
            throw new MissingDataException(__('No form data fields are set.'));
470
        }
471
472 25
        return $allowedTypes[$type]['formData'];
473
    }
474
475
    /**
476
     * Sets the formData variable if you want to modify the default/initial values.
477
     *
478
     * @param string $type The type you want to set the data for.
479
     *  - Needs to be in the allowedTypes already.
480
     * @param array<string, mixed> $data The definition of the allowed types
481
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If that type is not configured.
482
     * @throws \Fr3nch13\Jira\Exception\MissingDataException Uf the fields aren't defined.
483
     * @return void
484
     */
485 26
    public function setFormData(string $type, array $data = []): void
486
    {
487 26
        if (!$this->isAllowedType($type)) {
488 1
            $this->setJiraError($type, 'MissingAllowedTypeException');
489 1
            throw new MissingAllowedTypeException($type);
490
        }
491
492 25
        if (!isset($data['fields'])) {
493 1
            $this->setJiraError('No form data fields are set.', 'MissingDataException');
494 1
            throw new MissingDataException(__('No form data fields are set.'));
495
        }
496
497 24
        $this->allowedTypes[$type]['formData'] = $data;
498
    }
499
500
    /**
501
     * Submits the Issue
502
     *
503
     * @param string $type The type you want to set the data for.
504
     *  - Needs to be in the allowedTypes already.
505
     * @param array<string, mixed> $data The array of details about the issue.
506
     * @throws \Fr3nch13\Jira\Exception\IssueSubmissionException If submitting the issue fails.
507
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If that issue type is not configured.
508
     * @throws \Fr3nch13\Jira\Exception\MissingIssueFieldException If we're adding a new issue, and required fields aren't defined.
509
     * @return int > 0 If the request was successfully submitted.
510
     */
511 8
    public function submitIssue(string $type, array $data = []): int
512
    {
513 8
        if (!$this->isAllowedType($type)) {
514 1
            $this->setJiraError($type, 'MissingAllowedTypeException');
515 1
            throw new MissingAllowedTypeException($type);
516
        }
517
518 7
        if (!isset($data['summary'])) {
519 1
            $this->setJiraError('summary', 'MissingIssueFieldException');
520 1
            throw new MissingIssueFieldException('summary');
521
        }
522
523 6
        $issueField = $this->buildSubmittedIssue($type, $data);
524
525 6
        $issueService = new IssueService($this->ConfigObj);
526
527
        try {
528 6
            $ret = $issueService->create($issueField);
529
        } catch (JiraException $e) {
530
            //Sample return error with json in it.
531
            //Pasting here so I can mock this return message in the unit tests.
532
            //CURL HTTP Request Failed: Status Code : 400, URL:https://[hostname]/rest/api/2/issue
533
            //Error Message : {"errorMessages":[],"errors":{"user_type":"Field 'user_type' cannot be set. It is not on the appropriate screen, or unknown."}}             */
534
            $msg = $e->getMessage();
535
            if ($msg) {
536
                $msg = $this->extractJiraError($msg);
537
            }
538
539
            $this->setJiraError($msg, 'IssueSubmissionException');
540
            throw new IssueSubmissionException($msg);
541
        }
542
543 6
        if ($ret instanceof Issue && $ret->id) {
544 6
            return (int)$ret->id;
545
        }
546
547
        return 0;
548
    }
549
550
    /**
551
     * Creates the issue to send to the server.
552
     *
553
     * @param string $type The type of isse we're creating.
554
     * @param array<string, mixed> $data The data from the submitted form.
555
     * @throws \Fr3nch13\Jira\Exception\MissingProjectException If submitting the issue fails.
556
     * @return \JiraRestApi\Issue\IssueField
557
     */
558 7
    public function buildSubmittedIssue(string $type, array $data = []): IssueField
559
    {
560 7
        $typeInfo = $this->getAllowedTypes($type);
561
562
        // make sure we can get the project info first.
563
        // getInfo will throw an exception if it can't find the project.
564
        // putting a try/catch around it so scrutinizer stops complaining.
565
        try {
566 7
            $project = $this->getInfo();
567
        } catch (MissingProjectException $e) {
568
            $this->setJiraError($this->projectKey, 'MissingProjectException');
569
            throw $e;
570
        }
571
572 7
        $issueField = new IssueField();
573 7
        $issueField->setProjectKey($this->projectKey)
574 7
            ->setIssueType($typeInfo['jiraType']);
575
576 7
        if (isset($data['summary'])) {
577 7
            $issueField->setSummary($data['summary']);
578
        }
579 7
        if (isset($data['description'])) {
580 2
            $issueField->setDescription($data['description']);
581
        }
582 7
        if (isset($data['priority'])) {
583 1
            $issueField->setPriorityName($data['priority']);
584
        }
585 7
        if (isset($data['assignee'])) {
586 1
            $issueField->setAssigneeName($data['assignee']);
587
        }
588 7
        if (isset($data['version'])) {
589 1
            $issueField->addVersion($data['version']);
590
        }
591 7
        if (isset($data['components'])) {
592 1
            $issueField->addComponents($data['components']);
593
        }
594 7
        if (isset($data['duedate'])) {
595 1
            $issueField->setDueDate($data['duedate']);
596
        }
597
598
        // labels should be space seperated
599 7
        if (isset($typeInfo['jiraLabels'])) {
600 7
            if (is_string($typeInfo['jiraLabels'])) {
601 7
                $typeInfo['jiraLabels'] = preg_split('/\s+/', $typeInfo['jiraLabels']);
602
            }
603
            // track the type with a label
604 7
            $typeInfo['jiraLabels'][] = 'user-submitted-type-' . $type;
605 7
            foreach ($typeInfo['jiraLabels'] as $jiralabel) {
606 7
                $issueField->addLabel($jiralabel);
607
            }
608
        }
609
610 7
        return $issueField;
611
    }
612
613
    /**
614
     * Sets an error
615
     *
616
     * @param string $msg The error message.
617
     * @param string $key The key to use in the this->errors array.
618
     * @return bool If saved or not.
619
     */
620 21
    public function setJiraError(string $msg = '', string $key = ''): bool
621
    {
622 21
        if (!trim($msg)) {
623 1
            return false;
624
        }
625 21
        if ($key) {
626 21
            $this->errors[$key] = $msg;
627
        } else {
628 1
            $this->errors[] = $msg;
629
        }
630
631 21
        return true;
632
    }
633
634
    /**
635
     * Gets the accumulated error messages.
636
     * If a key is given, return that specific message. If that key doesn't exist, return false.
637
     *
638
     * @return array<int|string, string>
639
     */
640 1
    public function getJiraErrors(): array
641
    {
642 1
        return $this->errors;
643
    }
644
645
    /**
646
     * Extracts the error message from the JiraException.
647
     *
648
     * @param string $msg The message from the Jir a Exception
649
     * @return string The extracted message if it is in json.
650
     */
651 2
    public function extractJiraError(string $msg): string
652
    {
653 2
        if (strpos($msg, '{') !== false) {
654 1
            $msgArray = str_split($msg);
655
            // extract the json message.
656 1
            $json = '';
657 1
            $in = 0;
658 1
            foreach ($msgArray as $i => $char) {
659 1
                if ($char == '{') {
660 1
                    $in++;
661
                }
662 1
                if ($in) {
663 1
                    $json .= $msg[$i];
664
                }
665 1
                if ($char == '}') {
666 1
                    $in--;
667
                }
668
            }
669 1
            if ($json) {
670 1
                $json = json_decode($json, true);
671
            }
672 1
            if ($json) {
673 1
                $newMsg = [];
674 1
                if (isset($json['errorMessages'])) {
675 1
                    foreach ($json['errorMessages'] as $jsonMsg) {
676
                        $newMsg[] = $jsonMsg;
677
                    }
678 1
                    foreach ($json['errors'] as $jsonMsg) {
679 1
                        $newMsg[] = $jsonMsg;
680
                    }
681 1
                    $msg = implode("\n", $newMsg);
682
                }
683
            }
684
        }
685
686 2
        return $msg;
687
    }
688
}
689