1<?php
2
3
4namespace ComboStrap;
5
6
7use Slug;
8
9/**
10 * Class PageUrlPath
11 * @package ComboStrap
12 *
13 *
14 * The path (ie id attribute in the url) in a absolute format (ie with root)
15 *
16 * url path: name for ns + slug (title) + page id
17 * or
18 * url path: canonical path + page id
19 * or
20 * url path: page path + page id
21 *
22 *
23 *   - slug
24 *   - hierarchical slug
25 *   - permanent canonical path (page id)
26 *   - canonical path
27 *   - permanent page path (page id)
28 *   - page path
29 *
30 * This is not the URL of the page but of the generated HTML web page (Ie {@link HtmlDocument}) with all pages (slots)
31 */
32class PageUrlPath extends MetadataWikiPath
33{
34
35    /**
36     *
37     * The page id is separated in the URL with a "-"
38     * and not the standard "/"
39     * because in the devtool or any other tool, they takes
40     * the last part of the path as name.
41     *
42     * The name would be the short page id `22h2s2j4`
43     * and would have therefore no signification
44     *
45     * Instead the name is `metadata-manager-22h2s2j4`
46     * we can see then a page description, even order on it
47     */
48    public const PAGE_ID_URL_SEPARATOR = "-";
49    /**
50     * The canonical page for the page url
51     */
52    public const CANONICAL = "page:url";
53    const PROPERTY_NAME = "page-url-path";
54
55    public static function createForPage(Page $page)
56    {
57        return (new PageUrlPath())
58            ->setResource($page);
59    }
60
61    public static function getShortEncodedPageIdFromUrlId($lastPartName)
62    {
63        $lastPosition = strrpos($lastPartName, PageUrlPath::PAGE_ID_URL_SEPARATOR);
64        if ($lastPosition === false) {
65            return null;
66        }
67        return substr($lastPartName, $lastPosition + 1);
68    }
69
70    public function getTab(): string
71    {
72        return MetaManagerForm::TAB_REDIRECTION_VALUE;
73    }
74
75    public function getValue(): ?string
76    {
77
78        $page = $this->getResource();
79        if (!($page instanceof Page)) {
80            LogUtility::msg("The Url Path is not implemented for the resource type (" . $page->getType() . ")");
81            return null;
82        }
83
84        /**
85         * Type of Url
86         */
87        $urlType = PageUrlType::getOrCreateForPage($page)->getValue();
88        $urlTypeDefault = PageUrlType::getOrCreateForPage($page)->getDefaultValue();
89        if ($urlType === $urlTypeDefault) {
90            return null;
91        }
92        return $this->getUrlPathFromType($urlType);
93
94    }
95
96
97    public function getDescription(): string
98    {
99        return "The path used in the page url";
100    }
101
102    public function getLabel(): string
103    {
104        return "Url Path";
105    }
106
107    static public function getName(): string
108    {
109        return self::PROPERTY_NAME;
110    }
111
112    public function getPersistenceType(): string
113    {
114        return Metadata::DERIVED_METADATA;
115    }
116
117    public function getMutable(): bool
118    {
119        return false;
120    }
121
122    public function getDefaultValue()
123    {
124
125        $urlTypeDefault = PageUrlType::getOrCreateForPage($this->getResource())->getDefaultValue();
126        return $this->getUrlPathFromType($urlTypeDefault);
127
128    }
129
130    public function getCanonical(): string
131    {
132        return self::CANONICAL;
133    }
134
135
136    private
137    function toPermanentUrlPath(string $id): string
138    {
139        return $id . self::PAGE_ID_URL_SEPARATOR . $this->getPageIdAbbrUrlEncoded();
140    }
141
142    /**
143     * Add a one letter checksum
144     * to verify that this is a page id abbr
145     * ( and not to hit the index for nothing )
146     * @return string
147     */
148    public
149    function getPageIdAbbrUrlEncoded(): ?string
150    {
151        $page = $this->getPage();
152        if ($page->getPageIdAbbr() == null) return null;
153        $abbr = $page->getPageIdAbbr();
154        return self::encodePageId($abbr);
155    }
156
157    /**
158     * Add a checksum character to the page id
159     * to check if it's a page id that we get in the url
160     * @param string $pageId
161     * @return string
162     */
163    public static function encodePageId(string $pageId): string
164    {
165        return self::getPageIdChecksumCharacter($pageId) . $pageId;
166    }
167
168    /**
169     * @param string $encodedPageId
170     * @return string|null return the decoded page id or null if it's not an encoded page id
171     */
172    public static function decodePageId(string $encodedPageId): ?string
173    {
174        if (empty($encodedPageId)) return null;
175        $checkSum = $encodedPageId[0];
176        $extractedEncodedPageId = substr($encodedPageId, 1);
177        $calculatedCheckSum = self::getPageIdChecksumCharacter($extractedEncodedPageId);
178        if ($calculatedCheckSum == null) return null;
179        if ($calculatedCheckSum != $checkSum) return null;
180        return $extractedEncodedPageId;
181    }
182
183    /**
184     * @param string $pageId
185     * @return string|null - the checksum letter or null if this is not a page id
186     */
187    public static function getPageIdChecksumCharacter(string $pageId): ?string
188    {
189        $total = 0;
190        for ($i = 0; $i < strlen($pageId); $i++) {
191            $letter = $pageId[$i];
192            $pos = strpos(PageId::PAGE_ID_ALPHABET, $letter);
193            if ($pos === false) {
194                return null;
195            }
196            $total += $pos;
197        }
198        $checkSum = $total % strlen(PageId::PAGE_ID_ALPHABET);
199        return PageId::PAGE_ID_ALPHABET[$checkSum];
200    }
201
202    /**
203     * Utility to change the type of the resource
204     * @return Page|null
205     */
206    private function getPage(): ?Page
207    {
208        $resource = $this->getResource();
209        if ($resource instanceof Page) {
210            return $resource;
211        }
212        return null;
213    }
214
215    public function getUrlPathFromType(?string $urlType)
216    {
217        $page = $this->getResource();
218        if((!$page instanceof Page)){
219            LogUtility::msg("The url path is only for page resources", LogUtility::LVL_MSG_ERROR, $this->getCanonical());
220            return null;
221        }
222
223        $pagePath = $page->getPath()->toString();
224        switch ($urlType) {
225            case PageUrlType::CONF_VALUE_PAGE_PATH:
226                // the default
227                return $pagePath;
228            case PageUrlType::CONF_VALUE_PERMANENT_PAGE_PATH:
229                return $this->toPermanentUrlPath($pagePath);
230            case PageUrlType::CONF_VALUE_CANONICAL_PATH:
231                return $page->getCanonicalOrDefault();
232            case PageUrlType::CONF_VALUE_PERMANENT_CANONICAL_PATH:
233                return $this->toPermanentUrlPath($page->getCanonicalOrDefault());
234            case PageUrlType::CONF_VALUE_SLUG:
235                return $this->toPermanentUrlPath($page->getSlugOrDefault());
236            case PageUrlType::CONF_VALUE_HIERARCHICAL_SLUG:
237                $urlPath = $page->getSlugOrDefault();
238                while (($parentPage = $page->getParentPage()) != null) {
239                    if(!$parentPage->isRootHomePage()) {
240                        $urlPath = Slug::toSlugPath($parentPage->getNameOrDefault()) . $urlPath;
241                    }
242                }
243                return $this->toPermanentUrlPath($urlPath);
244            case PageUrlType::CONF_VALUE_HOMED_SLUG:
245                $urlPath = $page->getSlugOrDefault();
246                if (($parentPage = $page->getParentPage()) != null) {
247                    if(!$parentPage->isRootHomePage()) {
248                        $urlPath = Slug::toSlugPath($parentPage->getNameOrDefault()) . $urlPath;
249                    }
250                }
251                return $this->toPermanentUrlPath($urlPath);
252            default:
253                LogUtility::msg("The url type ($urlType) is unknown and was unexpected", LogUtility::LVL_MSG_ERROR, self::PROPERTY_NAME);
254                return null;
255        }
256    }
257
258}
259