xref: /plugin/combo/cli.php (revision 4ebc325786ead9709aa582b2a0377b9dac4403d9)
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