1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeau 4*04fd306cSNickeaunamespace ComboStrap\Meta\Field; 5*04fd306cSNickeau 6*04fd306cSNickeau 7*04fd306cSNickeauuse ComboStrap\ExceptionCompile; 8*04fd306cSNickeauuse ComboStrap\ExceptionNotFound; 9*04fd306cSNickeauuse ComboStrap\ExceptionSqliteNotAvailable; 10*04fd306cSNickeauuse ComboStrap\LogUtility; 11*04fd306cSNickeauuse ComboStrap\MarkupPath; 12*04fd306cSNickeauuse ComboStrap\Meta\Api\Metadata; 13*04fd306cSNickeauuse ComboStrap\Meta\Api\MetadataSystem; 14*04fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore; 15*04fd306cSNickeauuse ComboStrap\Meta\Api\MetadataTabular; 16*04fd306cSNickeauuse ComboStrap\MetaManagerForm; 17*04fd306cSNickeauuse ComboStrap\Sqlite; 18*04fd306cSNickeauuse ComboStrap\StringUtility; 19*04fd306cSNickeauuse ComboStrap\WikiPath; 20*04fd306cSNickeau 21*04fd306cSNickeauclass Aliases extends MetadataTabular 22*04fd306cSNickeau{ 23*04fd306cSNickeau 24*04fd306cSNickeau public const PROPERTY_NAME = "aliases"; 25*04fd306cSNickeau 26*04fd306cSNickeau 27*04fd306cSNickeau 28*04fd306cSNickeau public static function createForPage(MarkupPath $page): Aliases 29*04fd306cSNickeau { 30*04fd306cSNickeau 31*04fd306cSNickeau return (new Aliases())->setResource($page); 32*04fd306cSNickeau 33*04fd306cSNickeau } 34*04fd306cSNickeau 35*04fd306cSNickeau public static function create(): Aliases 36*04fd306cSNickeau { 37*04fd306cSNickeau return new Aliases(); 38*04fd306cSNickeau } 39*04fd306cSNickeau 40*04fd306cSNickeau /** 41*04fd306cSNickeau * @return Alias[]|null 42*04fd306cSNickeau * @throws ExceptionNotFound 43*04fd306cSNickeau */ 44*04fd306cSNickeau public function getValueAsAlias(): array 45*04fd306cSNickeau { 46*04fd306cSNickeau $rows = $this->getValue(); 47*04fd306cSNickeau $aliases = []; 48*04fd306cSNickeau foreach ($rows as $row) { 49*04fd306cSNickeau /** 50*04fd306cSNickeau * @var AliasPath $aliasMeta 51*04fd306cSNickeau */ 52*04fd306cSNickeau $aliasMeta = $row[AliasPath::getPersistentName()]; 53*04fd306cSNickeau $alias = Alias::create($this->getResource(), $aliasMeta->getValue()); 54*04fd306cSNickeau /** 55*04fd306cSNickeau * @var AliasType $aliasType 56*04fd306cSNickeau */ 57*04fd306cSNickeau $aliasType = $row[AliasType::getPersistentName()]; 58*04fd306cSNickeau if ($aliasType !== null) { 59*04fd306cSNickeau try { 60*04fd306cSNickeau $alias->setType($aliasType->getValue()); 61*04fd306cSNickeau } catch (ExceptionNotFound $e) { 62*04fd306cSNickeau // ok 63*04fd306cSNickeau } 64*04fd306cSNickeau 65*04fd306cSNickeau } 66*04fd306cSNickeau $aliases[] = $alias; 67*04fd306cSNickeau } 68*04fd306cSNickeau return $aliases; 69*04fd306cSNickeau } 70*04fd306cSNickeau 71*04fd306cSNickeau 72*04fd306cSNickeau /** 73*04fd306cSNickeau * @param array|null $aliasesPersistentValues 74*04fd306cSNickeau * return Alias[] 75*04fd306cSNickeau */ 76*04fd306cSNickeau private function toNativeAliasArray(?array $aliasesPersistentValues): array 77*04fd306cSNickeau { 78*04fd306cSNickeau if ($aliasesPersistentValues === null) { 79*04fd306cSNickeau return []; 80*04fd306cSNickeau } 81*04fd306cSNickeau $aliases = []; 82*04fd306cSNickeau foreach ($aliasesPersistentValues as $key => $value) { 83*04fd306cSNickeau if (is_array($value)) { 84*04fd306cSNickeau $path = $value[AliasPath::PERSISTENT_NAME]; 85*04fd306cSNickeau if (empty($path)) { 86*04fd306cSNickeau if (is_string($key)) { 87*04fd306cSNickeau // Old way (deprecated) 88*04fd306cSNickeau $path = $key; 89*04fd306cSNickeau } else { 90*04fd306cSNickeau LogUtility::msg("The path of the alias should not be empty to create a path", Alias::CANONICAL); 91*04fd306cSNickeau } 92*04fd306cSNickeau } 93*04fd306cSNickeau $type = $value[AliasType::PERSISTENT_NAME]; 94*04fd306cSNickeau 95*04fd306cSNickeau /** 96*04fd306cSNickeau * We don't create via the {@link Aliases::addAlias()} 97*04fd306cSNickeau * to not persist for each each alias value 98*04fd306cSNickeau **/ 99*04fd306cSNickeau $aliases[] = Alias::create($this->getResource(), $path) 100*04fd306cSNickeau ->setType($type); 101*04fd306cSNickeau } else { 102*04fd306cSNickeau $path = $value; 103*04fd306cSNickeau if (empty($path)) { 104*04fd306cSNickeau LogUtility::msg("The value of the alias array should not be empty as it's the alias path", Alias::CANONICAL); 105*04fd306cSNickeau } 106*04fd306cSNickeau if (!is_string($path)) { 107*04fd306cSNickeau $path = StringUtility::toString($path); 108*04fd306cSNickeau LogUtility::error("The alias element ($path) is not a string", Alias::CANONICAL); 109*04fd306cSNickeau } 110*04fd306cSNickeau $path = WikiPath::createMarkupPathFromId($path); 111*04fd306cSNickeau $aliases[] = Alias::create($this->getResource(), $path); 112*04fd306cSNickeau } 113*04fd306cSNickeau } 114*04fd306cSNickeau return $aliases; 115*04fd306cSNickeau } 116*04fd306cSNickeau 117*04fd306cSNickeau 118*04fd306cSNickeau /** 119*04fd306cSNickeau * @param Alias[] $aliases 120*04fd306cSNickeau * @return null|array - the array to be saved in a text/json file 121*04fd306cSNickeau */ 122*04fd306cSNickeau public static function toMetadataArray(?array $aliases): ?array 123*04fd306cSNickeau { 124*04fd306cSNickeau if ($aliases === null) { 125*04fd306cSNickeau return null; 126*04fd306cSNickeau } 127*04fd306cSNickeau $array = []; 128*04fd306cSNickeau foreach ($aliases as $alias) { 129*04fd306cSNickeau $array[$alias->getPath()->toAbsoluteId()] = [ 130*04fd306cSNickeau AliasPath::PERSISTENT_NAME => $alias->getPath()->toAbsoluteId(), 131*04fd306cSNickeau AliasType::PERSISTENT_NAME => $alias->getType() 132*04fd306cSNickeau ]; 133*04fd306cSNickeau } 134*04fd306cSNickeau return array_values($array); 135*04fd306cSNickeau } 136*04fd306cSNickeau 137*04fd306cSNickeau public static function getName(): string 138*04fd306cSNickeau { 139*04fd306cSNickeau return self::PROPERTY_NAME; 140*04fd306cSNickeau } 141*04fd306cSNickeau 142*04fd306cSNickeau 143*04fd306cSNickeau static public function getPersistenceType(): string 144*04fd306cSNickeau { 145*04fd306cSNickeau return MetadataDokuWikiStore::PERSISTENT_DOKUWIKI_KEY; 146*04fd306cSNickeau } 147*04fd306cSNickeau 148*04fd306cSNickeau /** 149*04fd306cSNickeau * Code refactoring 150*04fd306cSNickeau * This method is not in the database page 151*04fd306cSNickeau * because it would create a cycle 152*04fd306cSNickeau * 153*04fd306cSNickeau * The old data was saved in the database 154*04fd306cSNickeau * but should have been saved on the file system 155*04fd306cSNickeau * 156*04fd306cSNickeau * Once 157*04fd306cSNickeau * @return Alias[] 158*04fd306cSNickeau * @throws ExceptionSqliteNotAvailable 159*04fd306cSNickeau * @deprecated 2021-10-31 160*04fd306cSNickeau */ 161*04fd306cSNickeau private 162*04fd306cSNickeau function getAndDeleteDeprecatedAlias(): array 163*04fd306cSNickeau { 164*04fd306cSNickeau $sqlite = Sqlite::createOrGetSqlite(); 165*04fd306cSNickeau 166*04fd306cSNickeau try { 167*04fd306cSNickeau $canonicalOrDefault = $this->getResource()->getCanonicalOrDefault(); 168*04fd306cSNickeau } catch (ExceptionNotFound $e) { 169*04fd306cSNickeau return []; 170*04fd306cSNickeau } 171*04fd306cSNickeau /** @noinspection SqlResolve */ 172*04fd306cSNickeau $request = $sqlite 173*04fd306cSNickeau ->createRequest() 174*04fd306cSNickeau ->setQueryParametrized("select ALIAS from DEPRECATED_PAGES_ALIAS where CANONICAL = ?", [$canonicalOrDefault]); 175*04fd306cSNickeau $deprecatedAliases = []; 176*04fd306cSNickeau $deprecatedAliasInDb = []; 177*04fd306cSNickeau try { 178*04fd306cSNickeau $deprecatedAliasInDb = $request 179*04fd306cSNickeau ->execute() 180*04fd306cSNickeau ->getRows(); 181*04fd306cSNickeau } catch (ExceptionCompile $e) { 182*04fd306cSNickeau LogUtility::msg("An exception has occurred with the deprecated alias selection query. {$e->getMessage()}"); 183*04fd306cSNickeau return []; 184*04fd306cSNickeau } finally { 185*04fd306cSNickeau $request->close(); 186*04fd306cSNickeau } 187*04fd306cSNickeau 188*04fd306cSNickeau array_map( 189*04fd306cSNickeau function ($row) use ($deprecatedAliases) { 190*04fd306cSNickeau $alias = $row['ALIAS']; 191*04fd306cSNickeau $deprecatedAliases[$alias] = Alias::create($this->getResource(), $alias) 192*04fd306cSNickeau ->setType(AliasType::REDIRECT); 193*04fd306cSNickeau }, 194*04fd306cSNickeau $deprecatedAliasInDb 195*04fd306cSNickeau ); 196*04fd306cSNickeau 197*04fd306cSNickeau /** 198*04fd306cSNickeau * Delete them 199*04fd306cSNickeau */ 200*04fd306cSNickeau 201*04fd306cSNickeau if (sizeof($deprecatedAliasInDb) > 0) { 202*04fd306cSNickeau /** @noinspection SqlResolve */ 203*04fd306cSNickeau $request = $sqlite 204*04fd306cSNickeau ->createRequest() 205*04fd306cSNickeau ->setQueryParametrized("delete from DEPRECATED_PAGE_ALIASES where CANONICAL = ?", [$canonicalOrDefault]); 206*04fd306cSNickeau try { 207*04fd306cSNickeau $request->execute(); 208*04fd306cSNickeau } catch (ExceptionCompile $e) { 209*04fd306cSNickeau LogUtility::msg("An exception has occurred with the delete deprecated alias statement. {$e->getMessage()}", LogUtility::LVL_MSG_ERROR); 210*04fd306cSNickeau } finally { 211*04fd306cSNickeau $request->close(); 212*04fd306cSNickeau } 213*04fd306cSNickeau } 214*04fd306cSNickeau 215*04fd306cSNickeau 216*04fd306cSNickeau /** 217*04fd306cSNickeau * Return 218*04fd306cSNickeau */ 219*04fd306cSNickeau return $deprecatedAliases; 220*04fd306cSNickeau 221*04fd306cSNickeau } 222*04fd306cSNickeau 223*04fd306cSNickeau 224*04fd306cSNickeau /** 225*04fd306cSNickeau * @return Metadata[][] - an list of rows of metadata columns 226*04fd306cSNickeau */ 227*04fd306cSNickeau public function getDefaultValue(): array 228*04fd306cSNickeau { 229*04fd306cSNickeau return 230*04fd306cSNickeau [ 231*04fd306cSNickeau [ 232*04fd306cSNickeau AliasPath::getPersistentName() => AliasPath::createForParent($this), 233*04fd306cSNickeau AliasType::getPersistentName() => AliasType::createForParent($this)->setFromStoreValueWithoutException(AliasType::DEFAULT) 234*04fd306cSNickeau ] 235*04fd306cSNickeau ]; 236*04fd306cSNickeau } 237*04fd306cSNickeau 238*04fd306cSNickeau 239*04fd306cSNickeau public function getValue(): array 240*04fd306cSNickeau { 241*04fd306cSNickeau $this->buildCheck(); 242*04fd306cSNickeau 243*04fd306cSNickeau /** 244*04fd306cSNickeau * We don't do that on build because 245*04fd306cSNickeau * we are using a set a metadata method that creates 246*04fd306cSNickeau * a cycle via the {@link MetadataMutation::PAGE_METADATA_MUTATION_EVENT} 247*04fd306cSNickeau */ 248*04fd306cSNickeau if ( 249*04fd306cSNickeau !$this->valueIsNotNull() 250*04fd306cSNickeau && 251*04fd306cSNickeau $this->getReadStore() !== null 252*04fd306cSNickeau && 253*04fd306cSNickeau $this->getReadStore() instanceof MetadataDokuWikiStore 254*04fd306cSNickeau ) { 255*04fd306cSNickeau $this->getAndDeleteDeprecatedAlias(); 256*04fd306cSNickeau /** 257*04fd306cSNickeau * To validate the migration we set a value 258*04fd306cSNickeau * (the array may be empty) 259*04fd306cSNickeau */ 260*04fd306cSNickeau try { 261*04fd306cSNickeau $this->sendToWriteStore(); 262*04fd306cSNickeau } catch (ExceptionCompile $e) { 263*04fd306cSNickeau LogUtility::msg("Error while persisting the new data"); 264*04fd306cSNickeau } 265*04fd306cSNickeau } 266*04fd306cSNickeau 267*04fd306cSNickeau return parent::getValue(); 268*04fd306cSNickeau } 269*04fd306cSNickeau 270*04fd306cSNickeau /** 271*04fd306cSNickeau * @throws ExceptionCompile 272*04fd306cSNickeau */ 273*04fd306cSNickeau public 274*04fd306cSNickeau function addAlias(string $aliasPath, $aliasType = null): Aliases 275*04fd306cSNickeau { 276*04fd306cSNickeau $this->addAndGetAlias($aliasPath, $aliasType); 277*04fd306cSNickeau return $this; 278*04fd306cSNickeau } 279*04fd306cSNickeau 280*04fd306cSNickeau /** 281*04fd306cSNickeau * @throws ExceptionCompile 282*04fd306cSNickeau */ 283*04fd306cSNickeau public 284*04fd306cSNickeau function addAndGetAlias($aliasPath, $aliasType = null): Alias 285*04fd306cSNickeau { 286*04fd306cSNickeau $this->buildCheck(); 287*04fd306cSNickeau /** 288*04fd306cSNickeau * @var AliasPath $path 289*04fd306cSNickeau */ 290*04fd306cSNickeau $path = MetadataSystem::toMetadataObject(AliasPath::class, $this) 291*04fd306cSNickeau ->setFromStoreValue($aliasPath); 292*04fd306cSNickeau $row[$path::getPersistentName()] = $path; 293*04fd306cSNickeau 294*04fd306cSNickeau $alias = Alias::create($this->getResource(), $path->getValue()); 295*04fd306cSNickeau 296*04fd306cSNickeau if ($aliasType !== null) { 297*04fd306cSNickeau $aliasObject = MetadataSystem::toMetadataObject(AliasType::class, $this) 298*04fd306cSNickeau ->setFromStoreValue($aliasType); 299*04fd306cSNickeau $row[$aliasObject::getPersistentName()] = $aliasObject; 300*04fd306cSNickeau $alias->setType($aliasType); 301*04fd306cSNickeau } 302*04fd306cSNickeau $this->rows[$path->getValue()->toAbsoluteId()] = $row; 303*04fd306cSNickeau 304*04fd306cSNickeau return $alias; 305*04fd306cSNickeau } 306*04fd306cSNickeau 307*04fd306cSNickeau 308*04fd306cSNickeau static public 309*04fd306cSNickeau function getCanonical(): string 310*04fd306cSNickeau { 311*04fd306cSNickeau return Alias::CANONICAL; 312*04fd306cSNickeau } 313*04fd306cSNickeau 314*04fd306cSNickeau static public 315*04fd306cSNickeau function getTab(): string 316*04fd306cSNickeau { 317*04fd306cSNickeau return MetaManagerForm::TAB_REDIRECTION_VALUE; 318*04fd306cSNickeau } 319*04fd306cSNickeau 320*04fd306cSNickeau static public 321*04fd306cSNickeau function getDescription(): string 322*04fd306cSNickeau { 323*04fd306cSNickeau return "Aliases that will redirect to this page."; 324*04fd306cSNickeau } 325*04fd306cSNickeau 326*04fd306cSNickeau static public function getLabel(): string 327*04fd306cSNickeau { 328*04fd306cSNickeau return "Page Aliases"; 329*04fd306cSNickeau } 330*04fd306cSNickeau 331*04fd306cSNickeau 332*04fd306cSNickeau static public function isMutable(): bool 333*04fd306cSNickeau { 334*04fd306cSNickeau return true; 335*04fd306cSNickeau } 336*04fd306cSNickeau 337*04fd306cSNickeau public function getUidClass(): ?string 338*04fd306cSNickeau { 339*04fd306cSNickeau return AliasPath::class; 340*04fd306cSNickeau } 341*04fd306cSNickeau 342*04fd306cSNickeau /** 343*04fd306cSNickeau * @return Metadata[] 344*04fd306cSNickeau */ 345*04fd306cSNickeau static public function getChildrenClass(): array 346*04fd306cSNickeau { 347*04fd306cSNickeau return [AliasPath::class, AliasType::class]; 348*04fd306cSNickeau } 349*04fd306cSNickeau 350*04fd306cSNickeau 351*04fd306cSNickeau static public function isOnForm(): bool 352*04fd306cSNickeau { 353*04fd306cSNickeau return true; 354*04fd306cSNickeau } 355*04fd306cSNickeau} 356