diff --git a/composer.json b/composer.json index 7faba7bedc01..b2d3ea23a945 100644 --- a/composer.json +++ b/composer.json @@ -104,6 +104,7 @@ "fakerphp/faker": "^1.24", "guzzlehttp/promises": "^2.0.3", "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", "league/flysystem-aws-s3-v3": "^3.25.1", "league/flysystem-ftp": "^3.25.1", "league/flysystem-path-prefixing": "^3.25.1", diff --git a/pint.json b/pint.json new file mode 100644 index 000000000000..304eebba7ebd --- /dev/null +++ b/pint.json @@ -0,0 +1,9 @@ +{ + "preset": "empty", + "rules": { + "method_chaining_indentation": true + }, + "exclude": [ + "tests" + ] +} diff --git a/src/Illuminate/Auth/DatabaseUserProvider.php b/src/Illuminate/Auth/DatabaseUserProvider.php index aaaafd8a8b45..def86b346a55 100755 --- a/src/Illuminate/Auth/DatabaseUserProvider.php +++ b/src/Illuminate/Auth/DatabaseUserProvider.php @@ -87,8 +87,8 @@ public function retrieveByToken($identifier, #[\SensitiveParameter] $token) public function updateRememberToken(UserContract $user, #[\SensitiveParameter] $token) { $this->connection->table($this->table) - ->where($user->getAuthIdentifierName(), $user->getAuthIdentifier()) - ->update([$user->getRememberTokenName() => $token]); + ->where($user->getAuthIdentifierName(), $user->getAuthIdentifier()) + ->update([$user->getRememberTokenName() => $token]); } /** diff --git a/src/Illuminate/Auth/EloquentUserProvider.php b/src/Illuminate/Auth/EloquentUserProvider.php index 77c8fef712b1..dc7a21ecac5d 100755 --- a/src/Illuminate/Auth/EloquentUserProvider.php +++ b/src/Illuminate/Auth/EloquentUserProvider.php @@ -55,8 +55,8 @@ public function retrieveById($identifier) $model = $this->createModel(); return $this->newModelQuery($model) - ->where($model->getAuthIdentifierName(), $identifier) - ->first(); + ->where($model->getAuthIdentifierName(), $identifier) + ->first(); } /** diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index 5abccd59bafb..eb21f2c0662f 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -372,6 +372,8 @@ protected function retrieveChannelOptions($channel) */ protected function channelNameMatchesPattern($channel, $pattern) { + $pattern = str_replace('.', '\.', $pattern); + return preg_match('/^'.preg_replace('/\{(.*?)\}/', '([^\.]+)', $pattern).'$/', $channel); } diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 2799de29a8fa..962d814183a8 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -135,7 +135,7 @@ protected function decodePusherResponse($request, $response) } return response()->json(json_decode($response, true)) - ->withCallback($request->callback); + ->withCallback($request->callback); } /** diff --git a/src/Illuminate/Bus/Batch.php b/src/Illuminate/Bus/Batch.php index d551abb4e19e..bcfb898cb940 100644 --- a/src/Illuminate/Bus/Batch.php +++ b/src/Illuminate/Bus/Batch.php @@ -171,9 +171,9 @@ public function add($jobs) return with($this->prepareBatchedChain($job), function ($chain) { return $chain->first() - ->allOnQueue($this->options['queue'] ?? null) - ->allOnConnection($this->options['connection'] ?? null) - ->chain($chain->slice(1)->values()->all()); + ->allOnQueue($this->options['queue'] ?? null) + ->allOnConnection($this->options['connection'] ?? null) + ->chain($chain->slice(1)->values()->all()); }); } else { $job->withBatchId($this->id); diff --git a/src/Illuminate/Bus/DatabaseBatchRepository.php b/src/Illuminate/Bus/DatabaseBatchRepository.php index 2e0c7c68a9e6..31bd39878c57 100644 --- a/src/Illuminate/Bus/DatabaseBatchRepository.php +++ b/src/Illuminate/Bus/DatabaseBatchRepository.php @@ -58,14 +58,14 @@ public function __construct(BatchFactory $factory, Connection $connection, strin public function get($limit = 50, $before = null) { return $this->connection->table($this->table) - ->orderByDesc('id') - ->take($limit) - ->when($before, fn ($q) => $q->where('id', '<', $before)) - ->get() - ->map(function ($batch) { - return $this->toBatch($batch); - }) - ->all(); + ->orderByDesc('id') + ->take($limit) + ->when($before, fn ($q) => $q->where('id', '<', $before)) + ->get() + ->map(function ($batch) { + return $this->toBatch($batch); + }) + ->all(); } /** @@ -77,9 +77,9 @@ public function get($limit = 50, $before = null) public function find(string $batchId) { $batch = $this->connection->table($this->table) - ->useWritePdo() - ->where('id', $batchId) - ->first(); + ->useWritePdo() + ->where('id', $batchId) + ->first(); if ($batch) { return $this->toBatch($batch); @@ -185,8 +185,8 @@ protected function updateAtomicValues(string $batchId, Closure $callback) { return $this->connection->transaction(function () use ($batchId, $callback) { $batch = $this->connection->table($this->table)->where('id', $batchId) - ->lockForUpdate() - ->first(); + ->lockForUpdate() + ->first(); return is_null($batch) ? [] : tap($callback($batch), function ($values) use ($batchId) { $this->connection->table($this->table)->where('id', $batchId)->update($values); diff --git a/src/Illuminate/Cache/DatabaseLock.php b/src/Illuminate/Cache/DatabaseLock.php index 715d141c0d45..506696fdbd16 100644 --- a/src/Illuminate/Cache/DatabaseLock.php +++ b/src/Illuminate/Cache/DatabaseLock.php @@ -112,9 +112,9 @@ public function release() { if ($this->isOwnedByCurrentProcess()) { $this->connection->table($this->table) - ->where('key', $this->name) - ->where('owner', $this->owner) - ->delete(); + ->where('key', $this->name) + ->where('owner', $this->owner) + ->delete(); return true; } @@ -130,8 +130,8 @@ public function release() public function forceRelease() { $this->connection->table($this->table) - ->where('key', $this->name) - ->delete(); + ->where('key', $this->name) + ->delete(); } /** diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index 15ca30b322b7..56564c2988e3 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -263,7 +263,7 @@ protected function incrementOrDecrement($key, $value, Closure $callback) $prefixed = $this->prefix.$key; $cache = $this->table()->where('key', $prefixed) - ->lockForUpdate()->first(); + ->lockForUpdate()->first(); // If there is no value in the cache, we will return false here. Otherwise the // value will be decrypted and we will proceed with this function to either diff --git a/src/Illuminate/Cache/MemcachedStore.php b/src/Illuminate/Cache/MemcachedStore.php index 88198d9222bf..5197c2df71f5 100755 --- a/src/Illuminate/Cache/MemcachedStore.php +++ b/src/Illuminate/Cache/MemcachedStore.php @@ -45,7 +45,7 @@ public function __construct($memcached, $prefix = '') $this->memcached = $memcached; $this->onVersionThree = (new ReflectionMethod('Memcached', 'getMulti')) - ->getNumberOfParameters() == 2; + ->getNumberOfParameters() == 2; } /** diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index a01f4aedb209..a5f1df9db137 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -638,7 +638,7 @@ protected function getSeconds($ttl) * * @return string|null */ - protected function getName() + public function getName() { return $this->config['store'] ?? null; } diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index c2faf2d2f7ee..4fcca09b1f84 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -149,6 +149,10 @@ public function collapse() */ public function collapseWithKeys() { + if (! $this->items) { + return new static; + } + $results = []; foreach ($this->items as $key => $values) { diff --git a/src/Illuminate/Console/Scheduling/ManagesFrequencies.php b/src/Illuminate/Console/Scheduling/ManagesFrequencies.php index 105334e01b43..619d852e4817 100644 --- a/src/Illuminate/Console/Scheduling/ManagesFrequencies.php +++ b/src/Illuminate/Console/Scheduling/ManagesFrequencies.php @@ -391,7 +391,7 @@ protected function hourBasedSchedule($minutes, $hours) $hours = is_array($hours) ? implode(',', $hours) : $hours; return $this->spliceIntoPosition(1, $minutes) - ->spliceIntoPosition(2, $hours); + ->spliceIntoPosition(2, $hours); } /** @@ -492,8 +492,8 @@ public function sundays() public function weekly() { return $this->spliceIntoPosition(1, 0) - ->spliceIntoPosition(2, 0) - ->spliceIntoPosition(5, 0); + ->spliceIntoPosition(2, 0) + ->spliceIntoPosition(5, 0); } /** @@ -518,8 +518,8 @@ public function weeklyOn($dayOfWeek, $time = '0:0') public function monthly() { return $this->spliceIntoPosition(1, 0) - ->spliceIntoPosition(2, 0) - ->spliceIntoPosition(3, 1); + ->spliceIntoPosition(2, 0) + ->spliceIntoPosition(3, 1); } /** @@ -574,9 +574,9 @@ public function lastDayOfMonth($time = '0:0') public function quarterly() { return $this->spliceIntoPosition(1, 0) - ->spliceIntoPosition(2, 0) - ->spliceIntoPosition(3, 1) - ->spliceIntoPosition(4, '1-12/3'); + ->spliceIntoPosition(2, 0) + ->spliceIntoPosition(3, 1) + ->spliceIntoPosition(4, '1-12/3'); } /** @@ -591,7 +591,7 @@ public function quarterlyOn($dayOfQuarter = 1, $time = '0:0') $this->dailyAt($time); return $this->spliceIntoPosition(3, $dayOfQuarter) - ->spliceIntoPosition(4, '1-12/3'); + ->spliceIntoPosition(4, '1-12/3'); } /** @@ -602,9 +602,9 @@ public function quarterlyOn($dayOfQuarter = 1, $time = '0:0') public function yearly() { return $this->spliceIntoPosition(1, 0) - ->spliceIntoPosition(2, 0) - ->spliceIntoPosition(3, 1) - ->spliceIntoPosition(4, 1); + ->spliceIntoPosition(2, 0) + ->spliceIntoPosition(3, 1) + ->spliceIntoPosition(4, 1); } /** @@ -620,7 +620,7 @@ public function yearlyOn($month = 1, $dayOfMonth = 1, $time = '0:0') $this->dailyAt($time); return $this->spliceIntoPosition(3, $dayOfMonth) - ->spliceIntoPosition(4, $month); + ->spliceIntoPosition(4, $month); } /** diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 692dfdee2f67..64f2eb25bf2b 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -467,7 +467,7 @@ public function cursor($query, $bindings = [], $useReadPdo = true) // mode and prepare the bindings for the query. Once that's done we will be // ready to execute the query against the database and return the cursor. $statement = $this->prepared($this->getPdoForSelect($useReadPdo) - ->prepare($query)); + ->prepare($query)); $this->bindValues( $statement, $this->prepareBindings($bindings) diff --git a/src/Illuminate/Database/Console/DumpCommand.php b/src/Illuminate/Database/Console/DumpCommand.php index 64148e90f9ac..b27d6c66a93c 100644 --- a/src/Illuminate/Database/Console/DumpCommand.php +++ b/src/Illuminate/Database/Console/DumpCommand.php @@ -77,10 +77,10 @@ protected function schemaState(Connection $connection) $migrationTable = is_array($migrations) ? ($migrations['table'] ?? 'migrations') : $migrations; return $connection->getSchemaState() - ->withMigrationTable($migrationTable) - ->handleOutputUsing(function ($type, $buffer) { - $this->output->write($buffer); - }); + ->withMigrationTable($migrationTable) + ->handleOutputUsing(function ($type, $buffer) { + $this->output->write($buffer); + }); } /** diff --git a/src/Illuminate/Database/Console/Migrations/StatusCommand.php b/src/Illuminate/Database/Console/Migrations/StatusCommand.php index 191983288739..378c4a720d26 100644 --- a/src/Illuminate/Database/Console/Migrations/StatusCommand.php +++ b/src/Illuminate/Database/Console/Migrations/StatusCommand.php @@ -101,19 +101,19 @@ public function handle() protected function getStatusFor(array $ran, array $batches) { return (new Collection($this->getAllMigrationFiles())) - ->map(function ($migration) use ($ran, $batches) { - $migrationName = $this->migrator->getMigrationName($migration); + ->map(function ($migration) use ($ran, $batches) { + $migrationName = $this->migrator->getMigrationName($migration); - $status = in_array($migrationName, $ran) - ? 'Ran' - : 'Pending'; + $status = in_array($migrationName, $ran) + ? 'Ran' + : 'Pending'; - if (in_array($migrationName, $ran)) { - $status = '['.$batches[$migrationName].'] '.$status; - } + if (in_array($migrationName, $ran)) { + $status = '['.$batches[$migrationName].'] '.$status; + } - return [$migrationName, $status]; - }); + return [$migrationName, $status]; + }); } /** diff --git a/src/Illuminate/Database/Console/Seeds/SeedCommand.php b/src/Illuminate/Database/Console/Seeds/SeedCommand.php index 0d4dbd5ad4fe..4ce2b0213129 100644 --- a/src/Illuminate/Database/Console/Seeds/SeedCommand.php +++ b/src/Illuminate/Database/Console/Seeds/SeedCommand.php @@ -96,8 +96,8 @@ protected function getSeeder() } return $this->laravel->make($class) - ->setContainer($this->laravel) - ->setCommand($this); + ->setContainer($this->laravel) + ->setCommand($this); } /** diff --git a/src/Illuminate/Database/Console/WipeCommand.php b/src/Illuminate/Database/Console/WipeCommand.php index f756dd121de0..754c9eea8414 100644 --- a/src/Illuminate/Database/Console/WipeCommand.php +++ b/src/Illuminate/Database/Console/WipeCommand.php @@ -69,8 +69,8 @@ public function handle() protected function dropAllTables($database) { $this->laravel['db']->connection($database) - ->getSchemaBuilder() - ->dropAllTables(); + ->getSchemaBuilder() + ->dropAllTables(); } /** @@ -82,8 +82,8 @@ protected function dropAllTables($database) protected function dropAllViews($database) { $this->laravel['db']->connection($database) - ->getSchemaBuilder() - ->dropAllViews(); + ->getSchemaBuilder() + ->dropAllViews(); } /** @@ -95,8 +95,8 @@ protected function dropAllViews($database) protected function dropAllTypes($database) { $this->laravel['db']->connection($database) - ->getSchemaBuilder() - ->dropAllTypes(); + ->getSchemaBuilder() + ->dropAllTypes(); } /** diff --git a/src/Illuminate/Database/DatabaseManager.php b/src/Illuminate/Database/DatabaseManager.php index 6f8867c4e51d..34ba2cc01bd9 100755 --- a/src/Illuminate/Database/DatabaseManager.php +++ b/src/Illuminate/Database/DatabaseManager.php @@ -228,7 +228,7 @@ protected function configuration($name) } return (new ConfigurationUrlParser) - ->parseConfiguration($config); + ->parseConfiguration($config); } /** @@ -374,8 +374,8 @@ protected function refreshPdoConnections($name) ); return $this->connections[$name] - ->setPdo($fresh->getRawPdo()) - ->setReadPdo($fresh->getRawReadPdo()); + ->setPdo($fresh->getRawPdo()) + ->setReadPdo($fresh->getRawReadPdo()); } /** diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index e3ee48f9bd55..81a91ef271cf 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -53,6 +53,13 @@ class Builder implements BuilderContract */ protected $model; + /** + * The attributes that should be added to new models created by this builder. + * + * @var array + */ + public $pendingAttributes = []; + /** * The relationships that should be eager loaded. * @@ -622,6 +629,25 @@ public function updateOrCreate(array $attributes, array $values = []) }); } + /** + * Create a record matching the attributes, or increment the existing record. + * + * @param array $attributes + * @param string $column + * @param int|float $default + * @param int|float $step + * @param array $extra + * @return TModel + */ + public function incrementOrCreate(array $attributes, string $column = 'count', $default = 1, $step = 1, array $extra = []) + { + return tap($this->firstOrCreate($attributes, [$column => $default]), function ($instance) use ($column, $step, $extra) { + if (! $instance->wasRecentlyCreated) { + $instance->increment($column, $step, $extra); + } + }); + } + /** * Execute the query and get the first result or throw an exception. * @@ -1603,6 +1629,8 @@ public function withOnly($relations) */ public function newModelInstance($attributes = []) { + $attributes = array_merge($this->pendingAttributes, $attributes); + return $this->model->newInstance($attributes)->setConnection( $this->query->getConnection()->getName() ); @@ -1763,6 +1791,30 @@ protected function addNestedWiths($name, $results) return $results; } + /** + * Specify attributes that should be added to any new models created by this builder. + * + * The given key / value pairs will also be added as where conditions to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|array|string $attributes + * @param mixed $value + * @return $this + */ + public function withAttributes(Expression|array|string $attributes, $value = null) + { + if (! is_array($attributes)) { + $attributes = [$attributes => $value]; + } + + foreach ($attributes as $column => $value) { + $this->where($this->qualifyColumn($column), $value); + } + + $this->pendingAttributes = array_merge($this->pendingAttributes, $attributes); + + return $this; + } + /** * Apply query-time casts to the model instance. * diff --git a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php index a81337729c7f..67229b4a0332 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php @@ -220,8 +220,8 @@ protected function isGuardableColumn($key) if (! isset(static::$guardableColumns[get_class($this)])) { $columns = $this->getConnection() - ->getSchemaBuilder() - ->getColumnListing($this->getTable()); + ->getSchemaBuilder() + ->getColumnListing($this->getTable()); if (empty($columns)) { return true; diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 56d116454621..1e602ff35cb8 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -257,7 +257,7 @@ public function hasMorph($relation, $types, $operator = '>=', $count = 1, $boole } $query->where($this->qualifyColumn($relation->getMorphType()), '=', (new $type)->getMorphClass()) - ->whereHas($belongsTo, $callback, $operator, $count); + ->whereHas($belongsTo, $callback, $operator, $count); }); } }, null, null, $boolean); diff --git a/src/Illuminate/Database/Eloquent/Factories/HasFactory.php b/src/Illuminate/Database/Eloquent/Factories/HasFactory.php index 2078d9f025f3..ca37657def04 100644 --- a/src/Illuminate/Database/Eloquent/Factories/HasFactory.php +++ b/src/Illuminate/Database/Eloquent/Factories/HasFactory.php @@ -21,8 +21,8 @@ public static function factory($count = null, $state = []) $factory = static::newFactory() ?? Factory::factoryForModel(static::class); return $factory - ->count(is_numeric($count) ? $count : null) - ->state(is_callable($count) || is_array($count) ? $count : $state); + ->count(is_numeric($count) ? $count : null) + ->state(is_callable($count) || is_array($count) ? $count : $state); } /** diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 5d19f7f17f83..08e3c6488b6e 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -38,7 +38,7 @@ abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToSt Concerns\GuardsAttributes, Concerns\PreventsCircularRecursion, ForwardsCalls; - /** @use HasCollection<\Illuminate\Database\Eloquent\Collection> */ + /** @use HasCollection<\Illuminate\Database\Eloquent\Collection> */ use HasCollection; /** diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 500dcc20842a..a51d4e16fc71 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -1351,6 +1351,8 @@ public function saveManyQuietly($models, array $pivotAttributes = []) */ public function create(array $attributes = [], array $joining = [], $touch = true) { + $attributes = array_merge($this->getQuery()->pendingAttributes, $attributes); + $instance = $this->related->newInstance($attributes); // Once we save the related model, we need to attach it to the base model via diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/ComparesRelatedModels.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/ComparesRelatedModels.php index ca06698875e8..3dccf1310765 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/ComparesRelatedModels.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/ComparesRelatedModels.php @@ -22,8 +22,8 @@ public function is($model) if ($match && $this instanceof SupportsPartialRelations && $this->isOneOfMany()) { return $this->query - ->whereKey($model->getKey()) - ->exists(); + ->whereKey($model->getKey()) + ->exists(); } return $match; diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 77e4a48c0bef..adbbefcf8c09 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -91,7 +91,7 @@ public function sync($ids, $detaching = true) // in this joining table. We'll spin through the given IDs, checking to see // if they exist in the array of current ones, and if not we will insert. $current = $this->getCurrentlyAttachedPivots() - ->pluck($this->relatedPivotKey)->all(); + ->pluck($this->relatedPivotKey)->all(); $records = $this->formatRecordsList($this->parseIds($ids)); @@ -240,9 +240,9 @@ public function updateExistingPivot($id, array $attributes, $touch = true) protected function updateExistingPivotUsingCustomClass($id, array $attributes, $touch) { $pivot = $this->getCurrentlyAttachedPivots() - ->where($this->foreignPivotKey, $this->parent->{$this->parentKey}) - ->where($this->relatedPivotKey, $this->parseId($id)) - ->first(); + ->where($this->foreignPivotKey, $this->parent->{$this->parentKey}) + ->where($this->relatedPivotKey, $this->parseId($id)) + ->first(); $updated = $pivot ? $pivot->fill($attributes)->isDirty() : false; diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 0ba60ccc9cf7..de94098dcfeb 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -447,6 +447,12 @@ protected function setForeignAttributesForCreate(Model $model) { $model->setAttribute($this->getForeignKeyName(), $this->getParentKey()); + foreach ($this->getQuery()->pendingAttributes as $key => $value) { + if (! $model->hasAttribute($key)) { + $model->setAttribute($key, $value); + } + } + $this->applyInverseRelationToModel($model); } diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 3478f73859d4..44531957d5b7 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -96,6 +96,12 @@ protected function setForeignAttributesForCreate(Model $model) $model->{$this->getMorphType()} = $this->morphClass; + foreach ($this->getQuery()->pendingAttributes as $key => $value) { + if (! $model->hasAttribute($key)) { + $model->setAttribute($key, $value); + } + } + $this->applyInverseRelationToModel($model); } diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php index 6a3f395e73a6..566e198c9bea 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php @@ -148,9 +148,9 @@ public function newQueryForRestoration($ids) $segments = explode(':', $ids); return $this->newQueryWithoutScopes() - ->where($segments[0], $segments[1]) - ->where($segments[2], $segments[3]) - ->where($segments[4], $segments[5]); + ->where($segments[0], $segments[1]) + ->where($segments[2], $segments[3]) + ->where($segments[4], $segments[5]); } /** @@ -174,8 +174,8 @@ protected function newQueryForCollectionRestoration(array $ids) $query->orWhere(function ($query) use ($segments) { return $query->where($segments[0], $segments[1]) - ->where($segments[2], $segments[3]) - ->where($segments[4], $segments[5]); + ->where($segments[2], $segments[3]) + ->where($segments[4], $segments[5]); }); } diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index e743e93ea379..cc42984552a1 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -146,14 +146,14 @@ protected function getResultsByType($type) $ownerKey = $this->ownerKey ?? $instance->getKeyName(); $query = $this->replayMacros($instance->newQuery()) - ->mergeConstraintsFrom($this->getQuery()) - ->with(array_merge( - $this->getQuery()->getEagerLoads(), - (array) ($this->morphableEagerLoads[get_class($instance)] ?? []) - )) - ->withCount( - (array) ($this->morphableEagerLoadCounts[get_class($instance)] ?? []) - ); + ->mergeConstraintsFrom($this->getQuery()) + ->with(array_merge( + $this->getQuery()->getEagerLoads(), + (array) ($this->morphableEagerLoads[get_class($instance)] ?? []) + )) + ->withCount( + (array) ($this->morphableEagerLoadCounts[get_class($instance)] ?? []) + ); if ($callback = ($this->morphableConstraints[get_class($instance)] ?? null)) { $callback($query); diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index 9cb7445374d3..157202bccf21 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -129,7 +129,7 @@ protected function getCurrentlyAttachedPivots() return parent::getCurrentlyAttachedPivots()->map(function ($record) { return $record instanceof MorphPivot ? $record->setMorphType($this->morphType) - ->setMorphClass($this->morphClass) + ->setMorphClass($this->morphClass) : $record; }); } @@ -161,9 +161,9 @@ public function newPivot(array $attributes = [], $exists = false) : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists); $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey) - ->setRelatedModel($this->related) - ->setMorphType($this->morphType) - ->setMorphClass($this->morphClass); + ->setRelatedModel($this->related) + ->setMorphType($this->morphType) + ->setMorphClass($this->morphClass); return $pivot; } diff --git a/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php b/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php index cf020d64db06..c5d5252854f1 100755 --- a/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php +++ b/src/Illuminate/Database/Migrations/DatabaseMigrationRepository.php @@ -48,9 +48,9 @@ public function __construct(Resolver $resolver, $table) public function getRan() { return $this->table() - ->orderBy('batch', 'asc') - ->orderBy('migration', 'asc') - ->pluck('migration')->all(); + ->orderBy('batch', 'asc') + ->orderBy('migration', 'asc') + ->pluck('migration')->all(); } /** @@ -64,8 +64,8 @@ public function getMigrations($steps) $query = $this->table()->where('batch', '>=', '1'); return $query->orderBy('batch', 'desc') - ->orderBy('migration', 'desc') - ->take($steps)->get()->all(); + ->orderBy('migration', 'desc') + ->take($steps)->get()->all(); } /** @@ -103,9 +103,9 @@ public function getLast() public function getMigrationBatches() { return $this->table() - ->orderBy('batch', 'asc') - ->orderBy('migration', 'asc') - ->pluck('batch', 'migration')->all(); + ->orderBy('batch', 'asc') + ->orderBy('migration', 'asc') + ->pluck('batch', 'migration')->all(); } /** diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index c94324096e9c..4e7067a1f3aa 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2820,7 +2820,7 @@ public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') } return $this->orderBy($column, 'desc') - ->limit($perPage); + ->limit($perPage); } /** @@ -2840,7 +2840,7 @@ public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') } return $this->orderBy($column, 'asc') - ->limit($perPage); + ->limit($perPage); } /** @@ -2873,10 +2873,10 @@ public function reorder($column = null, $direction = 'asc') protected function removeExistingOrdersFor($column) { return (new Collection($this->orders)) - ->reject(function ($order) use ($column) { - return isset($order['column']) - ? $order['column'] === $column : false; - })->values()->all(); + ->reject(function ($order) use ($column) { + return isset($order['column']) + ? $order['column'] === $column : false; + })->values()->all(); } /** @@ -3307,9 +3307,9 @@ protected function runPaginationCountQuery($columns = ['*']) $without = $this->unions ? ['unionOrders', 'unionLimit', 'unionOffset'] : ['columns', 'orders', 'limit', 'offset']; return $this->cloneWithout($without) - ->cloneWithoutBindings($this->unions ? ['unionOrder'] : ['select', 'order']) - ->setAggregate('count', $this->withoutSelectAliases($columns)) - ->get()->all(); + ->cloneWithoutBindings($this->unions ? ['unionOrder'] : ['select', 'order']) + ->setAggregate('count', $this->withoutSelectAliases($columns)) + ->get()->all(); } /** @@ -3320,7 +3320,7 @@ protected function runPaginationCountQuery($columns = ['*']) protected function cloneForPaginationCount() { return $this->cloneWithout(['orders', 'limit', 'offset']) - ->cloneWithoutBindings(['order']); + ->cloneWithoutBindings(['order']); } /** @@ -3628,9 +3628,9 @@ public function average($column) public function aggregate($function, $columns = ['*']) { $results = $this->cloneWithout($this->unions || $this->havings ? [] : ['columns']) - ->cloneWithoutBindings($this->unions || $this->havings ? [] : ['select']) - ->setAggregate($function, $columns) - ->get($columns); + ->cloneWithoutBindings($this->unions || $this->havings ? [] : ['select']) + ->setAggregate($function, $columns) + ->get($columns); if (! $results->isEmpty()) { return array_change_key_case((array) $results[0])['aggregate']; @@ -4267,12 +4267,12 @@ public function mergeBindings(self $query) public function cleanBindings(array $bindings) { return (new Collection($bindings)) - ->reject(function ($binding) { - return $binding instanceof ExpressionContract; - }) - ->map($this->castBinding(...)) - ->values() - ->all(); + ->reject(function ($binding) { + return $binding instanceof ExpressionContract; + }) + ->map($this->castBinding(...)) + ->values() + ->all(); } /** diff --git a/src/Illuminate/Database/Query/Expression.php b/src/Illuminate/Database/Query/Expression.php index 7233e11dc091..1da00d5e9bc1 100755 --- a/src/Illuminate/Database/Query/Expression.php +++ b/src/Illuminate/Database/Query/Expression.php @@ -5,31 +5,27 @@ use Illuminate\Contracts\Database\Query\Expression as ExpressionContract; use Illuminate\Database\Grammar; +/** + * @template TValue of string|int|float + */ class Expression implements ExpressionContract { - /** - * The value of the expression. - * - * @var string|int|float - */ - protected $value; - /** * Create a new raw query expression. * - * @param string|int|float $value + * @param TValue $value * @return void */ - public function __construct($value) - { - $this->value = $value; + public function __construct( + protected $value + ) { } /** * Get the value of the expression. * * @param \Illuminate\Database\Grammar $grammar - * @return string|int|float + * @return TValue */ public function getValue(Grammar $grammar) { diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 20028ffc1bab..462abc7f2ddf 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -840,12 +840,12 @@ public function registered($callback) public function registerConfiguredProviders() { $providers = (new Collection($this->make('config')->get('app.providers'))) - ->partition(fn ($provider) => str_starts_with($provider, 'Illuminate\\')); + ->partition(fn ($provider) => str_starts_with($provider, 'Illuminate\\')); $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]); (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath())) - ->load($providers->collapse()->toArray()); + ->load($providers->collapse()->toArray()); $this->fireAppCallbacks($this->registeredCallbacks); } diff --git a/src/Illuminate/Foundation/Bus/PendingDispatch.php b/src/Illuminate/Foundation/Bus/PendingDispatch.php index d7a299d42f81..f7f2d0ed71bc 100644 --- a/src/Illuminate/Foundation/Bus/PendingDispatch.php +++ b/src/Illuminate/Foundation/Bus/PendingDispatch.php @@ -176,7 +176,7 @@ protected function shouldDispatch() } return (new UniqueLock(Container::getInstance()->make(Cache::class))) - ->acquire($this->job); + ->acquire($this->job); } /** diff --git a/src/Illuminate/Foundation/Console/BroadcastingInstallCommand.php b/src/Illuminate/Foundation/Console/BroadcastingInstallCommand.php index a1f7228830bd..93a8d6cf365a 100644 --- a/src/Illuminate/Foundation/Console/BroadcastingInstallCommand.php +++ b/src/Illuminate/Foundation/Console/BroadcastingInstallCommand.php @@ -200,7 +200,7 @@ protected function installNodeDependencies() } $command = Process::command(implode(' && ', $commands)) - ->path(base_path()); + ->path(base_path()); if (! windows_os()) { $command->tty(true); diff --git a/src/Illuminate/Foundation/Console/Kernel.php b/src/Illuminate/Foundation/Console/Kernel.php index 7a119cf85bab..e798169ea765 100644 --- a/src/Illuminate/Foundation/Console/Kernel.php +++ b/src/Illuminate/Foundation/Console/Kernel.php @@ -538,8 +538,8 @@ protected function getArtisan() { if (is_null($this->artisan)) { $this->artisan = (new Artisan($this->app, $this->events, $this->app->version())) - ->resolveCommands($this->commands) - ->setContainerCommandLoader(); + ->resolveCommands($this->commands) + ->setContainerCommandLoader(); if ($this->symfonyDispatcher instanceof EventDispatcher) { $this->artisan->setDispatcher($this->symfonyDispatcher); diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index 44c521b01900..b6c416b1363b 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -223,7 +223,7 @@ protected function isVendorRoute(Route $route) { if ($route->action['uses'] instanceof Closure) { $path = (new ReflectionFunction($route->action['uses'])) - ->getFileName(); + ->getFileName(); } elseif (is_string($route->action['uses']) && str_contains($route->action['uses'], 'SerializableClosure')) { return false; @@ -233,7 +233,7 @@ protected function isVendorRoute(Route $route) } $path = (new ReflectionClass($route->getControllerClass())) - ->getFileName(); + ->getFileName(); } else { return false; } diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 9e25dad5cdeb..52f10c379ee7 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -483,10 +483,10 @@ public function stopIgnoring(array|string $exceptions) $exceptions = Arr::wrap($exceptions); $this->dontReport = (new Collection($this->dontReport)) - ->reject(fn ($ignored) => in_array($ignored, $exceptions))->values()->all(); + ->reject(fn ($ignored) => in_array($ignored, $exceptions))->values()->all(); $this->internalDontReport = (new Collection($this->internalDontReport)) - ->reject(fn ($ignored) => in_array($ignored, $exceptions))->values()->all(); + ->reject(fn ($ignored) => in_array($ignored, $exceptions))->values()->all(); return $this; } @@ -748,8 +748,8 @@ protected function convertValidationExceptionToResponse(ValidationException $e, protected function invalid($request, ValidationException $exception) { return redirect($exception->redirectTo ?? url()->previous()) - ->withInput(Arr::except($request->input(), $this->dontFlash)) - ->withErrors($exception->errors(), $request->input('_error_bag', $exception->errorBag)); + ->withInput(Arr::except($request->input(), $this->dontFlash)) + ->withErrors($exception->errors(), $request->input('_error_bag', $exception->errorBag)); } /** diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 7c746f24c2f2..268c57e1a91f 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -166,8 +166,8 @@ protected function failedValidation(Validator $validator) $exception = $validator->getException(); throw (new $exception($validator)) - ->errorBag($this->errorBag) - ->redirectTo($this->getRedirectUrl()); + ->errorBag($this->errorBag) + ->redirectTo($this->getRedirectUrl()); } /** diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index 90c9fb010f4d..02c0f3fdbd95 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -171,9 +171,9 @@ protected function sendRequestThroughRouter($request) $this->bootstrap(); return (new Pipeline($this->app)) - ->send($request) - ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) - ->then($this->dispatchToRouter()); + ->send($request) + ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) + ->then($this->dispatchToRouter()); } /** diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index e993d714179d..fca2cc61057f 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -239,7 +239,7 @@ protected function registerExceptionTracking() $this->app->make('events')->listen(MessageLogged::class, function ($event) { if (isset($event->context['exception'])) { $this->app->make(LoggedExceptionCollection::class) - ->push($event->context['exception']); + ->push($event->context['exception']); } }); } diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 37e35477411d..788d6ed54b4b 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -146,18 +146,18 @@ public function shouldDiscoverEvents() public function discoverEvents() { return (new Collection($this->discoverEventsWithin())) - ->flatMap(function ($directory) { - return glob($directory, GLOB_ONLYDIR); - }) - ->reject(function ($directory) { - return ! is_dir($directory); - }) - ->reduce(function ($discovered, $directory) { - return array_merge_recursive( - $discovered, - DiscoverEvents::within($directory, $this->eventDiscoveryBasePath()) - ); - }, []); + ->flatMap(function ($directory) { + return glob($directory, GLOB_ONLYDIR); + }) + ->reject(function ($directory) { + return ! is_dir($directory); + }) + ->reduce(function ($discovered, $directory) { + return array_merge_recursive( + $discovered, + DiscoverEvents::within($directory, $this->eventDiscoveryBasePath()) + ); + }, []); } /** diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json b/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json index 37c0dc03e8bc..5ffbe5243951 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/package-lock.json @@ -11,7 +11,7 @@ "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "tippy.js": "^6.3.7", - "vite": "^5.2.14", + "vite": "^5.4.12", "vite-require": "^0.2.3" } }, @@ -27,12 +27,13 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "aix" @@ -42,12 +43,13 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -57,12 +59,13 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -72,12 +75,13 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -87,12 +91,13 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -102,12 +107,13 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -117,12 +123,13 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -132,12 +139,13 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -147,12 +155,13 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -162,12 +171,13 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -177,12 +187,13 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -192,12 +203,13 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -207,12 +219,13 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -222,12 +235,13 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -237,12 +251,13 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -252,12 +267,13 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -267,12 +283,13 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -282,12 +299,13 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -297,12 +315,13 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -312,12 +331,13 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "sunos" @@ -327,12 +347,13 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -342,12 +363,13 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -357,12 +379,13 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1023,10 +1046,11 @@ "integrity": "sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==" }, "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -1034,29 +1058,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -1462,9 +1486,10 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -1494,9 +1519,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", "funding": [ { "type": "opencollective", @@ -1511,10 +1536,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -1794,9 +1820,10 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -2079,13 +2106,14 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "5.2.14", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.14.tgz", - "integrity": "sha512-TFQLuwWLPms+NBNlh0D9LZQ+HXW471COABxw/9TEUBrjuHMo9BrYBPrN/SYAwIuVL+rLerycxiLT41t4f5MZpA==", + "version": "5.4.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.12.tgz", + "integrity": "sha512-KwUaKB27TvWwDJr1GjjWthLMATbGEbeWYZIbGZ5qFIsgPP3vWzLu4cVooqhm5/Z2SPDUMjyPVjTztm5tYKwQxA==", + "license": "MIT", "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -2104,6 +2132,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -2121,6 +2150,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, diff --git a/src/Illuminate/Foundation/resources/exceptions/renderer/package.json b/src/Illuminate/Foundation/resources/exceptions/renderer/package.json index af1daa2d9496..588c6aed9d86 100644 --- a/src/Illuminate/Foundation/resources/exceptions/renderer/package.json +++ b/src/Illuminate/Foundation/resources/exceptions/renderer/package.json @@ -12,7 +12,7 @@ "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "tippy.js": "^6.3.7", - "vite": "^5.2.14", + "vite": "^5.4.12", "vite-require": "^0.2.3" } } diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 6ece4cc79dd6..839c6e6debd5 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -1326,10 +1326,10 @@ public function buildStubHandler() return function ($handler) { return function ($request, $options) use ($handler) { $response = ($this->stubCallbacks ?? new Collection) - ->map - ->__invoke((new Request($request))->withData($options['laravel_data']), $options) - ->filter() - ->first(); + ->map + ->__invoke((new Request($request))->withData($options['laravel_data']), $options) + ->filter() + ->first(); if (is_null($response)) { if ($this->preventStrayRequests) { diff --git a/src/Illuminate/Http/RedirectResponse.php b/src/Illuminate/Http/RedirectResponse.php index 5c506ba6b00b..6e4a9cde5b1f 100755 --- a/src/Illuminate/Http/RedirectResponse.php +++ b/src/Illuminate/Http/RedirectResponse.php @@ -169,7 +169,7 @@ protected function parseErrors($provider) public function withFragment($fragment) { return $this->withoutFragment() - ->setTargetUrl($this->getTargetUrl().'#'.Str::after($fragment, '#')); + ->setTargetUrl($this->getTargetUrl().'#'.Str::after($fragment, '#')); } /** diff --git a/src/Illuminate/Http/Resources/CollectsResources.php b/src/Illuminate/Http/Resources/CollectsResources.php index fd06cdcce8f6..c1bad66733c8 100644 --- a/src/Illuminate/Http/Resources/CollectsResources.php +++ b/src/Illuminate/Http/Resources/CollectsResources.php @@ -80,8 +80,8 @@ public function jsonOptions() } return (new ReflectionClass($collects)) - ->newInstanceWithoutConstructor() - ->jsonOptions(); + ->newInstanceWithoutConstructor() + ->jsonOptions(); } /** diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 287118726b94..925cb032f9b0 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -205,12 +205,12 @@ public function send($mailer) return $mailer->send($this->buildView(), $this->buildViewData(), function ($message) { $this->buildFrom($message) - ->buildRecipients($message) - ->buildSubject($message) - ->buildTags($message) - ->buildMetadata($message) - ->runCallbacks($message) - ->buildAttachments($message); + ->buildRecipients($message) + ->buildSubject($message) + ->buildTags($message) + ->buildMetadata($message) + ->runCallbacks($message) + ->buildAttachments($message); }); }); } @@ -262,10 +262,10 @@ public function later($delay, Queue $queue) protected function newQueuedJob() { return Container::getInstance()->make(SendQueuedMailable::class, ['mailable' => $this]) - ->through(array_merge( - method_exists($this, 'middleware') ? $this->middleware() : [], - $this->middleware ?? [] - )); + ->through(array_merge( + method_exists($this, 'middleware') ? $this->middleware() : [], + $this->middleware ?? [] + )); } /** @@ -966,9 +966,9 @@ public function attach($file, array $options = []) } $this->attachments = (new Collection($this->attachments)) - ->push(compact('file', 'options')) - ->unique('file') - ->all(); + ->push(compact('file', 'options')) + ->unique('file') + ->all(); return $this; } @@ -1048,8 +1048,8 @@ private function hasEnvelopeAttachment($attachment, $options = []) $attachments = $this->attachments(); return (new Collection(is_object($attachments) ? [$attachments] : $attachments)) - ->map(fn ($attached) => $attached instanceof Attachable ? $attached->toMailAttachment() : $attached) - ->contains(fn ($attached) => $attached->isEquivalent($attachment, $options)); + ->map(fn ($attached) => $attached instanceof Attachable ? $attached->toMailAttachment() : $attached) + ->contains(fn ($attached) => $attached->isEquivalent($attachment, $options)); } /** diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php index 2ab1af6d7eab..daa3be18991e 100644 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ b/src/Illuminate/Mail/Transport/SesTransport.php @@ -68,10 +68,10 @@ protected function doSend(SentMessage $message): void $options, [ 'Source' => $message->getEnvelope()->getSender()->toString(), 'Destinations' => (new Collection($message->getEnvelope()->getRecipients())) - ->map - ->toString() - ->values() - ->all(), + ->map + ->toString() + ->values() + ->all(), 'RawMessage' => [ 'Data' => $message->toString(), ], diff --git a/src/Illuminate/Mail/Transport/SesV2Transport.php b/src/Illuminate/Mail/Transport/SesV2Transport.php index 3bb2985365b3..ab47b44b3ea8 100644 --- a/src/Illuminate/Mail/Transport/SesV2Transport.php +++ b/src/Illuminate/Mail/Transport/SesV2Transport.php @@ -69,10 +69,10 @@ protected function doSend(SentMessage $message): void 'Source' => $message->getEnvelope()->getSender()->toString(), 'Destination' => [ 'ToAddresses' => (new Collection($message->getEnvelope()->getRecipients())) - ->map - ->toString() - ->values() - ->all(), + ->map + ->toString() + ->values() + ->all(), ], 'Content' => [ 'Raw' => [ diff --git a/src/Illuminate/Notifications/Channels/BroadcastChannel.php b/src/Illuminate/Notifications/Channels/BroadcastChannel.php index e1010afc9e19..14739d8eb9d8 100644 --- a/src/Illuminate/Notifications/Channels/BroadcastChannel.php +++ b/src/Illuminate/Notifications/Channels/BroadcastChannel.php @@ -45,7 +45,7 @@ public function send($notifiable, Notification $notification) if ($message instanceof BroadcastMessage) { $event->onConnection($message->connection) - ->onQueue($message->queue); + ->onQueue($message->queue); } return $this->events->dispatch($event); diff --git a/src/Illuminate/Notifications/Messages/MailMessage.php b/src/Illuminate/Notifications/Messages/MailMessage.php index f01ef667ef16..a80117a50178 100644 --- a/src/Illuminate/Notifications/Messages/MailMessage.php +++ b/src/Illuminate/Notifications/Messages/MailMessage.php @@ -404,7 +404,7 @@ public function render() $markdown = Container::getInstance()->make(Markdown::class); return $markdown->theme($this->theme ?: $markdown->getTheme()) - ->render($this->markdown, $this->data()); + ->render($this->markdown, $this->data()); } /** diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index 983f8b41476f..cea407f70b9a 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -228,10 +228,10 @@ protected function queueNotification($notifiables, $notification) $this->bus->dispatch( (new SendQueuedNotifications($notifiable, $notification, [$channel])) - ->onConnection($connection) - ->onQueue($queue) - ->delay(is_array($delay) ? ($delay[$channel] ?? null) : $delay) - ->through($middleware) + ->onConnection($connection) + ->onQueue($queue) + ->delay(is_array($delay) ? ($delay[$channel] ?? null) : $delay) + ->through($middleware) ); } } diff --git a/src/Illuminate/Process/PendingProcess.php b/src/Illuminate/Process/PendingProcess.php index fa2cc7f0da38..7161dd5bfb8a 100644 --- a/src/Illuminate/Process/PendingProcess.php +++ b/src/Illuminate/Process/PendingProcess.php @@ -351,7 +351,7 @@ public function withFakeHandlers(array $fakeHandlers) protected function fakeFor(string $command) { return (new Collection($this->fakeHandlers)) - ->first(fn ($handler, $pattern) => Str::is($pattern, $command)); + ->first(fn ($handler, $pattern) => $pattern === '*' || Str::is($pattern, $command)); } /** diff --git a/src/Illuminate/Process/Pipe.php b/src/Illuminate/Process/Pipe.php index 1803c7d251ce..06e7e16598e8 100644 --- a/src/Illuminate/Process/Pipe.php +++ b/src/Illuminate/Process/Pipe.php @@ -69,22 +69,22 @@ public function run(?callable $output = null) call_user_func($this->callback, $this); return (new Collection($this->pendingProcesses)) - ->reduce(function ($previousProcessResult, $pendingProcess, $key) use ($output) { - if (! $pendingProcess instanceof PendingProcess) { - throw new InvalidArgumentException('Process pipe must only contain pending processes.'); - } + ->reduce(function ($previousProcessResult, $pendingProcess, $key) use ($output) { + if (! $pendingProcess instanceof PendingProcess) { + throw new InvalidArgumentException('Process pipe must only contain pending processes.'); + } - if ($previousProcessResult && $previousProcessResult->failed()) { - return $previousProcessResult; - } + if ($previousProcessResult && $previousProcessResult->failed()) { + return $previousProcessResult; + } - return $pendingProcess->when( - $previousProcessResult, - fn () => $pendingProcess->input($previousProcessResult->output()) - )->run(output: $output ? function ($type, $buffer) use ($key, $output) { - $output($type, $buffer, $key); - } : null); - }); + return $pendingProcess->when( + $previousProcessResult, + fn () => $pendingProcess->input($previousProcessResult->output()) + )->run(output: $output ? function ($type, $buffer) use ($key, $output) { + $output($type, $buffer, $key); + } : null); + }); } /** diff --git a/src/Illuminate/Process/Pool.php b/src/Illuminate/Process/Pool.php index e5271377d201..1a98a8541a57 100644 --- a/src/Illuminate/Process/Pool.php +++ b/src/Illuminate/Process/Pool.php @@ -79,7 +79,7 @@ public function start(?callable $output = null) $output($type, $buffer, $key); } : null)]; }) - ->all() + ->all() ); } diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index 4bd5aa30feb2..12f49b495152 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -66,10 +66,6 @@ public function call(Job $job, array $data) return $this->handleModelNotFound($job, $e); } - if ($command instanceof ShouldBeUniqueUntilProcessing) { - $this->ensureUniqueJobLockIsReleased($command); - } - $this->dispatchThroughMiddleware($job, $command); if (! $job->isReleased() && ! $command instanceof ShouldBeUniqueUntilProcessing) { @@ -121,12 +117,16 @@ protected function dispatchThroughMiddleware(Job $job, $command) } return (new Pipeline($this->container))->send($command) - ->through(array_merge(method_exists($command, 'middleware') ? $command->middleware() : [], $command->middleware ?? [])) - ->then(function ($command) use ($job) { - return $this->dispatcher->dispatchNow( - $command, $this->resolveHandler($job, $command) - ); - }); + ->through(array_merge(method_exists($command, 'middleware') ? $command->middleware() : [], $command->middleware ?? [])) + ->then(function ($command) use ($job) { + if ($command instanceof ShouldBeUniqueUntilProcessing) { + $this->ensureUniqueJobLockIsReleased($command); + } + + return $this->dispatcher->dispatchNow( + $command, $this->resolveHandler($job, $command) + ); + }); } /** diff --git a/src/Illuminate/Queue/DatabaseQueue.php b/src/Illuminate/Queue/DatabaseQueue.php index 213f99563484..41533f084217 100644 --- a/src/Illuminate/Queue/DatabaseQueue.php +++ b/src/Illuminate/Queue/DatabaseQueue.php @@ -76,8 +76,8 @@ public function __construct( public function size($queue = null) { return $this->database->table($this->table) - ->where('queue', $this->getQueue($queue)) - ->count(); + ->where('queue', $this->getQueue($queue)) + ->count(); } /** @@ -239,14 +239,14 @@ public function pop($queue = null) protected function getNextAvailableJob($queue) { $job = $this->database->table($this->table) - ->lock($this->getLockForPopping()) - ->where('queue', $this->getQueue($queue)) - ->where(function ($query) { - $this->isAvailable($query); - $this->isReservedButExpired($query); - }) - ->orderBy('id', 'asc') - ->first(); + ->lock($this->getLockForPopping()) + ->where('queue', $this->getQueue($queue)) + ->where(function ($query) { + $this->isAvailable($query); + $this->isReservedButExpired($query); + }) + ->orderBy('id', 'asc') + ->first(); return $job ? new DatabaseJobRecord((object) $job) : null; } @@ -293,7 +293,7 @@ protected function isAvailable($query) { $query->where(function ($query) { $query->whereNull('reserved_at') - ->where('available_at', '<=', $this->currentTime()); + ->where('available_at', '<=', $this->currentTime()); }); } @@ -392,8 +392,8 @@ public function deleteAndRelease($queue, $job, $delay) public function clear($queue) { return $this->database->table($this->table) - ->where('queue', $this->getQueue($queue)) - ->delete(); + ->where('queue', $this->getQueue($queue)) + ->delete(); } /** diff --git a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php index 6d0bae90d031..c76a55ca8b1c 100644 --- a/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php +++ b/src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php @@ -72,7 +72,7 @@ public function log($connection, $queue, $payload, $exception) 'payload' => ['S' => $payload], 'exception' => ['S' => (string) $exception], 'failed_at' => ['N' => (string) $failedAt->getTimestamp()], - 'expires_at' => ['N' => (string) $failedAt->addDays(3)->getTimestamp()], + 'expires_at' => ['N' => (string) $failedAt->addDays(7)->getTimestamp()], ], ]); diff --git a/src/Illuminate/Queue/QueueManager.php b/src/Illuminate/Queue/QueueManager.php index a64e43345c9e..399b66bc8729 100755 --- a/src/Illuminate/Queue/QueueManager.php +++ b/src/Illuminate/Queue/QueueManager.php @@ -160,8 +160,8 @@ protected function resolve($name) } return $this->getConnector($config['driver']) - ->connect($config) - ->setConnectionName($name); + ->connect($config) + ->setConnectionName($name); } /** diff --git a/src/Illuminate/Routing/CreatesRegularExpressionRouteConstraints.php b/src/Illuminate/Routing/CreatesRegularExpressionRouteConstraints.php index 64e497986634..c17374cef7c6 100644 --- a/src/Illuminate/Routing/CreatesRegularExpressionRouteConstraints.php +++ b/src/Illuminate/Routing/CreatesRegularExpressionRouteConstraints.php @@ -90,7 +90,7 @@ public function whereIn($parameters, array $values) protected function assignExpressionToParameters($parameters, $expression) { return $this->where(Collection::wrap($parameters) - ->mapWithKeys(fn ($parameter) => [$parameter => $expression]) - ->all()); + ->mapWithKeys(fn ($parameter) => [$parameter => $expression]) + ->all()); } } diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index c710312d1202..050d3c39b13c 100755 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -378,7 +378,7 @@ public function bind(Request $request) $this->compileRoute(); $this->parameters = (new RouteParameterBinder($this)) - ->parameters($request); + ->parameters($request); $this->originalParameters = $this->parameters; diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index d10c0dff463f..8aaf0f36b643 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -259,8 +259,8 @@ public function fallback($action) public function redirect($uri, $destination, $status = 302) { return $this->any($uri, '\Illuminate\Routing\RedirectController') - ->defaults('destination', $destination) - ->defaults('status', $status); + ->defaults('destination', $destination) + ->defaults('status', $status); } /** @@ -288,12 +288,12 @@ public function permanentRedirect($uri, $destination) public function view($uri, $view, $data = [], $status = 200, array $headers = []) { return $this->match(['GET', 'HEAD'], $uri, '\Illuminate\Routing\ViewController') - ->setDefaults([ - 'view' => $view, - 'data' => $data, - 'status' => is_array($status) ? 200 : $status, - 'headers' => is_array($status) ? $status : $headers, - ]); + ->setDefaults([ + 'view' => $view, + 'data' => $data, + 'status' => is_array($status) ? 200 : $status, + 'headers' => is_array($status) ? $status : $headers, + ]); } /** @@ -669,8 +669,8 @@ protected function prependGroupController($class) public function newRoute($methods, $uri, $action) { return (new Route($methods, $uri, $action)) - ->setRouter($this) - ->setContainer($this->container); + ->setRouter($this) + ->setContainer($this->container); } /** @@ -802,11 +802,11 @@ protected function runRouteWithinStack(Route $route, Request $request) $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route); return (new Pipeline($this->container)) - ->send($request) - ->through($middleware) - ->then(fn ($request) => $this->prepareResponse( - $request, $route->run() - )); + ->send($request) + ->through($middleware) + ->then(fn ($request) => $this->prepareResponse( + $request, $route->run() + )); } /** diff --git a/src/Illuminate/Session/DatabaseSessionHandler.php b/src/Illuminate/Session/DatabaseSessionHandler.php index f4c1e9441323..132f1e347246 100644 --- a/src/Illuminate/Session/DatabaseSessionHandler.php +++ b/src/Illuminate/Session/DatabaseSessionHandler.php @@ -192,7 +192,7 @@ protected function getDefaultPayload($data) return tap($payload, function (&$payload) { $this->addUserInformation($payload) - ->addRequestInformation($payload); + ->addRequestInformation($payload); }); } diff --git a/src/Illuminate/Session/FileSessionHandler.php b/src/Illuminate/Session/FileSessionHandler.php index 08b2d80bd72d..82fe2245384b 100644 --- a/src/Illuminate/Session/FileSessionHandler.php +++ b/src/Illuminate/Session/FileSessionHandler.php @@ -112,10 +112,10 @@ public function destroy($sessionId): bool public function gc($lifetime): int { $files = Finder::create() - ->in($this->path) - ->files() - ->ignoreDotFiles(true) - ->date('<= now - '.$lifetime.' seconds'); + ->in($this->path) + ->files() + ->ignoreDotFiles(true) + ->date('<= now - '.$lifetime.' seconds'); $deletedSessions = 0; diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 5b8da6dda505..287341598113 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -83,8 +83,8 @@ protected function handleRequestWhileBlocking(Request $request, $session, Closur : $this->manager->defaultRouteBlockLockSeconds(); $lock = $this->cache($this->manager->blockDriver()) - ->lock('session:'.$session->getId(), $lockFor) - ->betweenBlockedAttemptsSleepFor(50); + ->lock('session:'.$session->getId(), $lockFor) + ->betweenBlockedAttemptsSleepFor(50); try { $lock->block( diff --git a/src/Illuminate/Support/Composer.php b/src/Illuminate/Support/Composer.php index 248e0177efe2..76c9c57544b5 100644 --- a/src/Illuminate/Support/Composer.php +++ b/src/Illuminate/Support/Composer.php @@ -69,9 +69,9 @@ public function requirePackages(array $packages, bool $dev = false, Closure|Outp 'require', ...$packages, ])) - ->when($dev, function ($command) { - $command->push('--dev'); - })->all(); + ->when($dev, function ($command) { + $command->push('--dev'); + })->all(); return 0 === $this->getProcess($command, ['COMPOSER_MEMORY_LIMIT' => '-1']) ->run( @@ -98,9 +98,9 @@ public function removePackages(array $packages, bool $dev = false, Closure|Outpu 'remove', ...$packages, ])) - ->when($dev, function ($command) { - $command->push('--dev'); - })->all(); + ->when($dev, function ($command) { + $command->push('--dev'); + })->all(); return 0 === $this->getProcess($command, ['COMPOSER_MEMORY_LIMIT' => '-1']) ->run( diff --git a/src/Illuminate/Support/DefaultProviders.php b/src/Illuminate/Support/DefaultProviders.php index 5c836c67f9b4..791e86072b75 100644 --- a/src/Illuminate/Support/DefaultProviders.php +++ b/src/Illuminate/Support/DefaultProviders.php @@ -86,9 +86,9 @@ public function replace(array $replacements) public function except(array $providers) { return new static((new Collection($this->providers)) - ->reject(fn ($p) => in_array($p, $providers)) - ->values() - ->toArray()); + ->reject(fn ($p) => in_array($p, $providers)) + ->values() + ->toArray()); } /** diff --git a/src/Illuminate/Support/Facades/Bus.php b/src/Illuminate/Support/Facades/Bus.php index e3155df5ae8a..337108f31d85 100644 --- a/src/Illuminate/Support/Facades/Bus.php +++ b/src/Illuminate/Support/Facades/Bus.php @@ -85,7 +85,7 @@ public static function dispatchChain($jobs) $jobs = is_array($jobs) ? $jobs : func_get_args(); return (new PendingChain(array_shift($jobs), $jobs)) - ->dispatch(); + ->dispatch(); } /** diff --git a/src/Illuminate/Support/Facades/Cache.php b/src/Illuminate/Support/Facades/Cache.php index f9c4b74cd4c0..1463306365ca 100755 --- a/src/Illuminate/Support/Facades/Cache.php +++ b/src/Illuminate/Support/Facades/Cache.php @@ -38,6 +38,7 @@ * @method static bool deleteMultiple(iterable $keys) * @method static bool clear() * @method static \Illuminate\Cache\TaggedCache tags(array|mixed $names) + * @method static string|null getName() * @method static bool supportsTags() * @method static int|null getDefaultCacheTime() * @method static \Illuminate\Cache\Repository setDefaultCacheTime(int|null $seconds) diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 4334e5ccf5aa..7f226a786faf 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -87,7 +87,7 @@ public function assertListening($expectedEvent, $expectedListener) { foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) { $actualListener = (new ReflectionFunction($listenerClosure)) - ->getStaticVariables()['listener']; + ->getStaticVariables()['listener']; $normalizedListener = $expectedListener; diff --git a/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php b/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php index 87cef8b6d02d..665a50588caf 100644 --- a/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php +++ b/src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php @@ -59,9 +59,9 @@ public function __construct(Connection $database, array $data, string $deletedAt public function matches($table): bool { return $this->database->table($table) - ->where($this->data) - ->whereNull($this->deletedAtColumn) - ->exists(); + ->where($this->data) + ->whereNull($this->deletedAtColumn) + ->exists(); } /** diff --git a/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php b/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php index 0d14f83b6c67..c764d5f39c4e 100644 --- a/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php +++ b/src/Illuminate/Testing/Constraints/SoftDeletedInDatabase.php @@ -61,9 +61,9 @@ public function __construct(Connection $database, array $data, string $deletedAt public function matches($table): bool { return $this->database->table($table) - ->where($this->data) - ->whereNotNull($this->deletedAtColumn) - ->exists(); + ->where($this->data) + ->whereNotNull($this->deletedAtColumn) + ->exists(); } /** diff --git a/src/Illuminate/Testing/PendingCommand.php b/src/Illuminate/Testing/PendingCommand.php index 0fc154612cb8..062d2a17738c 100644 --- a/src/Illuminate/Testing/PendingCommand.php +++ b/src/Illuminate/Testing/PendingCommand.php @@ -443,8 +443,8 @@ protected function mockConsoleOutput() private function createABufferedOutputMock() { $mock = Mockery::mock(BufferedOutput::class.'[doWrite]') - ->shouldAllowMockingProtectedMethods() - ->shouldIgnoreMissing(); + ->shouldAllowMockingProtectedMethods() + ->shouldIgnoreMissing(); if ($this->test->expectsOutput === false) { $mock->shouldReceive('doWrite')->never(); @@ -491,12 +491,12 @@ private function createABufferedOutputMock() foreach ($this->test->unexpectedOutputSubstrings as $text => $displayed) { $mock->shouldReceive('doWrite') - ->atLeast() - ->times(0) - ->withArgs(fn ($output) => str_contains($output, $text)) - ->andReturnUsing(function () use ($text) { - $this->test->unexpectedOutputSubstrings[$text] = true; - }); + ->atLeast() + ->times(0) + ->withArgs(fn ($output) => str_contains($output, $text)) + ->andReturnUsing(function () use ($text) { + $this->test->unexpectedOutputSubstrings[$text] = true; + }); } return $mock; diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 900bdb3698a0..59526d73c79a 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -1225,7 +1225,7 @@ public function addRules($rules) // of the explicit rules needed for the given data. For example the rule // names.* would get expanded to names.0, names.1, etc. for this data. $response = (new ValidationRuleParser($this->data)) - ->explode(ValidationRuleParser::filterConditionalRules($rules, $this->data)); + ->explode(ValidationRuleParser::filterConditionalRules($rules, $this->data)); foreach ($response->rules as $key => $rule) { $this->rules[$key] = array_merge($this->rules[$key] ?? [], $rule); diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 807da35bfe10..b8f01e02795c 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -331,8 +331,8 @@ public function render() }; $view = Container::getInstance() - ->make(ViewFactory::class) - ->make($component->resolveView(), $data); + ->make(ViewFactory::class) + ->make($component->resolveView(), $data); return tap($view->render(), function () use ($view, $deleteCachedView) { if ($deleteCachedView) { @@ -821,8 +821,8 @@ public function anonymousComponentPath(string $path, ?string $prefix = null) ]; Container::getInstance() - ->make(ViewFactory::class) - ->addNamespace($prefixHash, $path); + ->make(ViewFactory::class) + ->addNamespace($prefixHash, $path); } /** @@ -837,9 +837,9 @@ public function anonymousComponentNamespace(string $directory, ?string $prefix = $prefix ??= $directory; $this->anonymousComponentNamespaces[$prefix] = (new Stringable($directory)) - ->replace('/', '.') - ->trim('. ') - ->toString(); + ->replace('/', '.') + ->trim('. ') + ->toString(); } /** diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 3de2755f2a7f..357bcd241f58 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -421,8 +421,8 @@ public function findClassByComponent(string $component) public function guessClassName(string $component) { $namespace = Container::getInstance() - ->make(Application::class) - ->getNamespace(); + ->make(Application::class) + ->getNamespace(); $class = $this->formatClassName($component); @@ -787,12 +787,12 @@ protected function escapeSingleQuotesOutsideOfPhpBlocks(string $value) protected function attributesToString(array $attributes, $escapeBound = true) { return (new Collection($attributes)) - ->map(function (string $value, string $attribute) use ($escapeBound) { - return $escapeBound && isset($this->boundAttributes[$attribute]) && $value !== 'true' && ! is_numeric($value) - ? "'{$attribute}' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute({$value})" - : "'{$attribute}' => {$value}"; - }) - ->implode(','); + ->map(function (string $value, string $attribute) use ($escapeBound) { + return $escapeBound && isset($this->boundAttributes[$attribute]) && $value !== 'true' && ! is_numeric($value) + ? "'{$attribute}' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute({$value})" + : "'{$attribute}' => {$value}"; + }) + ->implode(','); } /** diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index befc983b3d36..780d93deb51d 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -274,12 +274,12 @@ public function merge(array $attributeDefaults = [], $escape = true) }, $attributeDefaults); [$appendableAttributes, $nonAppendableAttributes] = (new Collection($this->attributes)) - ->partition(function ($value, $key) use ($attributeDefaults) { - return $key === 'class' || $key === 'style' || ( - isset($attributeDefaults[$key]) && - $attributeDefaults[$key] instanceof AppendableAttributeValue - ); - }); + ->partition(function ($value, $key) use ($attributeDefaults) { + return $key === 'class' || $key === 'style' || ( + isset($attributeDefaults[$key]) && + $attributeDefaults[$key] instanceof AppendableAttributeValue + ); + }); $attributes = $appendableAttributes->mapWithKeys(function ($value, $key) use ($attributeDefaults, $escape) { $defaultsValue = isset($attributeDefaults[$key]) && $attributeDefaults[$key] instanceof AppendableAttributeValue diff --git a/tests/Broadcasting/UsePusherChannelsNamesTest.php b/tests/Broadcasting/UsePusherChannelsNamesTest.php index 122e83e8c3f4..d1ea01ed727e 100644 --- a/tests/Broadcasting/UsePusherChannelsNamesTest.php +++ b/tests/Broadcasting/UsePusherChannelsNamesTest.php @@ -30,6 +30,19 @@ public function testChannelNameNormalizationSpecialCase() ); } + public function testChannelNamePatternMatching() + { + $broadcaster = new FakeBroadcasterUsingPusherChannelsNames; + + $this->assertEquals( + 0, + $broadcaster->testChannelNameMatchesPattern( + 'TestChannel', + 'Test.{id}' + ) + ); + } + #[DataProvider('channelsProvider')] public function testIsGuardedChannel($requestChannelName, $_, $guarded) { @@ -103,4 +116,9 @@ public function broadcast(array $channels, $event, array $payload = []) { // } + + public function testChannelNameMatchesPattern($channel, $pattern) + { + return $this->channelNameMatchesPattern($channel, $pattern); + } } diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithAttributesTest.php new file mode 100755 index 000000000000..618616ed14ce --- /dev/null +++ b/tests/Database/DatabaseEloquentBelongsToManyWithAttributesTest.php @@ -0,0 +1,263 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + $db->bootEloquent(); + $db->setAsGlobal(); + $this->createSchema(); + } + + public function testCreatesWithAttributesAndPivotValues(): void + { + $post = ManyToManyWithAttributesPost::create(); + $tag = $post->metaTags()->create(['name' => 'long article']); + + $this->assertSame('long article', $tag->name); + $this->assertTrue($tag->visible); + + $pivot = DB::table('with_attributes_pivot')->first(); + $this->assertSame('meta', $pivot->type); + $this->assertSame($post->id, $pivot->post_id); + $this->assertSame($tag->id, $pivot->tag_id); + } + + public function testQueriesWithAttributesAndPivotValues(): void + { + $post = new ManyToManyWithAttributesPost(['id' => 2]); + $wheres = $post->metaTags()->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_tags.visible', + 'operator' => '=', + 'value' => true, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_pivot.type', + 'operator' => '=', + 'value' => 'meta', + 'boolean' => 'and', + ], $wheres); + } + + public function testMorphToManyWithAttributes(): void + { + $post = new ManyToManyWithAttributesPost(['id' => 2]); + $wheres = $post->morphedTags()->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_tags.visible', + 'operator' => '=', + 'value' => true, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_taggables.type', + 'operator' => '=', + 'value' => 'meta', + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_taggables.taggable_type', + 'operator' => '=', + 'value' => ManyToManyWithAttributesPost::class, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_taggables.taggable_id', + 'operator' => '=', + 'value' => 2, + 'boolean' => 'and', + ], $wheres); + + $tag = $post->morphedTags()->create(['name' => 'new tag']); + + $this->assertTrue($tag->visible); + $this->assertSame('new tag', $tag->name); + $this->assertSame($tag->id, $post->morphedTags()->first()->id); + } + + public function testMorphedByManyWithAttributes(): void + { + $tag = new ManyToManyWithAttributesTag(['id' => 4]); + $wheres = $tag->morphedPosts()->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_posts.title', + 'operator' => '=', + 'value' => 'Title!', + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_taggables.type', + 'operator' => '=', + 'value' => 'meta', + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_taggables.taggable_type', + 'operator' => '=', + 'value' => ManyToManyWithAttributesPost::class, + 'boolean' => 'and', + ], $wheres); + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_taggables.tag_id', + 'operator' => '=', + 'value' => 4, + 'boolean' => 'and', + ], $wheres); + + $post = $tag->morphedPosts()->create(); + $this->assertSame('Title!', $post->title); + $this->assertSame($post->id, $tag->morphedPosts()->first()->id); + } + + protected function createSchema() + { + $this->schema()->create('with_attributes_posts', function ($table) { + $table->increments('id'); + $table->string('title')->nullable(); + $table->timestamps(); + }); + + $this->schema()->create('with_attributes_tags', function ($table) { + $table->increments('id'); + $table->string('name'); + $table->boolean('visible')->nullable(); + $table->timestamps(); + }); + + $this->schema()->create('with_attributes_pivot', function ($table) { + $table->integer('post_id'); + $table->integer('tag_id'); + $table->string('type'); + }); + + $this->schema()->create('with_attributes_taggables', function ($table) { + $table->integer('tag_id'); + $table->integer('taggable_id'); + $table->string('taggable_type'); + $table->string('type'); + }); + } + + /** + * Tear down the database schema. + * + * @return void + */ + protected function tearDown(): void + { + $this->schema()->drop('with_attributes_posts'); + $this->schema()->drop('with_attributes_tags'); + $this->schema()->drop('with_attributes_pivot'); + } + + /** + * Get a database connection instance. + * + * @return \Illuminate\Database\Connection + */ + protected function connection($connection = 'default') + { + return Model::getConnectionResolver()->connection($connection); + } + + /** + * Get a schema builder instance. + * + * @return \Illuminate\Database\Schema\Builder + */ + protected function schema($connection = 'default') + { + return $this->connection($connection)->getSchemaBuilder(); + } +} + +class ManyToManyWithAttributesPost extends Model +{ + protected $guarded = []; + protected $table = 'with_attributes_posts'; + + public function tags(): BelongsToMany + { + return $this->belongsToMany( + ManyToManyWithAttributesTag::class, + 'with_attributes_pivot', + 'tag_id', + 'post_id', + ); + } + + public function metaTags(): BelongsToMany + { + return $this->tags() + ->withAttributes('visible', true) + ->withPivotValue('type', 'meta'); + } + + public function morphedTags(): MorphToMany + { + return $this + ->morphToMany( + ManyToManyWithAttributesTag::class, + 'taggable', + 'with_attributes_taggables', + relatedPivotKey: 'tag_id' + ) + ->withAttributes('visible', true) + ->withPivotValue('type', 'meta'); + } +} + +class ManyToManyWithAttributesTag extends Model +{ + protected $guarded = []; + protected $table = 'with_attributes_tags'; + + public function morphedPosts(): MorphToMany + { + return $this + ->morphedByMany( + ManyToManyWithAttributesPost::class, + 'taggable', + 'with_attributes_taggables', + 'tag_id', + ) + ->withAttributes('title', 'Title!') + ->withPivotValue('type', 'meta'); + } +} diff --git a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php index ea09aa234b91..b629194b6ea6 100755 --- a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php @@ -300,6 +300,175 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void ], $result->toArray()); } + public function testIncrementOrCreateMethodIncrementsExistingRecord(): void + { + $model = new EloquentBuilderCreateOrFirstTestModel(); + $this->mockConnectionForModel($model, 'SQLite'); + $model->getConnection()->shouldReceive('transactionLevel')->andReturn(0); + $model->getConnection()->shouldReceive('getName')->andReturn('sqlite'); + + $model->getConnection() + ->expects('select') + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->andReturn([[ + 'id' => 123, + 'attr' => 'foo', + 'count' => 1, + 'created_at' => '2023-01-01 00:00:00', + 'updated_at' => '2023-01-01 00:00:00', + ]]); + + $model->getConnection() + ->expects('raw') + ->with('"count" + 1') + ->andReturn('2'); + + $model->getConnection() + ->expects('update') + ->with( + 'update "table" set "count" = ?, "updated_at" = ? where "id" = ?', + ['2', '2023-01-01 00:00:00', 123], + ) + ->andReturn(1); + + $result = $model->newQuery()->incrementOrCreate(['attr' => 'foo'], 'count'); + $this->assertFalse($result->wasRecentlyCreated); + $this->assertEquals([ + 'id' => 123, + 'attr' => 'foo', + 'count' => 2, + 'created_at' => '2023-01-01T00:00:00.000000Z', + 'updated_at' => '2023-01-01T00:00:00.000000Z', + ], $result->toArray()); + } + + public function testIncrementOrCreateMethodCreatesNewRecord(): void + { + $model = new EloquentBuilderCreateOrFirstTestModel(); + $this->mockConnectionForModel($model, 'SQLite', [123]); + $model->getConnection()->shouldReceive('transactionLevel')->andReturn(0); + $model->getConnection()->shouldReceive('getName')->andReturn('sqlite'); + + $model->getConnection() + ->expects('select') + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->andReturn([]); + + $model->getConnection()->expects('insert')->with( + 'insert into "table" ("attr", "count", "updated_at", "created_at") values (?, ?, ?, ?)', + ['foo', '1', '2023-01-01 00:00:00', '2023-01-01 00:00:00'], + )->andReturnTrue(); + + $result = $model->newQuery()->incrementOrCreate(['attr' => 'foo']); + $this->assertTrue($result->wasRecentlyCreated); + $this->assertEquals([ + 'id' => 123, + 'attr' => 'foo', + 'count' => 1, + 'created_at' => '2023-01-01T00:00:00.000000Z', + 'updated_at' => '2023-01-01T00:00:00.000000Z', + ], $result->toArray()); + } + + public function testIncrementOrCreateMethodIncrementParametersArePassed(): void + { + $model = new EloquentBuilderCreateOrFirstTestModel(); + $this->mockConnectionForModel($model, 'SQLite'); + $model->getConnection()->shouldReceive('transactionLevel')->andReturn(0); + $model->getConnection()->shouldReceive('getName')->andReturn('sqlite'); + + $model->getConnection() + ->expects('select') + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->andReturn([[ + 'id' => 123, + 'attr' => 'foo', + 'val' => 'bar', + 'count' => 1, + 'created_at' => '2023-01-01 00:00:00', + 'updated_at' => '2023-01-01 00:00:00', + ]]); + + $model->getConnection() + ->expects('raw') + ->with('"count" + 2') + ->andReturn('3'); + + $model->getConnection() + ->expects('update') + ->with( + 'update "table" set "count" = ?, "val" = ?, "updated_at" = ? where "id" = ?', + ['3', 'baz', '2023-01-01 00:00:00', 123], + ) + ->andReturn(1); + + $result = $model->newQuery()->incrementOrCreate(['attr' => 'foo'], step: 2, extra: ['val' => 'baz']); + $this->assertFalse($result->wasRecentlyCreated); + $this->assertEquals([ + 'id' => 123, + 'attr' => 'foo', + 'count' => 3, + 'val' => 'baz', + 'created_at' => '2023-01-01T00:00:00.000000Z', + 'updated_at' => '2023-01-01T00:00:00.000000Z', + ], $result->toArray()); + } + + public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void + { + $model = new EloquentBuilderCreateOrFirstTestModel(); + $this->mockConnectionForModel($model, 'SQLite'); + $model->getConnection()->shouldReceive('transactionLevel')->andReturn(0); + $model->getConnection()->shouldReceive('getName')->andReturn('sqlite'); + + $model->getConnection() + ->expects('select') + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->andReturn([]); + + $sql = 'insert into "table" ("attr", "count", "updated_at", "created_at") values (?, ?, ?, ?)'; + $bindings = ['foo', '1', '2023-01-01 00:00:00', '2023-01-01 00:00:00']; + + $model->getConnection() + ->expects('insert') + ->with($sql, $bindings) + ->andThrow(new UniqueConstraintViolationException('sqlite', $sql, $bindings, new Exception())); + + $model->getConnection() + ->expects('select') + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->andReturn([[ + 'id' => 123, + 'attr' => 'foo', + 'count' => 1, + 'created_at' => '2023-01-01 00:00:00', + 'updated_at' => '2023-01-01 00:00:00', + ]]); + + $model->getConnection() + ->expects('raw') + ->with('"count" + 1') + ->andReturn('2'); + + $model->getConnection() + ->expects('update') + ->with( + 'update "table" set "count" = ?, "updated_at" = ? where "id" = ?', + ['2', '2023-01-01 00:00:00', 123], + ) + ->andReturn(1); + + $result = $model->newQuery()->incrementOrCreate(['attr' => 'foo']); + $this->assertFalse($result->wasRecentlyCreated); + $this->assertEquals([ + 'id' => 123, + 'attr' => 'foo', + 'count' => 2, + 'created_at' => '2023-01-01T00:00:00.000000Z', + 'updated_at' => '2023-01-01T00:00:00.000000Z', + ], $result->toArray()); + } + protected function mockConnectionForModel(Model $model, string $database, array $lastInsertIds = []): void { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; diff --git a/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesTest.php b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesTest.php new file mode 100755 index 000000000000..80f1e677eb37 --- /dev/null +++ b/tests/Database/DatabaseEloquentHasOneOrManyWithAttributesTest.php @@ -0,0 +1,275 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + $db->bootEloquent(); + $db->setAsGlobal(); + } + + public function testHasManyAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value]); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testHasOneAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasOne(RelatedWithAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value]); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testMorphManyAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->morphMany(RelatedWithAttributesModel::class, 'relatable') + ->withAttributes([$key => $value]); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->relatable_id); + $this->assertSame($parent::class, $relatedModel->relatable_type); + $this->assertSame($value, $relatedModel->$key); + } + + public function testMorphOneAddsAttributes(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->morphOne(RelatedWithAttributesModel::class, 'relatable') + ->withAttributes([$key => $value]); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->relatable_id); + $this->assertSame($parent::class, $relatedModel->relatable_type); + $this->assertSame($value, $relatedModel->$key); + } + + public function testWithAttributesCanBeOverriden(): void + { + $key = 'a key'; + $defaultValue = 'a value'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'relatable') + ->withAttributes([$key => $defaultValue]); + + $relatedModel = $relationship->make([$key => $value]); + + $this->assertSame($value, $relatedModel->$key); + } + + public function testQueryingDoesNotBreakWither(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'parent_id') + ->where($key, $value) + ->withAttributes([$key => $value]); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testAttributesCanBeAppended(): void + { + $parent = new RelatedWithAttributesModel; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'parent_id') + ->withAttributes(['a' => 'A']) + ->withAttributes(['b' => 'B']) + ->withAttributes(['a' => 'AA']); + + $relatedModel = $relationship->make([ + 'b' => 'BB', + 'c' => 'C', + ]); + + $this->assertSame('AA', $relatedModel->a); + $this->assertSame('BB', $relatedModel->b); + $this->assertSame('C', $relatedModel->c); + } + + public function testSingleAttributeApi(): void + { + $parent = new RelatedWithAttributesModel; + $key = 'attr'; + $value = 'Value'; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'parent_id') + ->withAttributes($key, $value); + + $relatedModel = $relationship->make(); + + $this->assertSame($value, $relatedModel->$key); + } + + public function testWheresAreSet(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value]); + + $wheres = $relationship->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'related_with_attributes_models.'.$key, + 'operator' => '=', + 'value' => $value, + 'boolean' => 'and', + ], $wheres); + + // Ensure this doesn't break the default where either. + $this->assertContains([ + 'type' => 'Basic', + 'column' => $parent->qualifyColumn('parent_id'), + 'operator' => '=', + 'value' => $parentId, + 'boolean' => 'and', + ], $wheres); + } + + public function testNullValueIsAccepted(): void + { + $parentId = 123; + $key = 'a key'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'parent_id') + ->withAttributes([$key => null]); + + $wheres = $relationship->toBase()->wheres; + $relatedModel = $relationship->make(); + + $this->assertNull($relatedModel->$key); + + $this->assertContains([ + 'type' => 'Null', + 'column' => 'related_with_attributes_models.'.$key, + 'boolean' => 'and', + ], $wheres); + } + + public function testOneKeepsAttributesFromHasMany(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->hasMany(RelatedWithAttributesModel::class, 'parent_id') + ->withAttributes([$key => $value]) + ->one(); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->parent_id); + $this->assertSame($value, $relatedModel->$key); + } + + public function testOneKeepsAttributesFromMorphMany(): void + { + $parentId = 123; + $key = 'a key'; + $value = 'the value'; + + $parent = new RelatedWithAttributesModel; + $parent->id = $parentId; + + $relationship = $parent + ->morphMany(RelatedWithAttributesModel::class, 'relatable') + ->withAttributes([$key => $value]) + ->one(); + + $relatedModel = $relationship->make(); + + $this->assertSame($parentId, $relatedModel->relatable_id); + $this->assertSame($parent::class, $relatedModel->relatable_type); + $this->assertSame($value, $relatedModel->$key); + } +} + +class RelatedWithAttributesModel extends Model +{ + protected $guarded = []; +} diff --git a/tests/Database/DatabaseEloquentWithAttributesTest.php b/tests/Database/DatabaseEloquentWithAttributesTest.php new file mode 100755 index 000000000000..85b11d7991f3 --- /dev/null +++ b/tests/Database/DatabaseEloquentWithAttributesTest.php @@ -0,0 +1,59 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + $db->bootEloquent(); + $db->setAsGlobal(); + } + + public function testAddsAttributes(): void + { + $key = 'a key'; + $value = 'the value'; + + $query = WithAttributesModel::query() + ->withAttributes([$key => $value]); + + $model = $query->make(); + + $this->assertSame($value, $model->$key); + } + + public function testAddsWheres(): void + { + $key = 'a key'; + $value = 'the value'; + + $query = WithAttributesModel::query() + ->withAttributes([$key => $value]); + + $wheres = $query->toBase()->wheres; + + $this->assertContains([ + 'type' => 'Basic', + 'column' => 'with_attributes_models.'.$key, + 'operator' => '=', + 'value' => $value, + 'boolean' => 'and', + ], $wheres); + } +} + +class WithAttributesModel extends Model +{ + protected $guarded = []; +} diff --git a/tests/Integration/Queue/UniqueJobTest.php b/tests/Integration/Queue/UniqueJobTest.php index 82e567282a6f..5ec58efdec2b 100644 --- a/tests/Integration/Queue/UniqueJobTest.php +++ b/tests/Integration/Queue/UniqueJobTest.php @@ -4,6 +4,7 @@ use Exception; use Illuminate\Bus\Queueable; +use Illuminate\Container\Container; use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; @@ -51,6 +52,14 @@ public function testUniqueJobsAreNotDispatched() ); } + public function testUniqueJobWithViaDispatched() + { + Bus::fake(); + + UniqueViaJob::dispatch(); + Bus::assertDispatched(UniqueViaJob::class); + } + public function testLockIsReleasedForSuccessfulJobs() { UniqueTestJob::$handled = false; @@ -222,3 +231,11 @@ public function __construct(public User $user) { } } + +class UniqueViaJob extends UniqueTestJob +{ + public function uniqueVia(): Cache + { + return Container::getInstance()->make(Cache::class); + } +} diff --git a/tests/Integration/Queue/UniqueUntilProcessingJobTest.php b/tests/Integration/Queue/UniqueUntilProcessingJobTest.php new file mode 100644 index 000000000000..79ce03e65694 --- /dev/null +++ b/tests/Integration/Queue/UniqueUntilProcessingJobTest.php @@ -0,0 +1,89 @@ +set('queue.default', 'database'); + $app['config']->set('cache.default', 'database'); + $this->driver = 'database'; + } + + public function testShouldBeUniqueUntilProcessingReleasesLockWhenJobIsReleasedByAMiddleware() + { + // Job that does not release and gets processed + UniqueTestJobThatDoesNotRelease::dispatch(); + $lockKey = DB::table('cache_locks')->orderBy('id')->first()->key; + $this->assertNotNull($lockKey); + $this->runQueueWorkerCommand(['--once' => true]); + $this->assertFalse(UniqueTestJobThatDoesNotRelease::$released); + $lockKey = DB::table('cache_locks')->first()->key ?? null; + $this->assertNull($lockKey); + $this->assertDatabaseCount('jobs', 0); + + // Job that releases and does not get processed + UniqueUntilProcessingJobThatReleases::dispatch(); + $lockKey = DB::table('cache_locks')->first()->key; + $this->assertNotNull($lockKey); + $this->runQueueWorkerCommand(['--once' => true]); + $this->assertFalse(UniqueUntilProcessingJobThatReleases::$handled); + $this->assertTrue(UniqueUntilProcessingJobThatReleases::$released); + $lockKey = DB::table('cache_locks')->orderBy('id')->first()->key ?? null; + $this->assertNotNull($lockKey); + + UniqueUntilProcessingJobThatReleases::dispatch(); + $this->assertDatabaseCount('jobs', 1); + } +} + +class UniqueTestJobThatDoesNotRelease implements ShouldQueue, ShouldBeUniqueUntilProcessing +{ + use InteractsWithQueue, Queueable, Dispatchable; + + public static $handled = false; + public static $released = false; + + public function __construct() + { + static::$handled = false; + static::$released = false; + } + + public function handle() + { + static::$handled = true; + } +} + +class UniqueUntilProcessingJobThatReleases extends UniqueTestJobThatDoesNotRelease +{ + public function middleware() + { + return [ + function ($job) { + static::$released = true; + + return $job->release(30); + }, + ]; + } + + public function uniqueId() + { + return 100; + } +} diff --git a/tests/Queue/DynamoDbFailedJobProviderTest.php b/tests/Queue/DynamoDbFailedJobProviderTest.php index dcd0cfe5f9d1..84baa1015a6e 100644 --- a/tests/Queue/DynamoDbFailedJobProviderTest.php +++ b/tests/Queue/DynamoDbFailedJobProviderTest.php @@ -43,7 +43,7 @@ public function testCanProperlyLogFailedJob() 'payload' => ['S' => json_encode(['uuid' => (string) $uuid])], 'exception' => ['S' => (string) $exception], 'failed_at' => ['N' => (string) $now->getTimestamp()], - 'expires_at' => ['N' => (string) $now->addDays(3)->getTimestamp()], + 'expires_at' => ['N' => (string) $now->addDays(7)->getTimestamp()], ], ]); diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 82044805b7cb..73676e981acf 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -39,6 +39,10 @@ public function testAdd() $this->assertEquals(['developer' => ['name' => 'Ferid']], Arr::add([], 'developer.name', 'Ferid')); $this->assertEquals([1 => 'hAz'], Arr::add([], 1, 'hAz')); $this->assertEquals([1 => [1 => 'hAz']], Arr::add([], 1.1, 'hAz')); + + // Case where the key already exists + $this->assertEquals(['type' => 'Table'], Arr::add(['type' => 'Table'], 'type', 'Chair')); + $this->assertEquals(['category' => ['type' => 'Table']], Arr::add(['category' => ['type' => 'Table']], 'category.type', 'Chair')); } public function testCollapse() @@ -48,8 +52,8 @@ public function testCollapse() $this->assertEquals(['foo', 'bar', 'baz'], Arr::collapse($data)); // Case including numeric and string elements - $array = [[1], [2], [3], ['foo', 'bar'], collect(['baz', 'boom'])]; - $this->assertEquals([1, 2, 3, 'foo', 'bar', 'baz', 'boom'], Arr::collapse($array)); + $array = [[1], [2], [3], ['foo', 'bar']]; + $this->assertEquals([1, 2, 3, 'foo', 'bar'], Arr::collapse($array)); // Case with empty two-dimensional arrays $emptyArray = [[], [], []]; @@ -504,6 +508,10 @@ public function testGet() $this->assertSame('dayle', Arr::get($array, 'names.otherDeveloper', function () { return 'dayle'; })); + + // Test array has a null key + $this->assertSame('bar', Arr::get(['' => 'bar'], '')); + $this->assertSame('bar', Arr::get(['' => ['' => 'bar']], '.')); } public function testHas() @@ -619,6 +627,8 @@ public function testIsList() $this->assertTrue(Arr::isList([0 => 'foo', 'bar'])); $this->assertTrue(Arr::isList([0 => 'foo', 1 => 'bar'])); + $this->assertFalse(Arr::isList([-1 => 1])); + $this->assertFalse(Arr::isList([-1 => 1, 0 => 2])); $this->assertFalse(Arr::isList([1 => 'foo', 'bar'])); $this->assertFalse(Arr::isList([1 => 'foo', 0 => 'bar'])); $this->assertFalse(Arr::isList([0 => 'foo', 'bar' => 'baz'])); @@ -632,6 +642,17 @@ public function testOnly() $array = Arr::only($array, ['name', 'price']); $this->assertEquals(['name' => 'Desk', 'price' => 100], $array); $this->assertEmpty(Arr::only($array, ['nonExistingKey'])); + + $this->assertEmpty(Arr::only($array, null)); + + // Test with array having numeric keys + $this->assertEquals(['foo'], Arr::only(['foo', 'bar', 'baz'], 0)); + $this->assertEquals([1 => 'bar', 2 => 'baz'], Arr::only(['foo', 'bar', 'baz'], [1, 2])); + $this->assertEmpty(Arr::only(['foo', 'bar', 'baz'], [3])); + + // Test with array having numeric key and string key + $this->assertEquals(['foo'], Arr::only(['foo', 'bar' => 'baz'], 0)); + $this->assertEquals(['bar' => 'baz'], Arr::only(['foo', 'bar' => 'baz'], 'bar')); } public function testPluck() @@ -1501,5 +1522,15 @@ public function testSelect() 'name' => 'Abigail', ], ], Arr::select($array, 'name')); + + $this->assertEquals([ + [], + [], + ], Arr::select($array, 'nonExistingKey')); + + $this->assertEquals([ + [], + [], + ], Arr::select($array, null)); } }