File "sql.php"

Full path: /home/dora/public_html/wp-content/plugins/jet-engine/includes/components/query-builder/queries/sql.php
File size: 13.18 KB
MIME-type: --
Charset: utf-8

<?php
namespace Jet_Engine\Query_Builder\Queries;

use Jet_Engine\Query_Builder\Manager;

class SQL_Query extends Base_Query {

	public $current_query = null;

	/**
	 * Returns queries items
	 *
	 * @return [type] [description]
	 */
	public function _get_items() {

		$sql    = $this->build_sql_query();
		$result = $this->wpdb()->get_results( $sql );

		return $result;

	}

	public function get_current_items_page() {

		$offset = ! empty( $this->final_query['offset'] ) ? absint( $this->final_query['offset'] ) : 0;
		$per_page = $this->get_items_per_page();

		if ( ! $offset || ! $per_page ) {
			return 1;
		} else {
			return ceil( $offset / $per_page ) + 1;
		}

	}

	/**
	 * Returns total found items count
	 *
	 * @return [type] [description]
	 */
	public function get_items_total_count() {

		$cached = $this->get_cached_data( 'count' );

		if ( false !== $cached ) {
			return $cached;
		}

		$this->setup_query();

		$sql    = $this->build_sql_query( true );
		$result = $this->wpdb()->get_var( $sql );

		$this->update_query_cache( $result, 'count' );

		return $result;

	}

	/**
	 * Returns count of the items visible per single listing grid loop/page
	 * @return [type] [description]
	 */
	public function get_items_per_page() {

		$this->setup_query();
		$limit = 0;

		if ( ! empty( $this->final_query['limit_per_page'] ) ) {
			$limit = absint( $this->final_query['limit_per_page'] );
		} elseif ( ! empty( $this->final_query['limit'] ) ) {
			$limit = absint( $this->final_query['limit'] );
		}

		return $limit;
	}

	/**
	 * Returns queried items count per page
	 *
	 * @return [type] [description]
	 */
	public function get_items_page_count() {
		return $this->get_items_total_count();
	}

	public function set_filtered_prop( $prop = '', $value = null ) {

		switch ( $prop ) {

			case '_page':

				$page = absint( $value );

				if ( 0 < $page ) {
					$offset = ( $page - 1 ) * $this->get_items_per_page();
					$this->final_query['offset'] = $offset;
				}

				break;

			case 'orderby':
			case 'order':
			case 'meta_key':

				$key = $prop;

				if ( 'orderby' === $prop ) {
					$key = 'type';
					$value = ( 'meta_key' === $value ) ? 'CHAR' : 'DECIMAL';
				} elseif ( 'meta_key' === $prop ) {
					$key = 'orderby';
				}

				$this->set_filtered_order( $key, $value );
				break;

			case 'meta_query':

				foreach ( $value as $row ) {

					$prepared_row = array(
						'column'  => ! empty( $row['key'] ) ? $row['key'] : false,
						'compare' => ! empty( $row['compare'] ) ? $row['compare'] : '=',
						'value'   => ! empty( $row['value'] ) ? $row['value'] : '',
						'type'    => ! empty( $row['type'] ) ? $row['type'] : false,
					);

					$this->update_where_row( $prepared_row );

				}

				break;
		}

	}

	public function set_filtered_order( $key, $value ) {

		if ( empty( $this->final_query['orderby'] ) ) {
			$this->final_query['orderby'] = array();
		}

		if ( ! isset( $this->final_query['orderby']['custom'] ) ) {
			$this->final_query['orderby'] = array_merge( array( 'custom' => array() ), $this->final_query['orderby'] );
		}

		$this->final_query['orderby']['custom'][ $key ] = $value;

	}

	public function update_where_row( $row ) {

		if ( empty( $this->final_query['where'] ) ) {
			$this->final_query['where'] = array();
		}

		foreach ( $this->final_query['where'] as $index => $existing_row ) {
			if ( $existing_row['column'] === $row['column'] && $existing_row['compare'] === $row['compare'] ) {
				$this->final_query['where'][ $index ] = $row;
				return;
			}
		}

		$this->final_query['where'][] = $row;

	}

	/**
	 * Returns queried items pages count
	 *
	 * @return [type] [description]
	 */
	public function get_items_pages_count() {

		$per_page = $this->get_items_per_page();
		$total    = $this->get_items_total_count();

		if ( ! $per_page || ! $total ) {
			return 1;
		} else {
			return ceil( $total / $per_page );
		}

	}

	public function wpdb() {
		global $wpdb;
		return $wpdb;
	}

