xref: /plugin/combo/ComboStrap/Meta/Field/Aliases.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeau
4*04fd306cSNickeaunamespace ComboStrap\Meta\Field;
5*04fd306cSNickeau
6*04fd306cSNickeau
7*04fd306cSNickeauuse ComboStrap\ExceptionCompile;
8*04fd306cSNickeauuse ComboStrap\ExceptionNotFound;
9*04fd306cSNickeauuse ComboStrap\ExceptionSqliteNotAvailable;
10*04fd306cSNickeauuse ComboStrap\LogUtility;
11*04fd306cSNickeauuse ComboStrap\MarkupPath;
12*04fd306cSNickeauuse ComboStrap\Meta\Api\Metadata;
13*04fd306cSNickeauuse ComboStrap\Meta\Api\MetadataSystem;
14*04fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore;
15*04fd306cSNickeauuse ComboStrap\Meta\Api\MetadataTabular;
16*04fd306cSNickeauuse ComboStrap\MetaManagerForm;
17*04fd306cSNickeauuse ComboStrap\Sqlite;
18*04fd306cSNickeauuse ComboStrap\StringUtility;
19*04fd306cSNickeauuse ComboStrap\WikiPath;
20*04fd306cSNickeau
21*04fd306cSNickeauclass Aliases extends MetadataTabular
22*04fd306cSNickeau{
23*04fd306cSNickeau
24*04fd306cSNickeau    public const PROPERTY_NAME = "aliases";
25*04fd306cSNickeau
26*04fd306cSNickeau
27*04fd306cSNickeau
28*04fd306cSNickeau    public static function createForPage(MarkupPath $page): Aliases
29*04fd306cSNickeau    {
30*04fd306cSNickeau
31*04fd306cSNickeau        return (new Aliases())->setResource($page);
32*04fd306cSNickeau
33*04fd306cSNickeau    }
34*04fd306cSNickeau
35*04fd306cSNickeau    public static function create(): Aliases
36*04fd306cSNickeau    {
37*04fd306cSNickeau        return new Aliases();
38*04fd306cSNickeau    }
39*04fd306cSNickeau
40*04fd306cSNickeau    /**
41*04fd306cSNickeau     * @return Alias[]|null
42*04fd306cSNickeau     * @throws ExceptionNotFound
43*04fd306cSNickeau     */
44*04fd306cSNickeau    public function getValueAsAlias(): array
45*04fd306cSNickeau    {
46*04fd306cSNickeau        $rows = $this->getValue();
47*04fd306cSNickeau        $aliases = [];
48*04fd306cSNickeau        foreach ($rows as $row) {
49*04fd306cSNickeau            /**
50*04fd306cSNickeau             * @var AliasPath $aliasMeta
51*04fd306cSNickeau             */
52*04fd306cSNickeau            $aliasMeta = $row[AliasPath::getPersistentName()];
53*04fd306cSNickeau            $alias = Alias::create($this->getResource(), $aliasMeta->getValue());
54*04fd306cSNickeau            /**
55*04fd306cSNickeau             * @var AliasType $aliasType
56*04fd306cSNickeau             */
57*04fd306cSNickeau            $aliasType = $row[AliasType::getPersistentName()];
58*04fd306cSNickeau            if ($aliasType !== null) {
59*04fd306cSNickeau                try {
60*04fd306cSNickeau                    $alias->setType($aliasType->getValue());
61*04fd306cSNickeau                } catch (ExceptionNotFound $e) {
62*04fd306cSNickeau                    // ok
63*04fd306cSNickeau                }
64*04fd306cSNickeau
65*04fd306cSNickeau            }
66*04fd306cSNickeau            $aliases[] = $alias;
67*04fd306cSNickeau        }
68*04fd306cSNickeau        return $aliases;
69*04fd306cSNickeau    }
70*04fd306cSNickeau
71*04fd306cSNickeau
72*04fd306cSNickeau    /**
73*04fd306cSNickeau     * @param array|null $aliasesPersistentValues
74*04fd306cSNickeau     * return Alias[]
75*04fd306cSNickeau     */
76*04fd306cSNickeau    private function toNativeAliasArray(?array $aliasesPersistentValues): array
77*04fd306cSNickeau    {
78*04fd306cSNickeau        if ($aliasesPersistentValues === null) {
79*04fd306cSNickeau            return [];
80*04fd306cSNickeau        }
81*04fd306cSNickeau        $aliases = [];
82*04fd306cSNickeau        foreach ($aliasesPersistentValues as $key => $value) {
83*04fd306cSNickeau            if (is_array($value)) {
84*04fd306cSNickeau                $path = $value[AliasPath::PERSISTENT_NAME];
85*04fd306cSNickeau                if (empty($path)) {
86*04fd306cSNickeau                    if (is_string($key)) {
87*04fd306cSNickeau                        // Old way (deprecated)
88*04fd306cSNickeau                        $path = $key;
89*04fd306cSNickeau                    } else {
90*04fd306cSNickeau                        LogUtility::msg("The path of the alias should not be empty to create a path", Alias::CANONICAL);
91*04fd306cSNickeau                    }
92*04fd306cSNickeau                }
93*04fd306cSNickeau                $type = $value[AliasType::PERSISTENT_NAME];
94*04fd306cSNickeau
95*04fd306cSNickeau                /**
96*04fd306cSNickeau                 * We don't create via the {@link Aliases::addAlias()}
97*04fd306cSNickeau                 * to not persist for each each alias value
98*04fd306cSNickeau                 **/
99*04fd306cSNickeau                $aliases[] = Alias::create($this->getResource(), $path)
100*04fd306cSNickeau                    ->setType($type);
101*04fd306cSNickeau            } else {
102*04fd306cSNickeau                $path = $value;
103*04fd306cSNickeau                if (empty($path)) {
104*04fd306cSNickeau                    LogUtility::msg("The value of the alias array should not be empty as it's the alias path", Alias::CANONICAL);
105*04fd306cSNickeau                }
106*04fd306cSNickeau                if (!is_string($path)) {
107*04fd306cSNickeau                    $path = StringUtility::toString($path);
108*04fd306cSNickeau                    LogUtility::error("The alias element ($path) is not a string", Alias::CANONICAL);
109*04fd306cSNickeau                }
110*04fd306cSNickeau                $path = WikiPath::createMarkupPathFromId($path);
111*04fd306cSNickeau                $aliases[] = Alias::create($this->getResource(), $path);
112*04fd306cSNickeau            }
113*04fd306cSNickeau        }
114*04fd306cSNickeau        return $aliases;
115*04fd306cSNickeau    }
116*04fd306cSNickeau
117*04fd306cSNickeau
118*04fd306cSNickeau    /**
119*04fd306cSNickeau     * @param Alias[] $aliases
120*04fd306cSNickeau     * @return null|array - the array to be saved in a text/json file
121*04fd306cSNickeau     */
122*04fd306cSNickeau    public static function toMetadataArray(?array $aliases): ?array
123*04fd306cSNickeau    {
124*04fd306cSNickeau        if ($aliases === null) {
125*04fd306cSNickeau            return null;
126*04fd306cSNickeau        }
127*04fd306cSNickeau        $array = [];
128*04fd306cSNickeau        foreach ($aliases as $alias) {
129*04fd306cSNickeau            $array[$alias->getPath()->toAbsoluteId()] = [
130*04fd306cSNickeau                AliasPath::PERSISTENT_NAME => $alias->getPath()->toAbsoluteId(),
131*04fd306cSNickeau                AliasType::PERSISTENT_NAME => $alias->getType()
132*04fd306cSNickeau            ];
133*04fd306cSNickeau        }
134*04fd306cSNickeau        return array_values($array);
135*04fd306cSNickeau    }
136*04fd306cSNickeau
137*04fd306cSNickeau    public static function getName(): string
138*04fd306cSNickeau    {
139*04fd306cSNickeau        return self::PROPERTY_NAME;
140*04fd306cSNickeau    }
141*04fd306cSNickeau
142*04fd306cSNickeau
143*04fd306cSNickeau    static public function getPersistenceType(): string
144*04fd306cSNickeau    {
145*04fd306cSNickeau        return MetadataDokuWikiStore::PERSISTENT_DOKUWIKI_KEY;
146*04fd306cSNickeau    }
147*04fd306cSNickeau
148*04fd306cSNickeau    /**
149*04fd306cSNickeau     * Code refactoring
150*04fd306cSNickeau     * This method is not in the database page
151*04fd306cSNickeau     * because it would create a cycle
152*04fd306cSNickeau     *
153*04fd306cSNickeau     * The old data was saved in the database
154*04fd306cSNickeau     * but should have been saved on the file system
155*04fd306cSNickeau     *
156*04fd306cSNickeau     * Once
157*04fd306cSNickeau     * @return Alias[]
158*04fd306cSNickeau     * @throws ExceptionSqliteNotAvailable
159*04fd306cSNickeau     * @deprecated 2021-10-31
160*04fd306cSNickeau     */
161*04fd306cSNickeau    private
162*04fd306cSNickeau    function getAndDeleteDeprecatedAlias(): array
163*04fd306cSNickeau    {
164*04fd306cSNickeau        $sqlite = Sqlite::createOrGetSqlite();
165*04fd306cSNickeau
166*04fd306cSNickeau        try {
167*04fd306cSNickeau            $canonicalOrDefault = $this->getResource()->getCanonicalOrDefault();
168*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
169*04fd306cSNickeau            return [];
170*04fd306cSNickeau        }
171*04fd306cSNickeau        /** @noinspection SqlResolve */
172*04fd306cSNickeau        $request = $sqlite
173*04fd306cSNickeau            ->createRequest()
174*04fd306cSNickeau            ->setQueryParametrized("select ALIAS from DEPRECATED_PAGES_ALIAS where CANONICAL = ?", [$canonicalOrDefault]);
175*04fd306cSNickeau        $deprecatedAliases = [];
176*04fd306cSNickeau        $deprecatedAliasInDb = [];
177*04fd306cSNickeau        try {
178*04fd306cSNickeau            $deprecatedAliasInDb = $request
179*04fd306cSNickeau                ->execute()
180*04fd306cSNickeau                ->getRows();
181*04fd306cSNickeau        } catch (ExceptionCompile $e) {
182*04fd306cSNickeau            LogUtility::msg("An exception has occurred with the deprecated alias selection query. {$e->getMessage()}");
183*04fd306cSNickeau            return [];
184*04fd306cSNickeau        } finally {
185*04fd306cSNickeau            $request->close();
186*04fd306cSNickeau        }
187*04fd306cSNickeau
188*04fd306cSNickeau        array_map(
189*04fd306cSNickeau            function ($row) use ($deprecatedAliases) {
190*04fd306cSNickeau                $alias = $row['ALIAS'];
191*04fd306cSNickeau                $deprecatedAliases[$alias] = Alias::create($this->getResource(), $alias)
192*04fd306cSNickeau                    ->setType(AliasType::REDIRECT);
193*04fd306cSNickeau            },
194*04fd306cSNickeau            $deprecatedAliasInDb
195*04fd306cSNickeau        );
196*04fd306cSNickeau
197*04fd306cSNickeau        /**
198*04fd306cSNickeau         * Delete them
199*04fd306cSNickeau         */
200*04fd306cSNickeau
201*04fd306cSNickeau        if (sizeof($deprecatedAliasInDb) > 0) {
202*04fd306cSNickeau            /** @noinspection SqlResolve */
203*04fd306cSNickeau            $request = $sqlite
204*04fd306cSNickeau                ->createRequest()
205*04fd306cSNickeau                ->setQueryParametrized("delete from DEPRECATED_PAGE_ALIASES where CANONICAL = ?", [$canonicalOrDefault]);
206*04fd306cSNickeau            try {
207*04fd306cSNickeau                $request->execute();
208*04fd306cSNickeau            } catch (ExceptionCompile $e) {
209*04fd306cSNickeau                LogUtility::msg("An exception has occurred with the delete deprecated alias statement. {$e->getMessage()}", LogUtility::LVL_MSG_ERROR);
210*04fd306cSNickeau            } finally {
211*04fd306cSNickeau                $request->close();
212*04fd306cSNickeau            }
213*04fd306cSNickeau        }
214*04fd306cSNickeau
215*04fd306cSNickeau
216*04fd306cSNickeau        /**
217*04fd306cSNickeau         * Return
218*04fd306cSNickeau         */
219*04fd306cSNickeau        return $deprecatedAliases;
220*04fd306cSNickeau
221*04fd306cSNickeau    }
222*04fd306cSNickeau
223*04fd306cSNickeau
224*04fd306cSNickeau    /**
225*04fd306cSNickeau     * @return Metadata[][] - an list of rows of metadata columns
226*04fd306cSNickeau     */
227*04fd306cSNickeau    public function getDefaultValue(): array
228*04fd306cSNickeau    {
229*04fd306cSNickeau        return
230*04fd306cSNickeau            [
231*04fd306cSNickeau                [
232*04fd306cSNickeau                    AliasPath::getPersistentName() => AliasPath::createForParent($this),
233*04fd306cSNickeau                    AliasType::getPersistentName() => AliasType::createForParent($this)->setFromStoreValueWithoutException(AliasType::DEFAULT)
234*04fd306cSNickeau                ]
235*04fd306cSNickeau            ];
236*04fd306cSNickeau    }
237*04fd306cSNickeau
238*04fd306cSNickeau
239*04fd306cSNickeau    public function getValue(): array
240*04fd306cSNickeau    {
241*04fd306cSNickeau        $this->buildCheck();
242*04fd306cSNickeau
243*04fd306cSNickeau        /**
244*04fd306cSNickeau         * We don't do that on build because
245*04fd306cSNickeau         * we are using a set a metadata method that creates
246*04fd306cSNickeau         * a cycle via the {@link MetadataMutation::PAGE_METADATA_MUTATION_EVENT}
247*04fd306cSNickeau         */
248*04fd306cSNickeau        if (
249*04fd306cSNickeau            !$this->valueIsNotNull()
250*04fd306cSNickeau            &&
251*04fd306cSNickeau            $this->getReadStore() !== null
252*04fd306cSNickeau            &&
253*04fd306cSNickeau            $this->getReadStore() instanceof MetadataDokuWikiStore
254*04fd306cSNickeau        ) {
255*04fd306cSNickeau            $this->getAndDeleteDeprecatedAlias();
256*04fd306cSNickeau            /**
257*04fd306cSNickeau             * To validate the migration we set a value
258*04fd306cSNickeau             * (the array may be empty)
259*04fd306cSNickeau             */
260*04fd306cSNickeau            try {
261*04fd306cSNickeau                $this->sendToWriteStore();
262*04fd306cSNickeau            } catch (ExceptionCompile $e) {
263*04fd306cSNickeau                LogUtility::msg("Error while persisting the new data");
264*04fd306cSNickeau            }
265*04fd306cSNickeau        }
266*04fd306cSNickeau
267*04fd306cSNickeau        return parent::getValue();
268*04fd306cSNickeau    }
269*04fd306cSNickeau
270*04fd306cSNickeau    /**
271*04fd306cSNickeau     * @throws ExceptionCompile
272*04fd306cSNickeau     */
273*04fd306cSNickeau    public
274*04fd306cSNickeau    function addAlias(string $aliasPath, $aliasType = null): Aliases
275*04fd306cSNickeau    {
276*04fd306cSNickeau        $this->addAndGetAlias($aliasPath, $aliasType);
277*04fd306cSNickeau        return $this;
278*04fd306cSNickeau    }
279*04fd306cSNickeau
280*04fd306cSNickeau    /**
281*04fd306cSNickeau     * @throws ExceptionCompile
282*04fd306cSNickeau     */
283*04fd306cSNickeau    public
284*04fd306cSNickeau    function addAndGetAlias($aliasPath, $aliasType = null): Alias
285*04fd306cSNickeau    {
286*04fd306cSNickeau        $this->buildCheck();
287*04fd306cSNickeau        /**
288*04fd306cSNickeau         * @var AliasPath $path
289*04fd306cSNickeau         */
290*04fd306cSNickeau        $path = MetadataSystem::toMetadataObject(AliasPath::class, $this)
291*04fd306cSNickeau            ->setFromStoreValue($aliasPath);
292*04fd306cSNickeau        $row[$path::getPersistentName()] = $path;
293*04fd306cSNickeau
294*04fd306cSNickeau        $alias = Alias::create($this->getResource(), $path->getValue());
295*04fd306cSNickeau
296*04fd306cSNickeau        if ($aliasType !== null) {
297*04fd306cSNickeau            $aliasObject = MetadataSystem::toMetadataObject(AliasType::class, $this)
298*04fd306cSNickeau                ->setFromStoreValue($aliasType);
299*04fd306cSNickeau            $row[$aliasObject::getPersistentName()] = $aliasObject;
300*04fd306cSNickeau            $alias->setType($aliasType);
301*04fd306cSNickeau        }
302*04fd306cSNickeau        $this->rows[$path->getValue()->toAbsoluteId()] = $row;
303*04fd306cSNickeau
304*04fd306cSNickeau        return $alias;
305*04fd306cSNickeau    }
306*04fd306cSNickeau
307*04fd306cSNickeau
308*04fd306cSNickeau    static public
309*04fd306cSNickeau    function getCanonical(): string
310*04fd306cSNickeau    {
311*04fd306cSNickeau        return Alias::CANONICAL;
312*04fd306cSNickeau    }
313*04fd306cSNickeau
314*04fd306cSNickeau    static public
315*04fd306cSNickeau    function getTab(): string
316*04fd306cSNickeau    {
317*04fd306cSNickeau        return MetaManagerForm::TAB_REDIRECTION_VALUE;
318*04fd306cSNickeau    }
319*04fd306cSNickeau
320*04fd306cSNickeau    static public
321*04fd306cSNickeau    function getDescription(): string
322*04fd306cSNickeau    {
323*04fd306cSNickeau        return "Aliases that will redirect to this page.";
324*04fd306cSNickeau    }
325*04fd306cSNickeau
326*04fd306cSNickeau    static public function getLabel(): string
327*04fd306cSNickeau    {
328*04fd306cSNickeau        return "Page Aliases";
329*04fd306cSNickeau    }
330*04fd306cSNickeau
331*04fd306cSNickeau
332*04fd306cSNickeau    static public function isMutable(): bool
333*04fd306cSNickeau    {
334*04fd306cSNickeau        return true;
335*04fd306cSNickeau    }
336*04fd306cSNickeau
337*04fd306cSNickeau    public function getUidClass(): ?string
338*04fd306cSNickeau    {
339*04fd306cSNickeau        return AliasPath::class;
340*04fd306cSNickeau    }
341*04fd306cSNickeau
342*04fd306cSNickeau    /**
343*04fd306cSNickeau     * @return Metadata[]
344*04fd306cSNickeau     */
345*04fd306cSNickeau    static public function getChildrenClass(): array
346*04fd306cSNickeau    {
347*04fd306cSNickeau        return [AliasPath::class, AliasType::class];
348*04fd306cSNickeau    }
349*04fd306cSNickeau
350*04fd306cSNickeau
351*04fd306cSNickeau    static public function isOnForm(): bool
352*04fd306cSNickeau    {
353*04fd306cSNickeau        return true;
354*04fd306cSNickeau    }
355*04fd306cSNickeau}
356