Skip to content

Commit f9e3b67

Browse files
authored
Merge pull request #208 from aik099/issue-type-fix
Added support for "entityId", "hierarchyLevel" and "untranslatedName" to the "IssueType" class
2 parents e4377b4 + f6fc760 commit f9e3b67

File tree

5 files changed

+156
-121
lines changed

5 files changed

+156
-121
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
4646
- Error details from failed API calls were not available back from `Api::api method` call by [@betterphp].
4747
- Warning about `count()` function usage on PHP 7.2, when searching for issues by [@aik099].
4848
- Capitalize `globalId` properly in `createRemotelink` [@glensc].
49+
- The `Api::getIssueTypes` was always returning an error by [@aik099].
4950

5051
## [1.0.0] - 2014-07-27
5152
### Added

src/Jira/IssueType.php

Lines changed: 50 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -25,151 +25,100 @@
2525
namespace chobie\Jira;
2626

2727

28+
/**
29+
* The issue type.
30+
*
31+
* @method integer getAvatarId() Gets avatar ID.
32+
* @method string getDescription() Gets description.
33+
* @method string getEntityId() Gets Unique ID for next-gen projects.
34+
* @method integer getHierarchyLevel() Gets hierarchy level.
35+
* @method string getIconUrl() Gets icon url.
36+
* @method string getId() Gets ID.
37+
* @method string getName() Gets name.
38+
* @method string getUntranslatedName() Gets untranslated name.
39+
* @method array getScope() Gets details of the next-gen projects the issue type is available in.
40+
* @method string getSelf() Gets the URL of these issue type details.
41+
*/
2842
class IssueType
2943
{
3044

3145
/**
32-
* Self.
33-
*
34-
* @var string
35-
*/
36-
protected $self;
37-
38-
/**
39-
* ID.
40-
*
41-
* @var string
42-
*/
43-
protected $id;
44-
45-
/**
46-
* Description.
47-
*
48-
* @var string
49-
*/
50-
protected $description;
51-
52-
/**
53-
* Icon URL.
46+
* Data.
5447
*
55-
* @var string
56-
*/
57-
protected $iconUrl;
58-
59-
/**
60-
* Name.
61-
*
62-
* @var string
63-
*/
64-
protected $name;
65-
66-
/**
67-
* Sub-task.
68-
*
69-
* @var string
70-
*/
71-
protected $subTask;
72-
73-
/**
74-
* Avatar ID.
75-
*
76-
* @var string
48+
* @var array
7749
*/
78-
protected $avatarId;
50+
private $_data;
7951

8052
/**
8153
* Acceptable keys.
8254
*
8355
* @var array
8456
*/
8557
private $_acceptableKeys = array(
86-
'self',
87-
'id',
58+
'avatarId',
8859
'description',
60+
'entityId',
61+
'hierarchyLevel',
8962
'iconUrl',
63+
'id',
9064
'name',
91-
'subtask',
92-
'avatarId',
9365
'scope',
66+
'self',
67+
'subtask',
68+
69+
'untranslatedName',
9470
);
9571

9672
/**
9773
* Creates issue instance.
9874
*
99-
* @param array $types Types.
75+
* @param array $data Data.
10076
*
101-
* @throws \Exception When unknown type is given.
77+
* @throws \Exception When an unknown data field is given.
10278
*/
103-
public function __construct(array $types)
79+
public function __construct(array $data)
10480
{
105-
foreach ( $types as $key => $value ) {
106-
if ( in_array($key, $this->_acceptableKeys) ) {
107-
$this->$key = $value;
108-
}
109-
else {
110-
throw new \Exception('the key ' . $key . ' does not support');
111-
}
81+
$unknown_fields = array_diff(array_keys($data), $this->_acceptableKeys);
82+
83+
if ( $unknown_fields ) {
84+
throw new \Exception(
85+
'The "' . implode('", "', $unknown_fields) . '" issue type keys are not supported.'
86+
);
11287
}
113-
}
11488

115-
/**
116-
* Gets name.
117-
*
118-
* @return string
119-
*/
120-
public function getName()
121-
{
122-
return $this->name;
89+
$this->_data = $data;
12390
}
12491

12592
/**
12693
* Gets sub-task.
12794
*
128-
* @return string
95+
* @return boolean
12996
*/
13097
public function isSubtask()
13198
{
132-
return $this->subTask;
99+
return $this->_data['subtask'];
133100
}
134101

135102
/**
136-
* Gets ID.
103+
* Allows accessing issue type properties.
137104
*
138-
* @return string
139-
*/
140-
public function getId()
141-
{
142-
return $this->id;
143-
}
144-
145-
/**
146-
* Gets description.
105+
* @param string $method Method name.
106+
* @param array $params Params.
147107
*
148-
* @return string
108+
* @return mixed
109+
* @throws \Exception When requested method wasn't found.
149110
*/
150-
public function getDescription()
111+
public function __call($method, array $params)
151112
{
152-
return $this->description;
153-
}
113+
if ( preg_match('/^get(.+)$/', $method, $regs) ) {
114+
$data_key = lcfirst($regs[1]);
154115

155-
/**
156-
* Gets icon url.
157-
*
158-
* @return string
159-
*/
160-
public function getIconUrl()
161-
{
162-
return $this->iconUrl;
163-
}
116+
if ( in_array($data_key, $this->_acceptableKeys) ) {
117+
return array_key_exists($data_key, $this->_data) ? $this->_data[$data_key] : null;
118+
}
119+
}
164120

165-
/**
166-
* Gets avatar id.
167-
*
168-
* @return string
169-
*/
170-
public function getAvatarId()
171-
{
172-
return $this->avatarId;
121+
throw new \Exception('The "' . __CLASS__ . '::' . $method . '" method does not exist.');
173122
}
174123

175124
}

tests/Jira/ApiTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use chobie\Jira\Api;
77
use chobie\Jira\Api\Authentication\AuthenticationInterface;
88
use chobie\Jira\Api\Result;
9+
use chobie\Jira\IssueType;
910
use PHPUnit\Framework\TestCase;
1011
use Prophecy\Prophecy\ObjectProphecy;
1112

@@ -289,6 +290,28 @@ public function testGetPriorities()
289290
$this->assertEquals($expected, $this->api->getPriorities(), 'Calling twice did not yield the same results');
290291
}
291292

