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