1final class JobController
2{
3 public function index(Request $request): View
4 {
5 $jobs = Job::query()
6 ->where('status', 'published')
7 ->where('expires_at', '>', now())
8 ->where('city', $request->query('city'))
9 ->latest('published_at')
10 ->paginate(20);
11
12 return view('jobs.index', ['jobs' => $jobs]);
13 }
14
15 public function close(Job $job): RedirectResponse
16 {
17 $job->update(['status' => 'closed', 'closed_at' => now()]);
18 Cache::forget('jobs:count');
19
20 return back();
21 }
22}
1<?php
2
3final class Job
4{
5 public function __construct(
6 public readonly int $id,
7 public readonly string $title,
8 public readonly string $city,
9 private bool $open = true,
10 ) {}
11
12 public function isOpen(): bool
13 {
14 return $this->open;
15 }
16
17 public function close(): void
18 {
19 $this->open = false;
20 }
21}
22
231interface JobRepository
24{
25 public function get(int $id): Job;
26
27 /** @return list<Job> */
28 public function openIn(string $city): array;
29
30 public function save(Job $job): void;
31}
32
332final class InMemoryJobRepository implements JobRepository
34{
35 /** @var array<int, Job> */
36 private array $jobs = [];
37
38 public function get(int $id): Job
39 {
40 return $this->jobs[$id] ?? throw new DomainException("Вакансії #{$id} немає");
41 }
42
43 public function openIn(string $city): array
44 {
45 return array_values(array_filter(
46 $this->jobs,
47 fn (Job $job): bool => $job->isOpen() && $job->city === $city,
48 ));
49 }
50
51 public function save(Job $job): void
52 {
53 $this->jobs[$job->id] = $job;
54 }
55}
56
573final class CloseJob
58{
59 public function __construct(private readonly JobRepository $jobs) {}
60
61 public function __invoke(int $id): void
62 {
63 $job = $this->jobs->get($id);
64 $job->close();
65 $this->jobs->save($job);
66 }
67}
68
694$jobs = new InMemoryJobRepository();
70$jobs->save(new Job(1, 'Senior Laravel Developer', 'Київ'));
71$jobs->save(new Job(2, 'Symfony Developer', 'Львів'));
72$jobs->save(new Job(3, 'PHP Team Lead', 'Київ'));
73
74(new CloseJob($jobs))(3);
75
76foreach (['Київ', 'Львів'] as $city) {
77 $titles = array_map(fn (Job $job): string => $job->title, $jobs->openIn($city));
78 echo $city, ': ', implode(', ', $titles), "\n";
79}
80
81try {
82 (new CloseJob($jobs))(42);
83} catch (DomainException $e) {
84 echo 'Помилка: ', $e->getMessage(), "\n";
85}