[增添]添加了datasource的setting数据库以及默认值
This commit is contained in:
560
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/JoinRelationship.php
vendored
Normal file
560
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/JoinRelationship.php
vendored
Normal file
@@ -0,0 +1,560 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins\Mixins;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Kirschbaum\PowerJoins\JoinsHelper;
|
||||
use Kirschbaum\PowerJoins\PowerJoinClause;
|
||||
use Kirschbaum\PowerJoins\StaticCache;
|
||||
|
||||
/**
|
||||
* @mixin Builder
|
||||
* @method \Illuminate\Database\Eloquent\Model getModel()
|
||||
* @property \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
class JoinRelationship
|
||||
{
|
||||
/**
|
||||
* New clause for making joins, where we pass the model to the joiner class.
|
||||
*/
|
||||
public function powerJoin(): Closure
|
||||
{
|
||||
return function ($table, $first, $operator = null, $second = null, $type = 'inner', $where = false): static {
|
||||
$model = $operator instanceof Model ? $operator : null;
|
||||
$join = $this->newPowerJoinClause($this->query, $type, $table, $model);
|
||||
|
||||
// If the first "column" of the join is really a Closure instance the developer
|
||||
// is trying to build a join with a complex "on" clause containing more than
|
||||
// one condition, so we'll add the join and call a Closure with the query.
|
||||
if ($first instanceof Closure) {
|
||||
$first($join);
|
||||
|
||||
$this->query->joins[] = $join;
|
||||
|
||||
$this->query->addBinding($join->getBindings(), 'join');
|
||||
}
|
||||
|
||||
// If the column is simply a string, we can assume the join simply has a basic
|
||||
// "on" clause with a single condition. So we will just build the join with
|
||||
// this simple join clauses attached to it. There is not a join callback.
|
||||
else {
|
||||
$method = $where ? 'where' : 'on';
|
||||
|
||||
$this->query->joins[] = $join->$method($first, $operator, $second);
|
||||
|
||||
$this->query->addBinding($join->getBindings(), 'join');
|
||||
}
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* New clause for making joins, where we pass the model to the joiner class.
|
||||
*/
|
||||
public function leftPowerJoin(): Closure
|
||||
{
|
||||
return function ($table, $first, $operator = null, $second = null) {
|
||||
return $this->powerJoin($table, $first, $operator, $second, 'left');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* New clause for making joins, where we pass the model to the joiner class.
|
||||
*/
|
||||
public function rightPowerJoin(): Closure
|
||||
{
|
||||
return function ($table, $first, $operator = null, $second = null) {
|
||||
return $this->powerJoin($table, $first, $operator, $second, 'right');
|
||||
};
|
||||
}
|
||||
|
||||
public function newPowerJoinClause(): Closure
|
||||
{
|
||||
return function (QueryBuilder $parentQuery, $type, $table, Model $model = null) {
|
||||
return new PowerJoinClause($parentQuery, $type, $table, $model);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the relationship(s).
|
||||
*/
|
||||
public function joinRelationship(): Closure
|
||||
{
|
||||
return function (
|
||||
$relationName,
|
||||
$callback = null,
|
||||
$joinType = 'join',
|
||||
$useAlias = false,
|
||||
bool $disableExtraConditions = false,
|
||||
string $morphable = null
|
||||
) {
|
||||
$joinType = JoinsHelper::$joinMethodsMap[$joinType] ?? $joinType;
|
||||
$useAlias = is_string($callback) ? false : $useAlias;
|
||||
$joinHelper = JoinsHelper::make($this->getModel());
|
||||
$callback = $joinHelper->formatJoinCallback($callback);
|
||||
|
||||
$this->getQuery()->beforeQuery(function () use ($joinHelper) {
|
||||
$joinHelper->clear();
|
||||
});
|
||||
|
||||
if (is_null($this->getSelect())) {
|
||||
$this->select(sprintf('%s.*', $this->getModel()->getTable()));
|
||||
}
|
||||
|
||||
if (Str::contains($relationName, '.')) {
|
||||
$this->joinNestedRelationship($relationName, $callback, $joinType, $useAlias, $disableExtraConditions);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$relationCallback = $callback;
|
||||
if ($callback && is_array($callback) && isset($callback[$relationName]) && is_array($callback[$relationName])) {
|
||||
$relationCallback = $callback[$relationName];
|
||||
}
|
||||
|
||||
$relation = $this->getModel()->{$relationName}();
|
||||
$relationQuery = $relation->getQuery();
|
||||
$alias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relationQuery->getModel()->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
|
||||
if ($relation instanceof BelongsToMany && !is_array($alias)) {
|
||||
$extraAlias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relation->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
$alias = [$extraAlias, $alias];
|
||||
}
|
||||
|
||||
$aliasString = is_array($alias) ? implode('.', $alias) : $alias;
|
||||
$useAlias = $alias ? true : $useAlias;
|
||||
|
||||
$relationJoinCache = $alias
|
||||
? "{$aliasString}.{$relationQuery->getModel()->getTable()}.{$relationName}"
|
||||
: "{$relationQuery->getModel()->getTable()}.{$relationName}";
|
||||
|
||||
if ($joinHelper->relationshipAlreadyJoined($this->getModel(), $relationJoinCache)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($useAlias) {
|
||||
StaticCache::setTableAliasForModel($relation->getModel(), $alias);
|
||||
}
|
||||
|
||||
$joinHelper->markRelationshipAsAlreadyJoined($this->getModel(), $relationJoinCache);
|
||||
StaticCache::clear();
|
||||
|
||||
$relation->performJoinForEloquentPowerJoins(
|
||||
builder: $this,
|
||||
joinType: $joinType,
|
||||
callback: $relationCallback,
|
||||
alias: $alias,
|
||||
disableExtraConditions: $disableExtraConditions,
|
||||
morphable: $morphable,
|
||||
);
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the relationship(s) using table aliases.
|
||||
*/
|
||||
public function joinRelationshipUsingAlias(): Closure
|
||||
{
|
||||
return function ($relationName, $callback = null, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relationName, $callback, 'join', true, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Left join the relationship(s) using table aliases.
|
||||
*/
|
||||
public function leftJoinRelationshipUsingAlias(): Closure
|
||||
{
|
||||
return function ($relationName, $callback = null, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relationName, $callback, 'leftJoin', true, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Right join the relationship(s) using table aliases.
|
||||
*/
|
||||
public function rightJoinRelationshipUsingAlias(): Closure
|
||||
{
|
||||
return function ($relationName, $callback = null, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relationName, $callback, 'rightJoin', true, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function joinRelation(): Closure
|
||||
{
|
||||
return function (
|
||||
$relationName,
|
||||
$callback = null,
|
||||
$joinType = 'join',
|
||||
$useAlias = false,
|
||||
bool $disableExtraConditions = false
|
||||
) {
|
||||
return $this->joinRelationship($relationName, $callback, $joinType, $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function leftJoinRelationship(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'leftJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function leftJoinRelation(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'leftJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function rightJoinRelationship(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'rightJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function rightJoinRelation(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'rightJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Join nested relationships.
|
||||
*/
|
||||
public function joinNestedRelationship(): Closure
|
||||
{
|
||||
return function (
|
||||
string $relationships,
|
||||
$callback = null,
|
||||
$joinType = 'join',
|
||||
$useAlias = false,
|
||||
bool $disableExtraConditions = false
|
||||
) {
|
||||
$relations = explode('.', $relationships);
|
||||
$joinHelper = JoinsHelper::make($this->getModel());
|
||||
/** @var Relation */
|
||||
$latestRelation = null;
|
||||
|
||||
$part = [];
|
||||
foreach ($relations as $relationName) {
|
||||
$part[] = $relationName;
|
||||
$fullRelationName = join(".", $part);
|
||||
|
||||
$currentModel = $latestRelation ? $latestRelation->getModel() : $this->getModel();
|
||||
$relation = $currentModel->{$relationName}();
|
||||
$relationCallback = null;
|
||||
|
||||
if ($callback && is_array($callback) && isset($callback[$relationName])) {
|
||||
$relationCallback = $callback[$relationName];
|
||||
}
|
||||
|
||||
if ($callback && is_array($callback) && isset($callback[$fullRelationName])) {
|
||||
$relationCallback = $callback[$fullRelationName];
|
||||
}
|
||||
|
||||
$alias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relation->getQuery()->getModel()->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
|
||||
if ($alias && $relation instanceof BelongsToMany && !is_array($alias)) {
|
||||
$extraAlias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relation->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
|
||||
$alias = [$extraAlias, $alias];
|
||||
}
|
||||
|
||||
$aliasString = is_array($alias) ? implode('.', $alias) : $alias;
|
||||
$useAlias = $alias ? true : $useAlias;
|
||||
|
||||
if ($alias) {
|
||||
$relationJoinCache = $latestRelation
|
||||
? "{$aliasString}.{$relation->getQuery()->getModel()->getTable()}.{$latestRelation->getModel()->getTable()}.{$relationName}"
|
||||
: "{$aliasString}.{$relation->getQuery()->getModel()->getTable()}.{$relationName}";
|
||||
} else {
|
||||
$relationJoinCache = $latestRelation
|
||||
? "{$relation->getQuery()->getModel()->getTable()}.{$latestRelation->getModel()->getTable()}.{$relationName}"
|
||||
: "{$relation->getQuery()->getModel()->getTable()}.{$relationName}";
|
||||
}
|
||||
|
||||
if ($useAlias) {
|
||||
StaticCache::setTableAliasForModel($relation->getModel(), $alias);
|
||||
}
|
||||
|
||||
|
||||
if ($joinHelper->relationshipAlreadyJoined($this->getModel(), $relationJoinCache)) {
|
||||
$latestRelation = $relation;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$relation->performJoinForEloquentPowerJoins(
|
||||
$this,
|
||||
$joinType,
|
||||
$relationCallback,
|
||||
$alias,
|
||||
$disableExtraConditions
|
||||
);
|
||||
|
||||
$latestRelation = $relation;
|
||||
$joinHelper->markRelationshipAsAlreadyJoined($this->getModel(), $relationJoinCache);
|
||||
}
|
||||
|
||||
StaticCache::clear();
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by a field in the defined relationship.
|
||||
*/
|
||||
public function orderByPowerJoins(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc', $aggregation = null, $joinType = 'join') {
|
||||
if (is_array($sort)) {
|
||||
$relationships = explode('.', $sort[0]);
|
||||
$column = $sort[1];
|
||||
$latestRelationshipName = $relationships[count($relationships) - 1];
|
||||
} else {
|
||||
$relationships = explode('.', $sort);
|
||||
$column = array_pop($relationships);
|
||||
$latestRelationshipName = $relationships[count($relationships) - 1];
|
||||
}
|
||||
|
||||
$this->joinRelationship(implode('.', $relationships), null, $joinType);
|
||||
|
||||
$latestRelationshipModel = array_reduce($relationships, function ($model, $relationshipName) {
|
||||
return $model->$relationshipName()->getModel();
|
||||
}, $this->getModel());
|
||||
|
||||
if ($aggregation) {
|
||||
$aliasName = sprintf(
|
||||
'%s_%s_%s',
|
||||
$latestRelationshipModel->getTable(),
|
||||
$column,
|
||||
$aggregation
|
||||
);
|
||||
|
||||
$this->selectRaw(
|
||||
sprintf(
|
||||
'%s(%s.%s) as %s',
|
||||
$aggregation,
|
||||
$latestRelationshipModel->getTable(),
|
||||
$column,
|
||||
$aliasName
|
||||
)
|
||||
)
|
||||
->groupBy(sprintf('%s.%s', $this->getModel()->getTable(), $this->getModel()->getKeyName()))
|
||||
->orderBy(DB::raw(sprintf('%s', $aliasName)), $direction);
|
||||
} else {
|
||||
if ($column instanceof Expression) {
|
||||
$this->orderBy($column, $direction);
|
||||
} else {
|
||||
$this->orderBy(
|
||||
sprintf('%s.%s', $latestRelationshipModel->getTable(), $column),
|
||||
$direction
|
||||
);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoins(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, null, 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the COUNT aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsCount(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'COUNT');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsCount(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'COUNT', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the SUM aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsSum(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'SUM');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsSum(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'SUM', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the AVG aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsAvg(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'AVG');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsAvg(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'AVG', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the MIN aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsMin(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MIN');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsMin(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MIN', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the MAX aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsMax(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MAX');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsMax(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MAX', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as Laravel 'has`, but using joins instead of where exists.
|
||||
*/
|
||||
public function powerJoinHas(): Closure
|
||||
{
|
||||
return function ($relation, $operator = '>=', $count = 1, $boolean = 'and', Closure|array $callback = null, string $morphable = null): static {
|
||||
if (is_null($this->getSelect())) {
|
||||
$this->select(sprintf('%s.*', $this->getModel()->getTable()));
|
||||
}
|
||||
|
||||
if (is_null($this->getGroupBy())) {
|
||||
$this->groupBy($this->getModel()->getQualifiedKeyName());
|
||||
}
|
||||
|
||||
if (is_string($relation)) {
|
||||
if (Str::contains($relation, '.')) {
|
||||
$this->hasNestedUsingJoins($relation, $operator, $count, 'and', $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$relation = $this->getRelationWithoutConstraintsProxy($relation);
|
||||
}
|
||||
$relation->performJoinForEloquentPowerJoins($this, 'leftPowerJoin', $callback, morphable: $morphable);
|
||||
$relation->performHavingForEloquentPowerJoins($this, $operator, $count, morphable: $morphable);
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
public function hasNestedUsingJoins(): Closure
|
||||
{
|
||||
return function ($relations, $operator = '>=', $count = 1, $boolean = 'and', Closure|array $callback = null): static {
|
||||
$relations = explode('.', $relations);
|
||||
|
||||
/** @var Relation */
|
||||
$latestRelation = null;
|
||||
|
||||
foreach ($relations as $index => $relation) {
|
||||
$relationName = $relation;
|
||||
|
||||
if (!$latestRelation) {
|
||||
$relation = $this->getRelationWithoutConstraintsProxy($relation);
|
||||
} else {
|
||||
$relation = $latestRelation->getModel()->query()->getRelationWithoutConstraintsProxy($relation);
|
||||
}
|
||||
|
||||
$relation->performJoinForEloquentPowerJoins($this, 'leftPowerJoin', is_callable($callback) ? $callback : $callback[$relationName] ?? null);
|
||||
|
||||
if (count($relations) === ($index + 1)) {
|
||||
$relation->performHavingForEloquentPowerJoins($this, $operator, $count);
|
||||
}
|
||||
|
||||
$latestRelation = $relation;
|
||||
}
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
public function powerJoinDoesntHave(): Closure
|
||||
{
|
||||
return function ($relation, $boolean = 'and', Closure $callback = null) {
|
||||
return $this->powerJoinHas($relation, '<', 1, $boolean, $callback);
|
||||
};
|
||||
}
|
||||
|
||||
public function powerJoinWhereHas(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $operator = '>=', $count = 1) {
|
||||
return $this->powerJoinHas($relation, $operator, $count, 'and', $callback);
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user