Skip to content

Commit 1201493

Browse files
committed
refactor: introduce validation rules for project states, changed livewire population logic and error handling
1 parent a87e826 commit 1201493

File tree

19 files changed

+310
-181
lines changed

19 files changed

+310
-181
lines changed

app/Livewire/Project/EditProject.php

Lines changed: 95 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
use Cknow\Money\Money;
1111
use Illuminate\Support\Collection;
1212
use Illuminate\Support\Facades\Auth;
13+
use Illuminate\Support\Facades\Date;
1314
use Illuminate\Support\Facades\DB;
1415
use Illuminate\Support\Facades\Gate;
16+
use Illuminate\Support\Facades\Validator;
17+
use Livewire\Attributes\Computed;
1518
use Livewire\Attributes\Locked;
1619
use Livewire\Attributes\Url;
1720
use Livewire\Component;
@@ -21,20 +24,28 @@ class EditProject extends Component
2124
{
2225
use WithFileUploads;
2326

24-
#[Locked]
25-
public string $state_name;
26-
27-
public ProjectForm $form;
28-
2927
#[Url]
3028
public ?int $project_id = null;
29+
#[Locked]
30+
public string $state_name;
3131

32+
#[Locked]
3233
public bool $isNew;
3334

34-
public Collection $posts;
35+
// Form data
36+
public string $name = '';
37+
public string $responsible = '';
38+
public string $org = '';
39+
public string $org_mail = '';
40+
public string $protokoll = '';
41+
public string $beschreibung = '';
42+
public string $recht = '';
43+
public string $recht_additional = '';
44+
public array $dateRange = [];
45+
public int $hhp_id;
46+
public int $version = 1;
3547

36-
// UI state
37-
public string $selectedRechtKey = '';
48+
public Collection $posts;
3849

3950
public array $attachments = [];
4051

@@ -44,29 +55,61 @@ public function mount(): void
4455

4556
if ($this->isNew) {
4657
Gate::authorize('create', Project::class);
47-
$this->form->initializeNew();
48-
$this->posts = collect();
49-
$this->attachments = [];
50-
$this->state_name = 'draft';
51-
58+
$project = new Project();
59+
$this->populateData($project);
5260
$this->addEmptyPost();
5361
} else {
5462
$project = Project::findOrFail($this->project_id);
5563
Gate::authorize('update', $project);
56-
$this->form->setProject($project);
57-
$this->state_name = $project->state->getValue();
58-
$this->posts = $project->posts->map(fn (ProjectPost $post) => [
59-
'id' => $post->id,
60-
'name' => $post->name,
61-
'bemerkung' => $post->bemerkung ?? '',
62-
'einnahmen' => $post->einnahmen,
63-
'ausgaben' => $post->ausgaben,
64-
'titel_id' => $post->titel_id,
65-
]);
66-
$this->attachments = []; // FIXME: load Attachments
64+
$this->populateData($project);
6765
}
6866
}
6967

68+
private function populateData(Project $project): void
69+
{
70+
$this->name = $project->name ?? '';
71+
$this->responsible = $project->responsible ?? '';
72+
$this->org = $project->org ?? '';
73+
$this->org_mail = $project->org_mail ?? '';
74+
$this->protokoll = $project->protokoll ?? '';
75+
$this->beschreibung = $project->beschreibung ?? '';
76+
$this->recht = $project->recht ?? '';
77+
$this->recht_additional = $project->recht_additional ?? '';
78+
$this->dateRange = ['start' => $project->date_start, 'end' => $project->date_end];
79+
$this->version = $project->version;
80+
$this->hhp_id = LegacyBudgetPlan::findByDate($project->createdat)->id;
81+
$this->state_name = $project->state->getValue();
82+
$this->posts = $project->posts->map(fn (ProjectPost $post) => [
83+
'id' => $post->id,
84+
'name' => $post->name,
85+
'bemerkung' => $post->bemerkung ?? '',
86+
'einnahmen' => $post->einnahmen,
87+
'ausgaben' => $post->ausgaben,
88+
'titel_id' => $post->titel_id,
89+
]);
90+
$this->attachments = []; // FIXME: load Attachments
91+
}
92+
93+
private function getValues(): array
94+
{
95+
return [
96+
'name' => $this->name,
97+
'responsible' => $this->responsible,
98+
'org' => $this->org,
99+
'org_mail' => $this->org_mail,
100+
'protokoll' => $this->protokoll,
101+
'beschreibung' => $this->beschreibung,
102+
'recht' => $this->recht,
103+
'recht_additional' => $this->recht_additional,
104+
// make compatible with legacy database
105+
'date_start' => $this->dateRange['start'] ?? null,
106+
'date_end' => $this->dateRange['end'] ?? null,
107+
'version' => $this->version,
108+
'createdat' => Date::parse(LegacyBudgetPlan::find($this->hhp_id)->von)->addDays(7),
109+
'posts' => $this->posts->toArray(),
110+
];
111+
}
112+
70113
public function isPostDeletable(int $index): bool
71114
{
72115
return
@@ -85,35 +128,44 @@ public function removePost(int $index): void
85128
}
86129
}
87130

