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

470 lines 11.3 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 $data[ $i ] = $this->toUTF8( $data[ $i ] );
241 break;
242 }
243 }
244
245 return apply_filters( 'visualizer_format_data', $data, $this->_series );
246 }
247
248
249 /**
250 * Converts values to UTF8, if required.
251 *
252 * @access protected
253 *
254 * @param string $datum The data to convert.
255 *
256 * @return string The converted data.
257 */
258 protected final function toUTF8( $datum ) {
259 if ( ! function_exists( 'mb_detect_encoding' ) || mb_detect_encoding( $datum ) !== 'ASCII' ) {
260 $datum = \ForceUTF8\Encoding::toUTF8( $datum );
261 }
262 return $datum;
263 }
264
265 /**
266 * Determines the formats of date/time columns.
267 *
268 * @access public
269 *
270 * @param array $series The actual array of series.
271 * @param array $data The actual array of data.
272 *
273 * @return array
274 */
275 public static final function get_date_formats_if_exists( $series, $data ) {
276 $date_formats = array();
277 $types = array();
278 $index = 0;
279 foreach ( $series as $column ) {
280 if ( in_array( $column['type'], array( 'date', 'datetime', 'timeofday' ), true ) ) {
281 $types[] = array( 'index' => $index, 'type' => $column['type'] );
282 }
283 $index++;
284 }
285
286 if ( ! $types ) {
287 return $date_formats;
288 }
289
290 $random = $data;
291 // let's randomly pick 5 data points instead of cycling through the entire data set.
292 if ( count( $data ) > 5 ) {
293 $random = array();
294 for ( $x = 0; $x < 5; $x++ ) {
295 $random[] = $data[ rand( 0, count( $data ) - 1 ) ];
296 }
297 }
298
299 foreach ( $types as $type ) {
300 $formats = array();
301 foreach ( $random as $datum ) {
302 $f = self::determine_date_format( $datum[ $type['index'] ], $type['type'] );
303 if ( $f ) {
304 $formats[] = $f;
305 }
306 }
307 // if there are multiple formats, use the most frequent format.
308 $formats = array_filter( $formats );
309 if ( $formats ) {
310 $formats = array_count_values( $formats );
311 arsort( $formats );
312 $formats = array_keys( $formats );
313 $final_format = reset( $formats );
314 // we have determined the PHP format; now we have to change this into the JS format where m = MM, d = DD etc.
315 $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 ) );
316 }
317 }
318 return $date_formats;
319 }
320
321 /**
322 * Determines the date/time format of the given string.
323 *
324 * @access private
325 *
326 * @param string $value The string.
327 * @param string $type 'date', 'timeofday' or 'datetime'.
328 *
329 * @return string|null
330 */
331 private static final function determine_date_format( $value, $type ) {
332 if ( version_compare( phpversion(), '5.3.0', '<' ) ) {
333 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'PHP version %s not supported', phpversion() ), 'error', __FILE__, __LINE__ );
334 return null;
335 }
336
337 $formats = array(
338 'Y/m/d',
339 'Y-m-d',
340 'm/d/Y',
341 'm-d-Y',
342 'd-m-Y',
343 'd/m/Y',
344 );
345
346 switch ( $type ) {
347 case 'datetime':
348 $formats = array_merge(
349 $formats, array(
350 'U',
351 'Y/m/d H:i:s',
352 'Y-m-d H:i:s',
353 'm/d/Y H:i:s',
354 'm-d-Y H:i:s',
355 )
356 );
357 break;
358 case 'timeofday':
359 $formats = array_merge(
360 $formats, array(
361 'H:i:s',
362 'H:i',
363 )
364 );
365 break;
366 }
367
368 $formats = apply_filters( 'visualizer_date_formats', $formats, $type );
369
370 foreach ( $formats as $format ) {
371 $return = DateTime::createFromFormat( $format, $value );
372 if ( $return !== false && ! is_wp_error( $return ) ) {
373 return $format;
374 }
375 }
376 // invalid format
377 return null;
378 }
379
380 /**
381 * Returns the error, if any.
382 *
383 * @access public
384 * @return string
385 */
386 public function get_error() {
387 return $this->_error;
388 }
389
390 /**
391 * Fetches information from the editable table and parses it to build series and data arrays.
392 *
393 * @since ?
394 *
395 * @access public
396 * @return boolean TRUE on success, otherwise FALSE.
397 */
398 public function fetchFromEditableTable() {
399 if ( empty( $this->_args ) ) {
400 return false;
401 }
402
403 $this->_fetchSeriesFromEditableTable();
404 $this->_fetchDataFromEditableTable();
405 return true;
406 }
407
408 /**
409 * Fetches series information from the editable table. This is fetched only through the UI and not while refreshing the chart data.
410 *
411 * @since 1.0.0
412 *
413 * @access private
414 */
415 private function _fetchSeriesFromEditableTable() {
416 $params = $this->_args;
417 $headers = array_filter( $params['header'] );
418 $types = array_filter( $params['type'] );
419 $header_row = $type_row = array();
420 if ( $headers ) {
421 foreach ( $headers as $header ) {
422 if ( ! empty( $types[ $header ] ) ) {
423 $this->_series[] = array(
424 'label' => $header,
425 'type' => $types[ $header ],
426 );
427 }
428 }
429 }
430
431 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__ );
432
433 return true;
434 }
435
436
437 /**
438 * Fetches data information from the editable table.
439 *
440 * @since 1.0.0
441 *
442 * @access private
443 */
444 private function _fetchDataFromEditableTable() {
445 $params = $this->_args;
446 $headers = wp_list_pluck( $this->_series, 'label' );
447 $this->fetch();
448
449 $data = $this->_data;
450 $this->_data = array();
451
452 foreach ( $data as $line ) {
453 $data_row = array();
454 foreach ( $line as $header => $value ) {
455 // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
456 if ( in_array( $header, $headers ) ) {
457 $data_row[] = $value;
458 }
459 }
460 $this->_data[] = $this->_normalizeData( $data_row );
461 }
462
463 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__ );
464
465 return true;
466 }
467
468
469 }
470