1c3437056SNickeau<?php 2c3437056SNickeau 3c3437056SNickeau 4c3437056SNickeaunamespace ComboStrap; 5c3437056SNickeau 6*4cadd4f8SNickeauuse DateTime; 7c3437056SNickeauuse ModificationDate; 8c3437056SNickeau 9c3437056SNickeau/** 10c3437056SNickeau * The class that manage the replication 11c3437056SNickeau * Class Replicate 12c3437056SNickeau * @package ComboStrap 13c3437056SNickeau * 14c3437056SNickeau * The database can also be seen as a {@link MetadataStore} 15c3437056SNickeau * and an {@link Index} 16c3437056SNickeau */ 17c3437056SNickeauclass DatabasePageRow 18c3437056SNickeau{ 19c3437056SNickeau 20c3437056SNickeau 21c3437056SNickeau /** 22c3437056SNickeau * The list of attributes that are set 23c3437056SNickeau * at build time 24c3437056SNickeau * used in the build functions such as {@link DatabasePageRow::getDatabaseRowFromPage()} 25c3437056SNickeau * to build the sql 26c3437056SNickeau */ 27c3437056SNickeau private const PAGE_BUILD_ATTRIBUTES = 28c3437056SNickeau [ 29c3437056SNickeau self::ROWID, 30c3437056SNickeau DokuwikiId::DOKUWIKI_ID_ATTRIBUTE, 31c3437056SNickeau self::ANALYTICS_ATTRIBUTE, 32c3437056SNickeau PageDescription::PROPERTY_NAME, 33c3437056SNickeau Canonical::PROPERTY_NAME, 34c3437056SNickeau ResourceName::PROPERTY_NAME, 35c3437056SNickeau PageTitle::TITLE, 36c3437056SNickeau PageH1::PROPERTY_NAME, 37c3437056SNickeau PagePublicationDate::PROPERTY_NAME, 38c3437056SNickeau ModificationDate::PROPERTY_NAME, 39c3437056SNickeau PageCreationDate::PROPERTY_NAME, 40c3437056SNickeau PagePath::PROPERTY_NAME, 41c3437056SNickeau StartDate::PROPERTY_NAME, 42c3437056SNickeau EndDate::PROPERTY_NAME, 43c3437056SNickeau Region::PROPERTY_NAME, 44c3437056SNickeau Lang::PROPERTY_NAME, 45c3437056SNickeau PageType::PROPERTY_NAME, 46c3437056SNickeau PageId::PROPERTY_NAME, 47c3437056SNickeau PageId::PAGE_ID_ABBR_ATTRIBUTE, 48c3437056SNickeau \ReplicationDate::PROPERTY_NAME, 49c3437056SNickeau BacklinkCount::PROPERTY_NAME 50c3437056SNickeau ]; 51c3437056SNickeau const ANALYTICS_ATTRIBUTE = "analytics"; 52c3437056SNickeau 53c3437056SNickeau /** 54c3437056SNickeau * For whatever reason, the row id is lowercase 55c3437056SNickeau */ 56c3437056SNickeau const ROWID = "rowid"; 57c3437056SNickeau 58c3437056SNickeau const CANONICAL = MetadataDbStore::CANONICAL; 59c3437056SNickeau 60c3437056SNickeau /** 61c3437056SNickeau * @var Page 62c3437056SNickeau */ 63c3437056SNickeau private $page; 64c3437056SNickeau /** 65c3437056SNickeau * @var Sqlite|null 66c3437056SNickeau */ 67c3437056SNickeau private $sqlite; 68c3437056SNickeau 69c3437056SNickeau /** 70c3437056SNickeau * @var array 71c3437056SNickeau */ 72c3437056SNickeau private $row; 73c3437056SNickeau 74c3437056SNickeau /** 75c3437056SNickeau * Replicate constructor. 76c3437056SNickeau */ 77c3437056SNickeau public function __construct() 78c3437056SNickeau { 79c3437056SNickeau 80c3437056SNickeau /** 81c3437056SNickeau * Persist on the DB 82c3437056SNickeau */ 83c3437056SNickeau $this->sqlite = Sqlite::createOrGetSqlite(); 84c3437056SNickeau 85c3437056SNickeau 86c3437056SNickeau } 87c3437056SNickeau 88c3437056SNickeau /** 89c3437056SNickeau * Delete the cache, 90c3437056SNickeau * Process the analytics 91c3437056SNickeau * Save it in the Db 92c3437056SNickeau * Delete from the page to refresh if any 93c3437056SNickeau * 94c3437056SNickeau * If you want the analytics: 95c3437056SNickeau * * from the cache use {@link self::getAnalyticsFromFs()} 96c3437056SNickeau * * from the db use {@link self::getAnalyticsFromDb()} 97c3437056SNickeau * 98c3437056SNickeau * 99c3437056SNickeau * @throws ExceptionCombo 100c3437056SNickeau */ 101c3437056SNickeau public function replicate(): DatabasePageRow 102c3437056SNickeau { 103c3437056SNickeau if ($this->sqlite === null) { 104c3437056SNickeau throw new ExceptionCombo("Sqlite is mandatory for database replication"); 105c3437056SNickeau } 106c3437056SNickeau 107c3437056SNickeau if (!$this->page->exists()) { 108c3437056SNickeau throw new ExceptionCombo("You can't replicate the non-existing page ($this->page) on the file system"); 109c3437056SNickeau } 110c3437056SNickeau 111c3437056SNickeau 112c3437056SNickeau /** 113c3437056SNickeau * Page Replication should appears 114c3437056SNickeau */ 115c3437056SNickeau $this->replicatePage(); 116c3437056SNickeau 117c3437056SNickeau /** 118c3437056SNickeau * @var Metadata $tabularMetadataToSync 119c3437056SNickeau */ 120c3437056SNickeau $tabularMetadataToSync = [ 121c3437056SNickeau (new References()), 122c3437056SNickeau (new Aliases()) 123c3437056SNickeau ]; 124c3437056SNickeau $fsStore = MetadataDokuWikiStore::getOrCreateFromResource($this->page); 125c3437056SNickeau $dbStore = MetadataDbStore::getOrCreateFromResource($this->page); 126c3437056SNickeau foreach ($tabularMetadataToSync as $tabular) { 127c3437056SNickeau $tabular 128c3437056SNickeau ->setResource($this->page) 129c3437056SNickeau ->setReadStore($fsStore) 130c3437056SNickeau ->buildFromReadStore() 131c3437056SNickeau ->setWriteStore($dbStore) 132c3437056SNickeau ->persist(); 133c3437056SNickeau } 134c3437056SNickeau 135c3437056SNickeau /** 136c3437056SNickeau * Analytics (derived) 137c3437056SNickeau * Should appear at the end of the replication because it is based 138c3437056SNickeau * on the previous replication (ie backlink count) 139c3437056SNickeau */ 140c3437056SNickeau $this->replicateAnalytics(); 141c3437056SNickeau 142c3437056SNickeau 143c3437056SNickeau return $this; 144c3437056SNickeau 145c3437056SNickeau } 146c3437056SNickeau 147c3437056SNickeau /** 148c3437056SNickeau * @throws ExceptionCombo 149c3437056SNickeau */ 150c3437056SNickeau public function replicateAndRebuild() 151c3437056SNickeau { 152c3437056SNickeau $this->replicate(); 153c3437056SNickeau $this->rebuild(); 154c3437056SNickeau return $this; 155c3437056SNickeau } 156c3437056SNickeau 157c3437056SNickeau private function addPageIdMeta(array &$metaRecord) 158c3437056SNickeau { 159c3437056SNickeau $metaRecord[PageId::PROPERTY_NAME] = $this->page->getPageId(); 160c3437056SNickeau $metaRecord[PageId::PAGE_ID_ABBR_ATTRIBUTE] = $this->page->getPageIdAbbr(); 161c3437056SNickeau } 162c3437056SNickeau 163c3437056SNickeau public static function createFromPageId(string $pageId): DatabasePageRow 164c3437056SNickeau { 165c3437056SNickeau $databasePage = new DatabasePageRow(); 166c3437056SNickeau $row = $databasePage->getDatabaseRowFromPageId($pageId); 167c3437056SNickeau if ($row != null) { 168c3437056SNickeau $databasePage->setRow($row); 169c3437056SNickeau } 170c3437056SNickeau return $databasePage; 171c3437056SNickeau } 172c3437056SNickeau 173c3437056SNickeau public static function createFromPageObject(Page $page): DatabasePageRow 174c3437056SNickeau { 175c3437056SNickeau 176c3437056SNickeau $databasePage = new DatabasePageRow(); 177c3437056SNickeau $row = $databasePage->getDatabaseRowFromPage($page); 178c3437056SNickeau if ($row !== null) { 179c3437056SNickeau $databasePage->setRow($row); 180c3437056SNickeau } 181c3437056SNickeau return $databasePage; 182c3437056SNickeau } 183c3437056SNickeau 184c3437056SNickeau public static function createFromPageIdAbbr(string $pageIdAbbr): DatabasePageRow 185c3437056SNickeau { 186c3437056SNickeau $databasePage = new DatabasePageRow(); 187c3437056SNickeau $row = $databasePage->getDatabaseRowFromAttribute(PageId::PAGE_ID_ABBR_ATTRIBUTE, $pageIdAbbr); 188c3437056SNickeau if ($row != null) { 189c3437056SNickeau $databasePage->setRow($row); 190c3437056SNickeau } 191c3437056SNickeau return $databasePage; 192c3437056SNickeau 193c3437056SNickeau } 194c3437056SNickeau 195c3437056SNickeau /** 196c3437056SNickeau * @param $canonical 197c3437056SNickeau * @return DatabasePageRow 198c3437056SNickeau */ 199c3437056SNickeau public static function createFromCanonical($canonical): DatabasePageRow 200c3437056SNickeau { 201c3437056SNickeau 202c3437056SNickeau DokuPath::addRootSeparatorIfNotPresent($canonical); 203c3437056SNickeau $databasePage = new DatabasePageRow(); 204c3437056SNickeau $row = $databasePage->getDatabaseRowFromAttribute(Canonical::PROPERTY_NAME, $canonical); 205c3437056SNickeau if ($row != null) { 206c3437056SNickeau $databasePage->setRow($row); 207c3437056SNickeau } 208c3437056SNickeau return $databasePage; 209c3437056SNickeau 210c3437056SNickeau 211c3437056SNickeau } 212c3437056SNickeau 213c3437056SNickeau public static function createFromAlias($alias): DatabasePageRow 214c3437056SNickeau { 215c3437056SNickeau 216c3437056SNickeau DokuPath::addRootSeparatorIfNotPresent($alias); 217c3437056SNickeau $databasePage = new DatabasePageRow(); 218c3437056SNickeau $row = $databasePage->getDatabaseRowFromAlias($alias); 219c3437056SNickeau if ($row != null) { 220c3437056SNickeau $databasePage->setRow($row); 22158317768Sgerardnico $page = $databasePage->getPage(); 22258317768Sgerardnico if ($page !== null) { 22358317768Sgerardnico // page may be null in production 22458317768Sgerardnico // PHP Fatal error: Uncaught Error: Call to a member function setBuildAliasPath() on null in 22558317768Sgerardnico // /opt/www/bytle/farmer.bytle.net/lib/plugins/combo/ComboStrap/DatabasePageRow.php:220 22658317768Sgerardnico $page->setBuildAliasPath($alias); 22758317768Sgerardnico } 228c3437056SNickeau } 229c3437056SNickeau return $databasePage; 230c3437056SNickeau 231c3437056SNickeau } 232c3437056SNickeau 233c3437056SNickeau public static function createFromDokuWikiId($id): DatabasePageRow 234c3437056SNickeau { 235c3437056SNickeau $databasePage = new DatabasePageRow(); 236c3437056SNickeau $row = $databasePage->getDatabaseRowFromDokuWikiId($id); 237c3437056SNickeau if ($row !== null) { 238c3437056SNickeau $databasePage->setRow($row); 239c3437056SNickeau } 240c3437056SNickeau return $databasePage; 241c3437056SNickeau } 242c3437056SNickeau 243c3437056SNickeau public function getPageId() 244c3437056SNickeau { 245c3437056SNickeau return $this->getFromRow(PageId::PROPERTY_NAME); 246c3437056SNickeau } 247c3437056SNickeau 248c3437056SNickeau 249c3437056SNickeau public 250c3437056SNickeau function shouldReplicate(): bool 251c3437056SNickeau { 252c3437056SNickeau 253*4cadd4f8SNickeau $dateReplication = $this->getReplicationDate(); 254*4cadd4f8SNickeau if ($dateReplication === null) { 255*4cadd4f8SNickeau return true; 256*4cadd4f8SNickeau } 257*4cadd4f8SNickeau 258*4cadd4f8SNickeau /** 259*4cadd4f8SNickeau * When the replication date is older than the actual document 260*4cadd4f8SNickeau */ 261*4cadd4f8SNickeau $modifiedTime = FileSystems::getModifiedTime($this->page->getPath()); 262*4cadd4f8SNickeau if ($modifiedTime > $dateReplication) { 263*4cadd4f8SNickeau return true; 264*4cadd4f8SNickeau } 265*4cadd4f8SNickeau 266c3437056SNickeau /** 267c3437056SNickeau * When the file does not exist 268c3437056SNickeau */ 269c3437056SNickeau $exist = FileSystems::exists($this->page->getAnalyticsDocument()->getCachePath()); 270c3437056SNickeau if (!$exist) { 271c3437056SNickeau return true; 272c3437056SNickeau } 273c3437056SNickeau 274c3437056SNickeau /** 275*4cadd4f8SNickeau * When the analytics document is older 276c3437056SNickeau */ 277c3437056SNickeau $modifiedTime = FileSystems::getModifiedTime($this->page->getAnalyticsDocument()->getCachePath()); 278c3437056SNickeau if ($modifiedTime > $dateReplication) { 279c3437056SNickeau return true; 280c3437056SNickeau } 281c3437056SNickeau 282*4cadd4f8SNickeau 283c3437056SNickeau /** 284c3437056SNickeau * When the database version file is higher 285c3437056SNickeau */ 286c3437056SNickeau $version = LocalPath::createFromPath(__DIR__ . "/../db/latest.version"); 287c3437056SNickeau $versionModifiedTime = FileSystems::getModifiedTime($version); 288c3437056SNickeau if ($versionModifiedTime > $dateReplication) { 289c3437056SNickeau return true; 290c3437056SNickeau } 291c3437056SNickeau 292c3437056SNickeau /** 293c3437056SNickeau * When the class date time is higher 294c3437056SNickeau */ 295c3437056SNickeau $code = LocalPath::createFromPath(__DIR__ . "/DatabasePageRow.php"); 296c3437056SNickeau $codeModified = FileSystems::getModifiedTime($code); 297c3437056SNickeau if ($codeModified > $dateReplication) { 298c3437056SNickeau return true; 299c3437056SNickeau } 300c3437056SNickeau 301c3437056SNickeau return false; 302c3437056SNickeau 303c3437056SNickeau } 304c3437056SNickeau 305c3437056SNickeau public 306c3437056SNickeau function delete() 307c3437056SNickeau { 308c3437056SNickeau 309c3437056SNickeau $request = Sqlite::createOrGetSqlite() 310c3437056SNickeau ->createRequest() 311c3437056SNickeau ->setQueryParametrized('delete from pages where id = ?', [$this->page->getDokuwikiId()]); 312c3437056SNickeau try { 313c3437056SNickeau $request->execute(); 314c3437056SNickeau } catch (ExceptionCombo $e) { 315c3437056SNickeau LogUtility::msg("Something went wrong when deleting the page ({$this->page}) from the database"); 316c3437056SNickeau } finally { 317c3437056SNickeau $request->close(); 318c3437056SNickeau } 319c3437056SNickeau $this->buildInitObjectFields(); 320c3437056SNickeau 321c3437056SNickeau } 322c3437056SNickeau 323c3437056SNickeau /** 324c3437056SNickeau * @return Json|null the analytics array or null if not in db 325c3437056SNickeau */ 326c3437056SNickeau public 327c3437056SNickeau function getAnalyticsData(): ?Json 328c3437056SNickeau { 329c3437056SNickeau 330c3437056SNickeau $jsonString = $this->getFromRow(self::ANALYTICS_ATTRIBUTE); 331c3437056SNickeau if ($jsonString === null) { 332c3437056SNickeau return null; 333c3437056SNickeau } 334c3437056SNickeau try { 335c3437056SNickeau return Json::createFromString($jsonString); 336c3437056SNickeau } catch (ExceptionCombo $e) { 337c3437056SNickeau LogUtility::msg("Error while building back the analytics JSON object. {$e->getMessage()}"); 338c3437056SNickeau return null; 339c3437056SNickeau } 340c3437056SNickeau 341c3437056SNickeau } 342c3437056SNickeau 343c3437056SNickeau /** 344c3437056SNickeau * Return the database row 345c3437056SNickeau * 346c3437056SNickeau * 347c3437056SNickeau */ 348c3437056SNickeau private 349c3437056SNickeau function getDatabaseRowFromPage(Page $page): ?array 350c3437056SNickeau { 351c3437056SNickeau 352c3437056SNickeau $this->setPage($page); 353c3437056SNickeau 354c3437056SNickeau if ($this->sqlite === null) return null; 355c3437056SNickeau 356c3437056SNickeau // Do we have a page attached to this page id 357c3437056SNickeau $pageId = $page->getPageId(); 358c3437056SNickeau if ($pageId !== null) { 359c3437056SNickeau $row = $this->getDatabaseRowFromPageId($pageId); 360c3437056SNickeau if ($row !== null) { 361c3437056SNickeau return $row; 362c3437056SNickeau } 363c3437056SNickeau } 364c3437056SNickeau 365c3437056SNickeau // Do we have a page attached to the canonical 366c3437056SNickeau $canonical = $page->getCanonical(); 367c3437056SNickeau if ($canonical != null) { 368c3437056SNickeau $row = $this->getDatabaseRowFromCanonical($canonical); 369c3437056SNickeau if ($row !== null) { 370c3437056SNickeau return $row; 371c3437056SNickeau } 372c3437056SNickeau } 373c3437056SNickeau 374c3437056SNickeau // Do we have a page attached to the path 375c3437056SNickeau $path = $page->getPath(); 376c3437056SNickeau $row = $this->getDatabaseRowFromPath($path); 377c3437056SNickeau if ($row !== null) { // the path may no yet updated in the db 378c3437056SNickeau return $row; 379c3437056SNickeau } 380c3437056SNickeau 381c3437056SNickeau /** 382c3437056SNickeau * Do we have a page attached to this ID 383c3437056SNickeau */ 384c3437056SNickeau $id = $page->getPath()->getDokuwikiId(); 385c3437056SNickeau return $this->getDatabaseRowFromDokuWikiId($id); 386c3437056SNickeau 387c3437056SNickeau 388c3437056SNickeau } 389c3437056SNickeau 390c3437056SNickeau 391*4cadd4f8SNickeau /** 392*4cadd4f8SNickeau * @return DateTime|null 393*4cadd4f8SNickeau */ 394*4cadd4f8SNickeau public function getReplicationDate(): ?DateTime 395c3437056SNickeau { 396c3437056SNickeau $dateString = $this->getFromRow(\ReplicationDate::getPersistentName()); 397c3437056SNickeau if ($dateString === null) { 398c3437056SNickeau return null; 399c3437056SNickeau } 400c3437056SNickeau try { 401c3437056SNickeau return Iso8601Date::createFromString($dateString)->getDateTime(); 402c3437056SNickeau } catch (ExceptionCombo $e) { 403c3437056SNickeau LogUtility::msg("Error while reading the replication date in the database. {$e->getMessage()}"); 404c3437056SNickeau return null; 405c3437056SNickeau } 406c3437056SNickeau 407c3437056SNickeau } 408c3437056SNickeau 409c3437056SNickeau /** 410c3437056SNickeau * @return bool 411c3437056SNickeau * @throws ExceptionCombo 412c3437056SNickeau */ 413c3437056SNickeau public function replicatePage(): bool 414c3437056SNickeau { 415c3437056SNickeau 416c3437056SNickeau if (!$this->page->exists()) { 417c3437056SNickeau throw new ExceptionCombo("You can't replicate the page ($this->page) because it does not exists."); 418c3437056SNickeau } 419c3437056SNickeau 420c3437056SNickeau /** 421c3437056SNickeau * Replication Date 422c3437056SNickeau */ 423c3437056SNickeau $replicationDate = \ReplicationDate::createFromPage($this->page) 424c3437056SNickeau ->setWriteStore(MetadataDbStore::class) 425*4cadd4f8SNickeau ->setValue(new DateTime()); 426c3437056SNickeau 427c3437056SNickeau /** 428c3437056SNickeau * Convenient variable 429c3437056SNickeau */ 430c3437056SNickeau $page = $this->page; 431c3437056SNickeau 432c3437056SNickeau 433c3437056SNickeau /** 434c3437056SNickeau * Same data as {@link Page::getMetadataForRendering()} 435c3437056SNickeau */ 436c3437056SNickeau $record = $this->getMetaRecord(); 437c3437056SNickeau $record['IS_HOME'] = ($page->isHomePage() === true ? 1 : 0); 438c3437056SNickeau $record[$replicationDate::getPersistentName()] = $replicationDate->toStoreValue(); 439c3437056SNickeau 440c3437056SNickeau return $this->upsertAttributes($record); 441c3437056SNickeau 442c3437056SNickeau } 443c3437056SNickeau 444c3437056SNickeau 445c3437056SNickeau /** 446c3437056SNickeau * @return bool when an update as occurred 447c3437056SNickeau * 448c3437056SNickeau * Attribute that are scalar / modifiable in the database 449c3437056SNickeau * (not aliases or json data for instance) 450c3437056SNickeau */ 451c3437056SNickeau public function replicateMetaAttributes(): bool 452c3437056SNickeau { 453c3437056SNickeau 454c3437056SNickeau return $this->upsertAttributes($this->getMetaRecord()); 455c3437056SNickeau 456c3437056SNickeau } 457c3437056SNickeau 458c3437056SNickeau public function upsertAttributes(array $attributes): bool 459c3437056SNickeau { 460c3437056SNickeau 461c3437056SNickeau if ($this->sqlite === null) { 462c3437056SNickeau return false; 463c3437056SNickeau } 464c3437056SNickeau 465c3437056SNickeau if (empty($attributes)) { 466c3437056SNickeau LogUtility::msg("The page database attribute passed should not be empty"); 467c3437056SNickeau return false; 468c3437056SNickeau } 469c3437056SNickeau 470c3437056SNickeau $values = []; 471c3437056SNickeau $columnClauses = []; 472c3437056SNickeau foreach ($attributes as $key => $value) { 473c3437056SNickeau if (is_array($value)) { 474c3437056SNickeau throw new ExceptionComboRuntime("The attribute ($key) has value that is an array (" . implode(", ", $value) . ")"); 475c3437056SNickeau } 476c3437056SNickeau $columnClauses[] = "$key = ?"; 477c3437056SNickeau $values[$key] = $value; 478c3437056SNickeau } 479c3437056SNickeau 480c3437056SNickeau /** 481c3437056SNickeau * Primary key has moved during the time 482c3437056SNickeau * It should be the UUID but not for older version 483c3437056SNickeau * 484c3437056SNickeau * If the primary key is null, no record was found 485c3437056SNickeau */ 486c3437056SNickeau $rowId = $this->getRowId(); 487c3437056SNickeau if ($rowId !== null) { 488c3437056SNickeau /** 489c3437056SNickeau * We just add the primary key 490c3437056SNickeau * otherwise as this is a associative 491c3437056SNickeau * array, we will miss a value for the update statement 492c3437056SNickeau */ 493c3437056SNickeau $values[] = $rowId; 494c3437056SNickeau 495c3437056SNickeau $updateStatement = "update PAGES SET " . implode(", ", $columnClauses) . " where ROWID = ?"; 496c3437056SNickeau $request = $this->sqlite 497c3437056SNickeau ->createRequest() 498c3437056SNickeau ->setQueryParametrized($updateStatement, $values); 499c3437056SNickeau $countChanges = 0; 500c3437056SNickeau try { 501c3437056SNickeau $countChanges = $request 502c3437056SNickeau ->execute() 503c3437056SNickeau ->getChangeCount(); 504c3437056SNickeau } catch (ExceptionCombo $e) { 505c3437056SNickeau LogUtility::msg("There was a problem during the page attribute updates. : {$e->getMessage()}"); 506c3437056SNickeau return false; 507c3437056SNickeau } finally { 508c3437056SNickeau $request->close(); 509c3437056SNickeau } 510c3437056SNickeau if ($countChanges !== 1) { 511c3437056SNickeau LogUtility::msg("The database replication has not updated exactly 1 record but ($countChanges) record", LogUtility::LVL_MSG_ERROR, \action_plugin_combo_fulldatabasereplication::CANONICAL); 512c3437056SNickeau } 513c3437056SNickeau 514c3437056SNickeau } else { 515c3437056SNickeau 516c3437056SNickeau /** 517c3437056SNickeau * Creation 518c3437056SNickeau */ 519c3437056SNickeau if ($this->page === null) { 520c3437056SNickeau LogUtility::msg("The page should be defined to create a page row"); 521c3437056SNickeau return false; 522c3437056SNickeau } 523c3437056SNickeau $values[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE] = $this->page->getPath()->getDokuwikiId(); 524c3437056SNickeau $values[PagePath::PROPERTY_NAME] = $this->page->getPath()->toAbsolutePath()->toString(); 525c3437056SNickeau /** 526c3437056SNickeau * Default implements the auto-canonical feature 527c3437056SNickeau */ 528c3437056SNickeau $values[Canonical::PROPERTY_NAME] = $this->page->getCanonicalOrDefault(); 529c3437056SNickeau 530c3437056SNickeau /** 531c3437056SNickeau * Analytics 532c3437056SNickeau */ 533c3437056SNickeau if (!isset($values[self::ANALYTICS_ATTRIBUTE])) { 534c3437056SNickeau // otherwise we get an empty string 535c3437056SNickeau // and a json function will not work 536c3437056SNickeau $values[self::ANALYTICS_ATTRIBUTE] = Json::createEmpty()->toPrettyJsonString(); 537c3437056SNickeau } 538c3437056SNickeau 539c3437056SNickeau /** 540c3437056SNickeau * Page Id / Abbr are mandatory for url redirection 541c3437056SNickeau */ 542c3437056SNickeau $this->addPageIdAttributeIfNeeded($values); 543c3437056SNickeau 544c3437056SNickeau $request = $this->sqlite 545c3437056SNickeau ->createRequest() 546c3437056SNickeau ->setTableRow('PAGES', $values); 547c3437056SNickeau try { 548c3437056SNickeau /** 549c3437056SNickeau * rowid is used in {@link DatabasePageRow::exists()} 550c3437056SNickeau * to check if the page exists in the database 551c3437056SNickeau * We update it 552c3437056SNickeau */ 553c3437056SNickeau $this->row[self::ROWID] = $request 554c3437056SNickeau ->execute() 555c3437056SNickeau ->getInsertId(); 556c3437056SNickeau $this->row = array_merge($values, $this->row); 557c3437056SNickeau } catch (ExceptionCombo $e) { 558c3437056SNickeau LogUtility::msg("There was a problem during the updateAttributes insert. : {$e->getMessage()}"); 559c3437056SNickeau return false; 560c3437056SNickeau } finally { 561c3437056SNickeau $request->close(); 562c3437056SNickeau } 563c3437056SNickeau 564c3437056SNickeau } 565c3437056SNickeau return true; 566c3437056SNickeau 567c3437056SNickeau } 568c3437056SNickeau 569c3437056SNickeau public 570c3437056SNickeau function getDescription() 571c3437056SNickeau { 572c3437056SNickeau return $this->getFromRow(PageDescription::DESCRIPTION_PROPERTY); 573c3437056SNickeau } 574c3437056SNickeau 575c3437056SNickeau 576c3437056SNickeau public 577c3437056SNickeau function getPageName() 578c3437056SNickeau { 579c3437056SNickeau return $this->getFromRow(ResourceName::PROPERTY_NAME); 580c3437056SNickeau } 581c3437056SNickeau 582c3437056SNickeau public 583c3437056SNickeau function exists(): bool 584c3437056SNickeau { 585c3437056SNickeau return $this->getFromRow(self::ROWID) !== null; 586c3437056SNickeau } 587c3437056SNickeau 588c3437056SNickeau /** 589c3437056SNickeau * Called when a page is moved 590c3437056SNickeau * @param $targetId 591c3437056SNickeau */ 592c3437056SNickeau public 593c3437056SNickeau function updatePathAndDokuwikiId($targetId) 594c3437056SNickeau { 595c3437056SNickeau if (!$this->exists()) { 596c3437056SNickeau LogUtility::msg("The `database` page ($this) does not exist and cannot be moved to ($targetId)", LogUtility::LVL_MSG_ERROR); 597c3437056SNickeau } 598c3437056SNickeau 599c3437056SNickeau $path = $targetId; 600c3437056SNickeau DokuPath::addRootSeparatorIfNotPresent($path); 601c3437056SNickeau $attributes = [ 602c3437056SNickeau DokuwikiId::DOKUWIKI_ID_ATTRIBUTE => $targetId, 603c3437056SNickeau PagePath::PROPERTY_NAME => $path 604c3437056SNickeau ]; 605c3437056SNickeau 606c3437056SNickeau $this->upsertAttributes($attributes); 607c3437056SNickeau 608c3437056SNickeau } 609c3437056SNickeau 610c3437056SNickeau public 611c3437056SNickeau function __toString() 612c3437056SNickeau { 613c3437056SNickeau return $this->page->__toString(); 614c3437056SNickeau } 615c3437056SNickeau 616c3437056SNickeau 617c3437056SNickeau /** 618c3437056SNickeau * Redirect are now added during a move 619c3437056SNickeau * Not when a duplicate is found. 620c3437056SNickeau * With the advent of the page id, it should never occurs anymore 621c3437056SNickeau * @param Page $page 622c3437056SNickeau * @deprecated 2012-10-28 623c3437056SNickeau */ 624c3437056SNickeau private 625c3437056SNickeau function deleteIfExistsAndAddRedirectAlias(Page $page): void 626c3437056SNickeau { 627c3437056SNickeau 628c3437056SNickeau if ($this->page != null) { 629c3437056SNickeau $page->getDatabasePage()->deleteIfExist(); 630c3437056SNickeau $this->addRedirectAliasWhileBuildingRow($page); 631c3437056SNickeau } 632c3437056SNickeau 633c3437056SNickeau } 634c3437056SNickeau 635c3437056SNickeau public 636c3437056SNickeau function getCanonical() 637c3437056SNickeau { 638c3437056SNickeau return $this->getFromRow(Canonical::PROPERTY_NAME); 639c3437056SNickeau } 640c3437056SNickeau 641c3437056SNickeau /** 642c3437056SNickeau * Set the field to their values 643c3437056SNickeau * @param $row 644c3437056SNickeau */ 645c3437056SNickeau public 646c3437056SNickeau function setRow($row) 647c3437056SNickeau { 648c3437056SNickeau if ($row === null) { 649c3437056SNickeau LogUtility::msg("A row should not be null"); 650c3437056SNickeau return; 651c3437056SNickeau } 652c3437056SNickeau if (!is_array($row)) { 653c3437056SNickeau LogUtility::msg("A row should be an array"); 654c3437056SNickeau return; 655c3437056SNickeau } 656c3437056SNickeau 657c3437056SNickeau /** 658c3437056SNickeau * All get function lookup the row 659c3437056SNickeau */ 660c3437056SNickeau $this->row = $row; 661c3437056SNickeau 662c3437056SNickeau 663c3437056SNickeau } 664c3437056SNickeau 665c3437056SNickeau private 666c3437056SNickeau function buildInitObjectFields() 667c3437056SNickeau { 668c3437056SNickeau $this->row = null; 669c3437056SNickeau 670c3437056SNickeau } 671c3437056SNickeau 672c3437056SNickeau public 673c3437056SNickeau function rebuild(): DatabasePageRow 674c3437056SNickeau { 675c3437056SNickeau 676c3437056SNickeau if ($this->page != null) { 677c3437056SNickeau $this->page->rebuild(); 678c3437056SNickeau $row = $this->getDatabaseRowFromPage($this->page); 679c3437056SNickeau if ($row !== null) { 680c3437056SNickeau $this->setRow($row); 681c3437056SNickeau } 682c3437056SNickeau } 683c3437056SNickeau return $this; 684c3437056SNickeau 685c3437056SNickeau } 686c3437056SNickeau 687c3437056SNickeau /** 688c3437056SNickeau * @return array - an array of the fix page metadata (ie not derived) 689c3437056SNickeau * Therefore quick to insert/update 690c3437056SNickeau * 691c3437056SNickeau */ 692c3437056SNickeau private 693c3437056SNickeau function getMetaRecord(): array 694c3437056SNickeau { 695c3437056SNickeau $sourceStore = MetadataDokuWikiStore::getOrCreateFromResource($this->page); 696c3437056SNickeau $targetStore = MetadataDbStore::getOrCreateFromResource($this->page); 697c3437056SNickeau 698c3437056SNickeau $record = array( 699c3437056SNickeau Canonical::PROPERTY_NAME, 700c3437056SNickeau PagePath::PROPERTY_NAME, 701c3437056SNickeau ResourceName::PROPERTY_NAME, 702c3437056SNickeau PageTitle::TITLE, 703c3437056SNickeau PageH1::PROPERTY_NAME, 704c3437056SNickeau PageDescription::PROPERTY_NAME, 705c3437056SNickeau PageCreationDate::PROPERTY_NAME, 706c3437056SNickeau ModificationDate::PROPERTY_NAME, 707c3437056SNickeau PagePublicationDate::PROPERTY_NAME, 708c3437056SNickeau StartDate::PROPERTY_NAME, 709c3437056SNickeau EndDate::PROPERTY_NAME, 710c3437056SNickeau Region::PROPERTY_NAME, 711c3437056SNickeau Lang::PROPERTY_NAME, 712c3437056SNickeau PageType::PROPERTY_NAME, 713c3437056SNickeau DokuwikiId::DOKUWIKI_ID_ATTRIBUTE, 714c3437056SNickeau ); 715c3437056SNickeau $metaRecord = []; 716c3437056SNickeau foreach ($record as $name) { 717c3437056SNickeau $metadata = Metadata::getForName($name); 718c3437056SNickeau if ($metadata === null) { 719c3437056SNickeau throw new ExceptionComboRuntime("The metadata ($name) is unknown"); 720c3437056SNickeau } 721c3437056SNickeau $metaRecord[$name] = $metadata 722c3437056SNickeau ->setResource($this->page) 723c3437056SNickeau ->setReadStore($sourceStore) 724c3437056SNickeau ->buildFromReadStore() 725c3437056SNickeau ->setWriteStore($targetStore) 726c3437056SNickeau ->toStoreValueOrDefault(); // used by the template, the value is or default 727c3437056SNickeau } 728c3437056SNickeau 729c3437056SNickeau if ($this->page->getPageId() !== null) { 730c3437056SNickeau $this->addPageIdMeta($metaRecord); 731c3437056SNickeau } 732c3437056SNickeau return $metaRecord; 733c3437056SNickeau } 734c3437056SNickeau 735c3437056SNickeau public 736c3437056SNickeau function deleteIfExist(): DatabasePageRow 737c3437056SNickeau { 738c3437056SNickeau if ($this->exists()) { 739c3437056SNickeau $this->delete(); 740c3437056SNickeau } 741c3437056SNickeau return $this; 742c3437056SNickeau } 743c3437056SNickeau 744c3437056SNickeau public 745c3437056SNickeau function getRowId() 746c3437056SNickeau { 747c3437056SNickeau return $this->getFromRow(self::ROWID); 748c3437056SNickeau } 749c3437056SNickeau 750c3437056SNickeau private 751c3437056SNickeau function getDatabaseRowFromPageId(string $pageId) 752c3437056SNickeau { 753c3437056SNickeau 754c3437056SNickeau if ($this->sqlite === null) { 755c3437056SNickeau return null; 756c3437056SNickeau } 757c3437056SNickeau 758c3437056SNickeau $pageIdAttribute = PageId::PROPERTY_NAME; 759c3437056SNickeau $query = $this->getParametrizedLookupQuery($pageIdAttribute); 760c3437056SNickeau $request = Sqlite::createOrGetSqlite() 761c3437056SNickeau ->createRequest() 762c3437056SNickeau ->setQueryParametrized($query, [$pageId]); 763c3437056SNickeau $rows = []; 764c3437056SNickeau try { 765c3437056SNickeau $rows = $request 766c3437056SNickeau ->execute() 767c3437056SNickeau ->getRows(); 768c3437056SNickeau } catch (ExceptionCombo $e) { 769c3437056SNickeau LogUtility::msg($e->getMessage(), LogUtility::LVL_MSG_ERROR, $e->getCanonical()); 770c3437056SNickeau return null; 771c3437056SNickeau } finally { 772c3437056SNickeau $request->close(); 773c3437056SNickeau } 774c3437056SNickeau 775c3437056SNickeau switch (sizeof($rows)) { 776c3437056SNickeau case 0: 777c3437056SNickeau return null; 778c3437056SNickeau case 1: 779c3437056SNickeau $id = $rows[0][DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 780c3437056SNickeau /** 781c3437056SNickeau * Page Id Collision detection 782c3437056SNickeau */ 783c3437056SNickeau if ($this->page != null && $id !== $this->page->getDokuwikiId()) { 784c3437056SNickeau $duplicatePage = Page::createPageFromId($id); 785c3437056SNickeau if (!$duplicatePage->exists()) { 786c3437056SNickeau // Move 787c3437056SNickeau LogUtility::msg("The non-existing duplicate page ($id) has been added as redirect alias for the page ($this->page)", LogUtility::LVL_MSG_INFO); 788c3437056SNickeau $this->addRedirectAliasWhileBuildingRow($duplicatePage); 789c3437056SNickeau } else { 790c3437056SNickeau // This can happens if two page were created not on the same website 791c3437056SNickeau // of if the sqlite database was deleted and rebuilt. 792c3437056SNickeau // The chance is really, really low 793c3437056SNickeau $errorMessage = "The page ($this->page) and the page ($id) have the same page id ($pageId)"; 794c3437056SNickeau LogUtility::msg($errorMessage, LogUtility::LVL_MSG_ERROR, self::CANONICAL); 795c3437056SNickeau // What to do ? 796c3437056SNickeau // The database does not allow two page id with the same value 797c3437056SNickeau // If it happens, ugh, ugh, ..., a replication process between website may be. 798c3437056SNickeau return null; 799c3437056SNickeau } 800c3437056SNickeau } 801c3437056SNickeau return $rows[0]; 802c3437056SNickeau default: 803c3437056SNickeau $existingPages = implode(", ", $rows); 804c3437056SNickeau LogUtility::msg("The pages ($existingPages) have all the same page id ($pageId)", LogUtility::LVL_MSG_ERROR); 805c3437056SNickeau return null; 806c3437056SNickeau } 807c3437056SNickeau 808c3437056SNickeau } 809c3437056SNickeau 810c3437056SNickeau 811c3437056SNickeau private 812c3437056SNickeau function getParametrizedLookupQuery(string $pageIdAttribute): string 813c3437056SNickeau { 814c3437056SNickeau $select = Sqlite::createSelectFromTableAndColumns("pages", self::PAGE_BUILD_ATTRIBUTES); 815c3437056SNickeau return "$select where $pageIdAttribute = ?"; 816c3437056SNickeau } 817c3437056SNickeau 818c3437056SNickeau 819c3437056SNickeau public function setPage(Page $page) 820c3437056SNickeau { 821c3437056SNickeau $this->page = $page; 822c3437056SNickeau return $this; 823c3437056SNickeau } 824c3437056SNickeau 825c3437056SNickeau private 826c3437056SNickeau function getDatabaseRowFromCanonical($canonical) 827c3437056SNickeau { 828c3437056SNickeau $query = $this->getParametrizedLookupQuery(Canonical::PROPERTY_NAME); 829c3437056SNickeau $request = $this->sqlite 830c3437056SNickeau ->createRequest() 831c3437056SNickeau ->setQueryParametrized($query, [$canonical]); 832c3437056SNickeau $rows = []; 833c3437056SNickeau try { 834c3437056SNickeau $rows = $request 835c3437056SNickeau ->execute() 836c3437056SNickeau ->getRows(); 837c3437056SNickeau } catch (ExceptionCombo $e) { 838c3437056SNickeau LogUtility::msg("An exception has occurred with the page search from CANONICAL. " . $e->getMessage()); 839c3437056SNickeau return null; 840c3437056SNickeau } finally { 841c3437056SNickeau $request->close(); 842c3437056SNickeau } 843c3437056SNickeau 844c3437056SNickeau switch (sizeof($rows)) { 845c3437056SNickeau case 0: 846c3437056SNickeau return null; 847c3437056SNickeau case 1: 848c3437056SNickeau $id = $rows[0][DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 849c3437056SNickeau if ($this->page !== null && $id !== $this->page->getDokuwikiId()) { 850c3437056SNickeau $duplicatePage = Page::createPageFromId($id); 851c3437056SNickeau if (!$duplicatePage->exists()) { 852c3437056SNickeau $this->addRedirectAliasWhileBuildingRow($duplicatePage); 853c3437056SNickeau LogUtility::msg("The non-existing duplicate page ($id) has been added as redirect alias for the page ($this->page)", LogUtility::LVL_MSG_INFO); 854c3437056SNickeau } else { 855c3437056SNickeau LogUtility::msg("The page ($this->page) and the page ($id) have the same canonical ($canonical)", LogUtility::LVL_MSG_ERROR); 856c3437056SNickeau } 857c3437056SNickeau } 858c3437056SNickeau return $rows[0]; 859c3437056SNickeau default: 860c3437056SNickeau $existingPages = []; 861c3437056SNickeau foreach ($rows as $row) { 862c3437056SNickeau $id = $row[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 863c3437056SNickeau $duplicatePage = Page::createPageFromId($id); 864c3437056SNickeau if (!$duplicatePage->exists()) { 865c3437056SNickeau 866c3437056SNickeau $this->deleteIfExistsAndAddRedirectAlias($duplicatePage); 867c3437056SNickeau 868c3437056SNickeau } else { 869c3437056SNickeau 870c3437056SNickeau /** 871c3437056SNickeau * Check if the error may come from the auto-canonical 872c3437056SNickeau * (Never ever save generated data) 873c3437056SNickeau */ 874c3437056SNickeau $canonicalLastNamesCount = PluginUtility::getConfValue(Canonical::CONF_CANONICAL_LAST_NAMES_COUNT, 0); 875c3437056SNickeau if ($canonicalLastNamesCount > 0) { 876c3437056SNickeau $this->page->unsetMetadata(Canonical::PROPERTY_NAME); 877c3437056SNickeau $duplicatePage->unsetMetadata(Canonical::PROPERTY_NAME); 878c3437056SNickeau } 879c3437056SNickeau 880c3437056SNickeau $existingPages[] = $row; 881c3437056SNickeau } 882c3437056SNickeau } 883c3437056SNickeau if (sizeof($existingPages) === 1) { 884c3437056SNickeau return $existingPages[0]; 885c3437056SNickeau } else { 886c3437056SNickeau $existingPages = implode(", ", $existingPages); 887c3437056SNickeau LogUtility::msg("The existing pages ($existingPages) have all the same canonical ($canonical)", LogUtility::LVL_MSG_ERROR); 888c3437056SNickeau return null; 889c3437056SNickeau } 890c3437056SNickeau } 891c3437056SNickeau } 892c3437056SNickeau 893c3437056SNickeau private 894c3437056SNickeau function getDatabaseRowFromPath(string $path): ?array 895c3437056SNickeau { 896c3437056SNickeau DokuPath::addRootSeparatorIfNotPresent($path); 897c3437056SNickeau return $this->getDatabaseRowFromAttribute(PagePath::PROPERTY_NAME, $path); 898c3437056SNickeau } 899c3437056SNickeau 900c3437056SNickeau private 901c3437056SNickeau function getDatabaseRowFromDokuWikiId(string $id): ?array 902c3437056SNickeau { 903c3437056SNickeau return $this->getDatabaseRowFromAttribute(DokuwikiId::DOKUWIKI_ID_ATTRIBUTE, $id); 904c3437056SNickeau } 905c3437056SNickeau 906c3437056SNickeau public 907c3437056SNickeau function getDatabaseRowFromAttribute(string $attribute, string $value) 908c3437056SNickeau { 909c3437056SNickeau $query = $this->getParametrizedLookupQuery($attribute); 910c3437056SNickeau $request = $this->sqlite 911c3437056SNickeau ->createRequest() 912c3437056SNickeau ->setQueryParametrized($query, [$value]); 913c3437056SNickeau $rows = []; 914c3437056SNickeau try { 915c3437056SNickeau $rows = $request 916c3437056SNickeau ->execute() 917c3437056SNickeau ->getRows(); 918c3437056SNickeau } catch (ExceptionCombo $e) { 919c3437056SNickeau LogUtility::msg("An exception has occurred with the page search from a PATH: " . $e->getMessage()); 920c3437056SNickeau return null; 921c3437056SNickeau } finally { 922c3437056SNickeau $request->close(); 923c3437056SNickeau } 924c3437056SNickeau 925c3437056SNickeau switch (sizeof($rows)) { 926c3437056SNickeau case 0: 927c3437056SNickeau return null; 928c3437056SNickeau case 1: 929c3437056SNickeau $value = $rows[0][DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 930c3437056SNickeau if ($this->page != null && $value !== $this->page->getDokuwikiId()) { 931c3437056SNickeau $duplicatePage = Page::createPageFromId($value); 932c3437056SNickeau if (!$duplicatePage->exists()) { 933c3437056SNickeau $this->addRedirectAliasWhileBuildingRow($duplicatePage); 934c3437056SNickeau } else { 935c3437056SNickeau LogUtility::msg("The page ($this->page) and the page ($value) have the same $attribute ($value)", LogUtility::LVL_MSG_ERROR); 936c3437056SNickeau } 937c3437056SNickeau } 938c3437056SNickeau return $rows[0]; 939c3437056SNickeau default: 940c3437056SNickeau $existingPages = []; 941c3437056SNickeau foreach ($rows as $row) { 942c3437056SNickeau $value = $row[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 943c3437056SNickeau $duplicatePage = Page::createPageFromId($value); 944c3437056SNickeau if (!$duplicatePage->exists()) { 945c3437056SNickeau 946c3437056SNickeau $this->deleteIfExistsAndAddRedirectAlias($duplicatePage); 947c3437056SNickeau 948c3437056SNickeau } else { 949c3437056SNickeau $existingPages[] = $row; 950c3437056SNickeau } 951c3437056SNickeau } 952c3437056SNickeau if (sizeof($existingPages) === 1) { 953c3437056SNickeau return $existingPages[0]; 954c3437056SNickeau } else { 955c3437056SNickeau $existingPages = implode(", ", $existingPages); 956c3437056SNickeau LogUtility::msg("The existing pages ($existingPages) have all the same $attribute ($value)", LogUtility::LVL_MSG_ERROR); 957c3437056SNickeau return null; 958c3437056SNickeau } 959c3437056SNickeau } 960c3437056SNickeau } 961c3437056SNickeau 962c3437056SNickeau public 963c3437056SNickeau function getPage(): ?Page 964c3437056SNickeau { 965c3437056SNickeau if ( 966c3437056SNickeau $this->page === null 967c3437056SNickeau && $this->row[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE] !== null 968c3437056SNickeau ) { 969c3437056SNickeau $this->page = Page::createPageFromId($this->row[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]); 970c3437056SNickeau } 971c3437056SNickeau return $this->page; 972c3437056SNickeau } 973c3437056SNickeau 974c3437056SNickeau private 975c3437056SNickeau function getDatabaseRowFromAlias($alias): ?array 976c3437056SNickeau { 977c3437056SNickeau 978c3437056SNickeau $pageIdAttribute = PageId::PROPERTY_NAME; 979c3437056SNickeau $buildFields = self::PAGE_BUILD_ATTRIBUTES; 980c3437056SNickeau $fields = array_reduce($buildFields, function ($carry, $element) { 981c3437056SNickeau if ($carry !== null) { 982c3437056SNickeau return "$carry, p.{$element}"; 983c3437056SNickeau } else { 984c3437056SNickeau return "p.{$element}"; 985c3437056SNickeau } 986c3437056SNickeau }, null); 987c3437056SNickeau $query = "select {$fields} from PAGES p, PAGE_ALIASES pa where p.{$pageIdAttribute} = pa.{$pageIdAttribute} and pa.PATH = ? "; 988c3437056SNickeau $request = $this->sqlite 989c3437056SNickeau ->createRequest() 990c3437056SNickeau ->setQueryParametrized($query, [$alias]); 991c3437056SNickeau $rows = []; 992c3437056SNickeau try { 993c3437056SNickeau $rows = $request 994c3437056SNickeau ->execute() 995c3437056SNickeau ->getRows(); 996c3437056SNickeau } catch (ExceptionCombo $e) { 997c3437056SNickeau LogUtility::msg("An exception has occurred with the alias selection query. {$e->getMessage()}"); 998c3437056SNickeau return null; 999c3437056SNickeau } finally { 1000c3437056SNickeau $request->close(); 1001c3437056SNickeau } 1002c3437056SNickeau switch (sizeof($rows)) { 1003c3437056SNickeau case 0: 1004c3437056SNickeau return null; 1005c3437056SNickeau case 1: 1006c3437056SNickeau return $rows[0]; 1007c3437056SNickeau default: 1008c3437056SNickeau $id = $rows[0]['ID']; 1009c3437056SNickeau $pages = implode(",", 1010c3437056SNickeau array_map( 1011c3437056SNickeau function ($row) { 1012c3437056SNickeau return $row['ID']; 1013c3437056SNickeau }, 1014c3437056SNickeau $rows 1015c3437056SNickeau ) 1016c3437056SNickeau ); 1017c3437056SNickeau LogUtility::msg("For the alias $alias, there is more than one page defined ($pages), the first one ($id) was used", LogUtility::LVL_MSG_ERROR, Aliases::PROPERTY_NAME); 1018c3437056SNickeau return $rows[0]; 1019c3437056SNickeau } 1020c3437056SNickeau } 1021c3437056SNickeau 1022c3437056SNickeau 1023c3437056SNickeau /** 1024c3437056SNickeau * Utility function 1025c3437056SNickeau * @param Page $pageAlias 1026c3437056SNickeau */ 1027c3437056SNickeau private 1028c3437056SNickeau function addRedirectAliasWhileBuildingRow(Page $pageAlias) 1029c3437056SNickeau { 1030c3437056SNickeau 1031c3437056SNickeau $aliasPath = $pageAlias->getPath()->toString(); 1032c3437056SNickeau try { 1033c3437056SNickeau Aliases::createForPage($this->page) 1034c3437056SNickeau ->addAlias($aliasPath) 1035c3437056SNickeau ->sendToWriteStore(); 1036c3437056SNickeau } catch (ExceptionCombo $e) { 1037c3437056SNickeau // we don't throw while getting 1038c3437056SNickeau LogUtility::msg("Unable to add the alias ($aliasPath) for the page ($this->page)"); 1039c3437056SNickeau } 1040c3437056SNickeau 1041c3437056SNickeau } 1042c3437056SNickeau 1043c3437056SNickeau private 1044c3437056SNickeau function addPageIdAttributeIfNeeded(array &$values) 1045c3437056SNickeau { 1046c3437056SNickeau if (!isset($values[PageId::getPersistentName()])) { 1047c3437056SNickeau $values[PageId::getPersistentName()] = $this->page->getPageId(); 1048c3437056SNickeau } 1049c3437056SNickeau if (!isset($values[PageId::PAGE_ID_ABBR_ATTRIBUTE])) { 1050c3437056SNickeau $values[PageId::PAGE_ID_ABBR_ATTRIBUTE] = $this->page->getPageIdAbbr(); 1051c3437056SNickeau } 1052c3437056SNickeau } 1053c3437056SNickeau 1054c3437056SNickeau public 1055c3437056SNickeau function getFromRow(string $attribute) 1056c3437056SNickeau { 1057c3437056SNickeau if ($this->row === null) { 1058c3437056SNickeau return null; 1059c3437056SNickeau } 1060c3437056SNickeau 1061c3437056SNickeau if (!array_key_exists($attribute, $this->row)) { 1062c3437056SNickeau /** 1063c3437056SNickeau * An attribute should be added to {@link DatabasePageRow::PAGE_BUILD_ATTRIBUTES} 1064c3437056SNickeau * or in the table 1065c3437056SNickeau */ 1066c3437056SNickeau throw new ExceptionComboRuntime("The metadata ($attribute) was not found in the returned database row.", $this->getCanonical()); 1067c3437056SNickeau } 1068c3437056SNickeau 1069c3437056SNickeau $value = $this->row[$attribute]; 1070c3437056SNickeau 1071c3437056SNickeau if ($value !== null) { 1072c3437056SNickeau return $value; 1073c3437056SNickeau } 1074c3437056SNickeau 1075c3437056SNickeau // don't know why but the sqlite plugin returns them uppercase 1076c3437056SNickeau // rowid is returned lowercase from the sqlite plugin 1077c3437056SNickeau $upperAttribute = strtoupper($attribute); 1078c3437056SNickeau return $this->row[$upperAttribute]; 1079c3437056SNickeau 1080c3437056SNickeau } 1081c3437056SNickeau 1082c3437056SNickeau 1083*4cadd4f8SNickeau /** 1084*4cadd4f8SNickeau * @throws ExceptionCombo 1085*4cadd4f8SNickeau */ 1086c3437056SNickeau public function replicateAnalytics() 1087c3437056SNickeau { 1088c3437056SNickeau 1089c3437056SNickeau try { 1090c3437056SNickeau $analyticsJson = $this->page->getAnalyticsDocument()->getOrProcessJson(); 1091c3437056SNickeau } catch (ExceptionCombo $e) { 1092*4cadd4f8SNickeau throw new ExceptionCombo("Unable to get the analytics document", self::CANONICAL, 0, $e); 1093c3437056SNickeau } 1094c3437056SNickeau 1095c3437056SNickeau /** 1096c3437056SNickeau * Replication Date 1097c3437056SNickeau */ 1098c3437056SNickeau $replicationDateMeta = \ReplicationDate::createFromPage($this->page) 1099c3437056SNickeau ->setWriteStore(MetadataDbStore::class) 1100*4cadd4f8SNickeau ->setValue(new DateTime()); 1101c3437056SNickeau 1102c3437056SNickeau /** 1103c3437056SNickeau * Analytics 1104c3437056SNickeau */ 1105c3437056SNickeau $analyticsJsonAsString = $analyticsJson->toPrettyJsonString(); 1106c3437056SNickeau $analyticsJsonAsArray = $analyticsJson->toArray(); 1107c3437056SNickeau 1108c3437056SNickeau /** 1109c3437056SNickeau * Record 1110c3437056SNickeau */ 1111c3437056SNickeau $record[self::ANALYTICS_ATTRIBUTE] = $analyticsJsonAsString; 1112c3437056SNickeau $record['IS_LOW_QUALITY'] = ($this->page->isLowQualityPage() === true ? 1 : 0); 1113c3437056SNickeau $record['WORD_COUNT'] = $analyticsJsonAsArray[AnalyticsDocument::STATISTICS][AnalyticsDocument::WORD_COUNT]; 1114c3437056SNickeau $record[BacklinkCount::getPersistentName()] = $analyticsJsonAsArray[AnalyticsDocument::STATISTICS][BacklinkCount::getPersistentName()]; 1115c3437056SNickeau $record[$replicationDateMeta::getPersistentName()] = $replicationDateMeta->toStoreValue(); 1116c3437056SNickeau $this->upsertAttributes($record); 1117c3437056SNickeau } 1118c3437056SNickeau 1119c3437056SNickeau 1120c3437056SNickeau} 1121