Passed
Pull Request — master (#30)
by Guillaume
34:31 queued 32:55
created

Clockify::startTimer()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4.0466

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 4
eloc 14
nc 5
nop 0
dl 0
loc 24
ccs 12
cts 14
cp 0.8571
crap 4.0466
rs 9.7998
c 1
b 0
f 1
1
<?php
2
3
namespace Godbout\Alfred\Time\Services;
4
5
use Carbon\Carbon;
6
use GuzzleHttp\Client;
7
8
class Clockify extends TimerService
9
{
10
    private $client;
11
12
    private $data = null;
0 ignored issues
show
introduced by
The private property $data is not used, and could be removed.
Loading history...
13
14
15 90
    public function __construct($apiToken)
16
    {
17 90
        $this->client = new Client([
18 90
            'base_uri' => 'https://api.clockify.me/api/v1/',
19
            'headers' => [
20 90
                'content-type' => 'application/json',
21 90
                'X-Api-Key' => $apiToken
22
            ]
23
        ]);
24 90
    }
25
26 12
    public function workspaces()
27
    {
28
        try {
29 12
            $response = $this->client->get('workspaces');
30 10
            $workspaces = json_decode($response->getBody()->getContents());
31
32 10
            return array_column($workspaces, 'name', 'id');
33 2
        } catch (\Exception $e) {
34 2
            return [];
35
        }
36
    }
37
38 22
    public function projects()
39
    {
40
        try {
41 22
            $user = json_decode(
42 22
                $this->client->get("user")->getBody()->getContents()
43
            );
44
45 20
            $response = $this->client->get("workspaces/{$user->activeWorkspace}/projects");
46
47 20
            $projects = json_decode($response->getBody()->getContents());
48
49 20
            return array_column($projects, 'name', 'id');
50 2
        } catch (\Exception $e) {
51 2
            return [];
52
        }
53
    }
54
55 22
    public function tags()
56
    {
57
        try {
58 22
            $workspaceId = getenv('timer_workspace_id');
59
60 22
            $response = $this->client->get("workspaces/$workspaceId/tags");
61 20
            $tags = json_decode($response->getBody()->getContents());
62
63 20
            return array_column($tags, 'name', 'id');
64 2
        } catch (\Exception $e) {
65 2
            return [];
66
        }
67
    }
68
69 50
    public function startTimer()
70
    {
71
        try {
72 50
            $workspaceId = getenv('timer_workspace_id');
73
74 50
            $response = $this->client->post("workspaces/$workspaceId/time-entries", [
75 20
                'json' => [
76 50
                    'start' => (new \DateTime())->format('Y-m-d\TH:i:s\Z'),
77 50
                    'description' => getenv('timer_description'),
78 50
                    'projectId' => getenv('timer_project_id'),
79 50
                    'tagIds' => getenv('timer_tag_id') ? [getenv('timer_tag_id')] : [''],
80
                ]
81
            ]);
82
83 50
            $timer = json_decode($response->getBody()->getContents());
84
85 50
            if (! isset($timer->id)) {
86 50
                return false;
87
            }
88
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The type Godbout\Alfred\Time\Services\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
89
            return false;
90
        }
91
92 50
        return $timer->id;
93
    }
94
95 50
    public function stopCurrentTimer()
96
    {
97 50
        $workspaceId = getenv('timer_workspace_id');
98 50
        $userId = getenv('timer_user_id');
99
100 50
        if ($timerId = $this->runningTimer()) {
0 ignored issues
show
Unused Code introduced by
The assignment to $timerId is dead and can be removed.
Loading history...
101 50
            $response = $this->client->patch("workspaces/$workspaceId/user/$userId/time-entries", [
102
                'json' => [
103 50
                    'end' => (new \DateTime())->format('Y-m-d\TH:i:s\Z'),
104
                ]
105
            ]) ;
106
107 50
            $timer = json_decode($response->getBody()->getContents());
108
109 50
            if (! isset($timer->timeInterval->end)) {
110
                throw new Exception("Can't stop current running timer.", 1);
111
112
                return false;
0 ignored issues
show
Unused Code introduced by
return false is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
113
            }
114
115 50
            return true;
116
        }
117
118 10
        return false;
119
    }
120
121 90
    public function runningTimer()
122
    {
123
        try {
124 90
            $workspaceId = getenv('timer_workspace_id');
125 90
            $userId = getenv('timer_user_id');
126
127 90
            $response = $this->client->get("workspaces/$workspaceId/user/$userId/time-entries?in-progress=true");
128
129 90
            $timer = json_decode($response->getBody()->getContents());
130
131 90
            return $timer[0]->id ?? false;
132
        } catch (\Exception $e) {
133
            return false;
134
        }
135
136
        return true;
0 ignored issues
show
Unused Code introduced by
return true is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
137
    }
138
139 10
    public function pastTimers()
140
    {
141
        try {
142 10
            $pastTimers = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $pastTimers is dead and can be removed.
Loading history...
143
144 10
            $workspaceId = getenv('timer_workspace_id');
145 10
            $userId = getenv('timer_user_id');
146
147 10
            $response = $this->client->get("workspaces/$workspaceId/user/$userId/time-entries", [
148 10
                'start' => Carbon::today(),
149 10
                'end' => Carbon::today()->subDays(30),
150
            ]);
151 10
            $clockifyTimers = json_decode($response->getBody()->getContents());
152
153 10
            return $this->convertToPastTimers($clockifyTimers);
154
        } catch (Exception $e) {
155
            return [];
156
        }
157
    }
158
159 10
    public function continueTimer($timerId = null)
160
    {
161
        /**
162
         * Timer attributes are stored in env variables
163
         * gathered in startTimer.
164
         */
165 10
        return $this->startTimer();
166
    }
167
168 10
    public function deleteTimer($timerId)
169
    {
170 10
        return false;
171
    }
172
173 10
    protected function convertToPastTimers($clockifyTimers)
174
    {
175 10
        $projects = $this->projects();
176 10
        $tags = $this->tags();
177
178
        return array_map(function ($clockifyTimer) use ($projects, $tags) {
179 10
            return $this->buildPastTimerObject($clockifyTimer, $projects, $tags);
180 10
        }, $clockifyTimers);
181
    }
182
183 10
    protected function buildPastTimerObject($clockifyTimer, $projects, $tags)
184
    {
185 10
        $pastTimer['id'] = $clockifyTimer->id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$pastTimer was never initialized. Although not strictly required by PHP, it is generally a good practice to add $pastTimer = array(); before regardless.
Loading history...
186 10
        $pastTimer['description'] = $clockifyTimer->description;
187
188 10
        if (isset($clockifyTimer->projectId)) {
189 10
            $pastTimer['project_id'] = $clockifyTimer->projectId;
190 10
            $pastTimer['project_name'] = $projects[$clockifyTimer->projectId];
191
        }
192
193 10
        if (isset($clockifyTimer->tagIds[0])) {
194 10
            $pastTimer['tag_id'] = $clockifyTimer->tagIds[0];
195 10
            $pastTimer['tags'] = $tags[$clockifyTimer->tagIds[0]];
196
        }
197
198 10
        $pastTimer['duration'] = $clockifyTimer->timeInterval->duration;
199
200 10
        return (object) $pastTimer;
201
    }
202
}
203