Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
86 / 86 |
|
100.00% |
6 / 6 |
CRAP | |
100.00% |
1 / 1 |
LocationsController | |
100.00% |
86 / 86 |
|
100.00% |
6 / 6 |
12 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
index | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
1 | |||
edit | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
save | |
100.00% |
49 / 49 |
|
100.00% |
1 / 1 |
6 | |||
delete | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
2 | |||
showEdit | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Engelsystem\Controllers\Admin; |
6 | |
7 | use Engelsystem\Controllers\BaseController; |
8 | use Engelsystem\Controllers\HasUserNotifications; |
9 | use Engelsystem\Http\Exceptions\ValidationException; |
10 | use Engelsystem\Http\Redirector; |
11 | use Engelsystem\Http\Request; |
12 | use Engelsystem\Http\Response; |
13 | use Engelsystem\Http\Validation\Validator; |
14 | use Engelsystem\Models\AngelType; |
15 | use Engelsystem\Models\Location; |
16 | use Engelsystem\Models\Shifts\NeededAngelType; |
17 | use Illuminate\Database\Eloquent\Collection; |
18 | use Psr\Log\LoggerInterface; |
19 | |
20 | class LocationsController extends BaseController |
21 | { |
22 | use HasUserNotifications; |
23 | |
24 | /** @var array<string> */ |
25 | protected array $permissions = [ |
26 | 'locations.view', |
27 | 'edit' => 'locations.edit', |
28 | 'save' => 'locations.edit', |
29 | 'delete' => 'locations.edit', |
30 | ]; |
31 | |
32 | public function __construct( |
33 | protected LoggerInterface $log, |
34 | protected Location $location, |
35 | protected Redirector $redirect, |
36 | protected Response $response |
37 | ) { |
38 | } |
39 | |
40 | public function index(): Response |
41 | { |
42 | $locations = $this->location |
43 | ->withCount('shifts') |
44 | ->orderBy('name') |
45 | ->get(); |
46 | |
47 | return $this->response->withView( |
48 | 'pages/locations/index', |
49 | [ |
50 | 'locations' => $locations, |
51 | 'is_index' => true, |
52 | ] |
53 | ); |
54 | } |
55 | |
56 | public function edit(Request $request): Response |
57 | { |
58 | $locationId = (int) $request->getAttribute('location_id'); |
59 | |
60 | $location = $this->location->find($locationId); |
61 | |
62 | return $this->showEdit($location); |
63 | } |
64 | |
65 | public function save(Request $request): Response |
66 | { |
67 | $locationId = (int) $request->getAttribute('location_id'); |
68 | |
69 | /** @var Location $location */ |
70 | $location = $this->location->findOrNew($locationId); |
71 | /** @var Collection|AngelType[] $angelTypes */ |
72 | $angelTypes = AngelType::all(); |
73 | $validation = []; |
74 | foreach ($angelTypes as $angelType) { |
75 | $validation['angel_type_' . $angelType->id] = 'optional|int'; |
76 | } |
77 | |
78 | if ($request->request->has('delete')) { |
79 | return $this->delete($request); |
80 | } |
81 | |
82 | $data = $this->validate( |
83 | $request, |
84 | [ |
85 | 'name' => 'required|max:35', |
86 | 'description' => 'optional', |
87 | 'dect' => 'optional', |
88 | 'map_url' => 'optional|url', |
89 | ] + $validation |
90 | ); |
91 | |
92 | if (Location::whereName($data['name'])->where('id', '!=', $location->id)->exists()) { |
93 | throw new ValidationException((new Validator())->addErrors(['name' => ['validation.name.exists']])); |
94 | } |
95 | |
96 | $location->name = $data['name']; |
97 | $location->description = $data['description']; |
98 | $location->dect = $data['dect']; |
99 | $location->map_url = $data['map_url']; |
100 | |
101 | $location->save(); |
102 | $location->neededAngelTypes()->getQuery()->delete(); |
103 | $angelsInfo = ''; |
104 | |
105 | // Associate angel types with the room |
106 | foreach ($angelTypes as $angelType) { |
107 | $count = $data['angel_type_' . $angelType->id]; |
108 | if (!$count) { |
109 | continue; |
110 | } |
111 | |
112 | $neededAngelType = new NeededAngelType(); |
113 | |
114 | $neededAngelType->location()->associate($location); |
115 | $neededAngelType->angelType()->associate($angelType); |
116 | |
117 | $neededAngelType->count = $data['angel_type_' . $angelType->id]; |
118 | |
119 | $neededAngelType->save(); |
120 | |
121 | $angelsInfo .= sprintf(', %s: %s', $angelType->name, $count); |
122 | } |
123 | |
124 | $this->log->info( |
125 | 'Updated location "{name}" ({id}): {description} {dect} {map_url} {angels}', |
126 | [ |
127 | 'id' => $location->id, |
128 | 'name' => $location->name, |
129 | 'description' => $location->description, |
130 | 'dect' => $location->dect, |
131 | 'map_url' => $location->map_url, |
132 | 'angels' => $angelsInfo, |
133 | ] |
134 | ); |
135 | |
136 | $this->addNotification('location.edit.success'); |
137 | |
138 | return $this->redirect->to('/locations'); |
139 | } |
140 | |
141 | public function delete(Request $request): Response |
142 | { |
143 | $data = $this->validate($request, [ |
144 | 'id' => 'required|int', |
145 | 'delete' => 'checked', |
146 | ]); |
147 | |
148 | $location = $this->location->findOrFail($data['id']); |
149 | |
150 | $shifts = $location->shifts; |
151 | foreach ($shifts as $shift) { |
152 | event('shift.deleting', ['shift' => $shift]); |
153 | } |
154 | $location->delete(); |
155 | |
156 | $this->log->info('Deleted location {location}', ['location' => $location->name]); |
157 | $this->addNotification('location.delete.success'); |
158 | |
159 | return $this->redirect->to('/locations'); |
160 | } |
161 | |
162 | protected function showEdit(?Location $location): Response |
163 | { |
164 | $angeltypes = AngelType::all() |
165 | ->sortBy('name'); |
166 | |
167 | return $this->response->withView( |
168 | 'admin/locations/edit', |
169 | [ |
170 | 'location' => $location, |
171 | 'angel_types' => $angeltypes, |
172 | 'needed_angel_types' => $location?->neededAngelTypes, |
173 | ] |
174 | ); |
175 | } |
176 | } |