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