You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
8.9 KiB
277 lines
8.9 KiB
<?php namespace Majestic\Model;
|
|
|
|
class SqlCriteria
|
|
{
|
|
const JOIN_TYPE_DEFAULT = 100;
|
|
const JOIN_TYPE_LEFT = 101;
|
|
const JOIN_TYPE_RIGHT = 102;
|
|
const JOIN_TYPE_INNER = 103;
|
|
const JOIN_TYPE_OUTER = 104;
|
|
|
|
private static $join_reserved_keyword = array(
|
|
self::JOIN_TYPE_DEFAULT => 'JOIN',
|
|
self::JOIN_TYPE_LEFT => 'LEFT JOIN',
|
|
self::JOIN_TYPE_RIGHT => 'RIGHT JOIN',
|
|
self::JOIN_TYPE_INNER => 'INNER JOIN',
|
|
self::JOIN_TYPE_OUTER => 'OUTER JOIN',
|
|
);
|
|
|
|
private $select = array();
|
|
|
|
private $distinct = '';
|
|
|
|
private $where = array();
|
|
|
|
private $group_by = array();
|
|
|
|
private $order = array('sort' => array(), 'order' => array());
|
|
|
|
private $limit = '';
|
|
|
|
/**
|
|
* @var SqlModel
|
|
*/
|
|
private $model;
|
|
|
|
private $sql_expression;
|
|
|
|
private $sql_expression_params = array();
|
|
|
|
private $sql_join_expressions = array();
|
|
|
|
private $join_table_placeholder = array();
|
|
|
|
/**
|
|
* @param $model SqlModel
|
|
* @param $sql_expression string|null Sql expression with SELECT and FROM operators. If fetched, then SqlCriteria::select(), SqlCriteria::distinct() disabled for use.
|
|
* @param $sql_expression_params array additional params to be replaced in sql expression
|
|
*/
|
|
public function __construct($model, $sql_expression = null, $sql_expression_params = array())
|
|
{
|
|
$this->model = $model;
|
|
$this->sql_expression = $sql_expression;
|
|
$this->sql_expression_params = $sql_expression_params;
|
|
}
|
|
|
|
/**
|
|
* @return SqlResultProvider
|
|
*/
|
|
public function find()
|
|
{
|
|
$this->defineJoinExpressions();
|
|
return $this->model->find($this->select, $this->distinct, $this->where, $this->order, $this->limit, null, $this->group_by, $this->sql_expression, $this->sql_expression_params);
|
|
}
|
|
|
|
private function defineJoinExpressions($select = null)
|
|
{
|
|
if ($this->sql_join_expressions) {
|
|
if (!$this->sql_expression) {
|
|
$select = $this->model->getDb()->selectExpr($select ? : $this->select, $this->distinct);
|
|
$this->sql_expression = 'SELECT ' . $select . ' FROM :table';
|
|
}
|
|
$this->sql_expression .= ' ' . implode(' ', $this->sql_join_expressions);
|
|
$this->sql_join_expressions = null;
|
|
}
|
|
}
|
|
|
|
public function delete()
|
|
{
|
|
return $this->model->find('', '', $this->where, null, null, null, null, 'DELETE FROM :table', $this->sql_expression_params)->affectedRows();
|
|
}
|
|
|
|
//TODO: перенести определение sql_expression в модель
|
|
public function count($select = null)
|
|
{
|
|
$this->defineJoinExpressions($select);
|
|
$sql_expression_backup = $this->sql_expression;
|
|
$group_by_backup = $this->group_by;
|
|
$select_parent_query = 'COUNT(*) as count';
|
|
$default_select = '*';
|
|
if ($this->group_by) {
|
|
$default_select = 'DISTINCT ' . $this->group_by[0];
|
|
}
|
|
$this->group_by = [];
|
|
if (!$this->sql_expression) {
|
|
$this->sql_expression = 'SELECT COUNT(' . ($select ? $select : $default_select) . ') as count FROM :table';
|
|
$select_parent_query = 'x.count';
|
|
} else {
|
|
$this->sql_expression = preg_replace('#SELECT.+FROM#i', 'SELECT COUNT(' . ($select ? $select : $default_select) . ') as count FROM', $this->sql_expression);
|
|
}
|
|
$count = $this->model->count($select_parent_query, $this->where, null, $this->group_by, $this->sql_expression, $this->sql_expression_params)->fetchField('count');
|
|
$this->sql_expression = $sql_expression_backup;
|
|
$this->group_by = $group_by_backup;
|
|
return $count;
|
|
}
|
|
|
|
private function defineJoinTablePlaceholder($table_name)
|
|
{
|
|
if (!isset($this->join_table_placeholder[$table_name])) {
|
|
$this->join_table_placeholder[$table_name] = ':table' . (count($this->join_table_placeholder) + 1);
|
|
}
|
|
}
|
|
|
|
public function getTablePh($table_name)
|
|
{
|
|
$this->defineJoinTablePlaceholder($table_name);
|
|
return $this->join_table_placeholder[$table_name];
|
|
}
|
|
|
|
public function join($join_table_name, $join_field_name, $donor_table_name = null, $donor_field_name = null, $join_type = self::JOIN_TYPE_DEFAULT)
|
|
{
|
|
$donor_field_name = $donor_field_name ? : $join_field_name;
|
|
$donor_table_placeholder = $donor_table_name ? $this->getTablePh($donor_table_name) : ':table';
|
|
$join_table_placeholder = $this->getTablePh($join_table_name);
|
|
$this->sql_join_expressions[] = self::$join_reserved_keyword[$join_type]
|
|
. ' ' . $join_table_placeholder
|
|
. ' ON ' . $donor_table_placeholder . '.' . $donor_field_name . '='
|
|
. ' ' . $join_table_placeholder . '.' . $join_field_name;
|
|
if ($donor_table_name) {
|
|
$this->sql_expression_params[substr($donor_table_placeholder, 1)] = new DbExpr($this->model->identify($donor_table_name));
|
|
}
|
|
$this->sql_expression_params[substr($join_table_placeholder, 1)] = new DbExpr($this->model->identify($join_table_name));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $cond string|array Condition with "?" placeholder @ex 'field=?' or 'field=1' or array('field=?' => 1', 'field=1')
|
|
* @param $value string|array|DbExpr|null Value. Array transformed to DbExpr(implode(',' Array)) All elements in the array mast be integer
|
|
* @return SqlCriteria
|
|
* @desc Allow multiple calls
|
|
*/
|
|
public function where($cond, $value = null)
|
|
{
|
|
if (is_null($value)) {
|
|
if (is_array($cond)) {
|
|
$this->where = $this->where + $cond;
|
|
} else {
|
|
$this->where[] = $cond;
|
|
}
|
|
} else {
|
|
$this->where[$cond] = $value;
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
public function whereJoin($join_table_name, $cond, $value = null)
|
|
{
|
|
$join_table_placeholder = $this->getTablePh($join_table_name);
|
|
if (is_array($cond)) {
|
|
$cond_replace = array();
|
|
foreach ($cond as $key => $value) {
|
|
$cond_replace[$this->getCondWithTablePlaceholderIfNeed($join_table_placeholder, $key)] = $value;
|
|
}
|
|
} else {
|
|
$cond = $this->getCondWithTablePlaceholderIfNeed($join_table_placeholder, $cond);
|
|
}
|
|
return $this->where($cond, $value);
|
|
}
|
|
|
|
private function getCondWithTablePlaceholderIfNeed($table_placeholder, $cond)
|
|
{
|
|
if (!strstr('.', $cond)) {
|
|
$cond = $table_placeholder . '.' . $cond;
|
|
}
|
|
return $cond;
|
|
}
|
|
|
|
/**
|
|
* @param $field string
|
|
* @param $value array
|
|
* @return SqlCriteria
|
|
*/
|
|
public function whereIn($field, $value)
|
|
{
|
|
return $this->where($field . ' in ?', $value);
|
|
}
|
|
|
|
/**
|
|
* @param $field string
|
|
* @param $value array
|
|
* @return SqlCriteria
|
|
*/
|
|
public function whereNotIn($field, $value)
|
|
{
|
|
return $this->where($field . ' not in ?', $value);
|
|
}
|
|
|
|
/**
|
|
* @param $field string
|
|
* @param $value array
|
|
* @return SqlCriteria
|
|
* @deprecated
|
|
*/
|
|
public function whereNot($field, $value)
|
|
{
|
|
return $this->whereNotIn($field, $value);
|
|
}
|
|
|
|
public function groupBy($fields)
|
|
{
|
|
if (is_array($fields)) {
|
|
$this->group_by = $this->group_by + $fields;
|
|
} else {
|
|
$this->group_by[] = $fields;
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $field string Field @ex 'field'
|
|
* @param $order_desc bool Descendant sort direction
|
|
* @return SqlCriteria
|
|
* @desc Allow multiple calls
|
|
*/
|
|
public function order($field, $order_desc = false)
|
|
{
|
|
$this->order['sort'][] = $field;
|
|
if ($order_desc) {
|
|
$this->order['order'][$field] = 'desc';
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $offset int
|
|
* @param $limit int
|
|
* @return SqlCriteria
|
|
*/
|
|
public function limit($offset = 0, $limit)
|
|
{
|
|
if ($offset) {
|
|
$this->limit = (int) $offset . ',';
|
|
}
|
|
$this->limit .= (int) $limit;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string|array $fields
|
|
* @param bool $convert_to_db_expression
|
|
* @ex SqlCriteria::select('field')
|
|
* @ex SqlCriteria->select(array('field1', 'field2'))
|
|
* @ex SqlCriteria->select('field1,field2')
|
|
* @return SqlCriteria
|
|
*/
|
|
public function select($fields, $convert_to_db_expression = false)
|
|
{
|
|
if (!is_array($fields)) {
|
|
$fields = explode(',', $fields);
|
|
}
|
|
$fields = array_map(function($item){return trim($item);},$fields);
|
|
if ($convert_to_db_expression) {
|
|
$fields = array_map(function($item){return new DbExpr($item);},$fields);
|
|
}
|
|
$this->select = array_merge($this->select,$fields);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $field string|bool If true then distinct by *
|
|
* @return SqlCriteria
|
|
*/
|
|
public function distinct($field)
|
|
{
|
|
$this->distinct = $field;
|
|
return $this;
|
|
}
|
|
}
|