Passed
Push — 1.x-dev ( 41151e...6e580d )
by Brian
03:15
created

JiraProject   F

Complexity

Total Complexity 77

Size/Duplication

Total Lines 617
Duplicated Lines 0 %

Test Coverage

Coverage 58.25%

Importance

Changes 11
Bugs 0 Features 0
Metric Value
eloc 239
c 11
b 0
f 0
dl 0
loc 617
ccs 120
cts 206
cp 0.5825
rs 2.24
wmc 77

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getOpenIssues() 0 20 5
A getInfo() 0 3 1
B configure() 0 34 6
A getIssues() 0 19 5
A getVersions() 0 3 1
A __construct() 0 15 2
A getOpenBugs() 0 3 1
C submitIssue() 0 65 16
A getFormData() 0 20 4
A getIssue() 0 12 3
A getErrors() 0 11 3
A modifyAllowedTypes() 0 23 6
A isAllowedType() 0 3 2
A setError() 0 12 3
A setFormData() 0 13 3
A getBugs() 0 3 1
F buildSubmittedIssue() 0 53 12
A getAllowedTypes() 0 12 3

How to fix   Complexity   

Complex Class

Complex classes like JiraProject often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use JiraProject, and based on these observations, apply Extract Interface, too.

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

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

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