PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.4
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.4
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
← All changes | classes/Visualizer/Source.php +225 -6 3.1.23.4.4 View file →
@@ -57,8 +57,16 @@
57 57 */
58 58 protected $_series = array();
59 59
60 60 /**
61 + * The error message.
62 + *
63 + * @access protected
64 + * @var string
65 + */
66 + protected $_error;
67 +
68 + /**
61 69 * Return allowed types
62 70 *
63 71 * @since 1.0.1
64 72 *
@@ -83,9 +91,9 @@
83 91 * @return boolean TRUE if sereis types are valid, otherwise FALSE.
84 92 */
85 93 protected static function _validateTypes( $types ) {
86 94 foreach ( $types as $type ) {
87 - if ( ! in_array( $type, self::$allowed_types ) ) {
95 + if ( ! in_array( $type, self::$allowed_types, true ) ) {
88 96 return false;
89 97 }
90 98 }
91 99
@@ -193,9 +201,8 @@
193 201 * @return array Normalized row of data.
194 202 */
195 203 protected function _normalizeData( $data ) {
196 204 // normalize values
197 - // error_log(print_r($data,true));
198 205 foreach ( $this->_series as $i => $series ) {
199 206 // if no value exists for the seires, then add null
200 207 if ( ! isset( $data[ $i ] ) ) {
201 208 $data[ $i ] = null;
@@ -207,9 +214,10 @@
207 214 case 'number':
208 215 $data[ $i ] = ( is_numeric( $data[ $i ] ) ) ? floatval( $data[ $i ] ) : ( is_numeric( str_replace( ',', '', $data[ $i ] ) ) ? floatval( str_replace( ',', '', $data[ $i ] ) ) : null );
209 216 break;
210 217 case 'boolean':
211 - $data[ $i ] = ! empty( $data[ $i ] ) ? filter_var( $data[ $i ], FILTER_VALIDATE_BOOLEAN ) : null;
218 + $datum = trim( strval( $data[ $i ] ) );
219 + $data[ $i ] = in_array( $datum, array( 'true', 'yes', '1' ), true ) ? 'true' : 'false';
212 220 break;
213 221 case 'timeofday':
214 222 $date = new DateTime( '1984-03-16T' . $data[ $i ] );
215 223 if ( $date ) {
@@ -220,16 +228,23 @@
220 228 0,
221 229 );
222 230 }
223 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;
224 239 case 'string':
225 - $data[ $i ] = $this->toUTF8( $data[ $i ] );
240 + // if a ' is provided, strip the backslash
241 + $data[ $i ] = stripslashes( $this->toUTF8( $data[ $i ] ) );
226 242 break;
227 243 }
228 244 }
229 245
230 - // error_log(print_r($data,true));
231 - return $data;
246 + return apply_filters( 'visualizer_format_data', $data, $this->_series );
232 247 }
233 248
234 249
235 250 /**
@@ -246,6 +261,210 @@
246 261 $datum = \ForceUTF8\Encoding::toUTF8( $datum );
247 262 }
248 263 return $datum;
249 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 +
250 469
251 470 }