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