PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.7
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.7
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.7, at classes/Visualizer/Source.php

479 lines 11.7 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( $fetch_from_editable_table = false ) {
145 if ( $fetch_from_editable_table ) {
146 $this->_fetchDataFromEditableTable();
147 }
148 return serialize( $this->_data );
149 }
150
151 /**
152 * Returns raw data array.
153 *
154 * @since 1.1.0
155 *
156 * @access public
157 * @return array
158 */
159 public function getRawData( $fetch_from_editable_table = false ) {
160 if ( $fetch_from_editable_table ) {
161 $this->_fetchDataFromEditableTable();
162 }
163 return $this->_data;
164 }
165
166 /**
167 * Re populates series if the source is dynamic.
168 *
169 * @since 1.1.0
170 *
171 * @access public
172 *
173 * @param array $series The actual array of series.
174 * @param int $chart_id The chart id.
175 *
176 * @return array The re populated array of series or old one.
177 */
178 public function repopulateSeries( $series, $chart_id ) {
179 return $series;
180 }
181
182 /**
183 * Re populates data if the source is dynamic.
184 *
185 * @since 1.1.0
186 *
187 * @access public
188 *
189 * @param array $data The actual array of data.
190 * @param int $chart_id The chart id.
191 *
192 * @return array The re populated array of data or old one.
193 */
194 public function repopulateData( $data, $chart_id ) {
195 return $data;
196 }
197
198 /**
199 * Normalizes values according to series' type.
200 *
201 * @since 1.0.0
202 *
203 * @access protected
204 *
205 * @param array $data The row of data.
206 *
207 * @return array Normalized row of data.
208 */
209 protected function _normalizeData( $data ) {
210 // normalize values
211 foreach ( $this->_series as $i => $series ) {
212 // if no value exists for the seires, then add null
213 if ( ! isset( $data[ $i ] ) ) {
214 $data[ $i ] = null;
215 }
216 if ( is_null( $data[ $i ] ) ) {
217 continue;
218 }
219 switch ( $series['type'] ) {
220 case 'number':
221 $data[ $i ] = ( is_numeric( $data[ $i ] ) ) ? floatval( $data[ $i ] ) : ( is_numeric( str_replace( ',', '', $data[ $i ] ) ) ? floatval( str_replace( ',', '', $data[ $i ] ) ) : null );
222 break;
223 case 'boolean':
224 $datum = trim( strval( $data[ $i ] ) );
225 $data[ $i ] = in_array( $datum, array( 'true', 'yes', '1' ), true ) ? 'true' : 'false';
226 break;
227 case 'timeofday':
228 $date = new DateTime( '1984-03-16T' . $data[ $i ] );
229 if ( $date ) {
230 $data[ $i ] = array(
231 intval( $date->format( 'H' ) ),
232 intval( $date->format( 'i' ) ),
233 intval( $date->format( 's' ) ),
234 0,
235 );
236 }
237 break;
238 case 'datetime':
239 // let's check if the date is a Unix epoch
240 $value = DateTime::createFromFormat( 'U', $data[ $i ] );
241 if ( $value !== false && ! is_wp_error( $value ) ) {
242 $data[ $i ] = $value->format( 'Y-m-d H:i:s' );
243 }
244 break;
245 case 'string':
246 // if a ' is provided, strip the backslash
247 $data[ $i ] = stripslashes( $this->toUTF8( $data[ $i ] ) );
248 break;
249 }
250 }
251
252 return apply_filters( 'visualizer_format_data', $data, $this->_series );
253 }
254
255
256 /**
257 * Converts values to UTF8, if required.
258 *
259 * @access protected
260 *
261 * @param string $datum The data to convert.
262 *
263 * @return string The converted data.
264 */
265 protected final function toUTF8( $datum ) {
266 if ( ! function_exists( 'mb_detect_encoding' ) || mb_detect_encoding( $datum ) !== 'ASCII' ) {
267 $datum = \ForceUTF8\Encoding::toUTF8( $datum );
268 }
269 return $datum;
270 }
271
272 /**
273 * Determines the formats of date/time columns.
274 *
275 * @access public
276 *
277 * @param array $series The actual array of series.
278 * @param array $data The actual array of data.
279 *
280 * @return array
281 */
282 public static final function get_date_formats_if_exists( $series, $data ) {
283 $date_formats = array();
284 $types = array();
285 $index = 0;
286 foreach ( $series as $column ) {
287 if ( in_array( $column['type'], array( 'date', 'datetime', 'timeofday' ), true ) ) {
288 $types[] = array( 'index' => $index, 'type' => $column['type'] );
289 }
290 $index++;
291 }
292
293 if ( ! $types ) {
294 return $date_formats;
295 }
296
297 $random = $data;
298 // let's randomly pick 5 data points instead of cycling through the entire data set.
299 if ( count( $data ) > 5 ) {
300 $random = array();
301 for ( $x = 0; $x < 5; $x++ ) {
302 $random[] = $data[ rand( 0, count( $data ) - 1 ) ];
303 }
304 }
305
306 foreach ( $types as $type ) {
307 $formats = array();
308 foreach ( $random as $datum ) {
309 $f = self::determine_date_format( $datum[ $type['index'] ], $type['type'] );
310 if ( $f ) {
311 $formats[] = $f;
312 }
313 }
314 // if there are multiple formats, use the most frequent format.
315 $formats = array_filter( $formats );
316 if ( $formats ) {
317 $formats = array_count_values( $formats );
318 arsort( $formats );
319 $formats = array_keys( $formats );
320 $final_format = reset( $formats );
321 // we have determined the PHP format; now we have to change this into the JS format where m = MM, d = DD etc.
322 $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 ) );
323 }
324 }
325 return $date_formats;
326 }
327
328 /**
329 * Determines the date/time format of the given string.
330 *
331 * @access private
332 *
333 * @param string $value The string.
334 * @param string $type 'date', 'timeofday' or 'datetime'.
335 *
336 * @return string|null
337 */
338 private static final function determine_date_format( $value, $type ) {
339 if ( version_compare( phpversion(), '5.3.0', '<' ) ) {
340 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'PHP version %s not supported', phpversion() ), 'error', __FILE__, __LINE__ );
341 return null;
342 }
343
344 $formats = array(
345 'Y/m/d',
346 'Y-m-d',
347 'm/d/Y',
348 'm-d-Y',
349 'd-m-Y',
350 'd/m/Y',
351 );
352
353 switch ( $type ) {
354 case 'datetime':
355 $formats = array_merge(
356 $formats, array(
357 'U',
358 'Y/m/d H:i:s',
359 'Y-m-d H:i:s',
360 'm/d/Y H:i:s',
361 'm-d-Y H:i:s',
362 )
363 );
364 break;
365 case 'timeofday':
366 $formats = array_merge(
367 $formats, array(
368 'H:i:s',
369 'H:i',
370 )
371 );
372 break;
373 }
374
375 $formats = apply_filters( 'visualizer_date_formats', $formats, $type );
376
377 foreach ( $formats as $format ) {
378 $return = DateTime::createFromFormat( $format, $value );
379 if ( $return !== false && ! is_wp_error( $return ) ) {
380 return $format;
381 }
382 }
383 // invalid format
384 return null;
385 }
386
387 /**
388 * Returns the error, if any.
389 *
390 * @access public
391 * @return string
392 */
393 public function get_error() {
394 return $this->_error;
395 }
396
397 /**
398 * Fetches information from the editable table and parses it to build series and data arrays.
399 *
400 * @since ?
401 *
402 * @access public
403 * @return boolean TRUE on success, otherwise FALSE.
404 */
405 public function fetchFromEditableTable() {
406 if ( empty( $this->_args ) ) {
407 return false;
408 }
409
410 $this->_fetchSeriesFromEditableTable();
411 $this->_fetchDataFromEditableTable();
412 return true;
413 }
414
415 /**
416 * Fetches series information from the editable table. This is fetched only through the UI and not while refreshing the chart data.
417 *
418 * @since 1.0.0
419 *
420 * @access private
421 */
422 private function _fetchSeriesFromEditableTable() {
423 $params = $this->_args;
424 $headers = array_filter( $params['header'] );
425 $types = array_filter( $params['type'] );
426 $header_row = $type_row = array();
427 if ( $headers ) {
428 foreach ( $headers as $header ) {
429 if ( ! empty( $types[ $header ] ) ) {
430 $this->_series[] = array(
431 'label' => $header,
432 'type' => $types[ $header ],
433 );
434 }
435 }
436 }
437
438 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__ );
439
440 return true;
441 }
442
443
444 /**
445 * Fetches data information from the editable table.
446 *
447 * @since 1.0.0
448 *
449 * @access private
450 */
451 private function _fetchDataFromEditableTable() {
452 $headers = wp_list_pluck( $this->_series, 'label' );
453 $this->fetch();
454
455 $data = $this->_data;
456 $this->_data = array();
457
458 foreach ( $data as $line ) {
459 $data_row = array();
460 // we have to make sure we are fetching the data in the right order
461 // in case the columns have been reordered
462 foreach ( $headers as $header ) {
463 $value = $line[ $header ];
464 // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
465 if ( in_array( $header, $headers ) ) {
466 $data_row[] = $value;
467 }
468 }
469 $this->_data[] = $this->_normalizeData( $data_row );
470 }
471
472 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__ );
473
474 return true;
475 }
476
477
478 }
479