xref: /plugin/struct/meta/CSVPageImporter.php (revision c09fb9e34d0bdb7bda0f61c26957d44d921755f6)
11fc2361fSSzymon Olewniczak<?php
21fc2361fSSzymon Olewniczak
31fc2361fSSzymon Olewniczaknamespace dokuwiki\plugin\struct\meta;
41fc2361fSSzymon Olewniczakuse dokuwiki\plugin\struct\types\Page;
51fc2361fSSzymon Olewniczak
61fc2361fSSzymon Olewniczakclass CSVPageImporter extends CSVImporter {
7e53295c5SSzymon Olewniczak
8e53295c5SSzymon Olewniczak    protected $importedPids = array();
9e53295c5SSzymon Olewniczak
10ee52a3aaSMichael Große    /** @var bool[]  */
1117dbef8aSMichael Große    protected $createPage = [];
1217dbef8aSMichael Große
131fc2361fSSzymon Olewniczak    /**
141fc2361fSSzymon Olewniczak     * Chceck if schema is page schema
151fc2361fSSzymon Olewniczak     *
161fc2361fSSzymon Olewniczak     * @throws StructException
171fc2361fSSzymon Olewniczak     * @param string $table
181fc2361fSSzymon Olewniczak     * @param string $file
191fc2361fSSzymon Olewniczak     */
201fc2361fSSzymon Olewniczak    public function __construct($table, $file) {
211fc2361fSSzymon Olewniczak        parent::__construct($table, $file);
221fc2361fSSzymon Olewniczak
231fc2361fSSzymon Olewniczak        if($this->schema->isLookup()) throw new StructException($table.' is not a page schema');
241fc2361fSSzymon Olewniczak    }
251fc2361fSSzymon Olewniczak
261fc2361fSSzymon Olewniczak    /**
271fc2361fSSzymon Olewniczak     * Import page schema only when the pid header is present.
281fc2361fSSzymon Olewniczak     */
291fc2361fSSzymon Olewniczak    protected function readHeaders() {
301fc2361fSSzymon Olewniczak
311fc2361fSSzymon Olewniczak        //add pid to struct
321fc2361fSSzymon Olewniczak        $pageType = new Page(null, 'pid');
3317dbef8aSMichael Große        $this->columns[] = new Column(0, $pageType, 0, true, $this->schema->getTable());
341fc2361fSSzymon Olewniczak
351fc2361fSSzymon Olewniczak        parent::readHeaders();
361fc2361fSSzymon Olewniczak
371fc2361fSSzymon Olewniczak        if(!in_array('pid', $this->header)) throw new StructException('There is no "pid" header in the CSV. Schema not imported.');
381fc2361fSSzymon Olewniczak    }
391fc2361fSSzymon Olewniczak
401fc2361fSSzymon Olewniczak    /**
411fc2361fSSzymon Olewniczak     * Creates the insert string for the single value table
421fc2361fSSzymon Olewniczak     *
431fc2361fSSzymon Olewniczak     * @return string
441fc2361fSSzymon Olewniczak     */
451fc2361fSSzymon Olewniczak    protected function getSQLforAllValues() {
461fc2361fSSzymon Olewniczak        $colnames = array();
471fc2361fSSzymon Olewniczak        foreach($this->columns as $i => $col) {
481fc2361fSSzymon Olewniczak            $colnames[] = 'col' . $col->getColref();
491fc2361fSSzymon Olewniczak        }
501fc2361fSSzymon Olewniczak        //replace first column with pid
511fc2361fSSzymon Olewniczak        $colnames[0] = 'pid';
521fc2361fSSzymon Olewniczak        //insert rev at the end
531fc2361fSSzymon Olewniczak        $colnames[] = 'rev';
541fc2361fSSzymon Olewniczak
551fc2361fSSzymon Olewniczak        $placeholds = join(', ', array_fill(0, count($colnames), '?'));
561fc2361fSSzymon Olewniczak        $colnames = join(', ', $colnames);
571fc2361fSSzymon Olewniczak        $table = $this->schema->getTable();
581fc2361fSSzymon Olewniczak
59e53295c5SSzymon Olewniczak        return "INSERT INTO data_$table ($colnames, latest) VALUES ($placeholds, 1)";
601fc2361fSSzymon Olewniczak    }
611fc2361fSSzymon Olewniczak
621fc2361fSSzymon Olewniczak    /**
631fc2361fSSzymon Olewniczak     * Add the revision.
641fc2361fSSzymon Olewniczak     *
651fc2361fSSzymon Olewniczak     * @param string[] $values
661fc2361fSSzymon Olewniczak     * @param          $line
671fc2361fSSzymon Olewniczak     * @param string   $single
681fc2361fSSzymon Olewniczak     * @param string   $multi
691fc2361fSSzymon Olewniczak     */
701fc2361fSSzymon Olewniczak    protected function saveLine($values, $line, $single, $multi) {
71e53295c5SSzymon Olewniczak        //create new page revision
7295ea798eSMichael Große        $pid = cleanID($values[0]);
7317dbef8aSMichael Große        if ($this->createPage[$pid]) {
7417dbef8aSMichael Große            $this->createPage($pid, $line);
7517dbef8aSMichael Große        }
76e53295c5SSzymon Olewniczak        $helper = plugin_load('helper', 'struct');
77e53295c5SSzymon Olewniczak        $revision = $helper->createPageRevision($pid, 'CSV data imported');
78e53295c5SSzymon Olewniczak        p_get_metadata($pid); // reparse the metadata of the page top update the titles/rev/lasteditor table
79e53295c5SSzymon Olewniczak
80e53295c5SSzymon Olewniczak        // make sure this schema is assigned
81e53295c5SSzymon Olewniczak        /** @noinspection PhpUndefinedVariableInspection */
82e53295c5SSzymon Olewniczak        Assignments::getInstance()->assignPageSchema(
83e53295c5SSzymon Olewniczak            $pid,
84e53295c5SSzymon Olewniczak            $this->schema->getTable()
85e53295c5SSzymon Olewniczak        );
86e53295c5SSzymon Olewniczak
87e53295c5SSzymon Olewniczak        //add page revision to values
88e53295c5SSzymon Olewniczak        $values[] = $revision;
89e53295c5SSzymon Olewniczak
901fc2361fSSzymon Olewniczak        parent::saveLine($values, $line, $single, $multi);
911fc2361fSSzymon Olewniczak    }
921fc2361fSSzymon Olewniczak
931fc2361fSSzymon Olewniczak    /**
9417dbef8aSMichael Große     * Create a page from a namespace template and replace column-label-placeholders
9517dbef8aSMichael Große     *
9617dbef8aSMichael Große     * This is intended to use the same placeholders as bureaucracy in their most basic version
9717dbef8aSMichael Große     * (i.e. without default values, formatting, etc. )
9817dbef8aSMichael Große     *
9917dbef8aSMichael Große     * @param string $pid
10017dbef8aSMichael Große     * @param array  $line
10117dbef8aSMichael Große     */
10217dbef8aSMichael Große    protected function createPage($pid, $line)
10317dbef8aSMichael Große    {
10417dbef8aSMichael Große        $text = pageTemplate($pid);
10517dbef8aSMichael Große        if (trim($text) === '') {
10617dbef8aSMichael Große            $pageParts = explode(':', $pid);
10717dbef8aSMichael Große            $pagename = end($pageParts);
10817dbef8aSMichael Große            $text = "====== $pagename ======\n";
10917dbef8aSMichael Große        }
110*c09fb9e3SMichael Große        $keys = array_reduce($this->columns,
111*c09fb9e3SMichael Große            function ($keys, Column $col) {
112*c09fb9e3SMichael Große                if (!in_array($col->getLabel(), $keys, true)) {
113*c09fb9e3SMichael Große                    return $keys;
114*c09fb9e3SMichael Große                }
115*c09fb9e3SMichael Große                $index = array_search($col->getLabel(), $keys, true);
116*c09fb9e3SMichael Große                $keys[$index] = $col->getFullQualifiedLabel();
117*c09fb9e3SMichael Große                return $keys;
118*c09fb9e3SMichael Große            },
119*c09fb9e3SMichael Große            $this->header
120*c09fb9e3SMichael Große        );
121*c09fb9e3SMichael Große
12217dbef8aSMichael Große        $keysAt = array_map(function ($key) { return "@@$key@@";}, $keys);
12317dbef8aSMichael Große        $keysHash = array_map(function ($key) { return "##$key##";}, $keys);
12417dbef8aSMichael Große        $flatValues = array_map(
12517dbef8aSMichael Große            function($value) {
12617dbef8aSMichael Große                if (is_array($value)) {
12717dbef8aSMichael Große                    return implode(', ', $value);
12817dbef8aSMichael Große                }
12917dbef8aSMichael Große                return $value;
13017dbef8aSMichael Große            }, $line);
13117dbef8aSMichael Große        $text = str_replace($keysAt, $flatValues, $text);
13217dbef8aSMichael Große        /** @noinspection CascadeStringReplacementInspection */
13317dbef8aSMichael Große        $text = str_replace($keysHash, $flatValues, $text);
13417dbef8aSMichael Große        saveWikiText($pid, $text, 'Created by struct csv import');
13517dbef8aSMichael Große    }
13617dbef8aSMichael Große
13717dbef8aSMichael Große    /**
1381fc2361fSSzymon Olewniczak     * In the paga schemas primary key is a touple of (pid, rev)
1391fc2361fSSzymon Olewniczak     *
1401fc2361fSSzymon Olewniczak     * @param string[] $values
1411fc2361fSSzymon Olewniczak     * @param string   $single
1421fc2361fSSzymon Olewniczak     * @return array(pid, rev)
1431fc2361fSSzymon Olewniczak     */
1441fc2361fSSzymon Olewniczak    protected function insertIntoSingle($values, $single) {
1451fc2361fSSzymon Olewniczak        $pid = $values[0];
1461fc2361fSSzymon Olewniczak        $rev = $values[count($values) - 1];
147e53295c5SSzymon Olewniczak
148e53295c5SSzymon Olewniczak        //update latest
149e53295c5SSzymon Olewniczak        $table = $this->schema->getTable();
150e53295c5SSzymon Olewniczak        $this->sqlite->query("UPDATE data_$table SET latest = 0 WHERE latest = 1 AND pid = ?", array($pid));
151e53295c5SSzymon Olewniczak
152e53295c5SSzymon Olewniczak        //insert into table
153e53295c5SSzymon Olewniczak        parent::insertIntoSingle($values, $single);
154e53295c5SSzymon Olewniczak
1551fc2361fSSzymon Olewniczak        //primary key is touple of (pid, rev)
1561fc2361fSSzymon Olewniczak        return array($pid, $rev);
1571fc2361fSSzymon Olewniczak    }
1581fc2361fSSzymon Olewniczak
1591fc2361fSSzymon Olewniczak    /**
1601fc2361fSSzymon Olewniczak     * Add pid and rev to insert query parameters
1611fc2361fSSzymon Olewniczak     *
1621fc2361fSSzymon Olewniczak     * @param string $multi
1631fc2361fSSzymon Olewniczak     * @param string $pk
1641fc2361fSSzymon Olewniczak     * @param string $column
1651fc2361fSSzymon Olewniczak     * @param string $row
1661fc2361fSSzymon Olewniczak     * @param string $value
1671fc2361fSSzymon Olewniczak     */
1681fc2361fSSzymon Olewniczak    protected function insertIntoMulti($multi, $pk, $column, $row, $value) {
1691fc2361fSSzymon Olewniczak        list($pid, $rev) = $pk;
170e53295c5SSzymon Olewniczak
171e53295c5SSzymon Olewniczak        //update latest
172e53295c5SSzymon Olewniczak        $table = $this->schema->getTable();
173e53295c5SSzymon Olewniczak        $this->sqlite->query("UPDATE multi_$table SET latest = 0 WHERE latest = 1 AND pid = ?", array($pid));
174e53295c5SSzymon Olewniczak
1751fc2361fSSzymon Olewniczak        $this->sqlite->query($multi, array($pid, $rev, $column->getColref(), $row + 1, $value));
1761fc2361fSSzymon Olewniczak    }
1771fc2361fSSzymon Olewniczak
1781fc2361fSSzymon Olewniczak    /**
1791fc2361fSSzymon Olewniczak     * In page schemas we use REPLACE instead of INSERT to prevent ambiguity
1801fc2361fSSzymon Olewniczak     *
1811fc2361fSSzymon Olewniczak     * @return string
1821fc2361fSSzymon Olewniczak     */
1831fc2361fSSzymon Olewniczak    protected function getSQLforMultiValue() {
1841fc2361fSSzymon Olewniczak        $table = $this->schema->getTable();
1851fc2361fSSzymon Olewniczak        /** @noinspection SqlResolve */
186e53295c5SSzymon Olewniczak        return "INSERT INTO multi_$table (pid, rev, colref, row, value, latest) VALUES (?,?,?,?,?,1)";
1871fc2361fSSzymon Olewniczak    }
1881fc2361fSSzymon Olewniczak
1891fc2361fSSzymon Olewniczak    /**
1901fc2361fSSzymon Olewniczak     * Check if page id realy exists
1911fc2361fSSzymon Olewniczak     *
1921fc2361fSSzymon Olewniczak     * @param Column $col
1931fc2361fSSzymon Olewniczak     * @param mixed  $rawvalue
1941fc2361fSSzymon Olewniczak     * @return bool
1951fc2361fSSzymon Olewniczak     */
1961fc2361fSSzymon Olewniczak    protected function validateValue(Column $col, &$rawvalue) {
197e53295c5SSzymon Olewniczak        //check if page id exists and schema is bounded to the page
1981fc2361fSSzymon Olewniczak        if($col->getLabel() == 'pid') {
199e53295c5SSzymon Olewniczak            $pid = cleanID($rawvalue);
200e53295c5SSzymon Olewniczak            if (isset($this->importedPids[$pid])) {
201e53295c5SSzymon Olewniczak                $this->errors[] = 'Page "'.$pid.'" already imported. Skipping the row.';
202e53295c5SSzymon Olewniczak                return false;
203e53295c5SSzymon Olewniczak            }
204e53295c5SSzymon Olewniczak            if(page_exists($pid)) {
205e53295c5SSzymon Olewniczak                $this->importedPids[$pid] = true;
2061fc2361fSSzymon Olewniczak                return true;
2071fc2361fSSzymon Olewniczak            }
20817dbef8aSMichael Große            global $INPUT;
20917dbef8aSMichael Große            if ($INPUT->bool('createPage')) {
21017dbef8aSMichael Große                $this->createPage[$pid] = true;
21117dbef8aSMichael Große                return true;
21217dbef8aSMichael Große            }
213e53295c5SSzymon Olewniczak            $this->errors[] = 'Page "'.$pid.'" does not exists. Skipping the row.';
2141fc2361fSSzymon Olewniczak            return false;
2151fc2361fSSzymon Olewniczak        }
2161fc2361fSSzymon Olewniczak
2171fc2361fSSzymon Olewniczak        return parent::validateValue($col, $rawvalue);
2181fc2361fSSzymon Olewniczak    }
2191fc2361fSSzymon Olewniczak}
220