|  |  |  | @ -143,4 +143,141 @@ class ActiveQuery extends Query implements ActiveQueryInterface | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		return $db->createCommand($sql, $params); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	public function joinWith($with, $eagerLoading = true, $joinType = 'INNER JOIN') | 
			
		
	
		
			
				
					|  |  |  |  | 	{ | 
			
		
	
		
			
				
					|  |  |  |  | 		$with = (array)$with; | 
			
		
	
		
			
				
					|  |  |  |  | 		$this->joinWithRelations(new $this->modelClass, $with, $joinType); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (is_array($eagerLoading)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			foreach ($with as $name => $callback) { | 
			
		
	
		
			
				
					|  |  |  |  | 				if (is_integer($name)) { | 
			
		
	
		
			
				
					|  |  |  |  | 					if (!in_array($callback, $eagerLoading, true)) { | 
			
		
	
		
			
				
					|  |  |  |  | 						unset($with[$name]); | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				} elseif (!in_array($name, $eagerLoading, true)) { | 
			
		
	
		
			
				
					|  |  |  |  | 					unset($with[$name]); | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			$this->with($with); | 
			
		
	
		
			
				
					|  |  |  |  | 		} elseif ($eagerLoading) { | 
			
		
	
		
			
				
					|  |  |  |  | 			$this->with($with); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		return $this; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @param ActiveRecord $model | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @param array $with | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @param string|array $joinType | 
			
		
	
		
			
				
					|  |  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  |  | 	private function joinWithRelations($model, $with, $joinType) | 
			
		
	
		
			
				
					|  |  |  |  | 	{ | 
			
		
	
		
			
				
					|  |  |  |  | 		$relations = []; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		foreach ($with as $name => $callback) { | 
			
		
	
		
			
				
					|  |  |  |  | 			if (is_integer($name)) { | 
			
		
	
		
			
				
					|  |  |  |  | 				$name = $callback; | 
			
		
	
		
			
				
					|  |  |  |  | 				$callback = null; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			$primaryModel = $model; | 
			
		
	
		
			
				
					|  |  |  |  | 			$parent = $this; | 
			
		
	
		
			
				
					|  |  |  |  | 			$prefix = ''; | 
			
		
	
		
			
				
					|  |  |  |  | 			while (($pos = strpos($name, '.')) !== false) { | 
			
		
	
		
			
				
					|  |  |  |  | 				$childName = substr($name, $pos + 1); | 
			
		
	
		
			
				
					|  |  |  |  | 				$name = substr($name, 0, $pos); | 
			
		
	
		
			
				
					|  |  |  |  | 				$fullName = $prefix === '' ? $name : "$prefix.$name"; | 
			
		
	
		
			
				
					|  |  |  |  | 				if (!isset($relations[$fullName])) { | 
			
		
	
		
			
				
					|  |  |  |  | 					$relations[$fullName] = $relation = $primaryModel->getRelation($name); | 
			
		
	
		
			
				
					|  |  |  |  | 					$this->joinWithRelation($parent, $relation, $this->getJoinType($joinType, $fullName)); | 
			
		
	
		
			
				
					|  |  |  |  | 				} else { | 
			
		
	
		
			
				
					|  |  |  |  | 					$relation = $relations[$fullName]; | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 				$primaryModel = new $relation->modelClass; | 
			
		
	
		
			
				
					|  |  |  |  | 				$parent = $relation; | 
			
		
	
		
			
				
					|  |  |  |  | 				$prefix = $fullName; | 
			
		
	
		
			
				
					|  |  |  |  | 				$name = $childName; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			$fullName = $prefix === '' ? $name : "$prefix.$name"; | 
			
		
	
		
			
				
					|  |  |  |  | 			if (!isset($relations[$fullName])) { | 
			
		
	
		
			
				
					|  |  |  |  | 				$relations[$fullName] = $relation = $primaryModel->getRelation($name); | 
			
		
	
		
			
				
					|  |  |  |  | 				if ($callback !== null) { | 
			
		
	
		
			
				
					|  |  |  |  | 					call_user_func($callback, $relation); | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 				$this->joinWithRelation($parent, $relation, $this->getJoinType($joinType, $fullName)); | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	private function getJoinType($joinType, $name) | 
			
		
	
		
			
				
					|  |  |  |  | 	{ | 
			
		
	
		
			
				
					|  |  |  |  | 		if (is_array($joinType) && isset($joinType[$name])) { | 
			
		
	
		
			
				
					|  |  |  |  | 			return $joinType[$name]; | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			return is_string($joinType) ? $joinType : 'INNER JOIN'; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @param ActiveQuery $query | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @return string | 
			
		
	
		
			
				
					|  |  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  |  | 	private function getQueryTableName($query) | 
			
		
	
		
			
				
					|  |  |  |  | 	{ | 
			
		
	
		
			
				
					|  |  |  |  | 		if (empty($query->from)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			/** @var ActiveRecord $modelClass */ | 
			
		
	
		
			
				
					|  |  |  |  | 			$modelClass = $query->modelClass; | 
			
		
	
		
			
				
					|  |  |  |  | 			return $modelClass::tableName(); | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			return reset($query->from); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @param ActiveQuery $parent | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @param ActiveRelation $child | 
			
		
	
		
			
				
					|  |  |  |  | 	 * @param string $joinType | 
			
		
	
		
			
				
					|  |  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  |  | 	private function joinWithRelation($parent, $child, $joinType) | 
			
		
	
		
			
				
					|  |  |  |  | 	{ | 
			
		
	
		
			
				
					|  |  |  |  | 		$parentTable = $this->getQueryTableName($parent); | 
			
		
	
		
			
				
					|  |  |  |  | 		$childTable = $this->getQueryTableName($child); | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->link)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			$on = []; | 
			
		
	
		
			
				
					|  |  |  |  | 			foreach ($child->link as $childColumn => $parentColumn) { | 
			
		
	
		
			
				
					|  |  |  |  | 				$on[] = '{{' . $parentTable . "}}.[[$parentColumn]] = {{" . $childTable . "}}.[[$childColumn]]"; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			$on = implode(' AND ', $on); | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			$on = ''; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		$this->join($joinType, $childTable, $on); | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->where)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			$this->andWhere($child->where); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->having)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			$this->andHaving($child->having); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->orderBy)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			$this->addOrderBy($child->orderBy); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->groupBy)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			$this->addGroupBy($child->groupBy); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->params)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			$this->addParams($child->params); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->join)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			foreach ($child->join as $join) { | 
			
		
	
		
			
				
					|  |  |  |  | 				$this->join[] = $join; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!empty($child->union)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			foreach ($child->union as $union) { | 
			
		
	
		
			
				
					|  |  |  |  | 				$this->union[] = $union; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |