编程语言
首页 > 编程语言> > 【Laravel3.0.0源码阅读分析】查询语法类

【Laravel3.0.0源码阅读分析】查询语法类

作者:互联网

<?php namespace Laravel\Database\Query\Grammars;

use Laravel\Database\Query;
use Laravel\Database\Expression;

class Grammar extends \Laravel\Database\Grammar {

	/**
	 * All of the query componenets in the order they should be built.
	 * 所有查询组件按照它们应该被构建的顺序。
	 * @var array
	 */
	protected $components = array(
		'aggregate', 'selects', 'from', 'joins', 'wheres',
		'groupings', 'orderings', 'limit', 'offset',
	);

	/**
	 * Compile a SQL SELECT statement from a Query instance.
	 * 从 Query 实例编译 SQL SELECT 语句
	 * @param  Query   $query
	 * @return string
	 */
	public function select(Query $query)
	{
		return $this->concatenate($this->components($query));
	}

	/**
	 * Generate the SQL for every component of the query.
	 * 为查询的每个组件生成 SQL。
	 * @param  Query  $query
	 * @return array
	 */
	final protected function components($query)
	{
		// Each portion of the statement is compiled by a function corresponding
		// to an item in the components array. This lets us to keep the creation
		// of the query very granular and very flexible.
        // 语句的每个部分都由对应于 components 数组中的一项的函数编译。 这让我们可以非常细化和非常灵活地创建查询。
		//
		// Note that each component also connects to a public property on the
		// query instance, allowing us to pass the correct data into each
		// of the compiler functions.
        // 请注意,每个组件还连接到查询实例上的公共属性,允许我们将正确的数据传递给每个编译器函数。
		foreach ($this->components as $component)
		{
			if ( ! is_null($query->$component))
			{
				$sql[$component] = call_user_func(array($this, $component), $query);
			}
		}

		return (array) $sql;
	}

	/**
	 * Concatenate an array of SQL segments, removing those that are empty.
	 * 连接一组 SQL 段,删除那些为空的段。
	 * @param  array   $components
	 * @return string
	 */
	final protected function concatenate($components)
	{
		return implode(' ', array_filter($components, function($value)
		{
			return (string) $value !== '';
		}));
	}

	/**
	 * Compile the SELECT clause for a query.
	 * 为查询编译 SELECT 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function selects(Query $query)
	{
		if ( ! is_null($query->aggregate)) return;

		$select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';

		return $select.$this->columnize($query->selects);
	}

	/**
	 * Compile an aggregating SELECT clause for a query.
	 * 为查询编译聚合 SELECT 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function aggregate(Query $query)
	{
		$column = $this->columnize($query->aggregate['columns']);

		if ($query->distinct and $column !== '*') $column = 'DISTINCT '.$column;

		return 'SELECT '.$query->aggregate['aggregator'].'('.$column.') AS '.$this->wrap('aggregate');
	}

	/**
	 * Compile the FROM clause for a query.
	 * 为查询编译 FROM 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function from(Query $query)
	{
		return 'FROM '.$this->wrap_table($query->from);
	}

	/**
	 * Compile the JOIN clauses for a query.
	 * 为查询编译 JOIN 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function joins(Query $query)
	{
		// We need to iterate through each JOIN clause that is attached to the
		// query an translate it into SQL. The table and the columns will be
		// wrapped in identifiers to avoid naming collisions.
		// 我们需要遍历附加到查询的每个 JOIN 子句并将其转换为 SQL。 表和列将包含在标识符中以避免命名冲突。

		// Once all of the JOINs have been compiled, we can concatenate them
		// together using a single space, which should give us the complete
		// set of joins in valid SQL that can appended to the query.
        // 一旦编译了所有 JOIN,我们就可以使用单个空格将它们连接在一起,这应该为我们提供可以附加到查询的有效 SQL 中的完整连接集。
		foreach ($query->joins as $join)
		{
			$table = $this->wrap_table($join->table);

			$clauses = array();

			// Each JOIN statement may have multiple clauses, so we will
			// iterate through each clause creating the conditions then
			// we will concatenate them all together.
            // 每个 JOIN 语句可能有多个子句,因此我们将遍历每个子句创建条件,然后将它们连接在一起。
			foreach ($join->clauses as $clause)
			{
				extract($clause);

				$column1 = $this->wrap($column1);

				$column2 = $this->wrap($column2);

				$clauses[] = "{$connector} {$column1} {$operator} {$column2}";
			}

			// The first clause will have a connector on the front,
			// but it is not needed on the first condition, so we
			// will strip it off of the condition before adding
			// it to the array of joins.
            // 第一个子句将在前面有一个连接器,但在第一个条件下不需要它,因此我们将在将其添加到连接数组之前将其从条件中剥离。
			$search = array('AND ', 'OR ');

			$clauses[0] = str_replace($search, '', $clauses[0]);

			$clauses = implode(' ', $clauses);

			$sql[] = "{$join->type} JOIN {$table} ON {$clauses}";
		}

		// Finally, we should have an array of JOIN clauses
		// that we can implode together and return as the
		// complete SQL for the JOIN of the query.
        // 最后,我们应该有一个 JOIN 子句数组,我们可以将它们组合在一起并作为查询的 JOIN 的完整 SQL 返回。
		return implode(' ', $sql);
	}

	/**
	 * Compile the WHERE clause for a query.
	 * 为查询编译 WHERE 子句。
	 * @param  Query   $query
	 * @return string
	 */
	final protected function wheres(Query $query)
	{
		if (is_null($query->wheres)) return '';

		// Each WHERE clause array has a "type" that is assigned by the query
		// builder, and each type has its own compiler function. We will call
		// the appropriate compiler for each where clause in the query.
		// 每个 WHERE 子句数组都有一个由查询构建器分配的“类型”,每种类型都有自己的编译器函数。
        // 我们将为查询中的每个 where 子句调用适当的编译器。
		// Keeping each particular where clause in its own "compiler" allows
		// us to keep the query generation process very granular, making it
		// easier to customize derived grammars for other databases.
        // 将每个特定的 where 子句保留在其自己的“编译器”中,
        // 我们可以将查询生成过程保持在非常精细的状态,从而更容易为其他数据库定制派生语法。
		foreach ($query->wheres as $where)
		{
			$sql[] = $where['connector'].' '.$this->{$where['type']}($where);
		}

		if  (isset($sql))
		{
			// We attach the boolean connector to every where segment just
			// for convenience. Once we have built the entire clause we'll
			// remove the first instance of a connector from the clause.
            // 为了方便起见,我们将布尔连接器附加到每个 where 段。 一旦我们构建了整个子句,我们将从子句中删除连接器的第一个实例。
			return 'WHERE '.preg_replace('/AND |OR /', '', implode(' ', $sql), 1);
		}
	}

