Passed
Pull Request — master (#18)
by Brian
05:45
created

JiraProject::buildSubmittedIssue()   F

Complexity

Conditions 12
Paths 385

Size

Total Lines 53
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 14.7316

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 12
eloc 30
c 2
b 0
f 0
nc 385
nop 2
dl 0
loc 53
ccs 22
cts 30
cp 0.7332
crap 14.7316
rs 3.8208

How to fix   Long Method    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\Exception;
12
use Fr3nch13\Jira\Exception\IssueSubmissionException;
13
use Fr3nch13\Jira\Exception\MissingAllowedTypeException;
14
use Fr3nch13\Jira\Exception\MissingConfigException;
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
     * Config Object.
33
     * @var \JiraRestApi\Configuration\ArrayConfiguration
34
     */
35
    public $ConfigObj;
36
37
    /**
38
     * The key for the project.
39
     * @var string|null
40
     */
41
    public $projectKey = null;
42
43
    /**
44
     * The project service object.
45
     * @var \JiraRestApi\Project\ProjectService
46
     */
47
    public $ProjectService;
48
49
    /**
50
     * The project object.
51
     * @var \JiraRestApi\Project\Project
52
     */
53
    protected $Project;
54
55
    /**
56
     * The list of a Project's Versions.
57
     * @var array
58
     */
59
    protected $Versions = [];
60
61
    /**
62
     * The project service object.
63
     * @var \JiraRestApi\Issue\IssueService
64
     */
65
    public $IssueService;
66
67
    /**
68
     * The Cached list of issues.
69
     * @var array
70
     */
71
    protected $Issues = [];
72
73
    /**
74
     * The cached list of returned issue info from the below getIssue() method.
75
     * @var array
76
     */
77
    protected $issuesCache = [];
78
79
    /**
80
     * Valid Types.
81
     * Used to ensure we're getting a valid type when filtering.
82
     * Currently only support Jira Core and Software.
83
     * @see https://confluence.atlassian.com/adminjiracloud/issue-types-844500742.html
84
     * @var array
85
     */
86
    protected $validTypes = [
87
        'Bug',
88
        'Epic',
89
        'Story',
90
        'Subtask',
91
        'Task',
92
    ];
93
94
    /**
95
     * Types of issues allowed to be submitted.
96
     * @var array
97
     */
98
    protected $allowedTypes = [
99
        'Task' => [
100
            'jiraType' => 'Task', // Must be one of the types in the $this->validTypes.
101
            'jiraLabels' => 'task-submitted', // The label used to tag user submitted bugs.
102
            // The form's field information.
103
            'formData' => [
104
                'fields' => [
105
                    'summary' => [
106
                        'type' => 'text',
107
                        'required' => true,
108
                    ],
109
                    'details' => [
110
                        'type' => 'textarea',
111
                        'required' => true,
112
                    ],
113
                ],
114
            ],
115
        ],
116
        'Bug' => [
117
            'jiraType' => 'Bug', // Must be one of the types in the $this->validTypes.
118
            'jiraLabels' => 'bug-submitted', // The label used to tag user submitted bugs.
119
            // The form's field information.
120
            'formData' => [
121
                'fields' => [
122
                    'summary' => [
123
                        'type' => 'text',
124
                        'required' => true,
125
                    ],
126
                    'details' => [
127
                        'type' => 'textarea',
128
                        'required' => true,
129
                    ],
130
                ],
131
            ],
132
        ],
133
        'FeatureRequest' => [
134
            'jiraType' => 'Story', // Must be one of the types in the $this->validTypes.
135
            'jiraLabels' => 'feature-request', // The label used to tag feature requests.
136
            // The form's field information.
137
            'formData' => [
138
                'fields' => [
139
                    'summary' => [
140
                        'type' => 'text',
141
                        'required' => true,
142
                    ],
143
                    'details' => [
144
                        'type' => 'textarea',
145
                        'required' => true,
146
                    ],
147
                ],
148
            ],
149
        ],
150
    ];
151
152
    /**
153
     * This is here for the Form object (or any other object) to use.
154
     * It tacks all errors, even if an exception is thrown.
155
     * @var array
156
     */
157
    protected $errors = [];
158
159
    /**
160
     * Constructor
161
     *
162
     * Reads the configuration, and crdate a config object to be passed to the other objects.
163
     *
164
     * @throws \Fr3nch13\Jira\Exception\MissingProjectException When the project can't be found.
165
     * @return void
166
     */
167 27
    public function __construct()
168
    {
169 27
        $this->configure();
170
171
        // setup the objects
172 27
        $this->ProjectService = new ProjectService($this->ConfigObj);
173
        try {
174 27
            $this->Project = $this->ProjectService->get($this->projectKey);
175
        } catch (JiraException $e) {
176
            $this->setError($this->projectKey, 'MissingProjectException');
0 ignored issues
show
Bug introduced by
It seems like $this->projectKey can also be of type null; however, parameter $msg of Fr3nch13\Jira\Lib\JiraProject::setError() does only seem to accept string, 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

176
            $this->setError(/** @scrutinizer ignore-type */ $this->projectKey, 'MissingProjectException');
Loading history...
177
            throw new MissingProjectException($this->projectKey);
178
        }
179
180 27
        $this->Versions = $this->ProjectService->getVersions($this->projectKey);
181 27
        $this->IssueService = new IssueService($this->ConfigObj);
182 27
    }
183
184
    /**
185
     * Configures the object.
186
     * Broken out of construct.
187
     *
188
     * @throws \Fr3nch13\Jira\Exception\MissingConfigException When a config setting isn't set.
189
     * @return void
190
     */
191 27
    public function configure(): void
192
    {
193 27
        $schema = Configure::read('Jira.schema');
194 27
        if (!$schema) {
195
            $this->setError('schema', 'MissingConfigException');
196
            throw new MissingConfigException('schema');
197
        }
198 27
        $host = Configure::read('Jira.host');
199 27
        if (!$host) {
200
            $this->setError('host', 'MissingConfigException');
201
            throw new MissingConfigException('host');
202
        }
203 27
        $username = Configure::read('Jira.username');
204 27
        if (!$username) {
205
            $this->setError('username', 'MissingConfigException');
206
            throw new MissingConfigException('username');
207
        }
208 27
        $apiKey = Configure::read('Jira.apiKey');
209 27
        if (!$apiKey) {
210
            $this->setError('apiKey', 'MissingConfigException');
211
            throw new MissingConfigException('apiKey');
212
        }
213 27
        $projectKey = Configure::read('Jira.projectKey');
214 27
        if (!$projectKey) {
215
            $this->setError('projectKey', 'MissingConfigException');
216
            throw new MissingConfigException('projectKey');
217
        }
218 27
        $this->ConfigObj = new ArrayConfiguration([
219 27
            'jiraHost' => $schema . '://' . $host,
220 27
            'jiraUser' => $username,
221 27
            'jiraPassword' => $apiKey,
222
        ]);
223
224 27
        $this->projectKey = $projectKey;
225 27
    }
226
227
    /**
228
     * Get the Project's Info.
229
     *
230
     * @return \JiraRestApi\Project\Project The information about the project.
231
     * @throws \Fr3nch13\Jira\Exception\MissingProjectException If the project can't be found.
232
     */
233 4
    public function getInfo(): \JiraRestApi\Project\Project
234
    {
235 4
        return $this->Project;
236
    }
237
238
    /**
239
     * Get the Project's Versions.
240
     *
241
     * @return array A list of version objects.
242
     */
243 2
    public function getVersions(): array
244
    {
245 2
        return $this->Versions;
246
    }
247
248
    /**
249
     * Get the Project's Issues.
250
     *
251
     * @param string|null $type Filter the Issues by type.
252
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
253
     */
254 4
    public function getIssues(?string $type = null): \JiraRestApi\Issue\IssueSearchResult
255
    {
256 4
        $cacheKey = 'all';
257 4
        if ($type) {
258 2
            $cacheKey .= '-' . $type;
259
        }
260 4
        if (!isset($this->Issues[$cacheKey])) {
261 4
            $jql = new JqlQuery();
262
263 4
            $jql->setProject($this->projectKey);
264 4
            if ($type && in_array($type, $this->validTypes)) {
265 2
                $jql->setType($type);
266
            }
267 4
            $jql->addAnyExpression('ORDER BY key DESC');
268
269 4
            $this->Issues[$cacheKey] = $this->IssueService->search($jql->getQuery(), 0, 1000);
270
        }
271
272 4
        return $this->Issues[$cacheKey];
273
    }
274
275
    /**
276
     * Get the Project's Open Issues.
277
     *
278
     * @param string|null $type Filter the Issues by type.
279
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
280
     */
281 4
    public function getOpenIssues(?string $type = null): \JiraRestApi\Issue\IssueSearchResult
282
    {
283 4
        $cacheKey = 'open';
284 4
        if ($type) {
285 2
            $cacheKey .= '-' . $type;
286
        }
287 4
        if (!isset($this->Issues[$cacheKey])) {
288 4
            $jql = new JqlQuery();
289
290 4
            $jql->setProject($this->projectKey);
291 4
            if ($type && in_array($type, $this->validTypes)) {
292 2
                $jql->setType($type);
293
            }
294 4
            $jql->addAnyExpression('AND resolution is EMPTY');
295 4
            $jql->addAnyExpression('ORDER BY key DESC');
296
297 4
            $this->Issues[$cacheKey] = $this->IssueService->search($jql->getQuery(), 0, 1000);
298
        }
299
300 4
        return $this->Issues[$cacheKey];
301
    }
302
303
    /**
304
     * Gets info on a particular issue within your project.
305
     *
306
     * @param int|null $id The issue id. The integer part without the project key.
307
     * @return \JiraRestApi\Issue\Issue|\JiraRestApi\Issue\IssueV3 the object that has the info of that issue.
308
     * @throws \Fr3nch13\Jira\Exception\Exception If the issue's id isn't given.
309
     * @throws \Fr3nch13\Jira\Exception\MissingIssueException If the project's issue can't be found.
310
     */
311 2
    public function getIssue(?int $id = null): \JiraRestApi\Issue\Issue
312
    {
313 2
        if (!is_int($id)) {
314
            $this->setError(__('Missing the Issue\'s ID.'), 'Exception');
315
            throw new Exception(__('Missing the Issue\'s ID.'));
316
        }
317 2
        $key = $this->projectKey . '-' . $id;
318 2
        if (!isset($this->issuesCache[$key])) {
319 2
            $this->issuesCache[$key] = $this->IssueService->get($key);
320 2
            if (!$this->issuesCache[$key]) {
321
                $this->setError($key, 'MissingIssueException');
322
                throw new MissingIssueException($key);
323
            }
324
        }
325
326 2
        return $this->issuesCache[$key];
327
    }
328
329
    /**
330
     * Gets a list of issues that are considered bugs.
331
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
332
     */
333 2
    public function getBugs(): \JiraRestApi\Issue\IssueSearchResult
334
    {
335 2
        return $this->getIssues('Bug');
336
    }
337
338
    /**
339
     * Gets a list of open issues that are considered bugs.
340
     * @return \JiraRestApi\Issue\IssueSearchResult|\JiraRestApi\Issue\IssueSearchResultV3 A list of issue objects.
341
     */
342 2
    public function getOpenBugs(): \JiraRestApi\Issue\IssueSearchResult
343
    {
344 2
        return $this->getOpenIssues('Bug');
345
    }
346
347
    /**
348
     * Methods used to submit an Issue to Jira.
349
     */
350
351
    /**
352
     * Returns the allowed types and their settings
353
     *
354
     * @param string|null $type The type of issue you want to get.
355
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If a type is given, and that type is not configured.
356
     * @return array the content of $this->allowedTypes.
357
     */
358 12
    public function getAllowedTypes(?string $type = null): array
359
    {
360 12
        if ($type) {
361 2
            if (!isset($this->allowedTypes[$type])) {
362
                $this->setError($type, 'MissingAllowedTypeException');
363
                throw new MissingAllowedTypeException($type);
364
            }
365
366 2
            return $this->allowedTypes[$type];
367
        }
368
369 11
        return $this->allowedTypes;
370
    }
371
372
    /**
373
     * Allows you to modify the form allowdTypes to fir your situation.
374
     *
375
     * @param string $type The type of issue you want to add/modify.
376
     * @param array $settings The settings for the type.
377
     * @throws \Fr3nch13\Jira\Exception\MissingIssueFieldException If we're adding a new issue type, and the summary field isn't defined.
378
     * @return void
379
     */
380 5
    public function modifyAllowedTypes(string $type, array $settings = []): void
381
    {
382 5
        if (!isset($this->allowedTypes[$type])) {
383 5
            $this->allowedTypes[$type] = [];
384 5
            if (!isset($settings['jiraType'])) {
385
                $this->setError('jiraType', 'MissingIssueFieldException');
386
                throw new MissingIssueFieldException('jiraType');
387
            }
388 5
            if (!isset($settings['formData'])) {
389
                $this->setError('formData', 'MissingIssueFieldException');
390
                throw new MissingIssueFieldException('formData');
391
            }
392 5
            if (!isset($settings['formData']['fields'])) {
393
                $this->setError('formData.fields', 'MissingIssueFieldException');
394
                throw new MissingIssueFieldException('formData.fields');
395
            }
396 5
            if (!isset($settings['formData']['fields']['summary'])) {
397
                $this->setError('formData.fields.summary', 'MissingIssueFieldException');
398
                throw new MissingIssueFieldException('formData.fields.summary');
399
            }
400
        }
401
402 5
        $this->allowedTypes[$type] += $settings;
403 5
    }
404
405
    /**
406
     * Checks to see if a type is allowed.
407
     *
408
     * @param string $type The type to check.
409
     * @return bool if it's allowed or not.
410
     */
411 12
    public function isAllowedType(string $type): bool
412
    {
413 12
        return isset($this->allowedTypes[$type]) ? true : false;
414
    }
415
416
    /**
417
     * Gets the array for the forms when submitting an issue to Jira.
418
     *
419
     * @param string|null $type The type of issue we're submitting.
420
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If that type is not configured.
421
     * @throws \Fr3nch13\Jira\Exception\Exception If the form data for that type is missing.
422
     * @return array The array of data to fill in the form with.
423
     */
424 10
    public function getFormData(?string $type = null): array
425
    {
426 10
        if (!$type) {
427
            $this->setError('[$type is not set]', 'MissingAllowedTypeException');
428
            throw new MissingAllowedTypeException('[$type is not set]');
429
        }
430
431 10
        if (!$this->isAllowedType($type)) {
432
            $this->setError($type, 'MissingAllowedTypeException');
433
            throw new MissingAllowedTypeException($type);
434
        }
435
436 10
        $allowedTypes = $this->getAllowedTypes();
437
438 10
        if (!isset($allowedTypes[$type]['formData'])) {
439
            $this->setError('No form data is set.', 'Exception');
440
            throw new Exception(__('No form data is set.'));
441
        }
442
443 10
        return $allowedTypes[$type]['formData'];
444
    }
445
446
    /**
447
     * Sets the formData variable if you want to modify the default/initial values.
448
     *
449
     * @param string $type The type you want to set the data for.
450
     *  - Needs to be in the allowedTypes already.
451
     * @param array $data The definition of the allowed types
452
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If that type is not configured.
453
     * @return void
454
     */
455 9
    public function setFormData(string $type, array $data = []): void
456
    {
457 9
        if (!$type) {
458
            $this->setError('[$type is not set]', 'MissingAllowedTypeException');
459
            throw new MissingAllowedTypeException('[$type is not set]');
460
        }
461
462 9
        if (!$this->isAllowedType($type)) {
463
            $this->setError($type, 'MissingAllowedTypeException');
464
            throw new MissingAllowedTypeException($type);
465
        }
466
467 9
        $this->allowedTypes[$type]['formData'] = $data;
468 9
    }
469
470
    /**
471
     * Submits the Issue
472
     *
473
     * @param string $type The type you want to set the data for.
474
     *  - Needs to be in the allowedTypes already.
475
     * @param array $data The array of details about the issue.
476
     * @throws \Fr3nch13\Jira\Exception\IssueSubmissionException If submitting the issue fails.
477
     * @throws \Fr3nch13\Jira\Exception\MissingAllowedTypeException If that issue type is not configured.
478
     * @throws \Fr3nch13\Jira\Exception\MissingIssueFieldException If we're adding a new issue, and required fields aren't defined.
479
     * @return int > 0 If the request was successfully submitted.
480
     */
481 2
    public function submitIssue(string $type, array $data = []): int
482
    {
483 2
        if (!$type) {
484
            $this->setError('[$type is not set]', 'MissingAllowedTypeException');
485
            throw new MissingAllowedTypeException('[$type is not set]');
486
        }
487
488 2
        if (!$this->isAllowedType($type)) {
489
            $this->setError($type, 'MissingAllowedTypeException');
490
            throw new MissingAllowedTypeException($type);
491
        }
492
493 2
        if (!isset($data['summary'])) {
494
            $this->setError('summary', 'MissingIssueFieldException');
495
            throw new MissingIssueFieldException('summary');
496
        }
497
498 2
        $issueField = $this->buildSubmittedIssue($type, $data);
499
500 2
        $issueService = new IssueService($this->ConfigObj);
501
502
        try {
503 2
            $ret = $issueService->create($issueField);
504
        } catch (JiraException $e) {
505
            //Sample return error with json in it.
506
            //Pasting here so I can mock this return message in the unit tests.
507
            //CURL HTTP Request Failed: Status Code : 400, URL:https://[hostname]/rest/api/2/issue
508
            //Error Message : {"errorMessages":[],"errors":{"user_type":"Field 'user_type' cannot be set. It is not on the appropriate screen, or unknown."}}             */
509
            $msg = $e->getMessage();
510
            if (strpos($msg, '{') !== false) {
511
                $msgArray = str_split($msg);
512
                // extract the json message.
513
                $json = '';
514
                $in = 0;
515
                foreach ($msgArray as $i => $char) {
516
                    if ($char == '{') {
517
                        $in++;
518
                    }
519
                    if ($in) {
520
                        $json .= $msg[$i];
521
                    }
522
                    if ($char == '}') {
523
                        $in--;
524
                    }
525
                }
526
                if ($json) {
527
                    $json = json_decode($json, true);
528
                }
529
                if ($json) {
530
                    $newMsg = [];
531
                    if (isset($json['errorMessages'])) {
532
                        foreach ($json['errorMessages'] as $jsonMsg) {
533
                            $newMsg[] = $jsonMsg;
534
                        }
535
                        foreach ($json['errors'] as $jsonMsg) {
536
                            $newMsg[] = $jsonMsg;
537
                        }
538
                        $msg = implode("\n", $newMsg);
539
                    }
540
                }
541
            }
542
            $this->setError($msg, 'IssueSubmissionException');
543
            throw new IssueSubmissionException($msg);
544
        }
545
546 2
        if ($ret instanceof Issue && $ret->id) {
547 2
            return (int)$ret->id;
548
        }
549
550
        return 0;
551
    }
552
553
    /**
554
     * Creates the issue to send to the server.
555
     *
556
     * @param string $type The type of isse we're creating.
557
     * @param array $data The data from the submitted form.
558
     * @throws \Fr3nch13\Jira\Exception\MissingProjectException If submitting the issue fails.
559
     * @return \JiraRestApi\Issue\IssueField
560
     */
561 2
    public function buildSubmittedIssue(string $type, array $data = []): \JiraRestApi\Issue\IssueField
562
    {
563 2
        $typeInfo = $this->getAllowedTypes($type);
564
565
        // make sure we can get the project info first.
566
        // getInfo will throw an exception if it can't find the project.
567
        // putting a try/catch around it so scrutinizer stops complaining.
568
        try {
569 2
            $project = $this->getInfo();
570
        } catch (MissingProjectException $e) {
571
            $this->setError($this->projectKey, 'MissingProjectException');
0 ignored issues
show
Bug introduced by
It seems like $this->projectKey can also be of type null; however, parameter $msg of Fr3nch13\Jira\Lib\JiraProject::setError() does only seem to accept string, 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

571
            $this->setError(/** @scrutinizer ignore-type */ $this->projectKey, 'MissingProjectException');
Loading history...
572
            throw $e;
573
        }
574
575 2
        $issueField = new IssueField();
576 2
        $issueField->setProjectKey($this->projectKey)
577 2
            ->setIssueType($typeInfo['jiraType']);
578
579 2
        if (isset($data['summary'])) {
580 2
            $issueField->setSummary($data['summary']);
581
        }
582 2
        if (isset($data['description'])) {
583 1
            $issueField->setDescription($data['description']);
584
        }
585 2
        if (isset($data['priority'])) {
586
            $issueField->setPriorityName($data['priority']);
587
        }
588 2
        if (isset($data['assignee'])) {
589
            $issueField->setPriorityName($data['assignee']);
590
        }
591 2
        if (isset($data['version'])) {
592
            $issueField->addVersion($data['version']);
593
        }
594 2
        if (isset($data['components'])) {
595
            $issueField->addComponents($data['components']);
596
        }
597 2
        if (isset($data['duedate'])) {
598
            $issueField->setDueDate($data['duedate']);
599
        }
600
601
        // labels should be space seperated
602 2
        if (isset($typeInfo['jiraLabels'])) {
603 2
            if (is_string($typeInfo['jiraLabels'])) {
604 2
                $typeInfo['jiraLabels'] = preg_split('/\s+/', $typeInfo['jiraLabels']);
605
            }
606
            // track the type with a label
607 2
            $typeInfo['jiraLabels'][] = 'user-submitted-type-' . $type;
608 2
            foreach ($typeInfo['jiraLabels'] as $jiralabel) {
609 2
                $issueField->addLabel($jiralabel);
610
            }
611
        }
612
613 2
        return $issueField;
614
    }
615
616
    /**
617
     * Sets an error
618
     *
619
     * @param string $msg The error message.
620
     * @param string $key The key to use in the this->errors array.
621
     * @return bool If saved or not.
622
     */
623
    public function setError(string $msg = '', string $key = ''): bool
624
    {
625
        if (!trim($msg)) {
626
            return false;
627
        }
628
        if ($key) {
629
            $this->errors[$key] = $msg;
630
        } else {
631
            $this->errors[] = $msg;
632
        }
633
634
        return true;
635
    }
636
637
    /**
638
     * Gets the accumulated error messages.
639
     * If a key is given, return that specific message. If that key doesn't exist, return false.
640
     *
641
     * @param string|null $key The key to the specific message to get.
642
     * @return array|string|false
643
     */
644
    public function getErrors(?string $key = null)
645
    {
646
        if ($key) {
647
            if (isset($this->errors[$key])) {
648
                return $this->errors[$key];
649
            } else {
650
                return false;
651
            }
652
        }
653
654
        return $this->errors;
655
    }
656
}
657