diff --git a/.github/workflows/code-quality.yaml b/.github/workflows/code-quality.yaml index 840f47e5..7e3db30d 100644 --- a/.github/workflows/code-quality.yaml +++ b/.github/workflows/code-quality.yaml @@ -23,7 +23,7 @@ jobs: - name: Install PHP and PHP Code Sniffer uses: shivammathur/setup-php@v2 with: - php-version: '8.2' + php-version: '8.3' tools: phpcs coverage: none diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1ee4b8c9..2c36b2d5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: max-parallel: 6 matrix: operatingSystem: [ubuntu-latest, windows-latest] - phpVersion: ['8.2', '8.3', '8.4', '8.5'] + phpVersion: ['8.3', '8.4', '8.5'] fail-fast: false runs-on: ${{ matrix.operatingSystem }} name: ${{ matrix.operatingSystem }} / PHP ${{ matrix.phpVersion }} diff --git a/composer.json b/composer.json index 5eff4bd7..4ba7924d 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ } ], "require": { - "php": "^8.2", + "php": "^8.3", "ext-ctype": "*", "ext-curl": "*", "ext-dom": "*", @@ -38,33 +38,34 @@ "assetic/framework": "^3.2.1", "doctrine/dbal": "^3.0", "enshrined/svg-sanitize": "~0.16", - "laravel/framework": "^12.30.1", - "laravel/tinker": "^2.8.1", + "laravel/framework": "^13.0", + "laravel/tinker": "^3.0", "league/csv": "~9.1", - "nesbot/carbon": "^3.0", + "nesbot/carbon": "^3.8.4", "scssphp/scssphp": "~1.0", - "symfony/console": "^7.2", - "symfony/process": "^7.1", - "symfony/yaml": "^6.4|^7.0", + "symfony/console": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0", "twig/twig": "^3.14", "wikimedia/less.php": "^5.0", "wikimedia/minify": "~2.2", "winter/laravel-config-writer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^11.0", + "phpunit/phpunit": "^11.5.50", "squizlabs/php_codesniffer": "^3.2", "php-parallel-lint/php-parallel-lint": "^1.0", "meyfa/phpunit-assert-gd": "^4.2", "mockery/mockery": "^1.6|^2.0", "dms/phpunit-arraysubset-asserts": "dev-add-phpunit-11-support", - "orchestra/testbench": "^10.0", + "orchestra/testbench": "^11.0", "larastan/larastan": "^3.6.0" }, "repositories": [ { "type": "vcs", - "url": "https://github.com/pieterocp/phpunit-arraysubset-asserts" + "url": "https://github.com/pieterocp/phpunit-arraysubset-asserts", + "no-api": true } ], "suggest": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 37a96bd5..23c788eb 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -12,12 +12,6 @@ parameters: count: 1 path: src/Auth/Models/Group.php - - - message: '#^Method Winter\\Storm\\Auth\\Models\\Preferences\:\:findRecord\(\) should return Winter\\Storm\\Auth\\Models\\Preferences\|null but returns stdClass\|null\.$#' - identifier: return.type - count: 1 - path: src/Auth/Models/Preferences.php - - message: '#^Call to an undefined method \$this\(Winter\\Storm\\Auth\\Models\\Role\)\:\:getOriginalEncryptableValues\(\)\.$#' identifier: method.notFound @@ -174,54 +168,6 @@ parameters: count: 1 path: src/Database/Model.php - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\BelongsTo constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\BelongsToMany constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\HasMany constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\HasManyThrough constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\HasOne constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\HasOneThrough constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\MorphTo constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - - - message: '#^Parameter \#1 \$query of class Winter\\Storm\\Database\\Relations\\MorphToMany constructor expects Illuminate\\Database\\Eloquent\\Builder\, Illuminate\\Database\\Eloquent\\Builder\ given\.$#' - identifier: argument.type - count: 1 - path: src/Database/Model.php - - message: '#^Return type \(Winter\\Storm\\Database\\Collection\) of method Winter\\Storm\\Database\\Model\:\:newCollection\(\) should be compatible with return type \(Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\), static\(Illuminate\\Database\\Eloquent\\Model\)\>\) of method Illuminate\\Database\\Eloquent\\Model\:\:newCollection\(\)$#' identifier: method.childReturnType @@ -1021,7 +967,7 @@ parameters: path: src/Support/Testing/Fakes/MailFake.php - - message: '#^Parameter \#2 \$data \(array\) of method Winter\\Storm\\Support\\Testing\\Fakes\\MailFake\:\:queue\(\) should be compatible with parameter \$queue \(string\|null\) of method Illuminate\\Support\\Testing\\Fakes\\MailFake\:\:queue\(\)$#' + message: '#^Parameter \#2 \$data \(array\) of method Winter\\Storm\\Support\\Testing\\Fakes\\MailFake\:\:queue\(\) should be compatible with parameter \$queue \(BackedEnum\|string\|null\) of method Illuminate\\Support\\Testing\\Fakes\\MailFake\:\:queue\(\)$#' identifier: method.childParameterType count: 1 path: src/Support/Testing/Fakes/MailFake.php diff --git a/src/Auth/Models/Preferences.php b/src/Auth/Models/Preferences.php index 79317d40..532173df 100644 --- a/src/Auth/Models/Preferences.php +++ b/src/Auth/Models/Preferences.php @@ -13,8 +13,8 @@ * @property string|null $item Represents the item name of the preference. * @property int|null $user_id Represents the user ID that this preference belongs to. * - * @method static \Winter\Storm\Database\QueryBuilder applyKeyAndUser($key, $user = null) Scope to find a setting record - * for the specified module (or plugin) name, setting name and user. + * @method static \Illuminate\Database\Eloquent\Builder applyKeyAndUser($key, $user = null) Scope to find a + * setting record for the specified module (or plugin) name, setting name and user. */ class Preferences extends Model { @@ -167,10 +167,10 @@ public static function findRecord($key, $user = null) /** * Scope to find a setting record for the specified module (or plugin) name, setting name and user. - * @param \Winter\Storm\Database\QueryBuilder $query + * @param \Illuminate\Database\Eloquent\Builder $query * @param string $key Specifies the setting key value, for example 'backend:items.perpage' * @param mixed $user An optional user object. - * @return mixed Returns the found record or null. + * @return \Illuminate\Database\Eloquent\Builder Returns the scoped query builder. */ public function scopeApplyKeyAndUser($query, $key, $user = null) { diff --git a/src/Database/Concerns/HasRelationships.php b/src/Database/Concerns/HasRelationships.php index 2373a01c..7f745864 100644 --- a/src/Database/Concerns/HasRelationships.php +++ b/src/Database/Concerns/HasRelationships.php @@ -913,6 +913,11 @@ protected function relationMethodDefinition(string $name, bool $ignoreResolved = /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localKey) { @@ -926,6 +931,11 @@ protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localK /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newHasOneThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) { @@ -939,6 +949,11 @@ protected function newHasOneThrough(Builder $query, Model $farParent, Model $thr /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey) { @@ -968,6 +983,11 @@ public function guessBelongsToManyRelation() /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newBelongsTo(Builder $query, Model $child, $foreignKey, $ownerKey, $relation) { @@ -981,6 +1001,11 @@ protected function newBelongsTo(Builder $query, Model $child, $foreignKey, $owne /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation) { @@ -994,6 +1019,11 @@ protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $owner /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newHasMany(Builder $query, Model $parent, $foreignKey, $localKey) { @@ -1007,6 +1037,11 @@ protected function newHasMany(Builder $query, Model $parent, $foreignKey, $local /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newHasManyThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) { @@ -1020,6 +1055,11 @@ protected function newHasManyThrough(Builder $query, Model $farParent, Model $th /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey) { @@ -1033,6 +1073,11 @@ protected function newMorphMany(Builder $query, Model $parent, $type, $id, $loca /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newBelongsToMany( Builder $query, @@ -1054,6 +1099,11 @@ protected function newBelongsToMany( /** * {@inheritDoc} + * + * Storm's relation classes are non-generic and their constructors accept a + * `Builder`, so we override the inherited `Builder` param type here. + * + * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query */ protected function newMorphToMany( Builder $query, diff --git a/src/Database/Traits/ArraySource.php b/src/Database/Traits/ArraySource.php index 1c9e09fe..adc39acd 100644 --- a/src/Database/Traits/ArraySource.php +++ b/src/Database/Traits/ArraySource.php @@ -39,7 +39,20 @@ public static function bootArraySource(): void if (!in_array('sqlite', \PDO::getAvailableDrivers())) { throw new ApplicationException('You must enable the SQLite PDO driver to use the ArraySource trait'); } + } + /** + * Boots the temporary SQLite datasource for this model. + * + * This is deferred out of the trait's boot method (`bootArraySource`) because Laravel 13 no + * longer permits a model to be instantiated while it is still booting -- doing so throws a + * LogicException. Building the datasource requires an instance to read the model's (overridable) + * array source configuration, as well as model inserts (which themselves instantiate the model), + * so the work is performed lazily the first time the connection is resolved, by which point the + * model has always finished booting. + */ + protected static function arraySourceBootConnection(): void + { $instance = new static; static::arraySourceSetDbConnection( @@ -79,6 +92,10 @@ public function getRecords() */ public static function resolveConnection($connection = null) { + if (!isset(static::$arraySourceConnection)) { + static::arraySourceBootConnection(); + } + return static::$arraySourceConnection; } diff --git a/src/Foundation/Application.php b/src/Foundation/Application.php index aba5b55a..9655ab4a 100644 --- a/src/Foundation/Application.php +++ b/src/Foundation/Application.php @@ -468,7 +468,7 @@ public function registerCoreContainerAliases() 'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class], 'hash' => [\Illuminate\Contracts\Hashing\Hasher::class], 'translator' => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class], - 'log' => [\Illuminate\Log\Logger::class, \Psr\Log\LoggerInterface::class], + 'log' => [\Illuminate\Log\LogManager::class, \Psr\Log\LoggerInterface::class], 'mail.manager' => [\Illuminate\Mail\MailManager::class, \Illuminate\Contracts\Mail\Factory::class], 'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class], 'queue' => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class], diff --git a/src/Foundation/Console/DownCommand.php b/src/Foundation/Console/DownCommand.php index f4b336d8..32445db1 100644 --- a/src/Foundation/Console/DownCommand.php +++ b/src/Foundation/Console/DownCommand.php @@ -20,7 +20,7 @@ protected function getDownFilePayload() 'redirect' => $this->redirectPath(), 'retry' => $this->getRetryTime(), 'refresh' => $this->option('refresh'), - 'secret' => $this->option('secret'), + 'secret' => $this->getSecret(), 'status' => (int) $this->option('status'), 'template' => $this->prerenderView(), ];