xref: /template/strap/ComboStrap/Canonical.php (revision 70bbd7f1f72440223cc13f3495efdcb2b0a11514)
1c3437056SNickeau<?php
2c3437056SNickeau
3c3437056SNickeau
4c3437056SNickeaunamespace ComboStrap;
5c3437056SNickeau
6c3437056SNickeau
704fd306cSNickeauuse ComboStrap\Meta\Api\MetadataWikiPath;
804fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore;
904fd306cSNickeauuse ComboStrap\Web\Url;
1004fd306cSNickeauuse ComboStrap\Web\UrlEndpoint;
1104fd306cSNickeau
1204fd306cSNickeau
13c3437056SNickeauclass Canonical extends MetadataWikiPath
14c3437056SNickeau{
15c3437056SNickeau
16c3437056SNickeau    public const PROPERTY_NAME = "canonical";
17c3437056SNickeau    public const CANONICAL = "canonical";
18c3437056SNickeau
19c3437056SNickeau    /**
20c3437056SNickeau     * The auto-canonical feature does not create any canonical value on the file system
21c3437056SNickeau     * but creates a canonical in the database (where the {@link \action_plugin_combo_router}
22c3437056SNickeau     * takes its information and it enables to route via a calculated canonical
23c3437056SNickeau     * (ie the {@link Canonical::getDefaultValue()}
24c3437056SNickeau     */
25c3437056SNickeau    public const CONF_CANONICAL_LAST_NAMES_COUNT = 'MinimalNamesCountForAutomaticCanonical';
26c3437056SNickeau
2704fd306cSNickeau    public static function createForPage(MarkupPath $page): Canonical
28c3437056SNickeau    {
29c3437056SNickeau        return (new Canonical())
30c3437056SNickeau            ->setResource($page);
31c3437056SNickeau
32c3437056SNickeau    }
33c3437056SNickeau
3404fd306cSNickeau    /**
3504fd306cSNickeau     * @return WikiPath
3604fd306cSNickeau     * @throws ExceptionNotFound
3704fd306cSNickeau     */
3804fd306cSNickeau    public function getValueOrDefault(): WikiPath
3904fd306cSNickeau    {
4004fd306cSNickeau        try {
4104fd306cSNickeau            return $this->getValue();
4204fd306cSNickeau        } catch (ExceptionNotFound $e) {
4304fd306cSNickeau            return $this->getDefaultValue();
4404fd306cSNickeau        }
4504fd306cSNickeau    }
4604fd306cSNickeau
4704fd306cSNickeau
4804fd306cSNickeau    public static function getTab(): string
49c3437056SNickeau    {
50c3437056SNickeau        return MetaManagerForm::TAB_REDIRECTION_VALUE;
51c3437056SNickeau    }
52c3437056SNickeau
5304fd306cSNickeau    public static function getDescription(): string
54c3437056SNickeau    {
55c3437056SNickeau        return "The canonical path is a short unique path for the page (used in named permalink)";
56c3437056SNickeau    }
57c3437056SNickeau
5804fd306cSNickeau    public static function getLabel(): string
59c3437056SNickeau    {
60c3437056SNickeau        return "Canonical Path";
61c3437056SNickeau    }
62c3437056SNickeau
63c3437056SNickeau    public static function getName(): string
64c3437056SNickeau    {
65c3437056SNickeau        return self::PROPERTY_NAME;
66c3437056SNickeau    }
67c3437056SNickeau
6804fd306cSNickeau    public static function getPersistenceType(): string
69c3437056SNickeau    {
7004fd306cSNickeau        return MetadataDokuWikiStore::PERSISTENT_DOKUWIKI_KEY;
71c3437056SNickeau    }
72c3437056SNickeau
7304fd306cSNickeau    public static function isMutable(): bool
74c3437056SNickeau    {
75c3437056SNickeau        return true;
76c3437056SNickeau    }
77c3437056SNickeau
7804fd306cSNickeau    public static function createFromValue(string $canonical): Canonical
79c3437056SNickeau    {
8004fd306cSNickeau        /** @noinspection PhpIncompatibleReturnTypeInspection */
8104fd306cSNickeau        return (new Canonical())
8204fd306cSNickeau            ->setValue($canonical);
8304fd306cSNickeau    }
8404fd306cSNickeau
8504fd306cSNickeau
8604fd306cSNickeau    /**
8704fd306cSNickeau     * @return WikiPath
8804fd306cSNickeau     * @throws ExceptionNotFound
8904fd306cSNickeau     */
9004fd306cSNickeau    public function getDefaultValue(): WikiPath
9104fd306cSNickeau    {
9204fd306cSNickeau
9304fd306cSNickeau        $resourceCombo = $this->getResource();
9404fd306cSNickeau        if (!($resourceCombo instanceof MarkupPath)) {
9504fd306cSNickeau            throw new ExceptionNotFound("No default value for other resources than page");
9604fd306cSNickeau        }
9704fd306cSNickeau
98c3437056SNickeau        /**
99c3437056SNickeau         * The last part of the id as canonical
100c3437056SNickeau         */
101c3437056SNickeau        // How many last parts are taken into account in the canonical processing (2 by default)
10204fd306cSNickeau        $canonicalLastNamesCount = SiteConfig::getConfValue(self::CONF_CANONICAL_LAST_NAMES_COUNT, 0);
10304fd306cSNickeau        if ($canonicalLastNamesCount <= 0) {
10404fd306cSNickeau            throw new ExceptionNotFound("Default canonical value is not enabled, no default canonical");
10504fd306cSNickeau        }
10604fd306cSNickeau
107c3437056SNickeau        /**
108c3437056SNickeau         * Takes the last names part
109c3437056SNickeau         */
11004fd306cSNickeau        $namesOriginal = $this->getResource()->getPathObject()->getNamesWithoutExtension();
111c3437056SNickeau        /**
112c3437056SNickeau         * Delete the identical names at the end
113c3437056SNickeau         * To resolve this problem
114c3437056SNickeau         * The page (viz:viz) and the page (data:viz:viz) have the same canonical.
115c3437056SNickeau         * The page (viz:viz) will get the canonical viz
116c3437056SNickeau         * The page (data:viz) will get the canonical  data:viz
117c3437056SNickeau         */
118c3437056SNickeau        $i = sizeof($namesOriginal) - 1;
119c3437056SNickeau        $names = $namesOriginal;
120*70bbd7f1Sgerardnico        while ($namesOriginal[$i] == ($namesOriginal[$i - 1] ?? null)) {
121c3437056SNickeau            unset($names[$i]);
122c3437056SNickeau            $i--;
123c3437056SNickeau            if ($i <= 0) {
124c3437056SNickeau                break;
125c3437056SNickeau            }
126c3437056SNickeau        }
127c3437056SNickeau        /**
128c3437056SNickeau         * Minimal length check
129c3437056SNickeau         */
130c3437056SNickeau        $namesLength = sizeof($names);
131c3437056SNickeau        if ($namesLength > $canonicalLastNamesCount) {
132c3437056SNickeau            $names = array_slice($names, $namesLength - $canonicalLastNamesCount);
133c3437056SNickeau        }
134c3437056SNickeau        /**
135c3437056SNickeau         * If this is a `start` page, delete the name
136c3437056SNickeau         * ie javascript:start will become javascript
137c3437056SNickeau         * (Not a home page)
13804fd306cSNickeau         *
13904fd306cSNickeau         * We don't use the {@link MarkupPath::isIndexPage()}
14004fd306cSNickeau         * because the path `ns:ns` is also an index if the
14104fd306cSNickeau         * page `ns:start` does not exists
142c3437056SNickeau         */
14304fd306cSNickeau        if ($resourceCombo->getPathObject()->getLastNameWithoutExtension() === Site::getIndexPageName()) {
144c3437056SNickeau            $names = array_slice($names, 0, $namesLength - 1);
145c3437056SNickeau        }
146c3437056SNickeau        $calculatedCanonical = implode(":", $names);
14704fd306cSNickeau        WikiPath::addRootSeparatorIfNotPresent($calculatedCanonical);
14804fd306cSNickeau        try {
14904fd306cSNickeau            return WikiPath::createMarkupPathFromPath($calculatedCanonical);
15004fd306cSNickeau        } catch (ExceptionBadArgument $e) {
15104fd306cSNickeau            LogUtility::internalError("A canonical should not be the root, should not happen", self::CANONICAL);
15204fd306cSNickeau            throw new ExceptionNotFound();
153c3437056SNickeau        }
154c3437056SNickeau
15504fd306cSNickeau    }
15604fd306cSNickeau
15704fd306cSNickeau    public static function getCanonical(): string
158c3437056SNickeau    {
159c3437056SNickeau        return self::CANONICAL;
160c3437056SNickeau    }
161c3437056SNickeau
162c3437056SNickeau
16304fd306cSNickeau    public static function getDrive(): string
16404fd306cSNickeau    {
16504fd306cSNickeau        return WikiPath::MARKUP_DRIVE;
16604fd306cSNickeau    }
16704fd306cSNickeau
16804fd306cSNickeau    public static function isOnForm(): bool
16904fd306cSNickeau    {
17004fd306cSNickeau        return true;
17104fd306cSNickeau    }
17204fd306cSNickeau
17304fd306cSNickeau
17404fd306cSNickeau    /**
17504fd306cSNickeau     * The Url of the local web server
17604fd306cSNickeau     * @throws ExceptionNotFound
17704fd306cSNickeau     */
17804fd306cSNickeau    public function getLocalUrl(): Url
17904fd306cSNickeau    {
18004fd306cSNickeau        return UrlEndpoint::createDokuUrl()
18104fd306cSNickeau            ->addQueryParameter(DokuwikiId::DOKUWIKI_ID_ATTRIBUTE, $this->getValue()->getWikiId());
18204fd306cSNickeau    }
18304fd306cSNickeau
18404fd306cSNickeau    /**
18504fd306cSNickeau     *
18604fd306cSNickeau     * @return Url - the url of the combostrap web server for documentation
18704fd306cSNickeau     * @throws ExceptionNotFound
18804fd306cSNickeau     */
18904fd306cSNickeau    public function getComboStrapUrlForDocumentation(): Url
19004fd306cSNickeau    {
19104fd306cSNickeau        $path = $this->getValue()->toAbsoluteId();
19204fd306cSNickeau        $path = str_replace(":", "/", $path);
19304fd306cSNickeau        try {
19404fd306cSNickeau            return Url::createFromString(PluginUtility::$INFO_PLUGIN['url'])
19504fd306cSNickeau                ->setPath($path);
19604fd306cSNickeau        } catch (ExceptionBadArgument|ExceptionBadSyntax $e) {
19704fd306cSNickeau            $message = "The url in the plugin info file seems to be broken.";
19804fd306cSNickeau            LogUtility::internalError($message, self::CANONICAL, $e);
19904fd306cSNickeau            throw new ExceptionNotFound($message);
20004fd306cSNickeau        }
20104fd306cSNickeau    }
20204fd306cSNickeau
203c3437056SNickeau}
204