	public function build_sql_query( $is_count = false ) {

		$prefix = $this->wpdb()->prefix;

		$select_query = "SELECT ";

		if ( $is_count ) {
			$select_query .= " COUNT(*) ";
		} else {
			if ( ! empty( $this->final_query['include_columns'] ) ) {
				$implode = array();
				foreach ( $this->final_query['include_columns'] as $col ) {
					$implode[] = $col . " AS '" . $col . "'";
				}

				$select_query .= implode( ', ', $implode ) . " ";
			} else {
				$select_query .= "* ";
			}
		}

		if ( null === $this->current_query ) {

			$raw_table      = $this->final_query['table'];
			$prefixed_table = $prefix . $raw_table;
			$current_query  = "";

			$tables = array(
				$raw_table => 1
			);

			$current_query .= "FROM $prefixed_table AS $raw_table ";

			if ( ! empty( $this->final_query['join_tables'] ) ) {
				foreach ( $this->final_query['join_tables'] as $table ) {

					$type           = $table['type'];
					$raw_join_table = $table['table'];
					$join_table     = $prefix . $table['table'];

					if ( ! empty( $tables[ $raw_join_table ] ) ) {
						$tables[ $raw_join_table ] = $tables[ $raw_join_table ] + 1;
						$as_table = $raw_join_table . $tables[ $raw_join_table ];
					} else {
						$tables[ $raw_join_table ] = 1;
						$as_table = $raw_join_table;
					}

					$base_col    = $table['on_base'];
					$current_col = $table['on_current'];

					$current_query .= "$type $join_table AS $as_table ON $raw_table.$base_col = $as_table.$current_col ";

				}
			}

			if ( ! empty( $this->final_query['where'] ) ) {

				$where = array();

				foreach ( $this->final_query['where'] as $row ) {
					$where[] = $row;
				}

				$current_query .= $this->add_where_args( $where );
			}

			if ( ! empty( $this->final_query['orderby'] ) ) {

				$orderby        = array();
				$current_query .= " ";

				foreach ( $this->final_query['orderby'] as $row ) {
					$row['column'] = $row['orderby'];
					$orderby[] = $row;
				}

				$current_query .= $this->add_order_args( $orderby );
			}

			$this->current_query = $current_query;

		}

		$limit_offset = "";

		if ( ! $is_count ) {
			$limit = $this->get_items_per_page();
		} else {
			$limit = ! empty( $this->final_query['limit'] ) ? absint( $this->final_query['limit'] ) : 0;;
		}

		if ( $limit ) {
			$limit_offset .= " ";
			$limit_offset .= "LIMIT $limit";
			$offset = ! empty( $this->final_query['offset'] ) ? absint( $this->final_query['offset'] ) : 0;
			if ( $offset ) {
				$limit_offset .= ", $offset";
			}
		}

		$result = apply_filters(
			'jet-engine/query-builder/build-query/result',
			$select_query . $this->current_query . $limit_offset . ";",
			$this,
			$is_count
		);

		return $result;

	}

	/**
	 * Add ordering arguments
	 */
	public function add_order_args( $args = array() ) {

		$query = "ORDER BY ";
		$glue  = ' ';

		foreach ( $args as $arg ) {

			$column = $arg['column'];
			$type   = $arg['type'];
			$order  = $arg['order'];

			$query .= $glue;

			switch ( $arg['type'] ) {
				case 'NUMERIC':
				case 'DECIMAL':
					$query .= "CAST( $column as DECIMAL )";
					break;

				case 'CHAR':
					$query .= $column;
					break;

				default:
					$query .= "CAST( $column as $type )";
					break;
			}

			$query .= " ";
			$query .= $order;

			$glue = ", ";
		}

		return $query;
	}

	/**
	 * Add nested query arguments
	 *
	 * @param  [type]  $key    [description]
	 * @param  [type]  $value  [description]
	 * @param  boolean $format [description]
	 * @return [type]          [description]
	 */
	public function get_sub_query( $key, $value, $format = false ) {

		$query = '';
		$glue  = '';

		if ( ! $format ) {

			if ( false !== strpos( $key, '!' ) ) {
				$format = '%1$s != \'%2$s\'';
				$key    = ltrim( $key, '!' );
			} else {
				$format = '%1$s = \'%2$s\'';
			}

		}

		foreach ( $value as $child ) {
			$query .= $glue;
			$query .= sprintf( $format, esc_sql( $key ), esc_sql( $child ) );
			$glue   = ' OR ';
		}

		return $query;

	}

	/**
	 * Add where arguments to query
	 *
	 * @param array  $args [description]
	 * @param string $rel  [description]
	 */
	public function add_where_args( $args = array(), $rel = 'AND', $add_where_string = true ) {

		$query      = '';
		$multi_args = false;

		if ( ! empty( $args ) ) {

			if ( $add_where_string ) {
				$query .= ' WHERE ';
			}

			$glue = '';

			if ( count( $args ) > 1 ) {
				$multi_args = true;
			}

			foreach ( $args as $key => $arg ) {

				if ( is_array( $arg ) && isset( $arg['column'] ) ) {
					$column  = ! empty( $arg['column'] ) ? $arg['column'] : false;
					$compare = ! empty( $arg['compare'] ) ? $arg['compare'] : '=';
					$value   = ! empty( $arg['value'] ) ? $arg['value'] : '';
					$type    = ! empty( $arg['type'] ) ? $arg['type'] : false;
				} else {
					$column  = $key;
					$compare = '=';
					$value   = $arg;
					$type    = false;
				}

				$clause = $this->prepare_where_clause( $column, $compare, $value, $type );

				if ( $clause ) {
					$query .= $glue;
					$query .= $clause;
					$glue   = ' ' . $rel . ' ';
				}

			}

		}

		return $query;

	}

