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