xref: /plugin/struct/meta/CSVPageImporter.php (revision 0549dcc5bc88d4f9d923acdd09931d8d51be7097)
1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5class CSVPageImporter extends CSVImporter
6{
7    protected $importedPids = array();
8
9    /** @var bool[] */
10    protected $createPage = [];
11
12    /**
13     * Import page schema only when the pid header is present.
14     */
15    protected function readHeaders()
16    {
17        parent::readHeaders();
18        if (!in_array('pid', $this->header)) throw new StructException('There is no "pid" header in the CSV. Schema not imported.');
19    }
20
21    /**
22     * Add the revision.
23     *
24     * @param string[] $values
25     */
26    protected function saveLine($values)
27    {
28        //create new page revision
29        $pid = cleanID($values[0]);
30        if ($this->createPage[$pid]) {
31            $this->createPage($pid, $values);
32        }
33        // make sure this schema is assigned
34        /** @noinspection PhpUndefinedVariableInspection */
35        Assignments::getInstance()->assignPageSchema(
36            $pid,
37            $this->schema->getTable()
38        );
39        parent::saveLine($values);
40    }
41
42    /**
43     * Create a page from a namespace template and replace column-label-placeholders
44     *
45     * This is intended to use the same placeholders as bureaucracy in their most basic version
46     * (i.e. without default values, formatting, etc. )
47     *
48     * @param string $pid
49     * @param array $line
50     */
51    protected function createPage($pid, $line)
52    {
53        $text = pageTemplate($pid);
54        if (trim($text) === '') {
55            $pageParts = explode(':', $pid);
56            $pagename = end($pageParts);
57            $text = "====== $pagename ======\n";
58        }
59        $keys = array_reduce(
60            $this->columns,
61            function ($keys, Column $col) {
62                if (!in_array($col->getLabel(), $keys, true)) {
63                    return $keys;
64                }
65                $index = array_search($col->getLabel(), $keys, true);
66                $keys[$index] = $col->getFullQualifiedLabel();
67                return $keys;
68            },
69            $this->header
70        );
71
72        $keysAt = array_map(function ($key) {
73            return "@@$key@@";
74        }, $keys);
75        $keysHash = array_map(function ($key) {
76            return "##$key##";
77        }, $keys);
78        $flatValues = array_map(
79            function ($value) {
80                if (is_array($value)) {
81                    return implode(', ', $value);
82                }
83                return $value;
84            },
85            $line
86        );
87        $text = $this->evaluateIfNotEmptyTags($text, $keys, $flatValues);
88        $text = str_replace($keysAt, $flatValues, $text);
89        /** @noinspection CascadeStringReplacementInspection */
90        $text = str_replace($keysHash, $flatValues, $text);
91        saveWikiText($pid, $text, 'Created by struct csv import');
92    }
93
94    /**
95     * Replace conditional <ifnotempty fieldname></ifnotempty> tags
96     *
97     * @param string $text The template
98     * @param string[] $keys The array of qualified headers
99     * @param string[] $values The flat array of corresponding values
100     *
101     * @return string The template with the tags replaced
102     */
103    protected function evaluateIfNotEmptyTags($text, $keys, $values)
104    {
105        return preg_replace_callback(
106            '/<ifnotempty (.+?)>([^<]*?)<\/ifnotempty>/',
107            function ($matches) use ($keys, $values) {
108                list (, $blockKey, $textIfNotEmpty) = $matches;
109                $index = array_search($blockKey, $keys, true);
110                if ($index === false) {
111                    msg('Import error: Key "' . hsc($blockKey) . '" not found!', -1);
112                    return '';
113                }
114                if (trim($values[$index]) === '') {
115                    return '';
116                }
117                return $textIfNotEmpty;
118            },
119            $text
120        );
121    }
122
123    /**
124     * Check if page id realy exists
125     *
126     * @param Column $col
127     * @param mixed $rawvalue
128     * @return bool
129     */
130    protected function validateValue(Column $col, &$rawvalue)
131    {
132        //check if page id exists and schema is bound to the page
133        if ($col->getLabel() == 'pid') {
134            $pid = cleanID($rawvalue);
135            if (isset($this->importedPids[$pid])) {
136                $this->errors[] = 'Page "' . $pid . '" already imported. Skipping the row.';
137                return false;
138            }
139            if (page_exists($pid)) {
140                $this->importedPids[$pid] = true;
141                return true;
142            }
143            global $INPUT;
144            if ($INPUT->bool('createPage')) {
145                $this->createPage[$pid] = true;
146                return true;
147            }
148            $this->errors[] = 'Page "' . $pid . '" does not exists. Skipping the row.';
149            return false;
150        }
151
152        return parent::validateValue($col, $rawvalue);
153    }
154}
155