Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Preferences
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 5
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 locale
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 available
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 refererPath
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
30
 redirect
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Controller\Panel;
6
7use Celema\Container\Container;
8use Celema\Core\Factory\Factory;
9use Celema\Core\Request;
10use Celema\Core\Response;
11use Cosray\Auth as CmsAuth;
12use Cosray\Config;
13use Cosray\Locales;
14use Cosray\Users;
15
16final class Preferences extends Panel
17{
18    public function __construct(
19        Config $config,
20        Container $container,
21        Request $request,
22        private readonly CmsAuth $auth,
23        private readonly Users $users,
24    ) {
25        parent::__construct($config, $container, $request);
26    }
27
28    /**
29     * Persists the user's panel UI language. A value outside the selectable
30     * set resets the preference to NULL (inherit the negotiated default).
31     */
32    public function locale(Factory $factory): Response
33    {
34        $user = $this->auth->user();
35
36        if ($user !== null) {
37            $locale = $this->formData()['locale'] ?? null;
38
39            $this->users->savePanelLocale(
40                $user->id,
41                is_string($locale) && in_array($locale, $this->available(), true) ? $locale : null,
42            );
43        }
44
45        return $this->redirect($factory, $this->refererPath());
46    }
47
48    /** @return list<string> */
49    private function available(): array
50    {
51        $locales = $this->request->get('locales', null);
52
53        return $locales instanceof Locales ? $locales->panelLocales() : [];
54    }
55
56    /**
57     * The panel page the switcher was used on, so the reload lands where
58     * the user was. Anything outside the panel falls back to the index.
59     */
60    private function refererPath(): string
61    {
62        $referer = $this->request->header('Referer');
63        $path = parse_url($referer, PHP_URL_PATH);
64        $query = parse_url($referer, PHP_URL_QUERY);
65
66        if (is_string($path) && str_starts_with($path, $this->panelPath())) {
67            return is_string($query) && $query !== '' ? $path . '?' . $query : $path;
68        }
69
70        return $this->panelPath();
71    }
72
73    private function redirect(Factory $factory, string $target): Response
74    {
75        $response = Response::create($factory);
76
77        if ($this->request->hasHeader('HX-Request')) {
78            return $response
79                ->status(200)
80                ->header('HX-Redirect', $target);
81        }
82
83        return $response
84            ->status(303)
85            ->header('Location', $target);
86    }
87}