293+
public function testGetIssueTypes()
294+
{
295+
$response = file_get_contents(__DIR__ . '/resources/api_issue_types.json');
296+
297+
$this->expectClientCall(
298+
Api::REQUEST_GET,
299+
'/rest/api/2/issuetype',
300+
array(),
301+
$response
302+
);
303+
304+
$actual = $this->api->getIssueTypes();
305+
306+
$response_decoded = json_decode($response, true);
307+
308+
$expected = array(
309+
new IssueType($response_decoded[0]),
310+
new IssueType($response_decoded[1]),
311+
);
312+
$this->assertEquals($expected, $actual);
313+
}
314+
292315
/**
293316
* Expects a particular client call.
294317
*

tests/Jira/IssueTypeTest.php

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,83 @@
55

66
use chobie\Jira\IssueType;
77
use PHPUnit\Framework\TestCase;
8+
use Yoast\PHPUnitPolyfills\Polyfills\ExpectException;
89

910
class IssueTypeTest extends TestCase
1011
{
12+
use ExpectException;
1113

1214
public function testHandlesSingleIssueTypeWithAvatarId()
1315
{
14-
$issueTypeSource = array(
15-
'self' => 'https://hosted.atlassian.net/rest/api/2/issuetype/4',
16-
'id' => '4',
17-
'description' => 'An improvement or enhancement to an existing feature or task.',
18-
'iconUrl' => 'https://hosted.atlassian.net/secure/viewavatar?size=xsmall&avatarId=1&avatarType=issuetype',
19-
'name' => 'Improvement',
20-
'subtask' => false,
21-
'avatarId' => 1,
16+
$issue_type_source = array(
17+
'self' => 'https://hosted.atlassian.net/rest/api/2/issuetype/4',
18+
'id' => '4',
19+
'description' => 'An improvement or enhancement to an existing feature or task.',
20+
'entityId' => '9d7dd6f7-e8b6-4247-954b-7b2c9b2a5ba2',
21+
'iconUrl' => 'https://hosted.atlassian.net/secure/viewavatar?size=xsmall&avatarId=1&avatarType=issuetype',
22+
'name' => 'Improvement',
23+
'scope' => array(
24+
'project' => array('id' => '10000'),
25+
'type' => 'PROJECT',
26+
),
27+
'untranslatedName' => 'Epic',
28+
'subtask' => false,
29+
'hierarchyLevel' => 1,
30+
'avatarId' => 1,
2231
);
23-
$issueType = new IssueType($issueTypeSource);
24-
$this->assertEquals($issueType->getId(), $issueTypeSource['id']);
25-
$this->assertEquals($issueType->getDescription(), $issueTypeSource['description']);
26-
$this->assertEquals($issueType->getIconUrl(), $issueTypeSource['iconUrl']);
27-
$this->assertEquals($issueType->getName(), $issueTypeSource['name']);
28-
$this->assertEquals($issueType->getAvatarId(), $issueTypeSource['avatarId']);
32+
$issue_type = new IssueType($issue_type_source);
33+
$this->assertEquals($issue_type->getSelf(), $issue_type_source['self']);
34+
$this->assertEquals($issue_type->getId(), $issue_type_source['id']);
35+
$this->assertEquals($issue_type->getDescription(), $issue_type_source['description']);
36+
$this->assertEquals($issue_type->getEntityId(), $issue_type_source['entityId']);
37+
$this->assertEquals($issue_type->getIconUrl(), $issue_type_source['iconUrl']);
38+
$this->assertEquals($issue_type->getName(), $issue_type_source['name']);
39+
$this->assertEquals($issue_type->getScope(), $issue_type_source['scope']);
40+
$this->assertEquals($issue_type->isSubtask(), $issue_type_source['subtask']);
41+
$this->assertEquals($issue_type->getUntranslatedName(), $issue_type_source['untranslatedName']);
42+
$this->assertEquals($issue_type->getHierarchyLevel(), $issue_type_source['hierarchyLevel']);
43+
$this->assertEquals($issue_type->getAvatarId(), $issue_type_source['avatarId']);
2944
}
3045

3146
public function testHandlesSingleIssueTypeWithoutAvatarId()
3247
{
33-
$issueTypeSource = array(
48+
$issue_type_source = array(
3449
'self' => 'https://hosted.atlassian.net/rest/api/2/issuetype/4',
3550
'id' => '4',
3651
'description' => 'An improvement or enhancement to an existing feature or task.',
3752
'iconUrl' => 'https://hosted.atlassian.net/secure/viewavatar?size=xsmall&avatarId=1&avatarType=issuetype',
3853
'name' => 'Improvement',
3954
'subtask' => false,
4055
);
41-
$issueType = new IssueType($issueTypeSource);
42-
$this->assertEquals($issueType->getId(), $issueTypeSource['id']);
43-
$this->assertEquals($issueType->getDescription(), $issueTypeSource['description']);
44-
$this->assertEquals($issueType->getIconUrl(), $issueTypeSource['iconUrl']);
45-
$this->assertEquals($issueType->getName(), $issueTypeSource['name']);
56+
$issue_type = new IssueType($issue_type_source);
57+
$this->assertEquals($issue_type->getId(), $issue_type_source['id']);
58+
$this->assertEquals($issue_type->getDescription(), $issue_type_source['description']);
59+
$this->assertEquals($issue_type->getIconUrl(), $issue_type_source['iconUrl']);
60+
$this->assertEquals($issue_type->getName(), $issue_type_source['name']);
61+
}
62+
63+
public function testGettingUnknownProperty()
64+
{
65+
$issue_type_source = array(
66+
'self' => 'https://hosted.atlassian.net/rest/api/2/issuetype/4',
67+
);
68+
$issue_type = new IssueType($issue_type_source);
69+
70+
$this->expectException(\Exception::class);
71+
$this->expectExceptionMessage('The "chobie\Jira\IssueType::getUnknown" method does not exist.');
72+
$issue_type->getUnknown();
73+
}
74+
75+
public function testCreatingWithUnknownField()
76+
{
77+
$this->expectException(\Exception::class);
78+
$this->expectExceptionMessage('The "unknown" issue type keys are not supported.');
79+
80+
$issue_type_source = array(
81+
'self' => 'https://hosted.atlassian.net/rest/api/2/issuetype/4',
82+
'unknown' => '4',
83+
);
84+
new IssueType($issue_type_source);
4685
}
4786

4887
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[
2+
{
3+
"self": "https://test.atlassian.net/rest/api/2/issuetype/10000",
4+
"id": "10000",
5+
"description": "A big user story that needs to be broken down. Created by Jira Software - do not edit or delete.",
6+
"iconUrl": "https://test.atlassian.net/images/icons/issuetypes/epic.svg",
7+
"name": "Epic",
8+
"untranslatedName": "Epic",
9+
"subtask": false,
10+
"hierarchyLevel": 1
11+
},
12+
{
13+
"self": "https://test.atlassian.net/rest/api/2/issuetype/10034",
14+
"id": "10034",
15+
"description": "A problem which impairs or prevents the functions of the product. (Migrated on 31 Aug 2024 07:01 UTC)",
16+
"iconUrl": "https://test.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10300?size=medium",
17+
"name": "Bug Report",
18+
"untranslatedName": "Bug Report",
19+
"subtask": false,
20+
"avatarId": 10300,
21+
"hierarchyLevel": 0
22+
}
23+
]

0 commit comments

Comments
 (0)