xref: /template/strap/ComboStrap/Canonical.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1c3437056SNickeau<?php
2c3437056SNickeau
3c3437056SNickeau
4c3437056SNickeaunamespace ComboStrap;
5c3437056SNickeau
6c3437056SNickeau
7*04fd306cSNickeauuse action_plugin_combo_metaprocessing;
8*04fd306cSNickeauuse ComboStrap\Meta\Api\Metadata;
9*04fd306cSNickeauuse ComboStrap\Meta\Api\MetadataText;
10*04fd306cSNickeauuse ComboStrap\Meta\Api\MetadataWikiPath;
11*04fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore;
12*04fd306cSNickeauuse ComboStrap\Web\Url;
13*04fd306cSNickeauuse ComboStrap\Web\UrlEndpoint;
14*04fd306cSNickeau
15*04fd306cSNickeau
16c3437056SNickeauclass Canonical extends MetadataWikiPath
17c3437056SNickeau{
18c3437056SNickeau
19c3437056SNickeau    public const PROPERTY_NAME = "canonical";
20c3437056SNickeau    public const CANONICAL = "canonical";
21c3437056SNickeau
22c3437056SNickeau    /**
23c3437056SNickeau     * The auto-canonical feature does not create any canonical value on the file system
24c3437056SNickeau     * but creates a canonical in the database (where the {@link \action_plugin_combo_router}
25c3437056SNickeau     * takes its information and it enables to route via a calculated canonical
26c3437056SNickeau     * (ie the {@link Canonical::getDefaultValue()}
27c3437056SNickeau     */
28c3437056SNickeau    public const CONF_CANONICAL_LAST_NAMES_COUNT = 'MinimalNamesCountForAutomaticCanonical';
29c3437056SNickeau
30*04fd306cSNickeau    public static function createForPage(MarkupPath $page): Canonical
31c3437056SNickeau    {
32c3437056SNickeau        return (new Canonical())
33c3437056SNickeau            ->setResource($page);
34c3437056SNickeau
35c3437056SNickeau    }
36c3437056SNickeau
37*04fd306cSNickeau    /**
38*04fd306cSNickeau     * @return WikiPath
39*04fd306cSNickeau     * @throws ExceptionNotFound
40*04fd306cSNickeau     */
41*04fd306cSNickeau    public function getValueOrDefault(): WikiPath
42*04fd306cSNickeau    {
43*04fd306cSNickeau        try {
44*04fd306cSNickeau            return $this->getValue();
45*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
46*04fd306cSNickeau            return $this->getDefaultValue();
47*04fd306cSNickeau        }
48*04fd306cSNickeau    }
49*04fd306cSNickeau
50*04fd306cSNickeau
51*04fd306cSNickeau    public static function getTab(): string
52c3437056SNickeau    {
53c3437056SNickeau        return MetaManagerForm::TAB_REDIRECTION_VALUE;
54c3437056SNickeau    }
55c3437056SNickeau
56*04fd306cSNickeau    public static function getDescription(): string
57c3437056SNickeau    {
58c3437056SNickeau        return "The canonical path is a short unique path for the page (used in named permalink)";
59c3437056SNickeau    }
60c3437056SNickeau
61*04fd306cSNickeau    public static function getLabel(): string
62c3437056SNickeau    {
63c3437056SNickeau        return "Canonical Path";
64c3437056SNickeau    }
65c3437056SNickeau
66c3437056SNickeau    public static function getName(): string
67c3437056SNickeau    {
68c3437056SNickeau        return self::PROPERTY_NAME;
69c3437056SNickeau    }
70c3437056SNickeau
71*04fd306cSNickeau    public static function getPersistenceType(): string
72c3437056SNickeau    {
73*04fd306cSNickeau        return MetadataDokuWikiStore::PERSISTENT_DOKUWIKI_KEY;
74c3437056SNickeau    }
75c3437056SNickeau
76*04fd306cSNickeau    public static function isMutable(): bool
77c3437056SNickeau    {
78c3437056SNickeau        return true;
79c3437056SNickeau    }
80c3437056SNickeau
81*04fd306cSNickeau    public static function createFromValue(string $canonical): Canonical
82c3437056SNickeau    {
83*04fd306cSNickeau        /** @noinspection PhpIncompatibleReturnTypeInspection */
84*04fd306cSNickeau        return (new Canonical())
85*04fd306cSNickeau            ->setValue($canonical);
86*04fd306cSNickeau    }
87*04fd306cSNickeau
88*04fd306cSNickeau
89*04fd306cSNickeau    /**
90*04fd306cSNickeau     * @return WikiPath
91*04fd306cSNickeau     * @throws ExceptionNotFound
92*04fd306cSNickeau     */
93*04fd306cSNickeau    public function getDefaultValue(): WikiPath
94*04fd306cSNickeau    {
95*04fd306cSNickeau
96*04fd306cSNickeau        $resourceCombo = $this->getResource();
97*04fd306cSNickeau        if (!($resourceCombo instanceof MarkupPath)) {
98*04fd306cSNickeau            throw new ExceptionNotFound("No default value for other resources than page");
99*04fd306cSNickeau        }
100*04fd306cSNickeau
101c3437056SNickeau        /**
102c3437056SNickeau         * The last part of the id as canonical
103c3437056SNickeau         */
104c3437056SNickeau        // How many last parts are taken into account in the canonical processing (2 by default)
105*04fd306cSNickeau        $canonicalLastNamesCount = SiteConfig::getConfValue(self::CONF_CANONICAL_LAST_NAMES_COUNT, 0);
106*04fd306cSNickeau        if ($canonicalLastNamesCount <= 0) {
107*04fd306cSNickeau            throw new ExceptionNotFound("Default canonical value is not enabled, no default canonical");
108*04fd306cSNickeau        }
109*04fd306cSNickeau
110c3437056SNickeau        /**
111c3437056SNickeau         * Takes the last names part
112c3437056SNickeau         */
113*04fd306cSNickeau        $namesOriginal = $this->getResource()->getPathObject()->getNamesWithoutExtension();
114c3437056SNickeau        /**
115c3437056SNickeau         * Delete the identical names at the end
116c3437056SNickeau         * To resolve this problem
117c3437056SNickeau         * The page (viz:viz) and the page (data:viz:viz) have the same canonical.
118c3437056SNickeau         * The page (viz:viz) will get the canonical viz
119c3437056SNickeau         * The page (data:viz) will get the canonical  data:viz
120c3437056SNickeau         */
121c3437056SNickeau        $i = sizeof($namesOriginal) - 1;
122c3437056SNickeau        $names = $namesOriginal;
123c3437056SNickeau        while ($namesOriginal[$i] == $namesOriginal[$i - 1]) {
124c3437056SNickeau            unset($names[$i]);
125c3437056SNickeau            $i--;
126c3437056SNickeau            if ($i <= 0) {
127c3437056SNickeau                break;
128c3437056SNickeau            }
129c3437056SNickeau        }
130c3437056SNickeau        /**
131c3437056SNickeau         * Minimal length check
132c3437056SNickeau         */
133c3437056SNickeau        $namesLength = sizeof($names);
134c3437056SNickeau        if ($namesLength > $canonicalLastNamesCount) {
135c3437056SNickeau            $names = array_slice($names, $namesLength - $canonicalLastNamesCount);
136c3437056SNickeau        }
137c3437056SNickeau        /**
138c3437056SNickeau         * If this is a `start` page, delete the name
139c3437056SNickeau         * ie javascript:start will become javascript
140c3437056SNickeau         * (Not a home page)
141*04fd306cSNickeau         *
142*04fd306cSNickeau         * We don't use the {@link MarkupPath::isIndexPage()}
143*04fd306cSNickeau         * because the path `ns:ns` is also an index if the
144*04fd306cSNickeau         * page `ns:start` does not exists
145c3437056SNickeau         */
146*04fd306cSNickeau        if ($resourceCombo->getPathObject()->getLastNameWithoutExtension() === Site::getIndexPageName()) {
147c3437056SNickeau            $names = array_slice($names, 0, $namesLength - 1);
148c3437056SNickeau        }
149c3437056SNickeau        $calculatedCanonical = implode(":", $names);
150*04fd306cSNickeau        WikiPath::addRootSeparatorIfNotPresent($calculatedCanonical);
151*04fd306cSNickeau        try {
152*04fd306cSNickeau            return WikiPath::createMarkupPathFromPath($calculatedCanonical);
153*04fd306cSNickeau        } catch (ExceptionBadArgument $e) {
154*04fd306cSNickeau            LogUtility::internalError("A canonical should not be the root, should not happen", self::CANONICAL);
155*04fd306cSNickeau            throw new ExceptionNotFound();
156c3437056SNickeau        }
157c3437056SNickeau
158*04fd306cSNickeau    }
159*04fd306cSNickeau
160*04fd306cSNickeau    public static function getCanonical(): string
161c3437056SNickeau    {
162c3437056SNickeau        return self::CANONICAL;
163c3437056SNickeau    }
164c3437056SNickeau
165c3437056SNickeau
166*04fd306cSNickeau    public static function getDrive(): string
167*04fd306cSNickeau    {
168*04fd306cSNickeau        return WikiPath::MARKUP_DRIVE;
169*04fd306cSNickeau    }
170*04fd306cSNickeau
171*04fd306cSNickeau    public static function isOnForm(): bool
172*04fd306cSNickeau    {
173*04fd306cSNickeau        return true;
174*04fd306cSNickeau    }
175*04fd306cSNickeau
176*04fd306cSNickeau
177*04fd306cSNickeau    /**
178*04fd306cSNickeau     * The Url of the local web server
179*04fd306cSNickeau     * @throws ExceptionNotFound
180*04fd306cSNickeau     */
181*04fd306cSNickeau    public function getLocalUrl(): Url
182*04fd306cSNickeau    {
183*04fd306cSNickeau        return UrlEndpoint::createDokuUrl()
184*04fd306cSNickeau            ->addQueryParameter(DokuwikiId::DOKUWIKI_ID_ATTRIBUTE, $this->getValue()->getWikiId());
185*04fd306cSNickeau    }
186*04fd306cSNickeau
187*04fd306cSNickeau    /**
188*04fd306cSNickeau     *
189*04fd306cSNickeau     * @return Url - the url of the combostrap web server for documentation
190*04fd306cSNickeau     * @throws ExceptionNotFound
191*04fd306cSNickeau     */
192*04fd306cSNickeau    public function getComboStrapUrlForDocumentation(): Url
193*04fd306cSNickeau    {
194*04fd306cSNickeau        $path = $this->getValue()->toAbsoluteId();
195*04fd306cSNickeau        $path = str_replace(":", "/", $path);
196*04fd306cSNickeau        try {
197*04fd306cSNickeau            return Url::createFromString(PluginUtility::$INFO_PLUGIN['url'])
198*04fd306cSNickeau                ->setPath($path);
199*04fd306cSNickeau        } catch (ExceptionBadArgument|ExceptionBadSyntax $e) {
200*04fd306cSNickeau            $message = "The url in the plugin info file seems to be broken.";
201*04fd306cSNickeau            LogUtility::internalError($message, self::CANONICAL, $e);
202*04fd306cSNickeau            throw new ExceptionNotFound($message);
203*04fd306cSNickeau        }
204*04fd306cSNickeau    }
205*04fd306cSNickeau
206c3437056SNickeau}
207