diff --git a/src/Config/Repository.php b/src/Config/Repository.php index 40a334376..58679ba7b 100644 --- a/src/Config/Repository.php +++ b/src/Config/Repository.php @@ -174,11 +174,11 @@ public function set($key, $value = null) * Load the configuration group for the key. * * @param string $group - * @param string $namespace + * @param string|null $namespace * @param string $collection * @return void */ - protected function load($group, $namespace, $collection) + protected function load($group, ?string $namespace, $collection) { $env = $this->environment; @@ -191,10 +191,10 @@ protected function load($group, $namespace, $collection) $items = $this->loader->load($env, $group, $namespace); - // If we've already loaded this collection, we will just bail out since we do - // not want to load it again. Once items are loaded a first time they will - // stay kept in memory within this class and not loaded from disk again. - if (isset($this->afterLoad[$namespace])) { + // After load callbacks are only ever registered against a real namespace, so + // the global namespace (null) can never have one. Guarding here also avoids + // using null as an array offset, which is deprecated as of PHP 8.5. + if ($namespace !== null && isset($this->afterLoad[$namespace])) { $items = $this->callAfterLoad($namespace, $group, $items); } @@ -209,7 +209,7 @@ protected function load($group, $namespace, $collection) * @param array $items * @return array */ - protected function callAfterLoad($namespace, $group, $items) + protected function callAfterLoad(string $namespace, $group, $items) { $callback = $this->afterLoad[$namespace]; @@ -312,7 +312,7 @@ public function package($namespace, $hint) * @param \Closure $callback * @return void */ - public function afterLoading($namespace, Closure $callback) + public function afterLoading(string $namespace, Closure $callback) { $this->afterLoad[$namespace] = $callback; } diff --git a/src/Console/Traits/ProcessesQuery.php b/src/Console/Traits/ProcessesQuery.php index 19d88d758..06cbc1d21 100644 --- a/src/Console/Traits/ProcessesQuery.php +++ b/src/Console/Traits/ProcessesQuery.php @@ -16,7 +16,7 @@ trait ProcessesQuery * query by the provided chunkSize, running the callback on each record and * limiting number of records processed to the provided limit */ - public function processQuery(Builder $query, callable $callback, int $chunkSize = 100, int $limit = null): void + public function processQuery(Builder $query, callable $callback, int $chunkSize = 100, ?int $limit = null): void { $totalRecords = $query->count(); diff --git a/src/Halcyon/Processors/Processor.php b/src/Halcyon/Processors/Processor.php index 8a6b79df5..4d6ba3bc4 100644 --- a/src/Halcyon/Processors/Processor.php +++ b/src/Halcyon/Processors/Processor.php @@ -19,6 +19,11 @@ public function processSelectOne(Builder $query, $result) $fileName = array_get($result, 'fileName'); + // A record without a filename is not a valid template, so treat it as no result. + if ($fileName === null) { + return null; + } + return [$fileName => $this->parseTemplateContent($query, $result, $fileName)]; } @@ -39,6 +44,12 @@ public function processSelect(Builder $query, $results) foreach ($results as $result) { $fileName = array_get($result, 'fileName'); + + // Skip records without a filename so they cannot collide on an empty key. + if ($fileName === null) { + continue; + } + $items[$fileName] = $this->parseTemplateContent($query, $result, $fileName); } diff --git a/src/Html/FormBuilder.php b/src/Html/FormBuilder.php index 640d09c11..d59f49a07 100644 --- a/src/Html/FormBuilder.php +++ b/src/Html/FormBuilder.php @@ -478,12 +478,12 @@ public function selectYear(string $name, int $begin = 1900, ?int $end = null, st /** * Create a select month field. */ - public function selectMonth(string $name, string|array|null $selected = null, array $options = [], $format = '%B'): string + public function selectMonth(string $name, string|array|null $selected = null, array $options = [], $format = 'F'): string { $months = []; foreach (range(1, 12) as $month) { - $months[$month] = strftime($format, mktime(0, 0, 0, $month, 1)); + $months[$month] = date($format, mktime(0, 0, 0, $month, 1)); } return $this->select($name, $months, $selected, $options); diff --git a/src/Support/Facades/Form.php b/src/Support/Facades/Form.php index 10edf557d..098f68e01 100644 --- a/src/Support/Facades/Form.php +++ b/src/Support/Facades/Form.php @@ -19,9 +19,9 @@ * @method static string file(string $name, array $options = []) * @method static string textarea(string $name, string $value = null, array $options = []) * @method static string select(string $name, array $list = [], string $value = null, array $options = []) - * @method static string selectRange(string $name, string $begin, string $end, string $selected = null, array $options = []) + * @method static string selectRange(string $name, string|int|float $begin, string|int|float $end, string|array|null $selected = null, array $options = []) * @method static string selectYear() - * @method static string selectMonth(string $name, string $selected = null, array $options = [], string $format = '%B') + * @method static string selectMonth(string $name, string|array|null $selected = null, array $options = [], string $format = 'F') * @method static string getSelectOption(string|array $display, string $value, string $selected) * @method static string checkbox(string $name, $value = 1, bool $checked = null, array $options = []) * @method static string radio(string $name, $value = null, bool $checked = null, array $options = []) diff --git a/tests/Scheduling/ScheduleListCommandTest.php b/tests/Scheduling/ScheduleListCommandTest.php index 7e5e3b04c..02f678834 100644 --- a/tests/Scheduling/ScheduleListCommandTest.php +++ b/tests/Scheduling/ScheduleListCommandTest.php @@ -54,7 +54,7 @@ public function testDisplaySchedule() ->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooJob Next Due: 1 minute from now') ->expectsOutput(' 0 9,17 * * * php artisan inspire ......... Next Due: 9 hours from now') ->expectsOutput(' 0 10 * * * php artisan inspire ........ Next Due: 10 hours from now') - ->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now') + ->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now') ->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall::fooFunction Next Due: 1 minute from now') ->expectsOutput(' * * * * * Closure at: '.$closureFilePath.':'.$closureLineNumber.' Next Due: 1 minute from now'); } @@ -78,7 +78,7 @@ public function testDisplayScheduleWithSort() ->assertSuccessful() ->expectsOutput(' * * * * * php artisan foobar a='.ProcessUtils::escapeArgument('b').' ... Next Due: 1 minute from now') ->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooJob Next Due: 1 minute from now') - ->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now') + ->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now') ->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall::fooFunction Next Due: 1 minute from now') ->expectsOutput(' * * * * * Closure at: '.$closureFilePath.':'.$closureLineNumber.' Next Due: 1 minute from now') ->expectsOutput(' 0 9,17 * * * php artisan inspire ......... Next Due: 9 hours from now')