1007225e5Sgerardnico<?php 2007225e5Sgerardnico/** 3007225e5Sgerardnico * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved. 4007225e5Sgerardnico * 5007225e5Sgerardnico * This source code is licensed under the GPL license found in the 6007225e5Sgerardnico * COPYING file in the root directory of this source tree. 7007225e5Sgerardnico * 8007225e5Sgerardnico * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 9007225e5Sgerardnico * @author ComboStrap <support@combostrap.com> 10007225e5Sgerardnico * 11007225e5Sgerardnico */ 12007225e5Sgerardnico 13*4ebc3257Sgerardnicouse ComboStrap\DatabasePageRow; 14edc35203Sgerardnicouse ComboStrap\ExceptionNotExists; 15edc35203Sgerardnicouse ComboStrap\ExecutionContext; 1604fd306cSNickeauuse ComboStrap\Meta\Field\BacklinkCount; 17c3437056SNickeauuse ComboStrap\Event; 1804fd306cSNickeauuse ComboStrap\ExceptionBadSyntax; 1904fd306cSNickeauuse ComboStrap\ExceptionCompile; 2004fd306cSNickeauuse ComboStrap\ExceptionNotFound; 2104fd306cSNickeauuse ComboStrap\ExceptionRuntime; 2237748cd8SNickeauuse ComboStrap\FsWikiUtility; 23c3437056SNickeauuse ComboStrap\LogUtility; 2404fd306cSNickeauuse ComboStrap\MarkupPath; 2504fd306cSNickeauuse ComboStrap\Meta\Field\PageH1; 26c3437056SNickeauuse ComboStrap\MetadataFrontmatterStore; 2771f916b9Sgerardnicouse ComboStrap\Sqlite; 28007225e5Sgerardnicouse splitbrain\phpcli\Options; 29007225e5Sgerardnico 30e8b2ff59SNickeau/** 3104fd306cSNickeau * All dependency are loaded 32e8b2ff59SNickeau */ 3304fd306cSNickeaurequire_once(__DIR__ . '/vendor/autoload.php'); 34007225e5Sgerardnico 35007225e5Sgerardnico/** 36007225e5Sgerardnico * The memory of the server 128 is not enough 37007225e5Sgerardnico */ 38007225e5Sgerardnicoini_set('memory_limit', '256M'); 39007225e5Sgerardnico 40c3437056SNickeau 41007225e5Sgerardnico/** 42007225e5Sgerardnico * Class cli_plugin_combo 43007225e5Sgerardnico * 44007225e5Sgerardnico * This is a cli: 45007225e5Sgerardnico * https://www.dokuwiki.org/devel:cli_plugins#example 46007225e5Sgerardnico * 47007225e5Sgerardnico * Usage: 48007225e5Sgerardnico * 49007225e5Sgerardnico * ``` 50007225e5Sgerardnico * docker exec -ti $(CONTAINER) /bin/bash 51c3437056SNickeau * ``` 52c3437056SNickeau * ``` 53c3437056SNickeau * set animal=animal-directory-name 54c3437056SNickeau * php ./bin/plugin.php combo --help 55007225e5Sgerardnico * ``` 56007225e5Sgerardnico * or via the IDE 57007225e5Sgerardnico * 58007225e5Sgerardnico * 59007225e5Sgerardnico * Example: 60007225e5Sgerardnico * https://www.dokuwiki.org/tips:grapher 61007225e5Sgerardnico * 62007225e5Sgerardnico */ 63007225e5Sgerardnicoclass cli_plugin_combo extends DokuWiki_CLI_Plugin 64007225e5Sgerardnico{ 65c3437056SNickeau 66c3437056SNickeau const METADATA_TO_DATABASE = "metadata-to-database"; 6771f916b9Sgerardnico const ANALYTICS = "analytics"; 68c3437056SNickeau const METADATA_TO_FRONTMATTER = "metadata-to-frontmatter"; 6971f916b9Sgerardnico const SYNC = "sync"; 70c3437056SNickeau const PLUGINS_TO_UPDATE = "plugins-to-update"; 71c3437056SNickeau const FORCE_OPTION = 'force'; 72c3437056SNickeau const PORT_OPTION = 'port'; 73c3437056SNickeau const HOST_OPTION = 'host'; 74edc35203Sgerardnico const CANONICAL = "combo-cli"; 75c3437056SNickeau 76007225e5Sgerardnico 77007225e5Sgerardnico /** 78007225e5Sgerardnico * register options and arguments 79007225e5Sgerardnico * @param Options $options 8082a60d03SNickeau * 8182a60d03SNickeau * Note the animal is set in {@link DokuWikiFarmCore::detectAnimal()} 8282a60d03SNickeau * via the environment variable `animal` that is passed in the $_SERVER variable 83007225e5Sgerardnico */ 84007225e5Sgerardnico protected function setup(Options $options) 85007225e5Sgerardnico { 86c3437056SNickeau $help = <<<EOF 87c3437056SNickeauComboStrap Administrative Commands 88c3437056SNickeau 89c3437056SNickeau 90c3437056SNickeauExample: 91c3437056SNickeau * Replicate all pages into the database 92c3437056SNickeau```bash 9304fd306cSNickeauphp ./bin/plugin.php combo metadata-to-database --host serverHostName --port 80 : 94c3437056SNickeau# or 9504fd306cSNickeauphp ./bin/plugin.php combo metadata-to-database --host serverHostName --port 80 / 96c3437056SNickeau``` 97c3437056SNickeau * Replicate only the page `:namespace:my-page` 98c3437056SNickeau```bash 9904fd306cSNickeauphp ./bin/plugin.php combo metadata-to-database --host serverHostName --port 80 :namespace:my-page 100c3437056SNickeau# or 10104fd306cSNickeauphp ./bin/plugin.php combo metadata-to-database --host serverHostName --port 80 /namespace/my-page 102c3437056SNickeau``` 103c3437056SNickeau 104c3437056SNickeauAnimal: If you want to use it for an animal farm, you need to set first the animal directory name in a environment variable 105c3437056SNickeau```bash 1064cadd4f8SNickeauanimal=animal-directory-name php ./bin/plugin.php combo 107c3437056SNickeau``` 108c3437056SNickeau 109c3437056SNickeauEOF; 110c3437056SNickeau 111c3437056SNickeau $options->setHelp($help); 112007225e5Sgerardnico $options->registerOption('version', 'print version', 'v'); 113c3437056SNickeau $options->registerCommand(self::METADATA_TO_DATABASE, "Replicate the file system metadata into the database"); 114c3437056SNickeau $options->registerCommand(self::ANALYTICS, "Start the analytics and export optionally the data"); 115c3437056SNickeau $options->registerCommand(self::PLUGINS_TO_UPDATE, "List the plugins to update"); 116c3437056SNickeau $options->registerCommand(self::METADATA_TO_FRONTMATTER, "Replicate the file system metadata into the page frontmatter"); 117c3437056SNickeau $options->registerCommand(self::SYNC, "Delete the non-existing pages in the database"); 118c3437056SNickeau $options->registerArgument( 119c3437056SNickeau 'path', 120c3437056SNickeau "The start path (a page or a directory). For all pages, type the root directory '/'", 121c3437056SNickeau false 12271f916b9Sgerardnico ); 123007225e5Sgerardnico $options->registerOption( 124007225e5Sgerardnico 'output', 125007225e5Sgerardnico "Optional, where to store the analytical data as csv eg. a filename.", 126c3437056SNickeau 'o', 127c3437056SNickeau true 128c3437056SNickeau ); 129007225e5Sgerardnico $options->registerOption( 130c3437056SNickeau self::HOST_OPTION, 131c3437056SNickeau "The http host name of your server. This value is used by dokuwiki in the rendering cache key", 132c3437056SNickeau null, 133c3437056SNickeau true, 134c3437056SNickeau self::METADATA_TO_DATABASE 135c3437056SNickeau ); 136c3437056SNickeau $options->registerOption( 137c3437056SNickeau self::PORT_OPTION, 138c3437056SNickeau "The http host port of your server. This value is used by dokuwiki in the rendering cache key", 139c3437056SNickeau null, 140c3437056SNickeau true, 141c3437056SNickeau self::METADATA_TO_DATABASE 142c3437056SNickeau ); 143c3437056SNickeau $options->registerOption( 144c3437056SNickeau self::FORCE_OPTION, 145c3437056SNickeau "Replicate with force", 146c3437056SNickeau 'f', 147c3437056SNickeau false, 148c3437056SNickeau self::METADATA_TO_DATABASE 149c3437056SNickeau ); 15071f916b9Sgerardnico $options->registerOption( 15171f916b9Sgerardnico 'dry', 15271f916b9Sgerardnico "Optional, dry-run", 15371f916b9Sgerardnico 'd', false); 154c3437056SNickeau 155007225e5Sgerardnico 156007225e5Sgerardnico } 157007225e5Sgerardnico 158007225e5Sgerardnico /** 159007225e5Sgerardnico * The main entry 160007225e5Sgerardnico * @param Options $options 16104fd306cSNickeau * @throws ExceptionCompile 162007225e5Sgerardnico */ 163007225e5Sgerardnico protected function main(Options $options) 164007225e5Sgerardnico { 165007225e5Sgerardnico 166007225e5Sgerardnico 16782a60d03SNickeau if (isset($_REQUEST['animal'])) { 1684cadd4f8SNickeau // on linux 16982a60d03SNickeau echo "Animal detected: " . $_REQUEST['animal'] . "\n"; 17082a60d03SNickeau } else { 1714cadd4f8SNickeau // on windows 17282a60d03SNickeau echo "No Animal detected\n"; 17382a60d03SNickeau echo "Conf: " . DOKU_CONF . "\n"; 17482a60d03SNickeau } 17582a60d03SNickeau 176c3437056SNickeau $args = $options->getArgs(); 177c3437056SNickeau 178c3437056SNickeau 17971f916b9Sgerardnico $depth = $options->getOpt('depth', 0); 18021913ab3SNickeau $cmd = $options->getCmd(); 181*4ebc3257Sgerardnico 182*4ebc3257Sgerardnico try { 18321913ab3SNickeau switch ($cmd) { 184c3437056SNickeau case self::METADATA_TO_DATABASE: 185c3437056SNickeau $startPath = $this->getStartPath($args); 186c3437056SNickeau $force = $options->getOpt(self::FORCE_OPTION, false); 187c3437056SNickeau $hostOptionValue = $options->getOpt(self::HOST_OPTION, null); 188c3437056SNickeau if ($hostOptionValue === null) { 189c3437056SNickeau fwrite(STDERR, "The host name is mandatory"); 190c3437056SNickeau return; 191c3437056SNickeau } 192c3437056SNickeau $_SERVER['HTTP_HOST'] = $hostOptionValue; 193c3437056SNickeau $portOptionName = $options->getOpt(self::PORT_OPTION, null); 194c3437056SNickeau if ($portOptionName === null) { 195c3437056SNickeau fwrite(STDERR, "The host port is mandatory"); 196c3437056SNickeau return; 197c3437056SNickeau } 198c3437056SNickeau $_SERVER['SERVER_PORT'] = $portOptionName; 199c3437056SNickeau $this->index($startPath, $force, $depth); 200c3437056SNickeau break; 201c3437056SNickeau case self::METADATA_TO_FRONTMATTER: 202c3437056SNickeau $startPath = $this->getStartPath($args); 203c3437056SNickeau $this->frontmatter($startPath, $depth); 204c3437056SNickeau break; 20571f916b9Sgerardnico case self::ANALYTICS: 206c3437056SNickeau $startPath = $this->getStartPath($args); 207007225e5Sgerardnico $output = $options->getOpt('output', ''); 208007225e5Sgerardnico //if ($output == '-') $output = 'php://stdout'; 209c3437056SNickeau $this->analytics($startPath, $output, $depth); 21071f916b9Sgerardnico break; 21171f916b9Sgerardnico case self::SYNC: 212c3437056SNickeau $this->deleteNonExistingPageFromDatabase(); 213c3437056SNickeau break; 214c3437056SNickeau case self::PLUGINS_TO_UPDATE: 215c3437056SNickeau /** 216c3437056SNickeau * Endpoint: 217c3437056SNickeau * self::EXTENSION_REPOSITORY_API.'?fmt=php&ext[]='.urlencode($name) 218c3437056SNickeau * `http://www.dokuwiki.org/lib/plugins/pluginrepo/api.php?fmt=php&ext[]=`.urlencode($name) 219c3437056SNickeau */ 220c3437056SNickeau $pluginList = plugin_list('', true); 221c3437056SNickeau /* @var helper_plugin_extension_extension $extension */ 222c3437056SNickeau $extension = $this->loadHelper('extension_extension'); 223c3437056SNickeau foreach ($pluginList as $name) { 224c3437056SNickeau $extension->setExtension($name); 225c3437056SNickeau if ($extension->updateAvailable()) { 226c3437056SNickeau echo "The extension $name should be updated"; 227c3437056SNickeau } 228c3437056SNickeau } 22971f916b9Sgerardnico break; 23071f916b9Sgerardnico default: 231c3437056SNickeau if ($cmd !== "") { 232c3437056SNickeau fwrite(STDERR, "Combo: Command unknown (" . $cmd . ")"); 233c3437056SNickeau } else { 234c3437056SNickeau echo $options->help(); 235c3437056SNickeau } 236c3437056SNickeau exit(1); 23771f916b9Sgerardnico } 238*4ebc3257Sgerardnico } catch (\Exception $exception) { 239*4ebc3257Sgerardnico fwrite(STDERR, "An internal error has occured. ".$exception->getMessage() . "\n".$exception->getTraceAsString()); 240*4ebc3257Sgerardnico exit(1); 241*4ebc3257Sgerardnico } 242007225e5Sgerardnico 243007225e5Sgerardnico 244007225e5Sgerardnico } 245007225e5Sgerardnico 246007225e5Sgerardnico /** 24771f916b9Sgerardnico * @param array $namespaces 248c3437056SNickeau * @param bool $rebuild 249007225e5Sgerardnico * @param int $depth recursion depth. 0 for unlimited 25004fd306cSNickeau * @throws ExceptionCompile 251007225e5Sgerardnico */ 252c3437056SNickeau private function index($namespaces = array(), $rebuild = false, $depth = 0) 253c3437056SNickeau { 254c3437056SNickeau 255c3437056SNickeau /** 256c3437056SNickeau * Run as admin to overcome the fact that 257c3437056SNickeau * anonymous user cannot see all links and backlinks 258c3437056SNickeau */ 259c3437056SNickeau global $USERINFO; 260c3437056SNickeau $USERINFO['grps'] = array('admin'); 261c3437056SNickeau global $INPUT; 262c3437056SNickeau $INPUT->server->set('REMOTE_USER', "cli"); 263c3437056SNickeau 264c3437056SNickeau $pages = FsWikiUtility::getPages($namespaces, $depth); 265c3437056SNickeau 266c3437056SNickeau $pageCounter = 0; 267c3437056SNickeau $totalNumberOfPages = sizeof($pages); 268c3437056SNickeau while ($pageArray = array_shift($pages)) { 269c3437056SNickeau $id = $pageArray['id']; 2704cadd4f8SNickeau global $ID; 2714cadd4f8SNickeau $ID = $id; 272c3437056SNickeau /** 273c3437056SNickeau * Indexing the page start the database replication 27404fd306cSNickeau * See {@link action_plugin_combo_indexer} 275c3437056SNickeau */ 276c3437056SNickeau $pageCounter++; 277edc35203Sgerardnico $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 278c3437056SNickeau try { 279c3437056SNickeau /** 280c3437056SNickeau * If the page does not need to be indexed, there is no run 281c3437056SNickeau * and false is returned 282c3437056SNickeau */ 283c3437056SNickeau $indexedOrNot = idx_addPage($id, true, true); 284c3437056SNickeau if ($indexedOrNot) { 285c3437056SNickeau LogUtility::msg("The page {$id} ($pageCounter / $totalNumberOfPages) was indexed and replicated", LogUtility::LVL_MSG_INFO); 286c3437056SNickeau } else { 287c3437056SNickeau LogUtility::msg("The page {$id} ($pageCounter / $totalNumberOfPages) has an error", LogUtility::LVL_MSG_ERROR); 288c3437056SNickeau } 28904fd306cSNickeau } catch (ExceptionRuntime $e) { 290c3437056SNickeau LogUtility::msg("The page {$id} ($pageCounter / $totalNumberOfPages) has an error: " . $e->getMessage(), LogUtility::LVL_MSG_ERROR); 291edc35203Sgerardnico } finally { 292edc35203Sgerardnico $executionContext->close(); 293c3437056SNickeau } 294c3437056SNickeau } 295c3437056SNickeau /** 296c3437056SNickeau * Process all backlinks 297c3437056SNickeau */ 298c3437056SNickeau echo "Processing Replication Request\n"; 299c3437056SNickeau Event::dispatchEvent(PHP_INT_MAX); 300c3437056SNickeau 301c3437056SNickeau } 302c3437056SNickeau 303c3437056SNickeau private function analytics($namespaces = array(), $output = null, $depth = 0) 304007225e5Sgerardnico { 305007225e5Sgerardnico 306007225e5Sgerardnico $fileHandle = null; 307007225e5Sgerardnico if (!empty($output)) { 308007225e5Sgerardnico $fileHandle = @fopen($output, 'w'); 309007225e5Sgerardnico if (!$fileHandle) $this->fatal("Failed to open $output"); 310007225e5Sgerardnico } 311007225e5Sgerardnico 31237748cd8SNickeau /** 31337748cd8SNickeau * Run as admin to overcome the fact that 31437748cd8SNickeau * anonymous user cannot see all links and backlinks 31537748cd8SNickeau */ 31637748cd8SNickeau global $USERINFO; 31737748cd8SNickeau $USERINFO['grps'] = array('admin'); 31837748cd8SNickeau global $INPUT; 31937748cd8SNickeau $INPUT->server->set('REMOTE_USER', "cli"); 32037748cd8SNickeau 32137748cd8SNickeau $pages = FsWikiUtility::getPages($namespaces, $depth); 322007225e5Sgerardnico 323007225e5Sgerardnico 324007225e5Sgerardnico if (!empty($fileHandle)) { 325007225e5Sgerardnico $header = array( 326007225e5Sgerardnico 'id', 327007225e5Sgerardnico 'backlinks', 328007225e5Sgerardnico 'broken_links', 329007225e5Sgerardnico 'changes', 330007225e5Sgerardnico 'chars', 331007225e5Sgerardnico 'external_links', 332007225e5Sgerardnico 'external_medias', 333007225e5Sgerardnico 'h1', 334007225e5Sgerardnico 'h2', 335007225e5Sgerardnico 'h3', 336007225e5Sgerardnico 'h4', 337007225e5Sgerardnico 'h5', 338007225e5Sgerardnico 'internal_links', 339007225e5Sgerardnico 'internal_medias', 340007225e5Sgerardnico 'words', 341007225e5Sgerardnico 'score' 342007225e5Sgerardnico ); 343007225e5Sgerardnico fwrite($fileHandle, implode(",", $header) . PHP_EOL); 344007225e5Sgerardnico } 3459da76789Sgerardnico $pageCounter = 0; 346e8b2ff59SNickeau $totalNumberOfPages = sizeof($pages); 347c3437056SNickeau while ($pageArray = array_shift($pages)) { 348c3437056SNickeau $id = $pageArray['id']; 34904fd306cSNickeau $page = MarkupPath::createMarkupFromId($id); 350c3437056SNickeau 351007225e5Sgerardnico 3529da76789Sgerardnico $pageCounter++; 353c3437056SNickeau /** 354c3437056SNickeau * Analytics 355c3437056SNickeau */ 356edc35203Sgerardnico echo "Analytics Processing for the page {$id} ($pageCounter / $totalNumberOfPages)\n"; 357edc35203Sgerardnico $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 358edc35203Sgerardnico try { 35904fd306cSNickeau $analyticsPath = $page->fetchAnalyticsPath(); 360edc35203Sgerardnico } catch (ExceptionNotExists $e) { 361edc35203Sgerardnico LogUtility::error("The analytics document for the page ($page) was not found"); 362edc35203Sgerardnico continue; 363edc35203Sgerardnico } catch (ExceptionCompile $e) { 364edc35203Sgerardnico LogUtility::error("Error when get the analytics.", self::CANONICAL, $e); 365edc35203Sgerardnico continue; 366edc35203Sgerardnico } finally { 367edc35203Sgerardnico $executionContext->close(); 368edc35203Sgerardnico } 369edc35203Sgerardnico 37004fd306cSNickeau try { 37104fd306cSNickeau $data = \ComboStrap\Json::createFromPath($analyticsPath)->toArray(); 37204fd306cSNickeau } catch (ExceptionBadSyntax $e) { 37304fd306cSNickeau LogUtility::error("The analytics json of the page ($page) is not conform"); 37404fd306cSNickeau continue; 375edc35203Sgerardnico } catch (ExceptionNotFound|ExceptionNotExists $e) { 37604fd306cSNickeau LogUtility::error("The analytics document ({$analyticsPath}) for the page ($page) was not found"); 37704fd306cSNickeau continue; 37804fd306cSNickeau } 379c3437056SNickeau 380007225e5Sgerardnico if (!empty($fileHandle)) { 38104fd306cSNickeau $statistics = $data[renderer_plugin_combo_analytics::STATISTICS]; 382007225e5Sgerardnico $row = array( 383007225e5Sgerardnico 'id' => $id, 384c3437056SNickeau 'backlinks' => $statistics[BacklinkCount::getPersistentName()], 38504fd306cSNickeau 'broken_links' => $statistics[renderer_plugin_combo_analytics::INTERNAL_LINK_BROKEN_COUNT], 38604fd306cSNickeau 'changes' => $statistics[renderer_plugin_combo_analytics::EDITS_COUNT], 38704fd306cSNickeau 'chars' => $statistics[renderer_plugin_combo_analytics::CHAR_COUNT], 38804fd306cSNickeau 'external_links' => $statistics[renderer_plugin_combo_analytics::EXTERNAL_LINK_COUNT], 38904fd306cSNickeau 'external_medias' => $statistics[renderer_plugin_combo_analytics::EXTERNAL_MEDIA_COUNT], 39004fd306cSNickeau PageH1::PROPERTY_NAME => $statistics[renderer_plugin_combo_analytics::HEADING_COUNT][PageH1::PROPERTY_NAME], 39104fd306cSNickeau 'h2' => $statistics[renderer_plugin_combo_analytics::HEADING_COUNT]['h2'], 39204fd306cSNickeau 'h3' => $statistics[renderer_plugin_combo_analytics::HEADING_COUNT]['h3'], 39304fd306cSNickeau 'h4' => $statistics[renderer_plugin_combo_analytics::HEADING_COUNT]['h4'], 39404fd306cSNickeau 'h5' => $statistics[renderer_plugin_combo_analytics::HEADING_COUNT]['h5'], 39504fd306cSNickeau 'internal_links' => $statistics[renderer_plugin_combo_analytics::INTERNAL_LINK_COUNT], 39604fd306cSNickeau 'internal_medias' => $statistics[renderer_plugin_combo_analytics::INTERNAL_MEDIA_COUNT], 39704fd306cSNickeau 'words' => $statistics[renderer_plugin_combo_analytics::WORD_COUNT], 39804fd306cSNickeau 'low' => $data[renderer_plugin_combo_analytics::QUALITY]['low'] 399007225e5Sgerardnico ); 400007225e5Sgerardnico fwrite($fileHandle, implode(",", $row) . PHP_EOL); 401007225e5Sgerardnico } 402c3437056SNickeau 403007225e5Sgerardnico } 404007225e5Sgerardnico if (!empty($fileHandle)) { 405007225e5Sgerardnico fclose($fileHandle); 406007225e5Sgerardnico } 407007225e5Sgerardnico 408007225e5Sgerardnico } 40971f916b9Sgerardnico 410325fe0c5Sgerardnico 411*4ebc3257Sgerardnico /** 412*4ebc3257Sgerardnico * @throws \ComboStrap\ExceptionSqliteNotAvailable 413*4ebc3257Sgerardnico */ 414c3437056SNickeau private function deleteNonExistingPageFromDatabase() 41571f916b9Sgerardnico { 416c3437056SNickeau LogUtility::msg("Starting: Deleting non-existing page from database"); 417c3437056SNickeau $sqlite = Sqlite::createOrGetSqlite(); 418c3437056SNickeau $request = $sqlite 419c3437056SNickeau ->createRequest() 420c3437056SNickeau ->setQuery("select id as \"id\" from pages"); 421c3437056SNickeau $rows = []; 422c3437056SNickeau try { 423c3437056SNickeau $rows = $request 424c3437056SNickeau ->execute() 425c3437056SNickeau ->getRows(); 42604fd306cSNickeau } catch (ExceptionCompile $e) { 427c3437056SNickeau LogUtility::msg("Error while getting the id pages. {$e->getMessage()}"); 428c3437056SNickeau return; 429c3437056SNickeau } finally { 430c3437056SNickeau $request->close(); 43171f916b9Sgerardnico } 432c3437056SNickeau $counter = 0; 433c3437056SNickeau foreach ($rows as $row) { 434c3437056SNickeau $counter++; 435c3437056SNickeau $id = $row['id']; 43671f916b9Sgerardnico if (!page_exists($id)) { 437*4ebc3257Sgerardnico echo 'Page does not exist on the file system. Delete from the database (' . $id . ")\n"; 438*4ebc3257Sgerardnico try { 439*4ebc3257Sgerardnico DatabasePageRow::getFromDokuWikiId($id)->delete(); 440*4ebc3257Sgerardnico } catch (ExceptionNotFound $e) { 441*4ebc3257Sgerardnico // 442*4ebc3257Sgerardnico } 443c3437056SNickeau } 444c3437056SNickeau } 445c3437056SNickeau LogUtility::msg("Sync finished ($counter pages checked)"); 446c3437056SNickeau 447c3437056SNickeau 448c3437056SNickeau } 449c3437056SNickeau 450c3437056SNickeau private function frontmatter($namespaces, $depth) 451c3437056SNickeau { 452c3437056SNickeau $pages = FsWikiUtility::getPages($namespaces, $depth); 453c3437056SNickeau $pageCounter = 0; 454c3437056SNickeau $totalNumberOfPages = sizeof($pages); 455c3437056SNickeau $pagesWithChanges = []; 456c3437056SNickeau $pagesWithError = []; 457c3437056SNickeau $pagesWithOthers = []; 458c3437056SNickeau $notChangedCounter = 0; 459c3437056SNickeau while ($pageArray = array_shift($pages)) { 460c3437056SNickeau $id = $pageArray['id']; 4614cadd4f8SNickeau global $ID; 4624cadd4f8SNickeau $ID = $id; 46304fd306cSNickeau $page = MarkupPath::createMarkupFromId($id); 464c3437056SNickeau $pageCounter++; 465c3437056SNickeau LogUtility::msg("Processing page {$id} ($pageCounter / $totalNumberOfPages) ", LogUtility::LVL_MSG_INFO); 466edc35203Sgerardnico $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 467c3437056SNickeau try { 468c3437056SNickeau $message = MetadataFrontmatterStore::createFromPage($page) 469c3437056SNickeau ->sync(); 470c3437056SNickeau switch ($message->getStatus()) { 471c3437056SNickeau case syntax_plugin_combo_frontmatter::UPDATE_EXIT_CODE_NOT_CHANGED: 472c3437056SNickeau $notChangedCounter++; 473c3437056SNickeau break; 474c3437056SNickeau case syntax_plugin_combo_frontmatter::UPDATE_EXIT_CODE_DONE: 475c3437056SNickeau $pagesWithChanges[] = $id; 476c3437056SNickeau break; 477c3437056SNickeau case syntax_plugin_combo_frontmatter::UPDATE_EXIT_CODE_ERROR: 478c3437056SNickeau $pagesWithError[$id] = $message->getPlainTextContent(); 479c3437056SNickeau break; 480c3437056SNickeau default: 481c3437056SNickeau $pagesWithOthers[$id] = $message->getPlainTextContent(); 482c3437056SNickeau break; 483c3437056SNickeau 484c3437056SNickeau } 48504fd306cSNickeau } catch (ExceptionCompile $e) { 486c3437056SNickeau $pagesWithError[$id] = $e->getMessage(); 487edc35203Sgerardnico } finally { 488edc35203Sgerardnico $executionContext->close(); 489c3437056SNickeau } 490c3437056SNickeau 491c3437056SNickeau } 492c3437056SNickeau 493c3437056SNickeau echo "\n"; 494c3437056SNickeau echo "Result:\n"; 495c3437056SNickeau echo "$notChangedCounter pages without any frontmatter modifications\n"; 496c3437056SNickeau 497c3437056SNickeau if (sizeof($pagesWithError) > 0) { 498c3437056SNickeau echo "\n"; 499c3437056SNickeau echo "The following pages had errors\n"; 500c3437056SNickeau $pageCounter = 0; 501c3437056SNickeau $totalNumberOfPages = sizeof($pagesWithError); 502c3437056SNickeau foreach ($pagesWithError as $id => $message) { 503c3437056SNickeau $pageCounter++; 504c3437056SNickeau LogUtility::msg("Page {$id} ($pageCounter / $totalNumberOfPages): " . $message, LogUtility::LVL_MSG_ERROR); 505c3437056SNickeau } 506c3437056SNickeau } else { 507c3437056SNickeau echo "No error\n"; 508c3437056SNickeau } 509c3437056SNickeau 510c3437056SNickeau if (sizeof($pagesWithChanges) > 0) { 511c3437056SNickeau echo "\n"; 512c3437056SNickeau echo "The following pages had changed:\n"; 513c3437056SNickeau $pageCounter = 0; 514c3437056SNickeau $totalNumberOfPages = sizeof($pagesWithChanges); 515c3437056SNickeau foreach ($pagesWithChanges as $id) { 516c3437056SNickeau $pageCounter++; 517c3437056SNickeau LogUtility::msg("Page {$id} ($pageCounter / $totalNumberOfPages) ", LogUtility::LVL_MSG_ERROR); 518c3437056SNickeau } 519c3437056SNickeau } else { 520c3437056SNickeau echo "No changes\n"; 521c3437056SNickeau } 522c3437056SNickeau 523c3437056SNickeau if (sizeof($pagesWithOthers) > 0) { 524c3437056SNickeau echo "\n"; 525c3437056SNickeau echo "The following pages had an other status"; 526c3437056SNickeau $pageCounter = 0; 527c3437056SNickeau $totalNumberOfPages = sizeof($pagesWithOthers); 528c3437056SNickeau foreach ($pagesWithOthers as $id => $message) { 529c3437056SNickeau $pageCounter++; 530c3437056SNickeau LogUtility::msg("Page {$id} ($pageCounter / $totalNumberOfPages) " . $message, LogUtility::LVL_MSG_ERROR); 531c3437056SNickeau } 53271f916b9Sgerardnico } 53371f916b9Sgerardnico } 53471f916b9Sgerardnico 535c3437056SNickeau private function getStartPath($args) 536c3437056SNickeau { 537c3437056SNickeau $sizeof = sizeof($args); 538c3437056SNickeau switch ($sizeof) { 539c3437056SNickeau case 0: 540c3437056SNickeau fwrite(STDERR, "The start path is mandatory and was not given"); 541c3437056SNickeau exit(1); 542c3437056SNickeau case 1: 543c3437056SNickeau $startPath = $args[0]; 544c3437056SNickeau if (!in_array($startPath, [":", "/"])) { 545c3437056SNickeau // cleanId would return blank for a root 546c3437056SNickeau $startPath = cleanID($startPath); 547c3437056SNickeau } 548c3437056SNickeau break; 549c3437056SNickeau default: 550c3437056SNickeau fwrite(STDERR, "Too much arguments given $sizeof"); 551c3437056SNickeau exit(1); 552c3437056SNickeau } 553c3437056SNickeau return $startPath; 55471f916b9Sgerardnico } 555007225e5Sgerardnico} 556