PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.3
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.3
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / classes / Visualizer / Source.php

Source.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.4.3, at classes/Visualizer/Source.php

471 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
4 // +----------------------------------------------------------------------+
5 // | This program is free software; you can redistribute it and/or modify |
6 // | it under the terms of the GNU General Public License, version 2, as |
7 // | published by the Free Software Foundation. |
8 // | |
9 // | This program is distributed in the hope that it will be useful, |
10 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 // | GNU General Public License for more details. |
13 // | |
14 // | You should have received a copy of the GNU General Public License |
15 // | along with this program; if not, write to the Free Software |
16 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
17 // | MA 02110-1301 USA |
18 // +----------------------------------------------------------------------+
19 // | Author: Eugene Manuilov <eugene@manuilov.org> |
20 // +----------------------------------------------------------------------+
21 /**
22 * The abstract class for source managers.
23 *
24 * @category Visualizer
25 * @package Source
26 *
27 * @since 1.0.0
28 * @abstract
29 */
30 abstract class Visualizer_Source {
31
32 /**
33 * The array of allowed types.
34 *
35 * @since 1.0.0
36 *
37 * @access protected
38 * @var array
39 */
40 protected static $allowed_types = array( 'string', 'number', 'boolean', 'date', 'datetime', 'timeofday' );
41 /**
42 * The array of data.
43 *
44 * @since 1.0.0
45 *
46 * @access protected
47 * @var array
48 */
49 protected $_data = array();
50 /**
51 * The array of series.
52 *
53 * @since 1.0.0
54 *
55 * @access protected
56 * @var array
57 */
58 protected $_series = array();
59
60 /**
61 * The error message.
62 *
63 * @access protected
64 * @var string
65 */
66 protected $_error;
67
68 /**
69 * Return allowed types
70 *
71 * @since 1.0.1
72 *
73 * @static
74 * @access public
75 * @return array the allowed types
76 */
77 public static function getAllowedTypes() {
78 return self::$allowed_types;
79 }
80
81 /**
82 * Validates series tyeps.
83 *
84 * @since 1.0.1
85 *
86 * @static
87 * @access protected
88 *
89 * @param array $types The icoming series types.
90 *
91 * @return boolean TRUE if sereis types are valid, otherwise FALSE.
92 */
93 protected static function _validateTypes( $types ) {
94 foreach ( $types as $type ) {
95 if ( ! in_array( $type, self::$allowed_types, true ) ) {
96 return false;
97 }
98 }
99
100 return true;
101 }
102
103 /**
104 * Returns source name.
105 *
106 * @since 1.0.0
107 *
108 * @abstract
109 * @access public
110 * @return string The name of source.
111 */
112 public abstract function getSourceName();
113
114 /**
115 * Fetches information from source, parses it and builds series and data arrays.
116 *
117 * @since 1.0.0
118 *
119 * @abstract
120 * @access public
121 */
122 public abstract function fetch();
123
124 /**
125 * Returns series parsed from source.
126 *
127 * @since 1.0.0
128 *
129 * @access public
130 * @return array The array of series.
131 */
132 public function getSeries() {
133 return $this->_series;
134 }
135
136 /**
137 * Returns data parsed from source.
138 *
139 * @since 1.0.0
140 *
141 * @access public
142 * @return string The serialized array of data.
143 */
144 public function getData() {
145 return serialize( $this->_data );
146 }
147
148 /**
149 * Returns raw data array.
150 *
151 * @since 1.1.0
152 *
153 * @access public
154 * @return array
155 */
156 public function getRawData() {
157 return $this->_data;
158 }
159
160 /**
161 * Re populates series if the source is dynamic.
162 *
163 * @since 1.1.0
164 *
165 * @access public
166 *
167 * @param array $series The actual array of series.
168 * @param int $chart_id The chart id.
169 *
170 * @return array The re populated array of series or old one.
171 */
172 public function repopulateSeries( $series, $chart_id ) {
173 return $series;
174 }
175
176 /**
177 * Re populates data if the source is dynamic.
178 *
179 * @since 1.1.0
180 *
181 * @access public
182 *
183 * @param array $data The actual array of data.
184 * @param int $chart_id The chart id.
185 *
186 * @return array The re populated array of data or old one.
187 */
188 public function repopulateData( $data, $chart_id ) {
189 return $data;
190 }
191
192 /**
193 * Normalizes values according to series' type.
194 *
195 * @since 1.0.0
196 *
197 * @access protected
198 *
199 * @param array $data The row of data.
200 *
201 * @return array Normalized row of data.
202 */
203 protected function _normalizeData( $data ) {
204 // normalize values
205 foreach ( $this->_series as $i => $series ) {
206 // if no value exists for the seires, then add null
207 if ( ! isset( $data[ $i ] ) ) {
208 $data[ $i ] = null;
209 }
210 if ( is_null( $data[ $i ] ) ) {
211 continue;
212 }
213 switch ( $series['type'] ) {
214 case 'number':
215 $data[ $i ] = ( is_numeric( $data[ $i ] ) ) ? floatval( $data[ $i ] ) : ( is_numeric( str_replace( ',', '', $data[ $i ] ) ) ? floatval( str_replace( ',', '', $data[ $i ] ) ) : null );
216 break;
217 case 'boolean':
218 $datum = trim( strval( $data[ $i ] ) );
219 $data[ $i ] = in_array( $datum, array( 'true', 'yes', '1' ), true ) ? 'true' : 'false';
220 break;
221 case 'timeofday':
222 $date = new DateTime( '1984-03-16T' . $data[ $i ] );
223 if ( $date ) {
224 $data[ $i ] = array(
225 intval( $date->format( 'H' ) ),
226 intval( $date->format( 'i' ) ),
227 intval( $date->format( 's' ) ),
228 0,
229 );
230 }
231 break;
232 case 'datetime':
233 // let's check if the date is a Unix epoch
234 $value = DateTime::createFromFormat( 'U', $data[ $i ] );
235 if ( $value !== false && ! is_wp_error( $value ) ) {
236 $data[ $i ] = $value->format( 'Y-m-d H:i:s' );
237 }
238 break;
239 case 'string':
240 // if a ' is provided, strip the backslash
241 $data[ $i ] = stripslashes( $this->toUTF8( $data[ $i ] ) );
242 break;
243 }
244 }
245
246 return apply_filters( 'visualizer_format_data', $data, $this->_series );
247 }
248
249
250 /**
251 * Converts values to UTF8, if required.
252 *
253 * @access protected
254 *
255 * @param string $datum The data to convert.
256 *
257 * @return string The converted data.
258 */
259 protected final function toUTF8( $datum ) {
260 if ( ! function_exists( 'mb_detect_encoding' ) || mb_detect_encoding( $datum ) !== 'ASCII' ) {
261 $datum = \ForceUTF8\Encoding::toUTF8( $datum );
262 }
263 return $datum;
264 }
265
266 /**
267 * Determines the formats of date/time columns.
268 *
269 * @access public
270 *
271 * @param array $series The actual array of series.
272 * @param array $data The actual array of data.
273 *
274 * @return array
275 */
276 public static final function get_date_formats_if_exists( $series, $data ) {
277 $date_formats = array();
278 $types = array();
279 $index = 0;
280 foreach ( $series as $column ) {
281 if ( in_array( $column['type'], array( 'date', 'datetime', 'timeofday' ), true ) ) {
282 $types[] = array( 'index' => $index, 'type' => $column['type'] );
283 }
284 $index++;
285 }
286
287 if ( ! $types ) {
288 return $date_formats;
289 }
290
291 $random = $data;
292 // let's randomly pick 5 data points instead of cycling through the entire data set.
293 if ( count( $data ) > 5 ) {
294 $random = array();
295 for ( $x = 0; $x < 5; $x++ ) {
296 $random[] = $data[ rand( 0, count( $data ) - 1 ) ];
297 }
298 }
299
300 foreach ( $types as $type ) {
301 $formats = array();
302 foreach ( $random as $datum ) {
303 $f = self::determine_date_format( $datum[ $type['index'] ], $type['type'] );
304 if ( $f ) {
305 $formats[] = $f;
306 }
307 }
308 // if there are multiple formats, use the most frequent format.
309 $formats = array_filter( $formats );
310 if ( $formats ) {
311 $formats = array_count_values( $formats );
312 arsort( $formats );
313 $formats = array_keys( $formats );
314 $final_format = reset( $formats );
315 // we have determined the PHP format; now we have to change this into the JS format where m = MM, d = DD etc.
316 $date_formats[] = array( 'index' => $type['index'], 'format' => str_replace( array( 'Y', 'm', 'd', 'H', 'i', 's' ), array( 'YYYY', 'MM', 'DD', 'HH', 'mm', 'ss' ), $final_format ) );
317 }
318 }
319 return $date_formats;
320 }
321
322 /**
323 * Determines the date/time format of the given string.
324 *
325 * @access private
326 *
327 * @param string $value The string.
328 * @param string $type 'date', 'timeofday' or 'datetime'.
329 *
330 * @return string|null
331 */
332 private static final function determine_date_format( $value, $type ) {
333 if ( version_compare( phpversion(), '5.3.0', '<' ) ) {
334 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'PHP version %s not supported', phpversion() ), 'error', __FILE__, __LINE__ );
335 return null;
336 }
337
338 $formats = array(
339 'Y/m/d',
340 'Y-m-d',
341 'm/d/Y',
342 'm-d-Y',
343 'd-m-Y',
344 'd/m/Y',
345 );
346
347 switch ( $type ) {
348 case 'datetime':
349 $formats = array_merge(
350 $formats, array(
351 'U',
352 'Y/m/d H:i:s',
353 'Y-m-d H:i:s',
354 'm/d/Y H:i:s',
355 'm-d-Y H:i:s',
356 )
357 );
358 break;
359 case 'timeofday':
360 $formats = array_merge(
361 $formats, array(
362 'H:i:s',
363 'H:i',
364 )
365 );
366 break;
367 }
368
369 $formats = apply_filters( 'visualizer_date_formats', $formats, $type );
370
371 foreach ( $formats as $format ) {
372 $return = DateTime::createFromFormat( $format, $value );
373 if ( $return !== false && ! is_wp_error( $return ) ) {
374 return $format;
375 }
376 }
377 // invalid format
378 return null;
379 }
380
381 /**
382 * Returns the error, if any.
383 *
384 * @access public
385 * @return string
386 */
387 public function get_error() {
388 return $this->_error;
389 }
390
391 /**
392 * Fetches information from the editable table and parses it to build series and data arrays.
393 *
394 * @since ?
395 *
396 * @access public
397 * @return boolean TRUE on success, otherwise FALSE.
398 */
399 public function fetchFromEditableTable() {
400 if ( empty( $this->_args ) ) {
401 return false;
402 }
403
404 $this->_fetchSeriesFromEditableTable();
405 $this->_fetchDataFromEditableTable();
406 return true;
407 }
408
409 /**
410 * Fetches series information from the editable table. This is fetched only through the UI and not while refreshing the chart data.
411 *
412 * @since 1.0.0
413 *
414 * @access private
415 */
416 private function _fetchSeriesFromEditableTable() {
417 $params = $this->_args;
418 $headers = array_filter( $params['header'] );
419 $types = array_filter( $params['type'] );
420 $header_row = $type_row = array();
421 if ( $headers ) {
422 foreach ( $headers as $header ) {
423 if ( ! empty( $types[ $header ] ) ) {
424 $this->_series[] = array(
425 'label' => $header,
426 'type' => $types[ $header ],
427 );
428 }
429 }
430 }
431
432 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Series found for %s = %s', print_r( $this->_args, true ), print_r( $this->_series, true ) ), 'debug', __FILE__, __LINE__ );
433
434 return true;
435 }
436
437
438 /**
439 * Fetches data information from the editable table.
440 *
441 * @since 1.0.0
442 *
443 * @access private
444 */
445 private function _fetchDataFromEditableTable() {
446 $params = $this->_args;
447 $headers = wp_list_pluck( $this->_series, 'label' );
448 $this->fetch();
449
450 $data = $this->_data;
451 $this->_data = array();
452
453 foreach ( $data as $line ) {
454 $data_row = array();
455 foreach ( $line as $header => $value ) {
456 // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
457 if ( in_array( $header, $headers ) ) {
458 $data_row[] = $value;
459 }
460 }
461 $this->_data[] = $this->_normalizeData( $data_row );
462 }
463
464 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Data found for %s = %s', print_r( $this->_args, true ), print_r( $this->_data, true ) ), 'debug', __FILE__, __LINE__ );
465
466 return true;
467 }
468
469
470 }
471