1<?php
2
3namespace dokuwiki\plugin\structstatus;
4
5use dokuwiki\plugin\struct\meta\Column;
6use dokuwiki\plugin\struct\meta\QueryBuilder;
7use dokuwiki\plugin\struct\meta\Search;
8use dokuwiki\plugin\struct\types\AbstractBaseType;
9use dokuwiki\plugin\struct\types\Lookup;
10
11class Status extends Lookup {
12
13    protected $config = array(
14        'schema' => ''
15    );
16
17    /**
18     * @inheritDoc
19     */
20    protected function getLookupColumn() {
21        if($this->column !== null) return $this->column;
22        $this->column = $this->getColumn($this->config['schema'], 'name_$LANG');
23        return $this->column;
24    }
25
26    /**
27     * @inheritDoc
28     */
29    public function renderValue($value, \Doku_Renderer $R, $mode) {
30        list(, $value, $color, $icon) = json_decode($value);
31
32        if($mode == 'xhtml') {
33            $R->doc .= $this->xhtmlStatus($value, $color, $icon);
34        } else {
35            $R->cdata($value);
36        }
37
38        return true;
39    }
40
41    /**
42     * Creates a single status entry
43     *
44     * @param string $label
45     * @param string $color
46     * @param string $icon
47     * @param string $rid the identifier in the linked status lookup table
48     * @param array $classes
49     * @param bool  $button
50     * @return string
51     */
52    public function xhtmlStatus($label, $color, $icon='', $rid = 0, $classes=array(), $button=false) {
53        $html = '';
54        $classes[] = 'struct_status';
55        if($icon) $classes[] = 'struct_status_icon_'.$icon;
56        $class = hsc(join(' ', $classes));
57
58        $tag = $button ? 'button' : 'div';
59
60        $html .= "<$tag class=\"" . $class . '" style="border-color:' . hsc($color) . '; fill: ' . hsc($color) . ';" data-rid="'.hsc($rid).'">';
61        $html .= $this->inlineSVG($icon);
62        $html .= hsc($label);
63        $html .= "</$tag>";
64
65        return $html;
66    }
67
68    /**
69     * Returns the svg code of the given icon
70     *
71     * @param string $icon The icon identifier (no .svg extension)
72     * @return string
73     */
74    protected function inlineSVG($icon) {
75        $icon = preg_replace('@[\.\\\\/]+@', '', $icon);
76        $file = __DIR__ . '/svg/' . $icon . '.svg';
77        if(!file_exists($file)) return '';
78
79        $data = file_get_contents($file);
80        $data = preg_replace('/<\?xml .*?\?>/', '', $data);
81        $data = preg_replace('/<!DOCTYPE .*?>/', '', $data);
82
83        return $data;
84    }
85
86    /**
87     * @inheritDoc
88     */
89    public function renderMultiValue($values, \Doku_Renderer $R, $mode) {
90        foreach($values as $value) {
91            $this->renderValue($value, $R, $mode);
92        }
93        return true;
94    }
95
96    /**
97     * Merge with lookup table
98     *
99     * @param QueryBuilder $QB
100     * @param string $tablealias
101     * @param string $colname
102     * @param string $alias
103     */
104    public function select(QueryBuilder $QB, $tablealias, $colname, $alias) {
105        $schema = 'data_' . $this->config['schema'];
106
107        $rightalias = $QB->generateTableAlias();
108
109        // main status
110        $col_status = $this->getLookupColumn();
111        if(!$col_status) {
112            AbstractBaseType::select($QB, $tablealias, $colname, $alias);
113            return;
114        }
115        $field_status = $rightalias . '.' . $col_status->getColName();
116
117        // color
118        $col_color = $this->getColumn($this->config['schema'], 'color');
119        if(!$col_color) {
120            $field_color = "'#ffffff'"; // static fallback
121        } else {
122            $field_color = $rightalias . '.' . $col_color->getColName(true);
123        }
124
125        // icon
126        $col_icon = $this->getColumn($this->config['schema'], 'icon');
127        if(!$col_icon) {
128            $field_icon = "''"; // static fallback
129        } else {
130            $field_icon = $rightalias . '.' . $col_icon->getColName(true);
131        }
132
133        // join the lookup
134        $QB->addLeftJoin(
135            $tablealias, $schema, $rightalias,
136            "$tablealias.$colname = STRUCT_JSON($rightalias.pid, CAST($rightalias.rid AS DECIMAL)) AND $rightalias.latest = 1"
137        );
138
139        // get the values (pid, status, color)
140        $QB->addSelectStatement("STRUCT_JSON($tablealias.$colname, $field_status, $field_color, $field_icon)", $alias);
141    }
142
143    /**
144     * Returns a list of available statuses for this type
145     *
146     * This is similar to getOptions but returns some more info about each status
147     *
148     * @return array
149     */
150    public function getAllStatuses() {
151        $col = $this->getLookupColumn();
152        $colname = $col->getLabel();
153
154        $search = new Search();
155        $search->addSchema($col->getTable());
156        $search->addColumn($colname);
157        $search->addColumn('color');
158        $search->addColumn('icon');
159        $search->addSort($colname);
160        $values = $search->execute();
161        $rids = $search->getRids();
162
163        $statuses = array();
164        foreach($values as $status) {
165            $rid = json_encode(["", (int)array_shift($rids)]);
166            $label = $status[0]->getValue();
167            $color = $status[1]->getValue();
168            $icon = $status[2]->getValue();
169
170            $statuses[] = compact('rid', 'label', 'color', 'icon');
171        }
172
173        return $statuses;
174    }
175}
176