1 | <?php |
||
2 | /** |
||
3 | * @package midcom.grid |
||
4 | * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/ |
||
5 | * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/ |
||
6 | * @license http://www.gnu.org/licenses/gpl.html GNU General Public License |
||
7 | */ |
||
8 | |||
9 | namespace midcom\grid; |
||
10 | |||
11 | use midcom; |
||
12 | use midcom_error; |
||
13 | |||
14 | /** |
||
15 | * Helper class for jqgrid widgets |
||
16 | * |
||
17 | * @package midcom.grid |
||
18 | */ |
||
19 | class grid |
||
20 | { |
||
21 | /** |
||
22 | * The grid's ID |
||
23 | */ |
||
24 | private string $_identifier; |
||
25 | |||
26 | /** |
||
27 | * The grid's options (converted for use in JS constructor) |
||
28 | */ |
||
29 | private array $_options = []; |
||
30 | |||
31 | /** |
||
32 | * The grid's options as passed in PHP |
||
33 | */ |
||
34 | private array $_raw_options = []; |
||
35 | |||
36 | /** |
||
37 | * The grid's columns |
||
38 | * |
||
39 | * They have the following structure |
||
40 | * |
||
41 | * 'key' => [ |
||
42 | * 'label' => "Some label", |
||
43 | * 'options' => 'javascript option string' |
||
44 | * ] |
||
45 | */ |
||
46 | private array $_columns = []; |
||
47 | |||
48 | /** |
||
49 | * Flag that tracks if JS/CSS files have already been added |
||
50 | */ |
||
51 | private static bool $_head_elements_added = false; |
||
52 | |||
53 | /** |
||
54 | * Data for the table footer |
||
55 | */ |
||
56 | private array $_footer_data = []; |
||
57 | |||
58 | /** |
||
59 | * Should formatters be applied to footer row |
||
60 | */ |
||
61 | private bool $format_footer = true; |
||
62 | |||
63 | /** |
||
64 | * The data provider, if any |
||
65 | */ |
||
66 | private ?provider $_provider = null; |
||
67 | |||
68 | /** |
||
69 | * Javascript code that should be prepended to the widget constructor |
||
70 | */ |
||
71 | private string $_prepend_js = ''; |
||
72 | |||
73 | /** |
||
74 | * Adds the necessary javascript & css files for jqgrid |
||
75 | */ |
||
76 | 38 | public static function add_head_elements() |
|
77 | { |
||
78 | 38 | if (self::$_head_elements_added) { |
|
79 | 37 | return; |
|
80 | } |
||
81 | 1 | $version = '4.15.4'; |
|
82 | 1 | $jqgrid_path = '/midcom.grid/jqGrid-' . $version . '/'; |
|
83 | |||
84 | 1 | $head = midcom::get()->head; |
|
85 | 1 | $head->enable_jquery_ui(['button', 'mouse', 'resizable']); |
|
86 | |||
87 | //needed js/css-files for jqgrid |
||
88 | 1 | $lang = "en"; |
|
89 | 1 | $language = midcom::get()->i18n->get_current_language(); |
|
90 | 1 | if (file_exists(MIDCOM_STATIC_ROOT . $jqgrid_path . 'i18n/grid.locale-' . $language . '.js')) { |
|
91 | 1 | $lang = $language; |
|
92 | } |
||
93 | 1 | $head->add_jsfile(MIDCOM_STATIC_URL . $jqgrid_path . 'i18n/grid.locale-'. $lang . '.js'); |
|
94 | 1 | $head->add_jsfile(MIDCOM_STATIC_URL . $jqgrid_path . 'jquery.jqgrid.min.js'); |
|
95 | |||
96 | 1 | $head->add_jsfile(MIDCOM_STATIC_URL . '/midcom.grid/jqGrid.custom.js'); |
|
97 | |||
98 | 1 | $head->add_stylesheet(MIDCOM_STATIC_URL . $jqgrid_path . 'ui.jqgrid.min.css'); |
|
99 | 1 | $head->add_stylesheet(MIDCOM_STATIC_URL . "/stock-icons/font-awesome-4.7.0/css/font-awesome.min.css"); |
|
100 | 1 | $head->add_stylesheet(MIDCOM_STATIC_URL . '/midcom.grid/jqGrid.custom.css'); |
|
101 | 1 | self::$_head_elements_added = true; |
|
102 | } |
||
103 | |||
104 | /** |
||
105 | * Constructor. Add head elements when necessary and the ID column |
||
106 | */ |
||
107 | 37 | public function __construct(string $identifier, string $datatype) |
|
108 | { |
||
109 | 37 | $this->_identifier = $identifier; |
|
110 | 37 | $this->set_column('id', 'id', 'hidden:true, key:true'); |
|
111 | 37 | $this->set_option('datatype', $datatype); |
|
112 | 37 | self::add_head_elements(); |
|
113 | } |
||
114 | |||
115 | 32 | public function set_provider(provider $provider) |
|
116 | { |
||
117 | 32 | $this->_provider = $provider; |
|
118 | } |
||
119 | |||
120 | 3 | public function get_provider() |
|
121 | { |
||
122 | 3 | return $this->_provider; |
|
123 | } |
||
124 | |||
125 | /** |
||
126 | * Returns the grid's ID |
||
127 | */ |
||
128 | 31 | public function get_identifier() : string |
|
129 | { |
||
130 | 31 | return $this->_identifier; |
|
131 | } |
||
132 | |||
133 | /** |
||
134 | * Set an option |
||
135 | */ |
||
136 | 37 | public function set_option(string $key, $value, bool $autoquote_string = true) : self |
|
137 | { |
||
138 | 37 | $this->_raw_options[$key] = $value; |
|
139 | 37 | if ( $autoquote_string |
|
140 | 37 | && is_string($value)) { |
|
141 | 37 | $value = '"' . str_replace('"', '\\"', $value) . '"'; |
|
142 | 33 | } elseif ($value === true) { |
|
143 | 32 | $value = 'true'; |
|
144 | 33 | } elseif ($value === false) { |
|
145 | $value = 'false'; |
||
146 | 33 | } elseif (is_array($value)) { |
|
147 | 19 | $value = json_encode($value); |
|
148 | } |
||
149 | 37 | $this->_options[$key] = $value; |
|
150 | 37 | return $this; |
|
151 | } |
||
152 | |||
153 | 26 | public function get_option(string $key) |
|
154 | { |
||
155 | 26 | if (empty($this->_raw_options[$key])) { |
|
156 | 25 | return null; |
|
157 | } |
||
158 | 11 | return $this->_raw_options[$key]; |
|
159 | } |
||
160 | |||
161 | /** |
||
162 | * Set a column |
||
163 | * |
||
164 | * @param array $selectdata Should the column have a separate index, if so, which sort type |
||
165 | */ |
||
166 | 10 | public function set_select_column(string $name, string $label, string $options, array $selectdata) : self |
|
167 | { |
||
168 | 10 | $selectstring = implode(';', array_map( |
|
169 | 10 | function ($key, $value) { |
|
170 | 10 | return $key . ':' . $value; |
|
171 | 10 | }, |
|
172 | 10 | array_keys($selectdata), |
|
173 | 10 | $selectdata |
|
174 | 10 | )); |
|
175 | |||
176 | 10 | if ($options !== '') { |
|
177 | 8 | $options .= ', '; |
|
178 | } |
||
179 | 10 | $options .= 'stype: "select", searchoptions: {sopt: ["eq"], value: ":;' . $selectstring . '"}'; |
|
180 | 10 | $options .= ', edittype:"select", formatter:"select", editoptions:{value:"' . $selectstring . '"}'; |
|
181 | |||
182 | 10 | return $this->set_column($name, $label, $options); |
|
183 | } |
||
184 | |||
185 | /** |
||
186 | * Set a column |
||
187 | * |
||
188 | * @param string $separate_index Should the column have a separate index, if so, which sort type |
||
189 | */ |
||
190 | 37 | public function set_column(string $name, string $label, string $options = '', $separate_index = false) : self |
|
191 | { |
||
192 | 37 | if (empty($name)) { |
|
193 | throw new midcom_error('Invalid column name ' . $name); |
||
194 | } |
||
195 | 37 | $this->_columns[$name] = [ |
|
196 | 37 | 'label' => $label, |
|
197 | 37 | 'options' => $options, |
|
198 | 37 | 'separate_index' => $separate_index |
|
199 | 37 | ]; |
|
200 | 37 | return $this; |
|
201 | } |
||
202 | |||
203 | 2 | public function add_pager(int $rows_per_page = 30) : self |
|
204 | { |
||
205 | 2 | $this->set_option('pager', '#p_' . $this->_identifier); |
|
206 | 2 | $this->set_option('rowNum', $rows_per_page); |
|
207 | 2 | return $this; |
|
208 | } |
||
209 | |||
210 | /** |
||
211 | * Removes a column |
||
212 | */ |
||
213 | public function remove_column(string $name) |
||
214 | { |
||
215 | if ( empty($name) |
||
216 | || !array_key_exists($name, $this->_columns)) { |
||
217 | throw new midcom_error('Invalid column name ' . $name); |
||
218 | } |
||
219 | if ($this->_columns[$name]['separate_index']) { |
||
220 | unset($this->_columns[$name . '_index']); |
||
221 | } |
||
222 | unset($this->_columns[$name]); |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Set the grid's footer data |
||
227 | * |
||
228 | * @param mixed $data The data to set as array or the column name |
||
229 | * @param mixed $value The value, if setting individual columns |
||
230 | * @param boolean $formatted Should formatters be applied to footer data |
||
231 | */ |
||
232 | 17 | public function set_footer_data($data, $value = null, bool $formatted = true) |
|
233 | { |
||
234 | 17 | if (null == $value) { |
|
235 | 17 | $this->_footer_data = $data; |
|
236 | } else { |
||
237 | $this->_footer_data[$data] = $value; |
||
238 | } |
||
239 | 17 | $this->format_footer = $formatted; |
|
240 | 17 | $this->set_option('footerrow', true); |
|
241 | } |
||
242 | |||
243 | /** |
||
244 | * Add Javascript code that should be run before the widget constructor |
||
245 | */ |
||
246 | 25 | public function prepend_js(string $string) |
|
247 | { |
||
248 | 25 | $this->_prepend_js .= $string . "\n"; |
|
249 | } |
||
250 | |||
251 | /** |
||
252 | * Renders the grid as HTML |
||
253 | */ |
||
254 | 33 | public function render(?array $entries = null) |
|
255 | { |
||
256 | 33 | if (is_array($entries)) { |
|
257 | 10 | if (null !== $this->_provider) { |
|
258 | $this->_provider->set_rows($entries); |
||
259 | } else { |
||
260 | 10 | $this->_provider = new provider($entries, $this->get_option('datatype')); |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
261 | 10 | $this->_provider->set_grid($this); |
|
262 | } |
||
263 | } |
||
264 | 33 | echo (string) $this; |
|
265 | } |
||
266 | |||
267 | 34 | public function __toString() |
|
268 | { |
||
269 | 34 | if ($this->_provider) { |
|
270 | 31 | $this->_provider->setup_grid(); |
|
271 | } |
||
272 | |||
273 | 34 | $string = '<table id="' . $this->_identifier . '"></table>'; |
|
274 | 34 | $string .= '<div id="p_' . $this->_identifier . '"></div>'; |
|
275 | 34 | $string .= '<script type="text/javascript">//<![CDATA[' . "\n"; |
|
276 | 34 | $string .= $this->_prepend_js; |
|
277 | 34 | $string .= 'midcom_grid_helper.setup_grid("' . $this->_identifier . '", {'; |
|
278 | |||
279 | 34 | $colnames = []; |
|
280 | 34 | foreach ($this->_columns as $name => $column) { |
|
281 | 34 | if ($column['separate_index']) { |
|
282 | 32 | $colnames[] = 'index_' . $name; |
|
283 | } |
||
284 | 34 | $colnames[] = $column['label']; |
|
285 | } |
||
286 | 34 | $string .= "\ncolNames: " . json_encode($colnames) . ",\n"; |
|
287 | |||
288 | 34 | $string .= $this->_render_colmodel(); |
|
289 | |||
290 | 34 | $total_options = count($this->_options); |
|
291 | 34 | $i = 0; |
|
292 | 34 | foreach ($this->_options as $name => $value) { |
|
293 | 34 | $string .= $name . ': ' . $value; |
|
294 | 34 | if (++$i < $total_options) { |
|
295 | 33 | $string .= ','; |
|
296 | } |
||
297 | 34 | $string .= "\n"; |
|
298 | } |
||
299 | 34 | $string .= "});\n"; |
|
300 | |||
301 | 34 | if ($this->_footer_data) { |
|
0 ignored issues
–
show
The expression
$this->_footer_data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
302 | 17 | $format = $this->format_footer ? 'true' : 'false'; |
|
303 | 17 | $string .= 'jQuery("#' . $this->_identifier . '").jqGrid("footerData", "set", ' . json_encode($this->_footer_data) . ", " . $format . ");\n"; |
|
304 | } |
||
305 | |||
306 | 34 | $string .= '//]]></script>'; |
|
307 | 34 | return $string; |
|
308 | } |
||
309 | |||
310 | 34 | private function _render_colmodel() : string |
|
311 | { |
||
312 | 34 | $string = "colModel: [\n"; |
|
313 | 34 | $total_columns = count($this->_columns); |
|
314 | 34 | $i = 0; |
|
315 | 34 | foreach ($this->_columns as $name => $column) { |
|
316 | 34 | if ($column['separate_index']) { |
|
317 | 32 | $string .= '{name: "index_' . $name . '", index: "index_' . $name . '", '; |
|
318 | 32 | $string .= 'sorttype: "' . $column['separate_index'] . '", hidden: true}' . ",\n"; |
|
319 | } |
||
320 | |||
321 | 34 | $string .= '{name: "' . $name . '", '; |
|
322 | 34 | if ($column['separate_index']) { |
|
323 | 32 | $string .= 'index: "index_' . $name . '"'; |
|
324 | } else { |
||
325 | 34 | $string .= 'index: "' . $name . '"'; |
|
326 | } |
||
327 | 34 | if (!empty($column['options'])) { |
|
328 | 34 | $string .= ', ' . $column['options']; |
|
329 | } |
||
330 | 34 | $string .= '}'; |
|
331 | 34 | if (++$i < $total_columns) { |
|
332 | 33 | $string .= ",\n"; |
|
333 | } |
||
334 | } |
||
335 | 34 | $string .= "\n],\n"; |
|
336 | 34 | return $string; |
|
337 | } |
||
338 | } |
||
339 |