JiraHandler::parseProjectId()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Artack\Monolog\JiraHandler;
6
7
use Http\Client\Common\Plugin\AuthenticationPlugin;
8
use Http\Client\Common\Plugin\ContentLengthPlugin;
9
use Http\Client\Common\Plugin\HeaderDefaultsPlugin;
10
use Http\Client\Common\PluginClient;
11
use Http\Client\HttpClient;
12
use Http\Discovery\HttpClientDiscovery;
13
use Http\Discovery\Psr17FactoryDiscovery;
14
use Http\Message\Authentication\BasicAuth;
15
use Monolog\Logger;
16
17
class JiraHandler extends BatchHandler
18
{
19
    private $hostname;
20
    private $jql;
21
    private $hashFieldName;
22
    private $projectKey;
23
    private $issueTypeName;
24
    private $withComments;
25
    private $counterFieldName;
26
27
    private $requestFactory;
28
    private $urlFactory;
29
    private $streamFactory;
30
    private $httpClient;
31
32
    private $createdIssueId;
33
34 2
    public function __construct(string $hostname, string $username, string $password, string $jql, string $hashFieldName, string $projectKey, string $issueTypeName, bool $withComments = false, string $counterFieldName = null, HttpClient $httpClient = null, $level = Logger::DEBUG, $bubble = true)
35
    {
36 2
        parent::__construct($level, $bubble);
37
38 2
        $this->hostname = $hostname;
39 2
        $this->jql = $jql;
40 2
        $this->hashFieldName = $hashFieldName;
41 2
        $this->projectKey = $projectKey;
42 2
        $this->issueTypeName = $issueTypeName;
43 2
        $this->withComments = $withComments;
44 2
        $this->counterFieldName = $counterFieldName;
45
46 2
        $authentication = new BasicAuth($username, $password);
47 2
        $authenticationPlugin = new AuthenticationPlugin($authentication);
48
49 2
        $contentLengthPlugin = new ContentLengthPlugin();
50 2
        $headerDefaultsPlugin = new HeaderDefaultsPlugin([
51 2
            'Content-Type' => 'application/json',
52
        ]);
53
54 2
        $this->requestFactory = Psr17FactoryDiscovery::findRequestFactory();
55 2
        $this->urlFactory = Psr17FactoryDiscovery::findUrlFactory();
56 2
        $this->streamFactory = Psr17FactoryDiscovery::findStreamFactory();
57
58 2
        $this->httpClient = new PluginClient(
59 2
            $httpClient ?: HttpClientDiscovery::find(),
60 2
            [$authenticationPlugin, $headerDefaultsPlugin, $contentLengthPlugin]
61
        );
62 2
    }
63
64 2
    protected function send($content, array $records): void
65
    {
66 2
        $countFieldId = null;
67 2
        $highestRecord = $this->getHighestRecord($records);
68
69 2
        $recordForHash = $highestRecord;
70 2
        unset($recordForHash['datetime'], $recordForHash['formatted'], $recordForHash['context']);
71 2
        $hash = md5(serialize($recordForHash));
72
73 2
        $uri = $this->urlFactory->createUri(sprintf('https://%s/rest/api/2/customFields', $this->hostname));
74 2
        $request = $this->requestFactory->createRequest('GET', $uri);
75 2
        $response = $this->httpClient->sendRequest($request);
76 2
        $data = json_decode($response->getBody()->getContents(), true);
77 2
        $hashFieldId = $this->parseCustomFieldId($data, 'values', $this->hashFieldName);
78
79 2
        if ($this->counterFieldName) {
80 2
            $countFieldId = $this->parseCustomFieldId($data, 'values', $this->counterFieldName);
81
        }
82
83 2
        $jql = sprintf('%s AND %s ~ \'%s\'', $this->jql, $this->hashFieldName, $hash);
84
85
        $fields = [
86 2
            'issuetype',
87 2
            'status',
88 2
            'summary',
89 2
            $hashFieldId,
90 2
            $this->counterFieldName,
91
        ];
92
93 2
        if ($countFieldId) {
94 2
            $fields[] = $countFieldId;
95
        }
96
97 2
        $body = json_encode([
98 2
            'jql' => $jql,
99 2
            'fields' => $fields,
100
        ]);
101
102 2
        $uri = $this->urlFactory->createUri(sprintf('https://%s/rest/api/2/search', $this->hostname));
103 2
        $request = $this->requestFactory->createRequest('POST', $uri)->withBody($this->streamFactory->createStream($body));
104 2
        $response = $this->httpClient->sendRequest($request);
105 2
        $data = json_decode($response->getBody()->getContents(), true);
106
107 2
        if ($data['total'] > 0) {
108 1
            $issueId = $data['issues'][0]['id'];
109
110 1
            if ($this->counterFieldName) {
111 1
                $countFieldValue = $data['issues'][0]['fields'][$countFieldId];
112
113 1
                $uri = $this->urlFactory->createUri(sprintf('https://%s/rest/api/2/issue/%d', $this->hostname, $issueId).'?'.http_build_query([
114 1
                    'notifyUsers' => false,
115
                ]));
116
                $rawBody = [
117
                    'fields' => [
118 1
                        $countFieldId => ++$countFieldValue,
119
                    ],
120
                ];
121 1
                $body = json_encode($rawBody);
122 1
                $request = $this->requestFactory->createRequest('PUT', $uri)->withBody($this->streamFactory->createStream($body));
123 1
                $this->httpClient->sendRequest($request);
124
            }
125
126 1
            if ($this->withComments) {
127 1
                $uri = $this->urlFactory->createUri(sprintf('https://%s/rest/api/2/issue/%d/comment', $this->hostname, $issueId));
128 1
                $body = json_encode([
129 1
                    'body' => $content,
130
                ]);
131 1
                $request = $this->requestFactory->createRequest('POST', $uri)->withBody($this->streamFactory->createStream($body));
132 1
                $this->httpClient->sendRequest($request);
133
            }
134
135 1
            return;
136
        }
137
138 1
        $uri = $this->urlFactory->createUri(sprintf('https://%s/rest/api/2/issue/createmeta', $this->hostname).'?'.http_build_query([
139 1
            'projectKeys' => $this->projectKey,
140 1
            'expand' => 'projects.issuetypes.fields',
141
        ]));
142 1
        $request = $this->requestFactory->createRequest('GET', $uri);
143 1
        $response = $this->httpClient->sendRequest($request);
144 1
        $data = json_decode($response->getBody()->getContents(), true);
145
146 1
        $projectId = $this->parseProjectId($data);
147 1
        $issueType = $this->parseIssueType($data, $this->issueTypeName);
148 1
        $issueTypeId = (int) $issueType['id'];
149 1
        $summary = sprintf('%s: %s', $highestRecord['level_name'], $highestRecord['message']);
150
151 1
        $body = json_encode([
152
            'fields' => [
153
                'project' => [
154 1
                    'id' => $projectId,
155
                ],
156 1
                'issuetype' => ['id' => $issueTypeId],
157 1
                'summary' => strlen($summary) > 255 ? substr($summary, 0, 252).'...' : $summary,
158 1
                'description' => $content,
159 1
                $hashFieldId => $hash,
160 1
                $countFieldId => 1,
161
            ],
162
        ]);
163 1
        $uri = $this->urlFactory->createUri(sprintf('https://%s/rest/api/2/issue', $this->hostname));
164 1
        $request = $this->requestFactory->createRequest('POST', $uri)->withBody($this->streamFactory->createStream($body));
165 1
        $response = $this->httpClient->sendRequest($request);
166 1
        $data = json_decode($response->getBody()->getContents(), true);
167 1
        $this->createdIssueId = $data['id'];
168 1
    }
169
170 1
    protected function parseProjectId(array $data): int
171
    {
172 1
        return (int) $data['projects'][0]['id'];
173
    }
174
175 1
    protected function parseIssueType(array $data, string $issueTypeName): array
176
    {
177
        return array_values(array_filter($data['projects'][0]['issuetypes'], function ($data) use ($issueTypeName) {
178 1
            return $data['name'] === $issueTypeName;
179 1
        }))[0];
180
    }
181
182 2
    protected function parseCustomFieldId(array $data, string $part, string $fieldName): string
183
    {
184
        return array_values(array_filter($data[$part], function ($item) use ($fieldName) {
185 2
            return $item['name'] === $fieldName;
186 2
        }))[0]['id'];
187
    }
188
189 1
    public function getCreatedIssueId()
190
    {
191 1
        return $this->createdIssueId;
192
    }
193
}
194