Passed
Pull Request — master (#30)
by Guillaume
36:47 queued 35:00
created

Toggl::stopCurrentTimer()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 0
dl 0
loc 15
ccs 6
cts 7
cp 0.8571
crap 3.0261
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Godbout\Alfred\Time\Services;
4
5
use Carbon\Carbon;
6
use Carbon\CarbonInterval;
7
use Exception;
8
use MorningTrain\TogglApi\TogglApi;
9
10
class Toggl extends TimerService
11
{
12
    private $client;
13
14
    private $data = null;
15
16
17 168
    public function __construct($apiToken)
18
    {
19 168
        $this->client = new TogglApi($apiToken);
20 168
    }
21
22 36
    public function projects()
23
    {
24 36
        return $this->extractFromData('projects');
25
    }
26
27 18
    public function tags()
28
    {
29 18
        return $this->extractFromData('tags');
30
    }
31
32 9
    public function pastTimers()
33
    {
34
        try {
35 9
            $togglTimers = $this->client->getTimeEntriesInRange(Carbon::today(), Carbon::today()->subDays(30));
36
37 9
            return $this->convertToPastTimers($togglTimers);
38
        } catch (Exception $e) {
39
            return [];
40
        }
41
    }
42
43 99
    public function startTimer()
44
    {
45
        try {
46 99
            $timer = $this->client->startTimeEntry([
47 99
                'description' => getenv('timer_description'),
48 99
                'pid' => getenv('timer_project_id'),
49 99
                'tags' => getenv('timer_tag') ? [getenv('timer_tag')] : '',
50 99
                'created_with' => 'Alfred Time'
51
            ]);
52
53 99
            if (! isset($timer->id)) {
54 99
                return false;
55
            }
56
        } catch (Exception $e) {
57
            return false;
58
        }
59
60 99
        return $timer->id;
61
    }
62
63 81
    public function stopCurrentTimer()
64
    {
65 81
        if ($timerId = $this->runningTimer()) {
66 81
            $response = $this->client->stopTimeEntry($timerId);
67
68 81
            if (! isset($response->id)) {
69
                throw new Exception("Can't stop current running timer.", 1);
70
71
                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...
72
            }
73
74 81
            return true;
75
        }
76
77 9
        return false;
78
    }
79
80 150
    public function runningTimer()
81
    {
82 150
        $timer = $this->client->getRunningTimeEntry();
83
84 150
        return $timer->id ?? false;
85
    }
86
87 18
    public function continueTimer($timerId)
88
    {
89
        /**
90
         * Timer attributes are stored in env variables
91
         * gathered in startTimer.
92
         */
93 18
        return $this->startTimer();
94
    }
95
96 99
    public function deleteTimer($timerId)
97
    {
98
        try {
99 99
            $this->client->deleteTimeEntry($timerId);
100
        } catch (Exception $e) {
101
            return false;
102
        }
103
104 99
        return true;
105
    }
106
107 54
    private function extractFromData($needle)
108
    {
109 54
        $data = $this->getData();
110
111 54
        if (! isset($data->$needle)) {
112 18
            return [];
113
        }
114
115 36
        $nonDeletedData = $this->filterOutServerwiseDeletedItemsFromData($data->$needle);
116
117 36
        return array_column($nonDeletedData, 'name', 'id');
118
    }
119
120 54
    private function getData()
121
    {
122 54
        if (is_null($this->data)) {
123 54
            return $this->client->getMe(true);
124
        }
125
126
        return $this->data;
127
    }
128
129 36
    private function filterOutServerwiseDeletedItemsFromData($items = [])
130
    {
131
        return array_filter($items, function ($item) {
132 36
            return ! isset($item->server_deleted_at);
133 36
        });
134
    }
135
136 9
    protected function convertToPastTimers($togglTimers)
137
    {
138 9
        $projects = $this->projects();
139
140 9
        return array_reverse(
141
            array_map(function ($togglTimer) use ($projects) {
142 9
                return $this->buildPastTimerObject($togglTimer, $projects);
143 9
            }, $togglTimers)
144
        );
145
    }
146
147 9
    protected function buildPastTimerObject($togglTimer, $projects)
148
    {
149 9
        $pastTimer['id'] = $togglTimer->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...
150 9
        $pastTimer['description'] = $togglTimer->description ?? '';
151 9
        $pastTimer['duration'] = CarbonInterval::seconds($togglTimer->duration)->cascade()->format('%H:%I:%S');
152
153 9
        if (isset($togglTimer->pid)) {
154 9
            $pastTimer['project_id'] = $togglTimer->pid;
155 9
            $pastTimer['project_name'] = $projects[$togglTimer->pid];
156
        }
157
158 9
        if (isset($togglTimer->tags)) {
159 9
            $pastTimer['tags'] = implode(', ', (array) $togglTimer->tags);
160
        }
161
162 9
        return (object) $pastTimer;
163
    }
164
}
165