DatabaseDoorsRepository.php 5.22 KB
Newer Older
1
2
3
4
5
<?php


namespace Source\Gateways\Doors;

6
use Carbon\Carbon;
7
use Source\Entities\Door;
Jacob Priddy's avatar
Jacob Priddy committed
8
use Source\Sanitize\CastsTo;
9
use Illuminate\Support\Facades\Log;
10
use Source\Entities\HashedSearchable;
11
use Source\Gateways\PostgresSQLCodes;
12
use Illuminate\Database\QueryException;
Jacob Priddy's avatar
Jacob Priddy committed
13
use Source\Exceptions\EntityExistsException;
Jacob Priddy's avatar
Jacob Priddy committed
14
use Source\Exceptions\EntityNotFoundException;
15

Jacob Priddy's avatar
Jacob Priddy committed
16
17
class DatabaseDoorsRepository implements DoorsRepository
{
Jacob Priddy's avatar
Jacob Priddy committed
18
19
    use CastsTo;

20
    /**
21
22
23
     * @param \App\Door             $dbDoor
     * @param \Source\Entities\Door $door
     * @throws \Source\Exceptions\EntityExistsException
24
     */
25
    protected function saveDoor(\App\Door $dbDoor, Door $door): void
Jacob Priddy's avatar
Jacob Priddy committed
26
    {
27
28
29
        $dbDoor->setAttribute('location', $door->getLocation());
        $dbDoor->setAttribute('name', $door->getName());
        $dbDoor->setAttribute('api_token', $door->getToken()->getHash());
30
31
        $dbDoor->setAttribute('version', $door->getVersion());
        $dbDoor->setAttribute('last_seen_at', $door->getLastSeenAt());
Jacob Priddy's avatar
Jacob Priddy committed
32

33
34
35
        try {
            $dbDoor->save();
        } catch (QueryException $e) {
36
37
            if ($e->getCode() === PostgresSQLCodes::UNIQUE_CONSTRAINT_VIOLATION) {
                throw new EntityExistsException('Cannot save door. Door already exists.');
38
39
            }

40
            Log::error('Failed saving door: ' . $e);
41
42

            throw $e;
Jacob Priddy's avatar
Jacob Priddy committed
43
        }
44
45
46
47
48
49
50
51
52
53
    }

    /**
     * @inheritDoc
     */
    public function create(Door $door): Door
    {
        $dbDoor = new \App\Door();

        $this->saveDoor($dbDoor, $door);
54

Jacob Priddy's avatar
Jacob Priddy committed
55
        return self::makeDoorFromDb($dbDoor);
56
57
    }

Jacob Priddy's avatar
Jacob Priddy committed
58
59
60
    public static function makeDoorFromDb(\App\Door $door): Door
    {
        return new Door(
61
62
63
64
            $door->getAttribute('id'),
            $door->getAttribute('location'),
            $door->getAttribute('name'),
            new HashedSearchable($door->getAttribute('api_token')),
65
            $door->getAttribute('version'),
66
67
68
            $door->getAttribute('created_at'),
            $door->getAttribute('updated_at'),
            $door->getAttribute('last_seen_at')
Jacob Priddy's avatar
Jacob Priddy committed
69
70
71
        );
    }

72
73
74
    /**
     * @inheritDoc
     */
75
    public function getByToken(?HashedSearchable $token): ?Door
Jacob Priddy's avatar
Jacob Priddy committed
76
    {
Jacob Priddy's avatar
Jacob Priddy committed
77
78
79
80
        if (!$token) {
            return null;
        }

81
82
        /** @var \App\Door|null $door */
        $door = \App\Door::query()->where('api_token', $token->getHash())->first();
83

84
        if (!$door) {
85
86
87
            return null;
        }

88
        return self::makeDoorFromDb($door);
89
    }
90

91
92
93
94
95
96
97
98
99
100
101
102
103
104
    /**
     * @inheritDoc
     */
    public function touch(string $doorId, Carbon $seen, ?string $version): void
    {
        $updated = [
            'last_seen_at' => $seen,
        ];

        // If we have a new version to set, set it.
        if ($version) {
            $updated['version'] = $version;
        }

105
        \App\Door::query()->where('id', self::castToInt($doorId))->update($updated);
106
107
    }

108
109
110
111
112
    /**
     * @inheritDoc
     */
    public function get(string $doorId): ?Door
    {
113
        /** @var \App\Door|null $door */
114
        $door = \App\Door::query()->find(self::castToInt($doorId));
115
        if (!$door) {
Jacob Priddy's avatar
Jacob Priddy committed
116
117
118
119
120
121
122
123
124
            return null;
        }

        return self::makeDoorFromDb($door);
    }

