Passed
Push — clockify ( ce42cc...cc6058 )
by Guillaume
32:58
created

Clockify   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Test Coverage

Coverage 92.31%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 92
c 2
b 0
f 1
dl 0
loc 193
ccs 84
cts 91
cp 0.9231
rs 10
wmc 24

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A workspaces() 0 9 2
A convertToPastTimers() 0 8 1
A deleteTimer() 0 3 1
A stopCurrentTimer() 0 24 3
A projects() 0 14 2
A tags() 0 11 2
A pastTimers() 0 17 2
A startTimer() 0 24 4
A continueTimer() 0 7 1
A runningTimer() 0 16 2
A buildPastTimerObject() 0 18 3
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 78
    public function __construct($apiToken)
16
    {
17 78
        $this->client = new Client([
18 78
            'base_uri' => 'https://api.clockify.me/api/v1/',
19
            'headers' => [
20 78
                'content-type' => 'application/json',
21 78
                'X-Api-Key' => $apiToken
22
            ]
23
        ]);
24 78
    }
25
26 12
    public function workspaces()
27
    {
28
        try {
29 12
            $response = $this->client->get('workspaces');
30 6
            $workspaces = json_decode($response->getBody()->getContents());
31
32 6
            return array_column($workspaces, 'name', 'id');
33 6
        } catch (\Exception $e) {
34 6
            return [];
35
        }
36
    }
37
38 18
    public function projects()
39
    {
40
        try {
41 18
            $user = json_decode(
42 18
                $this->client->get("user")->getBody()->getContents()
43
            );
44
45 12
            $response = $this->client->get("workspaces/{$user->activeWorkspace}/projects");
46
47 12
            $projects = json_decode($response->getBody()->getContents());
48
49 12
            return array_column($projects, 'name', 'id');
50 6
        } catch (\Exception $e) {
51 6
            return [];
52
        }
53
    }
54
55 18
    public function tags()
56
    {
57
        try {
58 18
            $workspaceId = getenv('timer_workspace_id');
59
60 18
            $response = $this->client->get("workspaces/$workspaceId/tags");
61 12
            $tags = json_decode($response->getBody()->getContents());
62
63 12
            return array_column($tags, 'name', 'id');
64 6
        } catch (\Exception $e) {
65 6
            return [];
66
        }
67
    }
68
69 30
    public function startTimer()
70
    {
71
        try {
72 30
            $workspaceId = getenv('timer_workspace_id');
73
74 30
            $response = $this->client->post("workspaces/$workspaceId/time-entries", [
75 10
                'json' => [
76 30
                    'start' => (new \DateTime())->format('Y-m-d\TH:i:s\Z'),
77 30
                    'description' => getenv('timer_description'),
78 30
                    'projectId' => getenv('timer_project_id'),
79 30
                    'tagIds' => getenv('timer_tag_id') ? [getenv('timer_tag_id')] : [''],
80
                ]
81
            ]);
82
83 30
            $timer = json_decode($response->getBody()->getContents());
84
85 30
            if (! isset($timer->id)) {
86 30
                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 30
        return $timer->id;
93
    }
94
95 30
    public function stopCurrentTimer()
96
    {
97 30
        $workspaceId = getenv('timer_workspace_id');
98 30
        $userId = getenv('timer_user_id');
99
100 30
        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 30
            $response = $this->client->patch("workspaces/$workspaceId/user/$userId/time-entries", [
102
                'json' => [
103 30
                    'end' => (new \DateTime())->format('Y-m-d\TH:i:s\Z'),
104
                ]
105
            ]) ;
106
107 30
            $timer = json_decode($response->getBody()->getContents());
108
109 30
            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 30
            return true;
116
        }
117
118 6
        return false;
119
    }
120
121 78
    public function runningTimer()
122
    {
123
        try {
124 78
            $workspaceId = getenv('timer_workspace_id');
125 78
            $userId = getenv('timer_user_id');
126
127 78
            $response = $this->client->get("workspaces/$workspaceId/user/$userId/time-entries?in-progress=true");
128
129 78
            $timer = json_decode($response->getBody()->getContents());
130
131 78
            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 6
    public function pastTimers()
140
    {
141
        try {
142 6
            $pastTimers = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $pastTimers is dead and can be removed.
Loading history...
143
144 6
            $workspaceId = getenv('timer_workspace_id');
145 6
            $userId = getenv('timer_user_id');
146
147 6
            $response = $this->client->get("workspaces/$workspaceId/user/$userId/time-entries", [
148 6
                'start' => Carbon::today(),
149 6
                'end' => Carbon::today()->subDays(30),
150
            ]);
151 6
            $clockifyTimers = json_decode($response->getBody()->getContents());
152
153 6
            return $this->convertToPastTimers($clockifyTimers);
154
        } catch (Exception $e) {
155
            return [];
156
        }
157
    }
158
159 6
    public function continueTimer($timerId = null)
160
    {
161
        /**
162
         * Timer attributes are stored in env variables
163
         * gathered in startTimer.
164
         */
165 6
        return $this->startTimer();
166
    }
167
168 6
    public function deleteTimer($timerId)
169
    {
170 6
        return false;
171
    }
172
173 6
    protected function convertToPastTimers($clockifyTimers)
174
    {
175 6
        $projects = $this->projects();
176 6
        $tags = $this->tags();
177
178
        return array_map(function ($clockifyTimer) use ($projects, $tags) {
179 6
            return $this->buildPastTimerObject($clockifyTimer, $projects, $tags);
180 6
        }, $clockifyTimers);
181
    }
182
183 6
    protected function buildPastTimerObject($clockifyTimer, $projects, $tags)
184
    {
185 6
        $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 6
        $pastTimer['description'] = $clockifyTimer->description;
187
188 6
        if (isset($clockifyTimer->projectId)) {
189 6
            $pastTimer['project_id'] = $clockifyTimer->projectId;
190 6
            $pastTimer['project_name'] = $projects[$clockifyTimer->projectId];
191
        }
192
193 6
        if (isset($clockifyTimer->tagIds[0])) {
194 6
            $pastTimer['tag_id'] = $clockifyTimer->tagIds[0];
195 6
            $pastTimer['tags'] = $tags[$clockifyTimer->tagIds[0]];
196
        }
197
198 6
        $pastTimer['duration'] = $clockifyTimer->timeInterval->duration;
199
200 6
        return (object) $pastTimer;
201
    }
202
}
203