	/**
	 * Compile a nested WHERE clause.
	 * 编译嵌套的 WHERE 子句。
	 * @param  array   $where
	 * @return string
	 */
	protected function where_nested($where)
	{
		return '('.substr($this->wheres($where['query']), 6).')';
	}

	/**
	 * Compile a simple WHERE clause.
	 * 编译一个简单的 WHERE 子句。
	 * @param  array   $where
	 * @return string
	 */
	protected function where($where)
	{
		$parameter = $this->parameter($where['value']);

		return $this->wrap($where['column']).' '.$where['operator'].' '.$parameter;
	}

	/**
	 * Compile a WHERE IN clause.
	 * 编译一个 WHERE IN 子句。
	 * @param  array   $where
	 * @return string
	 */
	protected function where_in($where)
	{
		$parameters = $this->parameterize($where['values']);

		return $this->wrap($where['column']).' IN ('.$parameters.')';
	}

	/**
	 * Compile a WHERE NOT IN clause.
	 * 编译一个 WHERE NOT IN 子句。
	 * @param  array   $where
	 * @return string
	 */
	protected function where_not_in($where)
	{
		$parameters = $this->parameterize($where['values']);

		return $this->wrap($where['column']).' NOT IN ('.$parameters.')';
	}

	/**
	 * Compile a WHERE NULL clause.
	 * 编译一个 WHERE NULL 子句。
	 * @param  array   $where
	 * @return string
	 */
	protected function where_null($where)
	{
		return $this->wrap($where['column']).' IS NULL';
	}

	/**
	 * Compile a WHERE NULL clause.
	 * 编译一个 WHERE NULL 子句。
	 * @param  array   $where
	 * @return string
	 */
	protected function where_not_null($where)
	{
		return $this->wrap($where['column']).' IS NOT NULL';
	}

	/**
	 * Compile a raw WHERE clause.
	 * 编译一个原始的 WHERE 子句。
	 * @param  array   $where
	 * @return string
	 */
	final protected function where_raw($where)
	{
		return $where['sql'];
	}

	/**
	 * Compile the GROUP BY clause for a query.
	 * 为查询编译 GROUP BY 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function groupings(Query $query)
	{
		return 'GROUP BY '.$this->columnize($query->groupings);
	}

	/**
	 * Compile the ORDER BY clause for a query.
	 * 为查询编译 ORDER BY 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function orderings(Query $query)
	{
		foreach ($query->orderings as $ordering)
		{
			$direction = strtoupper($ordering['direction']);

			$sql[] = $this->wrap($ordering['column']).' '.$direction;
		}

		return 'ORDER BY '.implode(', ', $sql);
	}

	/**
	 * Compile the LIMIT clause for a query.
	 * 为查询编译 LIMIT 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function limit(Query $query)
	{
		return 'LIMIT '.$query->limit;
	}

	/**
	 * Compile the OFFSET clause for a query.
	 * 为查询编译 OFFSET 子句。
	 * @param  Query   $query
	 * @return string
	 */
	protected function offset(Query $query)
	{
		return 'OFFSET '.$query->offset;
	}