    /**
     * @inheritDoc
     */
125
    public function search(?string $query = null): array
Jacob Priddy's avatar
Jacob Priddy committed
126
    {
Jacob Priddy's avatar
Jacob Priddy committed
127
        if (!$query) {
128
129
130
            $doors = \App\Door::all()->values()->all();
        } else {
            $doors = \App\Door::query()
131
                ->where('location', 'ILIKE', "%$query%")
132
133
                ->orWhere('name', 'ILIKE', "%$query%")
                ->orWhere('version', 'ILIKE', "%$query%")
134
135
                ->get()->values()->all();
        }
Jacob Priddy's avatar
Jacob Priddy committed
136
137
138
139

        return array_map(
            static function (\App\Door $door) {
                return self::makeDoorFromDb($door);
Jacob Priddy's avatar
Jacob Priddy committed
140
141
            },
            $doors
Jacob Priddy's avatar
Jacob Priddy committed
142
        );
143
    }
Jacob Priddy's avatar
Jacob Priddy committed
144
145
146
147
148
149
150
151
152
153

    /**
     * @inheritDoc
     */
    public function findByName(?string $name): ?Door
    {
        if (!$name) {
            return null;
        }

154
155
156
157
158
159
160
161
        /** @var \App\Door|null $door */
        $door = \App\Door::query()->where('name', $name)->first();

        if (!$door) {
            return null;
        }

        return self::makeDoorFromDb($door);
Jacob Priddy's avatar
Jacob Priddy committed
162
    }
163
164
165
166

    /**
     * @inheritDoc
     */
Jacob Priddy's avatar
Jacob Priddy committed
167
    public function update(string $doorId, Door $door): Door
168
    {
169
        /** @var \App\Door|null $dbDoor */
170
        $dbDoor = \App\Door::query()->find(self::castToInt($doorId));
171
172

        if (!$dbDoor) {
Jacob Priddy's avatar
Jacob Priddy committed
173
            throw new EntityNotFoundException('Could not update door. Door not found.');
174
175
        }

176
        $this->saveDoor($dbDoor, $door);
177
178
179

        return self::makeDoorFromDb($dbDoor);
    }
Jacob Priddy's avatar
Jacob Priddy committed
180
181
182
183

    /**
     * @inheritDoc
     */
Jacob Priddy's avatar
Jacob Priddy committed
184
    public function delete(string $doorId): int
Jacob Priddy's avatar
Jacob Priddy committed
185
    {
186
        return \App\Door::destroy(self::castToInt($doorId));
Jacob Priddy's avatar
Jacob Priddy committed
187
    }
188
189
190
191
192
193
194
195

    /**
     * @inheritDoc
     */
    public function exists(string $doorId): bool
    {
        return (bool)$this->get($doorId);
    }
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210

    /**
     * @inheritDoc
     */
    public function awolFor(int $seconds): array
    {
        $doors = \App\Door::query()
            ->whereNotNull('last_seen_at')
            ->where('last_seen_at', '<', Carbon::now()->subRealSeconds($seconds))
            ->get();

        return array_map(static function (\App\Door $door): Door {
            return self::makeDoorFromDb($door);
        }, $doors);
    }
211
}