dep: package update
This commit is contained in:
+24
@@ -161,6 +161,13 @@ class Connection implements ConnectionInterface
|
||||
*/
|
||||
protected $pretending = false;
|
||||
|
||||
/**
|
||||
* All of the callbacks that should be invoked before a query is executed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $beforeExecutingCallbacks = [];
|
||||
|
||||
/**
|
||||
* The instance of Doctrine connection.
|
||||
*
|
||||
@@ -641,6 +648,10 @@ class Connection implements ConnectionInterface
|
||||
*/
|
||||
protected function run($query, $bindings, Closure $callback)
|
||||
{
|
||||
foreach ($this->beforeExecutingCallbacks as $beforeExecutingCallback) {
|
||||
$beforeExecutingCallback($query, $bindings, $this);
|
||||
}
|
||||
|
||||
$this->reconnectIfMissingConnection();
|
||||
|
||||
$start = microtime(true);
|
||||
@@ -807,6 +818,19 @@ class Connection implements ConnectionInterface
|
||||
$this->setPdo(null)->setReadPdo(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a hook to be run just before a database query is executed.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function beforeExecuting(Closure $callback)
|
||||
{
|
||||
$this->beforeExecutingCallbacks[] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a database query listener with the connection.
|
||||
*
|
||||
|
||||
@@ -3,17 +3,9 @@
|
||||
namespace {{ factoryNamespace }};
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use {{ namespacedModel }};
|
||||
|
||||
class {{ factory }}Factory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = {{ model }}::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
|
||||
+33
-2
@@ -19,7 +19,8 @@ class PruneCommand extends Command
|
||||
*/
|
||||
protected $signature = 'model:prune
|
||||
{--model=* : Class names of the models to be pruned}
|
||||
{--chunk=1000 : The number of models to retrieve per chunk of models to be deleted}';
|
||||
{--chunk=1000 : The number of models to retrieve per chunk of models to be deleted}
|
||||
{--pretend : Display the number of prunable records found instead of deleting them}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@@ -44,6 +45,14 @@ class PruneCommand extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->option('pretend')) {
|
||||
$models->each(function ($model) {
|
||||
$this->pretendToPrune($model);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$events->listen(ModelsPruned::class, function ($event) {
|
||||
$this->info("{$event->count} [{$event->model}] records have been pruned.");
|
||||
});
|
||||
@@ -78,7 +87,7 @@ class PruneCommand extends Command
|
||||
return collect($models);
|
||||
}
|
||||
|
||||
return collect((new Finder)->in(app_path('Models'))->files())
|
||||
return collect((new Finder)->in(app_path('Models'))->files()->name('*.php'))
|
||||
->map(function ($model) {
|
||||
$namespace = $this->laravel->getNamespace();
|
||||
|
||||
@@ -104,4 +113,26 @@ class PruneCommand extends Command
|
||||
|
||||
return in_array(Prunable::class, $uses) || in_array(MassPrunable::class, $uses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display how many models will be pruned.
|
||||
*
|
||||
* @param string $model
|
||||
* @return void
|
||||
*/
|
||||
protected function pretendToPrune($model)
|
||||
{
|
||||
$instance = new $model;
|
||||
|
||||
$count = $instance->prunable()
|
||||
->when(in_array(SoftDeletes::class, class_uses_recursive(get_class($instance))), function ($query) {
|
||||
$query->withTrashed();
|
||||
})->count();
|
||||
|
||||
if ($count === 0) {
|
||||
$this->info("No prunable [$model] records found.");
|
||||
} else {
|
||||
$this->info("{$count} [{$model}] records will be pruned.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -4,12 +4,15 @@ namespace Illuminate\Database\DBAL;
|
||||
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\PhpDateTimeMappingType;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
class TimestampType extends Type
|
||||
class TimestampType extends Type implements PhpDateTimeMappingType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -97,6 +100,8 @@ class TimestampType extends Type
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ trait DetectsConcurrencyErrors
|
||||
*/
|
||||
protected function causedByConcurrencyError(Throwable $e)
|
||||
{
|
||||
if ($e instanceof PDOException && $e->getCode() === '40001') {
|
||||
if ($e instanceof PDOException && ($e->getCode() === 40001 || $e->getCode() === '40001')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ trait DetectsLostConnections
|
||||
'SQLSTATE[08S01]: Communication link failure',
|
||||
'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',
|
||||
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',
|
||||
'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.',
|
||||
'SQLSTATE[08006] [7] could not translate host name',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Eloquent\Casts;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\Castable;
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class AsStringable implements Castable
|
||||
{
|
||||
/**
|
||||
* Get the caster class to use when casting from / to this cast target.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return object|string
|
||||
*/
|
||||
public static function castUsing(array $arguments)
|
||||
{
|
||||
return new class implements CastsAttributes
|
||||
{
|
||||
public function get($model, $key, $value, $attributes)
|
||||
{
|
||||
return isset($value) ? Str::of($value) : null;
|
||||
}
|
||||
|
||||
public function set($model, $key, $value, $attributes)
|
||||
{
|
||||
return isset($value) ? (string) $value : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ use DateTimeInterface;
|
||||
use Illuminate\Contracts\Database\Eloquent\Castable;
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||
use Illuminate\Database\Eloquent\Casts\AsCollection;
|
||||
use Illuminate\Database\Eloquent\InvalidCastException;
|
||||
use Illuminate\Database\Eloquent\JsonEncodingException;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
@@ -262,6 +264,10 @@ trait HasAttributes
|
||||
$attributes[$key] = $this->serializeClassCastableAttribute($key, $attributes[$key]);
|
||||
}
|
||||
|
||||
if ($this->isEnumCastable($key)) {
|
||||
$attributes[$key] = isset($attributes[$key]) ? $attributes[$key]->value : null;
|
||||
}
|
||||
|
||||
if ($attributes[$key] instanceof Arrayable) {
|
||||
$attributes[$key] = $attributes[$key]->toArray();
|
||||
}
|
||||
@@ -620,6 +626,10 @@ trait HasAttributes
|
||||
return $this->asTimestamp($value);
|
||||
}
|
||||
|
||||
if ($this->isEnumCastable($key)) {
|
||||
return $this->getEnumCastableAttributeValue($key, $value);
|
||||
}
|
||||
|
||||
if ($this->isClassCastable($key)) {
|
||||
return $this->getClassCastableAttributeValue($key, $value);
|
||||
}
|
||||
@@ -655,6 +665,24 @@ trait HasAttributes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast the given attribute to an enum.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getEnumCastableAttributeValue($key, $value)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$castType = $this->getCasts()[$key];
|
||||
|
||||
return $castType::from($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of cast for a model attribute.
|
||||
*
|
||||
@@ -765,6 +793,12 @@ trait HasAttributes
|
||||
$value = $this->fromDateTime($value);
|
||||
}
|
||||
|
||||
if ($this->isEnumCastable($key)) {
|
||||
$this->setEnumCastableAttribute($key, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($this->isClassCastable($key)) {
|
||||
$this->setClassCastableAttribute($key, $value);
|
||||
|
||||
@@ -883,6 +917,18 @@ trait HasAttributes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of an enum castable attribute.
|
||||
*
|
||||
* @param string $key
|
||||
* @param \BackedEnum $value
|
||||
* @return void
|
||||
*/
|
||||
protected function setEnumCastableAttribute($key, $value)
|
||||
{
|
||||
$this->attributes[$key] = isset($value) ? $value->value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array attribute with the given key and value set.
|
||||
*
|
||||
@@ -1217,7 +1263,18 @@ trait HasAttributes
|
||||
*/
|
||||
protected function isDateCastable($key)
|
||||
{
|
||||
return $this->hasCast($key, ['date', 'datetime', 'custom_datetime', 'immutable_date', 'immutable_datetime', 'immutable_custom_datetime']);
|
||||
return $this->hasCast($key, ['date', 'datetime', 'immutable_date', 'immutable_datetime']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a value is Date / DateTime custom-castable for inbound manipulation.
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDateCastableWithCustomFormat($key)
|
||||
{
|
||||
return $this->hasCast($key, ['custom_datetime', 'immutable_custom_datetime']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1269,6 +1326,29 @@ trait HasAttributes
|
||||
throw new InvalidCastException($this->getModel(), $key, $castType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given key is cast using an enum.
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
protected function isEnumCastable($key)
|
||||
{
|
||||
if (! array_key_exists($key, $this->getCasts())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$castType = $this->getCasts()[$key];
|
||||
|
||||
if (in_array($castType, static::$primitiveCastTypes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (function_exists('enum_exists') && enum_exists($castType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the key is deviable using a custom class.
|
||||
*
|
||||
@@ -1294,8 +1374,9 @@ trait HasAttributes
|
||||
*/
|
||||
protected function isClassSerializable($key)
|
||||
{
|
||||
return $this->isClassCastable($key) &&
|
||||
method_exists($this->parseCasterClass($this->getCasts()[$key]), 'serialize');
|
||||
return ! $this->isEnumCastable($key) &&
|
||||
$this->isClassCastable($key) &&
|
||||
method_exists($this->resolveCasterClass($key), 'serialize');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1643,7 +1724,7 @@ trait HasAttributes
|
||||
return true;
|
||||
} elseif (is_null($attribute)) {
|
||||
return false;
|
||||
} elseif ($this->isDateAttribute($key) || $this->isDateCastable($key)) {
|
||||
} elseif ($this->isDateAttribute($key) || $this->isDateCastableWithCustomFormat($key)) {
|
||||
return $this->fromDateTime($attribute) ===
|
||||
$this->fromDateTime($original);
|
||||
} elseif ($this->hasCast($key, ['object', 'collection'])) {
|
||||
@@ -1658,6 +1739,8 @@ trait HasAttributes
|
||||
} elseif ($this->hasCast($key, static::$primitiveCastTypes)) {
|
||||
return $this->castAttribute($key, $attribute) ===
|
||||
$this->castAttribute($key, $original);
|
||||
} elseif ($this->isClassCastable($key) && in_array($this->getCasts()[$key], [AsArrayObject::class, AsCollection::class])) {
|
||||
return $this->fromJson($attribute) === $this->fromJson($original);
|
||||
}
|
||||
|
||||
return is_numeric($attribute) && is_numeric($original)
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
namespace Illuminate\Database\Eloquent\Concerns;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\RelationNotFoundException;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
@@ -455,6 +458,56 @@ trait QueriesRelationships
|
||||
return $this->whereMorphedTo($relation, $model, 'or');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a "belongs to" relationship where clause to the query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $related
|
||||
* @param string $relationship
|
||||
* @param string $boolean
|
||||
* @return $this
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function whereBelongsTo($related, $relationshipName = null, $boolean = 'and')
|
||||
{
|
||||
if ($relationshipName === null) {
|
||||
$relationshipName = Str::camel(class_basename($related));
|
||||
}
|
||||
|
||||
try {
|
||||
$relationship = $this->model->{$relationshipName}();
|
||||
} catch (BadMethodCallException $exception) {
|
||||
throw RelationNotFoundException::make($this->model, $relationshipName);
|
||||
}
|
||||
|
||||
if (! $relationship instanceof BelongsTo) {
|
||||
throw RelationNotFoundException::make($this->model, $relationshipName, BelongsTo::class);
|
||||
}
|
||||
|
||||
$this->where(
|
||||
$relationship->getQualifiedForeignKeyName(),
|
||||
'=',
|
||||
$related->getAttributeValue($relationship->getOwnerKeyName()),
|
||||
$boolean,
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an "BelongsTo" relationship with an "or where" clause to the query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $related
|
||||
* @param string $relationship
|
||||
* @return $this
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function orWhereBelongsTo($related, $relationshipName = null)
|
||||
{
|
||||
return $this->whereBelongsTo($related, $relationshipName, 'or');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add subselect queries to include an aggregate value for a relationship.
|
||||
*
|
||||
|
||||
@@ -10,20 +10,21 @@ use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Traits\Conditionable;
|
||||
use Illuminate\Support\Traits\ForwardsCalls;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use Throwable;
|
||||
|
||||
abstract class Factory
|
||||
{
|
||||
use ForwardsCalls, Macroable {
|
||||
use Conditionable, ForwardsCalls, Macroable {
|
||||
__call as macroCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
|
||||
+25
-2
@@ -8,6 +8,7 @@ use Illuminate\Contracts\Queue\QueueableCollection;
|
||||
use Illuminate\Contracts\Queue\QueueableEntity;
|
||||
use Illuminate\Contracts\Routing\UrlRoutable;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
|
||||
use Illuminate\Contracts\Support\Jsonable;
|
||||
use Illuminate\Database\ConnectionResolverInterface as Resolver;
|
||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||
@@ -22,7 +23,7 @@ use Illuminate\Support\Traits\ForwardsCalls;
|
||||
use JsonSerializable;
|
||||
use LogicException;
|
||||
|
||||
abstract class Model implements Arrayable, ArrayAccess, HasBroadcastChannel, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
|
||||
abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToString, HasBroadcastChannel, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
|
||||
{
|
||||
use Concerns\HasAttributes,
|
||||
Concerns\HasEvents,
|
||||
@@ -110,6 +111,13 @@ abstract class Model implements Arrayable, ArrayAccess, HasBroadcastChannel, Jso
|
||||
*/
|
||||
public $wasRecentlyCreated = false;
|
||||
|
||||
/**
|
||||
* Indicates that the object's string representation should be escaped when __toString is invoked.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeWhenCastingToString = false;
|
||||
|
||||
/**
|
||||
* The connection resolver instance.
|
||||
*
|
||||
@@ -2128,7 +2136,22 @@ abstract class Model implements Arrayable, ArrayAccess, HasBroadcastChannel, Jso
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toJson();
|
||||
return $this->escapeWhenCastingToString
|
||||
? e($this->toJson())
|
||||
: $this->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the object's string representation should be escaped when __toString is invoked.
|
||||
*
|
||||
* @param bool $escape
|
||||
* @return $this
|
||||
*/
|
||||
public function escapeWhenCastingToString($escape = true)
|
||||
{
|
||||
$this->escapeWhenCastingToString = $escape;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,13 +25,18 @@ class RelationNotFoundException extends RuntimeException
|
||||
*
|
||||
* @param object $model
|
||||
* @param string $relation
|
||||
* @param string|null $type
|
||||
* @return static
|
||||
*/
|
||||
public static function make($model, $relation)
|
||||
public static function make($model, $relation, $type = null)
|
||||
{
|
||||
$class = get_class($model);
|
||||
|
||||
$instance = new static("Call to undefined relationship [{$relation}] on model [{$class}].");
|
||||
$instance = new static(
|
||||
is_null($type)
|
||||
? "Call to undefined relationship [{$relation}] on model [{$class}]."
|
||||
: "Call to undefined relationship [{$relation}] on model [{$class}] of type [{$type}].",
|
||||
);
|
||||
|
||||
$instance->model = $class;
|
||||
$instance->relation = $relation;
|
||||
|
||||
@@ -277,7 +277,7 @@ class BelongsToMany extends Relation
|
||||
|
||||
// Once we have an array dictionary of child objects we can easily match the
|
||||
// children back to their parent using the dictionary and the keys on the
|
||||
// the parent models. Then we will return the hydrated models back out.
|
||||
// parent models. Then we should return these hydrated models back out.
|
||||
foreach ($models as $model) {
|
||||
$key = $this->getDictionaryKey($model->{$this->parentKey});
|
||||
|
||||
|
||||
@@ -102,7 +102,9 @@ trait CanBeOneOfMany
|
||||
|
||||
if (isset($previous)) {
|
||||
$this->addOneOfManyJoinSubQuery($subQuery, $previous['subQuery'], $previous['column']);
|
||||
} elseif (isset($closure)) {
|
||||
}
|
||||
|
||||
if (isset($closure)) {
|
||||
$closure($subQuery);
|
||||
}
|
||||
|
||||
@@ -122,6 +124,12 @@ trait CanBeOneOfMany
|
||||
|
||||
$this->addConstraints();
|
||||
|
||||
$columns = $this->query->getQuery()->columns;
|
||||
|
||||
if (is_null($columns) || $columns === ['*']) {
|
||||
$this->select([$this->qualifyColumn('*')]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -137,7 +145,7 @@ trait CanBeOneOfMany
|
||||
{
|
||||
return $this->ofMany(collect(Arr::wrap($column))->mapWithKeys(function ($column) {
|
||||
return [$column => 'MAX'];
|
||||
})->all(), 'MAX', $relation ?: $this->guessRelationship());
|
||||
})->all(), 'MAX', $relation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +160,7 @@ trait CanBeOneOfMany
|
||||
{
|
||||
return $this->ofMany(collect(Arr::wrap($column))->mapWithKeys(function ($column) {
|
||||
return [$column => 'MIN'];
|
||||
})->all(), 'MIN', $relation ?: $this->guessRelationship());
|
||||
})->all(), 'MIN', $relation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,14 +187,15 @@ trait CanBeOneOfMany
|
||||
protected function newOneOfManySubQuery($groupBy, $column = null, $aggregate = null)
|
||||
{
|
||||
$subQuery = $this->query->getModel()
|
||||
->newQuery();
|
||||
->newQuery()
|
||||
->withoutGlobalScopes($this->removedScopes());
|
||||
|
||||
foreach (Arr::wrap($groupBy) as $group) {
|
||||
$subQuery->groupBy($this->qualifyRelatedColumn($group));
|
||||
}
|
||||
|
||||
if (! is_null($column)) {
|
||||
$subQuery->selectRaw($aggregate.'('.$subQuery->getQuery()->grammar->wrap($column).') as '.$subQuery->getQuery()->grammar->wrap($column));
|
||||
$subQuery->selectRaw($aggregate.'('.$subQuery->getQuery()->grammar->wrap($subQuery->qualifyColumn($column)).') as '.$subQuery->getQuery()->grammar->wrap($column.'_aggregate'));
|
||||
}
|
||||
|
||||
$this->addOneOfManySubQueryConstraints($subQuery, $groupBy, $column, $aggregate);
|
||||
@@ -208,7 +217,7 @@ trait CanBeOneOfMany
|
||||
$subQuery->applyBeforeQueryCallbacks();
|
||||
|
||||
$parent->joinSub($subQuery, $this->relationName, function ($join) use ($on) {
|
||||
$join->on($this->qualifySubSelectColumn($on), '=', $this->qualifyRelatedColumn($on));
|
||||
$join->on($this->qualifySubSelectColumn($on.'_aggregate'), '=', $this->qualifyRelatedColumn($on));
|
||||
|
||||
$this->addOneOfManyJoinSubQueryConstraints($join, $on);
|
||||
});
|
||||
|
||||
@@ -407,7 +407,7 @@ abstract class Relation
|
||||
/**
|
||||
* Define the morph map for polymorphic relations and require all morphed models to be explicitly mapped.
|
||||
*
|
||||
* @param array|null $map
|
||||
* @param array $map
|
||||
* @param bool $merge
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,9 @@ use Doctrine\DBAL\Driver\AbstractSQLServerDriver;
|
||||
|
||||
class SqlServerDriver extends AbstractSQLServerDriver
|
||||
{
|
||||
/**
|
||||
* @return \Doctrine\DBAL\Driver\Connection
|
||||
*/
|
||||
public function connect(array $params)
|
||||
{
|
||||
return new SqlServerConnection(
|
||||
|
||||
+27
-5
@@ -20,6 +20,7 @@ use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Traits\ForwardsCalls;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use RuntimeException;
|
||||
|
||||
class Builder
|
||||
@@ -1960,7 +1961,7 @@ class Builder
|
||||
/**
|
||||
* Add an "order by" clause to the query.
|
||||
*
|
||||
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @param \Closure|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @param string $direction
|
||||
* @return $this
|
||||
*
|
||||
@@ -1993,7 +1994,7 @@ class Builder
|
||||
/**
|
||||
* Add a descending "order by" clause to the query.
|
||||
*
|
||||
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @param \Closure|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @return $this
|
||||
*/
|
||||
public function orderByDesc($column)
|
||||
@@ -2004,7 +2005,7 @@ class Builder
|
||||
/**
|
||||
* Add an "order by" clause for a timestamp to the query.
|
||||
*
|
||||
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @param \Closure|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @return $this
|
||||
*/
|
||||
public function latest($column = 'created_at')
|
||||
@@ -2015,7 +2016,7 @@ class Builder
|
||||
/**
|
||||
* Add an "order by" clause for a timestamp to the query.
|
||||
*
|
||||
* @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @param \Closure|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Query\Builder|\Illuminate\Database\Query\Expression|string $column
|
||||
* @return $this
|
||||
*/
|
||||
public function oldest($column = 'created_at')
|
||||
@@ -3000,6 +3001,27 @@ class Builder
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update records in a PostgreSQL database using the update from syntax.
|
||||
*
|
||||
* @param array $values
|
||||
* @return int
|
||||
*/
|
||||
public function updateFrom(array $values)
|
||||
{
|
||||
if (! method_exists($this->grammar, 'compileUpdateFrom')) {
|
||||
throw new LogicException('This database engine does not support the updateFrom method.');
|
||||
}
|
||||
|
||||
$this->applyBeforeQueryCallbacks();
|
||||
|
||||
$sql = $this->grammar->compileUpdateFrom($this, $values);
|
||||
|
||||
return $this->connection->update($sql, $this->cleanBindings(
|
||||
$this->grammar->prepareBindingsForUpdateFrom($this->bindings, $values)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update a record matching the attributes, and fill it with values.
|
||||
*
|
||||
@@ -3402,7 +3424,7 @@ class Builder
|
||||
/**
|
||||
* Die and dump the current SQL and bindings.
|
||||
*
|
||||
* @return void
|
||||
* @return never
|
||||
*/
|
||||
public function dd()
|
||||
{
|
||||
|
||||
@@ -260,6 +260,114 @@ class PostgresGrammar extends Grammar
|
||||
return "{$field} = jsonb_set({$field}::jsonb, {$path}, {$this->parameter($value)})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile an update from statement into SQL.
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query
|
||||
* @param array $values
|
||||
* @return string
|
||||
*/
|
||||
public function compileUpdateFrom(Builder $query, $values)
|
||||
{
|
||||
$table = $this->wrapTable($query->from);
|
||||
|
||||
// Each one of the columns in the update statements needs to be wrapped in the
|
||||
// keyword identifiers, also a place-holder needs to be created for each of
|
||||
// the values in the list of bindings so we can make the sets statements.
|
||||
$columns = $this->compileUpdateColumns($query, $values);
|
||||
|
||||
$from = '';
|
||||
|
||||
if (isset($query->joins)) {
|
||||
// When using Postgres, updates with joins list the joined tables in the from
|
||||
// clause, which is different than other systems like MySQL. Here, we will
|
||||
// compile out the tables that are joined and add them to a from clause.
|
||||
$froms = collect($query->joins)->map(function ($join) {
|
||||
return $this->wrapTable($join->table);
|
||||
})->all();
|
||||
|
||||
if (count($froms) > 0) {
|
||||
$from = ' from '.implode(', ', $froms);
|
||||
}
|
||||
}
|
||||
|
||||
$where = $this->compileUpdateWheres($query);
|
||||
|
||||
return trim("update {$table} set {$columns}{$from} {$where}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the additional where clauses for updates with joins.
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query
|
||||
* @return string
|
||||
*/
|
||||
protected function compileUpdateWheres(Builder $query)
|
||||
{
|
||||
$baseWheres = $this->compileWheres($query);
|
||||
|
||||
if (! isset($query->joins)) {
|
||||
return $baseWheres;
|
||||
}
|
||||
|
||||
// Once we compile the join constraints, we will either use them as the where
|
||||
// clause or append them to the existing base where clauses. If we need to
|
||||
// strip the leading boolean we will do so when using as the only where.
|
||||
$joinWheres = $this->compileUpdateJoinWheres($query);
|
||||
|
||||
if (trim($baseWheres) == '') {
|
||||
return 'where '.$this->removeLeadingBoolean($joinWheres);
|
||||
}
|
||||
|
||||
return $baseWheres.' '.$joinWheres;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the "join" clause where clauses for an update.
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query
|
||||
* @return string
|
||||
*/
|
||||
protected function compileUpdateJoinWheres(Builder $query)
|
||||
{
|
||||
$joinWheres = [];
|
||||
|
||||
// Here we will just loop through all of the join constraints and compile them
|
||||
// all out then implode them. This should give us "where" like syntax after
|
||||
// everything has been built and then we will join it to the real wheres.
|
||||
foreach ($query->joins as $join) {
|
||||
foreach ($join->wheres as $where) {
|
||||
$method = "where{$where['type']}";
|
||||
|
||||
$joinWheres[] = $where['boolean'].' '.$this->$method($query, $where);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', $joinWheres);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the bindings for an update statement.
|
||||
*
|
||||
* @param array $bindings
|
||||
* @param array $values
|
||||
* @return array
|
||||
*/
|
||||
public function prepareBindingsForUpdateFrom(array $bindings, array $values)
|
||||
{
|
||||
$values = collect($values)->map(function ($value, $column) {
|
||||
return is_array($value) || ($this->isJsonSelector($column) && ! $this->isExpression($value))
|
||||
? json_encode($value)
|
||||
: $value;
|
||||
})->all();
|
||||
|
||||
$bindingsWithoutWhere = Arr::except($bindings, ['select', 'where']);
|
||||
|
||||
return array_values(
|
||||
array_merge($values, $bindings['where'], Arr::flatten($bindingsWithoutWhere))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile an update statement with joins or limit into SQL.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,16 @@ class ForeignKeyDefinition extends Fluent
|
||||
return $this->onUpdate('cascade');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that updates should be restricted.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function restrictOnUpdate()
|
||||
{
|
||||
return $this->onUpdate('restrict');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that deletes should cascade.
|
||||
*
|
||||
|
||||
@@ -198,6 +198,7 @@ class ChangeColumn
|
||||
'binary',
|
||||
'boolean',
|
||||
'date',
|
||||
'dateTime',
|
||||
'decimal',
|
||||
'double',
|
||||
'float',
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ class MySqlSchemaState extends SchemaState
|
||||
*/
|
||||
protected function baseDumpCommand()
|
||||
{
|
||||
$command = 'mysqldump '.$this->connectionString().' --skip-add-locks --skip-comments --skip-set-charset --tz-utc';
|
||||
$command = 'mysqldump '.$this->connectionString().' --no-tablespaces --skip-add-locks --skip-comments --skip-set-charset --tz-utc';
|
||||
|
||||
if (! $this->connection->isMaria()) {
|
||||
$command .= ' --column-statistics=0 --set-gtid-purged=OFF';
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ abstract class SchemaState
|
||||
$this->files = $files ?: new Filesystem;
|
||||
|
||||
$this->processFactory = $processFactory ?: function (...$arguments) {
|
||||
return Process::fromShellCommandline(...$arguments);
|
||||
return Process::fromShellCommandline(...$arguments)->setTimeout(null);
|
||||
};
|
||||
|
||||
$this->handleOutputUsing(function () {
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).",
|
||||
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.2).",
|
||||
"fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).",
|
||||
"illuminate/console": "Required to use the database commands (^8.0).",
|
||||
"illuminate/events": "Required to use the observers with Eloquent (^8.0).",
|
||||
|
||||
Reference in New Issue
Block a user