Completed
Branch master (d2829c)
by Marek
05:16 queued 02:32
created

ExternalLibraryJiraService   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 78.48%

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 11
dl 0
loc 177
ccs 62
cts 79
cp 0.7848
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A onApplicationInitialized() 0 10 3
A validateCredentials() 0 19 3
B fetchTicketsByStatus() 0 24 3
A fetchAllTickets() 0 20 2
A flattenArray() 0 9 2
A createUrl() 0 8 1
A mapToJiraTicket() 0 15 4
A dispatchJiraTicketMappedEvent() 0 7 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace AppBuilder\Application\Module\Jira;
6
7
use AppBuilder\Application\Module\HttpClient\ExternalLibraryHttpClient;
8
use AppBuilder\Application\Module\Jira\Exception\InvalidJiraStatusException;
9
use AppBuilder\Application\Module\Jira\Exception\NullResultReturned;
10
use AppBuilder\Application\Module\Jira\ValueObject\JiraTicketStatus;
11
use AppBuilder\Application\Utils\Mapper\Factory\JiraMapperFactory;
12
use AppBuilder\Event\Application\ApplicationInitializedEvent;
13
use AppBuilder\Event\Application\ApplicationInitializedEventAware;
14
use AppBuilder\Event\Application\JiraTicketMappedEvent;
15
use GuzzleHttp\Exception\ClientException;
16
use GuzzleHttp\Exception\ConnectException;
17
use Psr\Log\LoggerInterface;
18
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
19
20
class ExternalLibraryJiraService implements JiraService, ApplicationInitializedEventAware
21
{
22
    /** @var ExternalLibraryHttpClient */
23
    private $httpClient;
24
25
    /** @var LoggerInterface */
26
    private $logger;
27
28
    /** @var EventDispatcherInterface */
29
    private $dispatcher;
30
31
    /** @var QueryRepository */
32
    private $queryRepository;
33
34 4
    public function __construct(
35
        ExternalLibraryHttpClient $httpClient,
36
        LoggerInterface $logger,
37
        EventDispatcherInterface $dispatcher,
38
        QueryRepository $queryRepository
39
    ) {
40 4
        $this->httpClient      = $httpClient;
41 4
        $this->logger          = $logger;
42 4
        $this->dispatcher      = $dispatcher;
43 4
        $this->queryRepository = $queryRepository;
44 4
    }
45
46
    /**
47
     * Service connects to JIRA with specified credentials when event occurs.
48
     * If connected successfully, fetches all tickets from JIRA.
49
     */
50
    public function onApplicationInitialized(ApplicationInitializedEvent $event = null) : void
51
    {
52
        if ($this->validateCredentials()) {
53
            try {
54
                $this->fetchAllTickets();
55
            } catch (NullResultReturned $exception) {
56
                $this->logger->warning($exception->getMessage(), [$exception]);
57
            }
58
        }
59
    }
60
61
    /**
62
     * Method uses provided credentials to connect JIRA.
63
     * If successful returns true. If credentials are invalid.
64
     * JiraException is thrown.
65
     */
66
    public function validateCredentials() : bool
67
    {
68
        try {
69
            $this->httpClient->request(
70
                ExternalLibraryHttpClient::GET,
71
                $this->createUrl($this->queryRepository->validateCredentials())
72
            );
73
74
            return true;
75
        } catch (ClientException $exception) {
76
            $this->logger->warning('Invalid login or password');
77
78
            return false;
79
        } catch (ConnectException $exception) {
80
            $this->logger->warning('Invalid host');
81
82
            return false;
83
        }
84
    }
85
86
    /**
87
     * Fetches tickets with passed status and passes them to flattenArray method.
88
     *
89
     * @throws NullResultReturned
90
     */
91 2
    public function fetchTicketsByStatus(string $status) : void
92
    {
93 2
        $tickets = null;
94
        try {
95
            $response = $this
96 2
                ->httpClient->request(
97 2
                    ExternalLibraryHttpClient::GET,
98
                    $this
99 2
                        ->createUrl($this
100 2
                            ->queryRepository
101 2
                            ->fetchTicketsByStatus(JiraTicketStatus::createFromString($status)->status()))
102
                );
103 1
            $this->logger->info('Tickets fetched.');
104
105 1
            $tickets = json_decode($response->getBody()->getContents(), true);
106 1
        } catch (InvalidJiraStatusException $exception) {
107 1
            $this->logger->warning('Error: ' . $exception->getMessage(), [$exception]);
108
        }
109
110 2
        if (null === $tickets) {
111 1
            throw new NullResultReturned('Error. Fetching method returned null');
112
        }
113 1
        $this->flattenArray($tickets);
114 1
    }
115
116
    /**
117
     * Fetches all tickets and passes them to flattenArray method.
118
     *
119
     * @throws NullResultReturned
120
     */
121 2
    public function fetchAllTickets() : void
122
    {
123
        $response = $this
124 2
            ->httpClient->request(
125 2
                ExternalLibraryHttpClient::GET,
126
                $this
127 2
                    ->createUrl($this
128 2
                        ->queryRepository
129 2
                        ->fetchAllTickets())
130
            );
131 2
        $content = $response->getBody()->getContents();
132
133 2
        $tickets = json_decode($content, true);
134
135 2
        $this->logger->info('Tickets fetched.');
136 2
        if (null === $tickets) {
137 1
            throw new NullResultReturned('Error. Fetching method returned null');
138
        }
139 1
        $this->flattenArray($tickets);
140 1
    }
141
142
    /**
143
     * Reconstructs array structure.
144
     */
145 2
    private function flattenArray(array $tickets) : void
146
    {
147 2
        $ticketsArray = [];
148 2
        foreach ($tickets['issues'] as $issue) {
149 2
            $ticketsArray[$issue['key']] = $issue;
150
        }
151
152 2
        $this->mapToJiraTicket($ticketsArray);
153 2
    }
154
155
    /**
156
     * Combines jira rest api url with jql.
157
     */
158 3
    private function createUrl(string $jql) : string
159
    {
160 3
        return $this->httpClient->applicationParams()->jiraHost()
161 3
            . '/rest/api/2/search?jql='
162 3
            . $jql
163 3
            . '&maxResults='
164 3
            . $this->httpClient->applicationParams()->jiraSearchMaxResults();
165
    }
166
167
    /**
168
     * Maps and filters array with full Jira ticket into desired array format.
169
     */
170 2
    private function mapToJiraTicket(array $tickets) : void
171
    {
172 2
        $mappedTickets = [];
173 2
        $ticketMappers = [];
174 2
        foreach ($tickets as $key => $value) {
175 2
            $ticketMappers[$key] = JiraMapperFactory::create();
176 2
            foreach ($ticketMappers[$key] as $mapper) {
177 2
                $mappedTickets[$key][$mapper->outputKey()] = $mapper->map($value);
178
            }
179
        }
180 2
        $this->logger->info('Tickets mapped.');
181 2
        foreach ($mappedTickets as $mappedTicket) {
182 2
            $this->dispatchJiraTicketMappedEvent($mappedTicket);
183
        }
184 2
    }
185
186
    /**
187
     * Dispatches JiraTicketMappedEvent.
188
     */
189 2
    private function dispatchJiraTicketMappedEvent(array $ticket) : void
190
    {
191 2
        $this->dispatcher->dispatch(
192 2
            JiraTicketMappedEvent::NAME,
193 2
            new JiraTicketMappedEvent($ticket)
194
        );
195 2
    }
196
}
197