	/**
	 * Compile a SQL INSERT statment from a Query instance.
	 * 从 Query 实例编译 SQL INSERT 语句。
	 * This method handles the compilation of single row inserts and batch inserts.
	 * 该方法处理单行插入和批量插入的编译。
	 * @param  Query   $query
	 * @param  array   $values
	 * @return string
	 */
	public function insert(Query $query, $values)
	{
		$table = $this->wrap_table($query->from);

		// Force every insert to be treated like a batch insert. This simply makes
		// creating the SQL syntax a little easier on us since we can always treat
		// the values as if it is an array containing multiple inserts.
        // 强制每个插入都被视为批量插入。 这只是让我们更容易创建 SQL 语法,因为我们总是可以将值视为包含多个插入的数组。
		if ( ! is_array(reset($values))) $values = array($values);

		// Since we only care about the column names, we can pass any of the insert
		// arrays into the "columnize" method. The columns should be the same for
		// every insert to the table so we can just use the first record.
        // 由于我们只关心列名,我们可以将任何插入数组传递给“columnize”方法。
        // 每次插入表的列都应该相同,因此我们可以只使用第一条记录。
		$columns = $this->columnize(array_keys(reset($values)));

		// Build the list of parameter place-holders of values bound to the query.
		// Each insert should have the same number of bound paramters, so we can
		// just use the first array of values.
        // 构建绑定到查询的值的参数占位符列表。 每个插入应该有相同数量的绑定参数,所以我们可以只使用第一个值数组。
		$parameters = $this->parameterize(reset($values));

		$parameters = implode(', ', array_fill(0, count($values), "($parameters)"));

		return "INSERT INTO {$table} ({$columns}) VALUES {$parameters}";
	}

	/**
	 * Compile a SQL UPDATE statment from a Query instance.
	 * 从 Query 实例编译 SQL UPDATE 语句。
	 * @param  Query   $query
	 * @param  array   $values
	 * @return string
	 */
	public function update(Query $query, $values)
	{
		$table = $this->wrap_table($query->from);

		// Each column in the UPDATE statement needs to be wrapped in keyword
		// identifiers, and a place-holder needs to be created for each value
		// in the array of bindings. Of course, if the value of the binding
		// is an expression, the expression string will be injected.
        // UPDATE 语句中的每一列都需要包含在关键字标识符中,并且需要为绑定数组中的每个值创建一个占位符。
        // 当然,如果绑定的值为表达式,则表达式字符串会被注入。
		foreach ($values as $column => $value)
		{
			$columns[] = $this->wrap($column).' = '.$this->parameter($value);
		}

		$columns = implode(', ', $columns);

		// UPDATE statements may be constrained by a WHERE clause, so we'll
		// run the entire where compilation process for those contraints.
		// This is easily achieved by passing the query to the "wheres"
		// method which will call all of the where compilers.
        // UPDATE 语句可能受到 WHERE 子句的约束,因此我们将为这些约束运行整个 where 编译过程。
        // 这可以通过将查询传递给“wheres”方法来轻松实现,该方法将调用所有 where 编译器。
		return trim("UPDATE {$table} SET {$columns} ".$this->wheres($query));
	}

	/**
	 * Compile a SQL DELETE statment from a Query instance.
	 * 从 Query 实例编译 SQL DELETE 语句。
	 * @param  Query   $query
	 * @return string
	 */
	public function delete(Query $query)
	{
		$table = $this->wrap_table($query->from);

		// Like the UPDATE statement, the DELETE statement is constrained
		// by WHERE clauses, so we'll need to run the "wheres" method to
		// make the WHERE clauses for the query.
        // 与 UPDATE 语句一样,DELETE 语句受 WHERE 子句约束,因此我们需要运行“wheres”方法来为查询创建 WHERE 子句。
		return trim("DELETE FROM {$table} ".$this->wheres($query));
	}

	/**
	 * Transform an SQL short-cuts into real SQL for PDO.
	 * 将 SQL 快捷方式转换为用于 PDO 的真正 SQL。
	 * @param  string  $sql
	 * @param  array   $bindings
	 * @return string
	 */
	public function shortcut($sql, $bindings)
	{
		// Laravel provides an easy short-cut notation for writing raw
		// WHERE IN statements. If (...) is in the query, it will be
		// replaced with the correct number of parameters based on
		// the bindings for the query.
        // Laravel 为编写原始的 WHERE IN 语句提供了一种简单的快捷方式。
        // 如果 (...) 在查询中,它将被替换为基于查询绑定的正确数量的参数。
		if (strpos($sql, '(...)') !== false)
		{
			for ($i = 0; $i < count($bindings); $i++)
			{
				// If the binding is an array, we can just assume it's
				// used to fill a "where in" condition, so we'll just
				// replace the next place-holder in the query.
                // 如果绑定是一个数组,我们可以假设它用于填充“where in”条件,因此我们将替换查询中的下一个占位符。
				if (is_array($bindings[$i]))
				{
					$parameters = $this->parameterize($bindings[$i]);

					$sql = preg_replace('~\(\.\.\.\)~', "({$parameters})", $sql, 1);
				}
			}			
		}

		return trim($sql);
	}

}

github地址: https://github.com/liu-shilong/laravel3-scr   

标签:return,子句,Laravel3.0,语法,源码,Query,query,array,where
来源: https://blog.51cto.com/u_14097531/2972959