	/**
	 * Adjust SQL value string according queried argument type
	 *
	 * @param  string  $value [description]
	 * @param  boolean $type  [description]
	 * @return [type]         [description]
	 */
	public function adjust_value_by_type( $value = '', $type = false ) {

		if ( is_array( $value ) ) {
			return false;
		}

		if ( false !== strpos( strtolower( $type ), 'decimal' ) ) {
			$type = 'float';
		}

		switch ( $type ) {
			case 'integer':
				$value = absint( $value );
				break;
			case 'float':
				$value = floatval( $value );
				break;
			case 'timestamp':
				if ( ! \Jet_Engine_Tools::is_valid_timestamp( $value ) ) {
					$value = strtotime( $value );
				}
				$value = absint( $value );
				break;
			case 'date':
				$value = strtotime( $value );
				$value = sprintf( "'%s'", date( $value, 'Y-m-d H:i:s' ) );
				break;
			default:
				$value = sprintf( "'%s'", esc_sql( $value ) );
				break;
		}

		return $value;

	}

	/**
	 * Check if $haystack start from $needle
	 *
	 * @param  [type] $haystack [description]
	 * @param  [type] $needle   [description]
	 * @return [type]           [description]
	 */
	public function starts_with( $haystack, $needle ) {
		$length = strlen( $needle );
		return substr( $haystack, 0, $length ) === $needle;
	}

	/**
	 * Check if $haystack ends with $needle
	 *
	 * @param  [type] $haystack [description]
	 * @param  [type] $needle   [description]
	 * @return [type]           [description]
	 */
	public function ends_with( $haystack, $needle ) {

		$length = strlen( $needle );

		if ( ! $length ) {
			return true;
		}

		return substr( $haystack, -$length ) === $needle;
	}

	/**
	 * Prepare string to use in like or not like operator
	 *
	 * @param  [type] $value [description]
	 * @return [type]        [description]
	 */
	public function prepare_value_for_like_operator( $value ) {
		if ( $this->starts_with( $value, '%' ) || $this->ends_with( $value, '%' ) ) {
			return sprintf( "'%s'", $value );
		} else {
			return sprintf( "'%%%s%%'", esc_sql( $value ) );
		}
	}

	/**
	 * Prepare single query clause by arguments
	 *
	 * @return [type] [description]
	 */
	public function prepare_where_clause( $column = false, $compare = '=', $value = '', $type = false ) {

		if ( ! $column ) {
			return '';
		}

		$format = '%1$s %3$s %2$s';

		$array_operators = array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' );

		if ( ! is_array( $value ) && in_array( $compare, $array_operators ) && false !== strpos( $value, ',' ) ) {
			$value = explode( ',', $value );
			$value = array_map( 'trim', $value );
		}

		if ( is_array( $value ) ) {
			switch ( $compare ) {

				case 'IN':
				case 'NOT IN':

					array_walk( $value, function( &$item ) use ( $type ) {
						$item = $this->adjust_value_by_type( $item, $type );
					} );

					$value = sprintf( '( %s )', implode( ', ', $value ) );

					break;

				case 'BETWEEN':
				case 'NOT BETWEEN':

					$from = isset( $value[0] ) ? $value[0] : 0;
					$to   = isset( $value[1] ) ? $value[1] : $from;

					$from = $this->adjust_value_by_type( $from, $type );
					$to   = $this->adjust_value_by_type( $to, $type );

					$value = sprintf( '%1$s AND %2$s', $from, $to );

					break;

				default:
					$format = '(%2$s)';
					$args   = array();

					foreach ( $value as $val ) {
						$args[] = array(
							'column'  => $column,
							'compare' => $compare,
							'type'    => $type,
							'value'   => $val,
						);
					}

					$value = $this->add_where_args( $args, 'OR', false );
					break;

			}
		} else {

			if ( in_array( $compare, array( 'LIKE', 'NOT LIKE' ) ) ) {
				$value = $this->prepare_value_for_like_operator( $value );
			} else {
				$value = $this->adjust_value_by_type( $value, $type );
			}

			if ( in_array( $compare, $array_operators ) ) {
				$compare = '=';
			}

		}

		$result = sprintf( $format, esc_sql( $column ), $value, $compare );

		return $result;

	}

	/**
	 * Get fields list are available for the current instance of this query
	 *
	 * @return [type] [description]
	 */
	public function get_instance_fields() {

		$cols = array();

		if ( ! empty( $this->query['include_columns'] ) ) {
			$cols = $this->query['include_columns'];
		} elseif ( ! empty( $this->query['default_columns'] ) ) {
			$cols = $this->query['default_columns'];
		}

		$result = array();

		if ( ! empty( $cols ) ) {
			foreach ( $cols as $col ) {
				$result[ $col ] = $col;
			}
		}

		return $result;
	}

}