Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
62.07% covered (warning)
62.07%
54 / 87
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
PathManager
62.07% covered (warning)
62.07%
54 / 87
16.67% covered (danger)
16.67%
1 / 6
66.78
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 path
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 persist
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
7
 prepareUrlPath
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 createUrlPaths
87.50% covered (warning)
87.50%
14 / 16
0.00% covered (danger)
0.00%
0 / 1
5.05
 saveUrlPaths
32.26% covered (danger)
32.26%
10 / 31
0.00% covered (danger)
0.00%
0 / 1
27.90
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Node;
6
7use Celemas\Quma\Database;
8use Cosray\Exception\RuntimeException;
9use Cosray\Locale;
10use Cosray\Locales;
11use Cosray\Uid;
12
13class PathManager
14{
15    public function __construct(
16        private readonly Uid $uid = new Uid(Uid::ALPHABET_LOWERCASE_WORD_SAFE, 13),
17    ) {}
18
19    public function path(array $rawData, ?Locale $locale, Locale $requestLocale): string
20    {
21        $paths = $rawData['paths'];
22
23        if (!$locale) {
24            $locale = $requestLocale;
25        }
26
27        while ($locale) {
28            if (isset($paths[$locale->id])) {
29                return $paths[$locale->id];
30            }
31
32            $locale = $locale->fallback();
33        }
34
35        throw new RuntimeException('No url path found');
36    }
37
38    public function persist(
39        Database $db,
40        array $data,
41        int $editor,
42        int $nodeId,
43        Locales $locales,
44    ): void {
45        $noPathsGiven = true;
46
47        foreach ($data['paths'] ?? [] as $path) {
48            if (!$path) {
49                continue;
50            }
51
52            $noPathsGiven = false;
53            break;
54        }
55
56        if ($noPathsGiven) {
57            $data['paths'] = $data['generatedPaths'];
58        }
59
60        $defaultLocale = $locales->getDefault();
61        $defaultPath = trim($data['paths'][$defaultLocale->id] ?? '');
62
63        if (!$defaultPath) {
64            throw new RuntimeException(_(
65                'Der URL-Pfad für die Hauptsprache {$defaultLocale->title} muss gesetzt sein',
66            ));
67        }
68
69        $currentPaths = array_column($db->nodes->getPaths(['node' => $nodeId])->all(), 'path', 'locale');
70
71        if ($currentPaths) {
72            $baseStructure = [];
73
74            foreach ($locales as $locale) {
75                $baseStructure[$locale->id] = '';
76            }
77
78            $this->saveUrlPaths(
79                $db,
80                array_merge($baseStructure, $currentPaths),
81                $data['paths'],
82                $editor,
83                $nodeId,
84            );
85        } else {
86            $this->createUrlPaths($db, $data['paths'], $editor, $nodeId);
87        }
88    }
89
90    private function prepareUrlPath(Database $db, string $path): string
91    {
92        if (!str_starts_with($path, '/')) {
93            $path = '/' . $path;
94        }
95
96        $db->nodes->deleteInactivePath(['path' => $path])->run();
97
98        return $path;
99    }
100
101    private function createUrlPaths(Database $db, array $paths, int $editor, int $node): void
102    {
103        $alreadyPersisted = [];
104
105        foreach ($paths as $locale => $path) {
106            if (!$path) {
107                continue;
108            }
109
110            $this->prepareUrlPath($db, $path);
111
112            if (in_array($path, $alreadyPersisted, true)) {
113                continue;
114            }
115
116            if ($db->nodes->pathExists(['path' => $path])->first()) {
117                $path = $path . '-' . $this->uid->generate(5);
118            }
119
120            $db->nodes->savePath([
121                'node' => $node,
122                'path' => $path,
123                'locale' => $locale,
124                'editor' => $editor,
125            ])->run();
126
127            $alreadyPersisted[] = $path;
128        }
129    }
130
131    private function saveUrlPaths(
132        Database $db,
133        array $currentPaths,
134        array $paths,
135        int $editor,
136        int $node,
137    ): void {
138        $alreadyPersisted = [];
139
140        foreach ($currentPaths as $locale => $currentPath) {
141            $newPath = trim($paths[$locale] ?? '');
142
143            if ($newPath) {
144                $newPath = $this->prepareUrlPath($db, $newPath);
145
146                if ($currentPath) {
147                    if ($currentPath === $newPath) {
148                        $alreadyPersisted[] = $newPath;
149
150                        continue;
151                    }
152
153                    $db->nodes->deactivatePath([
154                        'path' => $currentPath,
155                        'locale' => $locale,
156                        'editor' => $editor,
157                    ])->run();
158                }
159
160                if (in_array($newPath, $alreadyPersisted, true)) {
161                    continue;
162                }
163
164                if ($db->nodes->pathExists(['path' => $newPath])->first()) {
165                    $newPath = $newPath . '-' . $this->uid->generate(5);
166                }
167
168                $db->nodes->savePath([
169                    'node' => $node,
170                    'path' => $newPath,
171                    'locale' => $locale,
172                    'editor' => $editor,
173                ])->run();
174
175                $alreadyPersisted[] = $newPath;
176            } else {
177                if ($currentPath) {
178                    $db->nodes->deactivatePath([
179                        'path' => $currentPath,
180                        'locale' => $locale,
181                        'editor' => $editor,
182                    ])->run();
183                }
184            }
185        }
186    }
187}