131+
public function rules() : array
132+
{
133+
return $this->getState()->rules();
134+
}
135+
88136
/**
89137
* Save the project
90138
*/
91139
public function save()
92140
{
93-
// $this->validate();
94-
// $this->form->validate();
141+
$validator = Validator::make($this->getValues(), $this->rules());
142+
$filtered = collect($validator->validate());
143+
$filteredMeta = $filtered->except('posts')->toArray();
144+
$filteredPosts = $filtered->get('posts');
145+
146+
95147
try {
96148
DB::beginTransaction();
97149
if ($this->isNew) {
98150
$project = Project::create([
99151
'creator_id' => Auth::id(),
100152
'stateCreator_id' => Auth::id(),
101-
...($this->form->getValues()),
153+
...$filteredMeta,
102154
]);
103155
} else {
104156
$project = Project::findOrFail($this->project_id);
105157
// Check if the project has been modified since the last load
106-
if ($project->version != $this->form->version) {
158+
if ($project->version !== $this->version) {
107159
$this->addError('save', 'Das Projekt wurde zwischenzeitlich von jemand anderem bearbeitet. Bitte laden Sie die Seite neu.');
108160

109161
return;
110162
}
111163
$project->update([
112-
...$this->form->getValues(),
164+
...$filteredMeta,
113165
'version' => $project->version + 1,
114166
]);
115167
}
116-
foreach ($this->posts as $post) {
168+
foreach ($filteredPosts as $post) {
117169
if (isset($post['id'])) {
118170
$project->posts()->findOrFail($post['id'])->update($post);
119171
} else {
@@ -129,32 +181,6 @@ public function save()
129181
}
130182
}
131183

132-
/**
133-
* Update existing project
134-
*/
135-
protected function updateProject()
136-
{
137-
$project = Project::findOrFail($this->project_id);
138-
139-
$updateData = [
140-
'lastupdated' => now(),
141-
'version' => $project->version + 1,
142-
];
143-
144-
// Only update fields that the user has permission to edit
145-
foreach ($this->form->toArray() as $field => $value) {
146-
if (Gate::allows('update-field', [$project, $field])) {
147-
$updateData[$field] = $value ?: null;
148-
}
149-
}
150-
151-
// FIXME: increment version
152-
// FIXME: save posts
153-
$project->update($updateData);
154-
$this->form->version = $project->version;
155-
156-
}
157-
158184
/**
159185
* Add an empty post row
160186
*/
@@ -198,7 +224,7 @@ public function removeAttachment(int $index): void
198224
*/
199225
protected function getBudgetTitleOptions(): \Illuminate\Database\Eloquent\Collection
200226
{
201-
$plan = LegacyBudgetPlan::findOrFail($this->form->hhp_id);
227+
$plan = LegacyBudgetPlan::findOrFail($this->hhp_id);
202228

203229
return $plan->budgetItems;
204230
}
@@ -241,11 +267,22 @@ public function render()
241267
$mailingLists = [];
242268
$rechtsgrundlagen = $this->getRechtsgrundlagenOptions();
243269
$budgetTitles = $this->getBudgetTitleOptions();
244-
$state = ProjectState::make($this->state_name, new Project);
270+
$state = $this->getState();
245271
$budgetPlans = LegacyBudgetPlan::all();
246272

247273
return view('livewire.project.edit-project', compact(
248274
'gremien', 'mailingLists', 'budgetTitles', 'rechtsgrundlagen', 'state', 'budgetPlans'
249275
));
250276
}
277+
278+
#[Computed]
279+
public function getState(): ProjectState {
280+
return ProjectState::make($this->state_name, $this->getProject());
281+
}
282+
283+
#[Computed]
284+
public function getProject(): Project {
285+
return Project::findOrFail($this->project_id);
286+
}
287+
251288
}

app/Livewire/Project/ProjectForm.php

Lines changed: 0 additions & 99 deletions
This file was deleted.

app/Livewire/Project/ShowProject.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ public function render()
2828

2929
public function changeState(): void
3030
{
31+
// check if given state string a valid state for this project
3132
$project = Project::findOrFail($this->project_id);
3233
$filtered = $this->validate(['newState' => ['required', new ValidStateRule(ProjectState::class)]]);
3334
$newState = ProjectState::make($filtered['newState'], $project);
35+
// Business Logic check: are some values missing for the new state
36+
$newState->validate();
37+
// Authorization check: can the user transition to this state
3438
$this->authorize('transition-to', [$project, $newState]);
3539

3640
try {
@@ -46,6 +50,7 @@ public function changeState(): void
4650
'timestamp' => now(),
4751
]);
4852
Flux::modal('state-modal')->close();
53+
$this->reset('newState');
4954
} catch (CouldNotPerformTransition $e) {
5055
$this->addError('newState', $e->getMessage());
5156
}

0 commit comments

Comments
 (0)