From f08994907db78caa12981bfd285a57231b52a773 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Mon, 8 Jan 2024 14:27:37 -0600 Subject: [PATCH 01/35] Add an option to specify the default path to the models directory --- src/Illuminate/Database/Console/PruneCommand.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index aeb10e2df6cc..255e5e26e7bc 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -23,7 +23,8 @@ class PruneCommand extends Command {--model=* : Class names of the models to be pruned} {--except=* : Class names of the models to be excluded from pruning} {--chunk=1000 : The number of models to retrieve per chunk of models to be deleted} - {--pretend : Display the number of prunable records found instead of deleting them}'; + {--pretend : Display the number of prunable records found instead of deleting them} + {--default-path=Models : The default path where models are located}'; /** * The console command description. @@ -121,7 +122,7 @@ protected function models() */ protected function getDefaultPath() { - return app_path('Models'); + return app_path($this->option('default-path')); } /** From e51f1460084c0efe5a8eca451e79bc87eeee706c Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 9 Jan 2024 09:23:02 -0600 Subject: [PATCH 02/35] Change the argument to path --- src/Illuminate/Database/Console/PruneCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index 255e5e26e7bc..003bc6044a91 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -24,7 +24,7 @@ class PruneCommand extends Command {--except=* : Class names of the models to be excluded from pruning} {--chunk=1000 : The number of models to retrieve per chunk of models to be deleted} {--pretend : Display the number of prunable records found instead of deleting them} - {--default-path=Models : The default path where models are located}'; + {--path=Models : The default path where models are located}'; /** * The console command description. @@ -122,7 +122,7 @@ protected function models() */ protected function getDefaultPath() { - return app_path($this->option('default-path')); + return app_path($this->option('path')); } /** From dcc653fc383a5cbdfd3b39cdc4352b1d93db9173 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Tue, 9 Jan 2024 17:22:40 +0100 Subject: [PATCH 03/35] [10.x] Add a `threshold` parameter to the `Number::spell` helper (#49610) * [10.x] Add a `threshold` parameter to the `Number::spell` helper Adds a parameter to limit how high numbers are spelled out. * Add docblock for the threshold parameter * adjust logic * formatting --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Number.php | 12 +++++++++++- tests/Support/SupportNumberTest.php | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Number.php b/src/Illuminate/Support/Number.php index fbd3edc38691..f034a66a8eec 100644 --- a/src/Illuminate/Support/Number.php +++ b/src/Illuminate/Support/Number.php @@ -46,12 +46,22 @@ public static function format(int|float $number, ?int $precision = null, ?int $m * * @param int|float $number * @param string|null $locale + * @param int|null $after + * @param int|null $until * @return string */ - public static function spell(int|float $number, ?string $locale = null) + public static function spell(int|float $number, ?string $locale = null, ?int $after = null, ?int $until = null) { static::ensureIntlExtensionIsInstalled(); + if (! is_null($after) && $number <= $after) { + return static::format($number, locale: $locale); + } + + if (! is_null($until) && $number >= $until) { + return static::format($number, locale: $locale); + } + $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::SPELLOUT); return $formatter->format($number); diff --git a/tests/Support/SupportNumberTest.php b/tests/Support/SupportNumberTest.php index ef1e619081f2..c15dafddf812 100644 --- a/tests/Support/SupportNumberTest.php +++ b/tests/Support/SupportNumberTest.php @@ -77,6 +77,22 @@ public function testSpelloutWithLocale() $this->assertSame('trois', Number::spell(3, 'fr')); } + public function testSpelloutWithThreshold() + { + $this->needsIntlExtension(); + + $this->assertSame('9', Number::spell(9, after: 10)); + $this->assertSame('10', Number::spell(10, after: 10)); + $this->assertSame('eleven', Number::spell(11, after: 10)); + + $this->assertSame('nine', Number::spell(9, until: 10)); + $this->assertSame('10', Number::spell(10, until: 10)); + $this->assertSame('11', Number::spell(11, until: 10)); + + $this->assertSame('ten thousand', Number::spell(10000, until: 50000)); + $this->assertSame('100,000', Number::spell(100000, until: 50000)); + } + public function testOrdinal() { $this->assertSame('1st', Number::ordinal(1)); From 299aae5462b17319d943879a4abf8b8f61347406 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 9 Jan 2024 17:13:05 +0000 Subject: [PATCH 04/35] Update CHANGELOG --- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6636b6639e1f..47ae112019c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,42 @@ # Release Notes for 10.x -## [Unreleased](https://github.com/laravel/framework/compare/v10.39.0...10.x) +## [Unreleased](https://github.com/laravel/framework/compare/v10.40.0...10.x) + +## [v10.40.0](https://github.com/laravel/framework/compare/v10.39.0...v10.40.0) - 2024-01-09 + +* [10.x] `Model::preventAccessingMissingAttributes()` raises exception for enums & primitive castable attributes that were not retrieved by [@cosmastech](https://github.com/cosmastech) in https://github.com/laravel/framework/pull/49480 +* [10.x] Include system versioned tables for MariaDB by [@hafezdivandari](https://github.com/hafezdivandari) in https://github.com/laravel/framework/pull/49509 +* [10.x] Fixes the `Arr::dot()` method to properly handle indexes array by [@kayw-geek](https://github.com/kayw-geek) in https://github.com/laravel/framework/pull/49507 +* [10.x] Expand Gate::allows & Gate::denies signature by [@antonkomarev](https://github.com/antonkomarev) in https://github.com/laravel/framework/pull/49503 +* [10.x] Improve numeric comparison for custom casts by [@imahmood](https://github.com/imahmood) in https://github.com/laravel/framework/pull/49504 +* [10.x] Add session except method by [@xurshudyan](https://github.com/xurshudyan) in https://github.com/laravel/framework/pull/49520 +* [10.x] Add `Number::clamp` by [@jbrooksuk](https://github.com/jbrooksuk) in https://github.com/laravel/framework/pull/49512 +* [10.x] Fix Schedule test by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/49538 +* [10.x] Use correct format of date by [@buismaarten](https://github.com/buismaarten) in https://github.com/laravel/framework/pull/49541 +* [10.x] Clean Arr by [@michaelnabil230](https://github.com/michaelnabil230) in https://github.com/laravel/framework/pull/49530 +* [10.x] Make ComponentAttributeBag Arrayable by [@iamgergo](https://github.com/iamgergo) in https://github.com/laravel/framework/pull/49524 +* [10.x] Fix whenAggregated when default is not specified by [@lovePizza](https://github.com/lovePizza) in https://github.com/laravel/framework/pull/49521 +* [10.x] Update AsArrayObject.php to use ARRAY_AS_PROPS flag by [@pintend](https://github.com/pintend) in https://github.com/laravel/framework/pull/49534 +* [10.x] Remove invalid `RedisCluster::client()` call by [@tillkruss](https://github.com/tillkruss) in https://github.com/laravel/framework/pull/49560 +* [10.x] Remove unused code from `PhpRedisConnector` by [@tillkruss](https://github.com/tillkruss) in https://github.com/laravel/framework/pull/49559 +* [10.x] Flush about command during test runs by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/49557 +* [10.x] Fix parentOfParameter method by [@iamgergo](https://github.com/iamgergo) in https://github.com/laravel/framework/pull/49548 +* [10.x] Make the Schema Builder macroable by [@kevinb1989](https://github.com/kevinb1989) in https://github.com/laravel/framework/pull/49547 +* [10.x] Remove unused code from tests by [@imahmood](https://github.com/imahmood) in https://github.com/laravel/framework/pull/49566 +* [10.x] Update Query/Builder.php $columns typehint by [@Grldk](https://github.com/Grldk) in https://github.com/laravel/framework/pull/49563 +* [10.x] Add assertViewEmpty to TestView by [@dwightwatson](https://github.com/dwightwatson) in https://github.com/laravel/framework/pull/49558 +* [10.x] Update tailwind.blade.php for dark mode by [@sabinchacko03](https://github.com/sabinchacko03) in https://github.com/laravel/framework/pull/49515 +* [10.x] Fix deprecation with null value in cache FileStore by [@driesvints](https://github.com/driesvints) in https://github.com/laravel/framework/pull/49578 +* [10.x] Allow Vite asset path customization by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/framework/pull/49437 +* [10.x] Type hinting of the second parameter of date- and time-related `where*()` methods of `Illuminate\Database\Query\Builder` by [@lorenzolosa](https://github.com/lorenzolosa) in https://github.com/laravel/framework/pull/49599 +* [10.x] Fix Stringable::convertCase() return type by [@vaites](https://github.com/vaites) in https://github.com/laravel/framework/pull/49590 +* Allow \Blade::stringable() to be called on native Iterables by [@tsjason](https://github.com/tsjason) in https://github.com/laravel/framework/pull/49591 +* [10.x] Refactor time handling using `InteractsWithTime` trait method by [@xurshudyan](https://github.com/xurshudyan) in https://github.com/laravel/framework/pull/49601 +* [10.x] Add `assertCount` test helper by [@xurshudyan](https://github.com/xurshudyan) in https://github.com/laravel/framework/pull/49609 +* [10.x] Ability to establish connection without using Config Repository by [@deleugpn](https://github.com/deleugpn) in https://github.com/laravel/framework/pull/49527 +* [10.x] Add APA style title helper by [@hotmeteor](https://github.com/hotmeteor) in https://github.com/laravel/framework/pull/49572 +* [10.x] Fix usage of alternatives in error output by [@Mrjavaci](https://github.com/Mrjavaci) in https://github.com/laravel/framework/pull/49614 +* [10.x] Use locks for queue job popping for PlanetScale's MySQL-compatible Vitess 19 engine by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/framework/pull/49561 ## [v10.39.0](https://github.com/laravel/framework/compare/v10.38.2...v10.39.0) - 2023-12-27 From 94550906944507d496d0e3735eea48efe69f799f Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 9 Jan 2024 11:35:23 -0600 Subject: [PATCH 05/35] Allow an array, but fall back to app/Models --- src/Illuminate/Database/Console/PruneCommand.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index 003bc6044a91..a2026a3f45c4 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -24,7 +24,7 @@ class PruneCommand extends Command {--except=* : Class names of the models to be excluded from pruning} {--chunk=1000 : The number of models to retrieve per chunk of models to be deleted} {--pretend : Display the number of prunable records found instead of deleting them} - {--path=Models : The default path where models are located}'; + {--path=* : Absolute path(s) to directories where models are located}'; /** * The console command description. @@ -97,7 +97,7 @@ protected function models() throw new InvalidArgumentException('The --models and --except options cannot be combined.'); } - return collect((new Finder)->in($this->getDefaultPath())->files()->name('*.php')) + return collect((new Finder)->in($this->getPath())->files()->name('*.php')) ->map(function ($model) { $namespace = $this->laravel->getNamespace(); @@ -120,9 +120,14 @@ protected function models() * * @return string */ - protected function getDefaultPath() + protected function getPath() { - return app_path($this->option('path')); + + if (! empty($path = $this->option('path'))) { + return $path; + } + + return app_path('Models'); } /** From 9d687c93033608adfb89cf64efe53ea4ec945c25 Mon Sep 17 00:00:00 2001 From: Davo Hynds Date: Tue, 9 Jan 2024 13:00:30 -0600 Subject: [PATCH 06/35] Fix styling and doc block --- src/Illuminate/Database/Console/PruneCommand.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index a2026a3f45c4..39481536a8d9 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -116,13 +116,12 @@ protected function models() } /** - * Get the default path where models are located. + * Get the path where models are located. * * @return string */ protected function getPath() { - if (! empty($path = $this->option('path'))) { return $path; } From 61d100a647e8b99aaef71265fb2497c895e0ece4 Mon Sep 17 00:00:00 2001 From: Luan Freitas <33601626+luanfreitasdev@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:24:03 -0300 Subject: [PATCH 07/35] Revert "[10.x] Make ComponentAttributeBag Arrayable (#49524)" (#49623) This reverts commit a5f661f403bd52feff3dc5d25f55fb8f97b551cc. --- src/Illuminate/View/ComponentAttributeBag.php | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/Illuminate/View/ComponentAttributeBag.php b/src/Illuminate/View/ComponentAttributeBag.php index b5302e3e3ec4..3c3d1a27dbff 100644 --- a/src/Illuminate/View/ComponentAttributeBag.php +++ b/src/Illuminate/View/ComponentAttributeBag.php @@ -4,7 +4,6 @@ use ArrayAccess; use ArrayIterator; -use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Arr; use Illuminate\Support\HtmlString; @@ -15,7 +14,7 @@ use JsonSerializable; use Traversable; -class ComponentAttributeBag implements Arrayable, ArrayAccess, IteratorAggregate, JsonSerializable, Htmlable +class ComponentAttributeBag implements ArrayAccess, IteratorAggregate, JsonSerializable, Htmlable { use Conditionable, Macroable; @@ -487,16 +486,6 @@ public function jsonSerialize(): mixed return $this->attributes; } - /** - * Convert the object into an array. - * - * @return array - */ - public function toArray() - { - return $this->attributes; - } - /** * Implode the attributes into a single HTML ready string. * From 47c2c6fa91330caaa560f7af3b155bda795118bd Mon Sep 17 00:00:00 2001 From: Dwight Watson Date: Wed, 10 Jan 2024 08:33:53 +1100 Subject: [PATCH 08/35] Fix return value and docblock (#49627) --- src/Illuminate/Testing/TestView.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Testing/TestView.php b/src/Illuminate/Testing/TestView.php index ad64fb5b73a7..350e17576ab6 100644 --- a/src/Illuminate/Testing/TestView.php +++ b/src/Illuminate/Testing/TestView.php @@ -108,12 +108,14 @@ public function assertViewMissing($key) /** * Assert that the view's rendered content is empty. + * + * @return $this */ public function assertViewEmpty() { PHPUnit::assertEmpty($this->rendered); - return true; + return $this; } /** From 1c496d0d7f7aa86025f5cf82d67134a7abfb838c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 9 Jan 2024 16:02:00 -0600 Subject: [PATCH 09/35] use base path --- src/Illuminate/Database/Console/PruneCommand.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index 65ac612167da..2cb0a603ef79 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -24,9 +24,9 @@ class PruneCommand extends Command protected $signature = 'model:prune {--model=* : Class names of the models to be pruned} {--except=* : Class names of the models to be excluded from pruning} + {--path=* : Absolute path(s) to directories where models are located} {--chunk=1000 : The number of models to retrieve per chunk of models to be deleted} - {--pretend : Display the number of prunable records found instead of deleting them} - {--path=* : Absolute path(s) to directories where models are located}'; + {--pretend : Display the number of prunable records found instead of deleting them}'; /** * The console command description. @@ -149,12 +149,14 @@ protected function models() /** * Get the path where models are located. * - * @return string|string[] + * @return string[]|string */ protected function getPath() { if (! empty($path = $this->option('path'))) { - return $path; + return collect($path)->map(function ($path) { + return base_path($path); + })->all(); } return app_path('Models'); From 8f48538ed651173d4dcb3ee42c9c90453adc5869 Mon Sep 17 00:00:00 2001 From: Frankie Jarrett Date: Tue, 9 Jan 2024 16:05:18 -0600 Subject: [PATCH 10/35] dispatchIf() and dispatchUnless() for job chains (#49624) --- .../Foundation/Bus/PendingChain.php | 24 +++++++++- tests/Integration/Queue/JobChainingTest.php | 48 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Bus/PendingChain.php b/src/Illuminate/Foundation/Bus/PendingChain.php index 8d3c6892615a..2fb14990c56a 100644 --- a/src/Illuminate/Foundation/Bus/PendingChain.php +++ b/src/Illuminate/Foundation/Bus/PendingChain.php @@ -132,7 +132,7 @@ public function catchCallbacks() } /** - * Dispatch the job with the given arguments. + * Dispatch the job chain. * * @return \Illuminate\Foundation\Bus\PendingDispatch */ @@ -165,4 +165,26 @@ public function dispatch() return app(Dispatcher::class)->dispatch($firstJob); } + + /** + * Dispatch the job chain if the given truth test passes. + * + * @param bool|\Closure $boolean + * @return \Illuminate\Foundation\Bus\PendingDispatch|null + */ + public function dispatchIf($boolean) + { + return value($boolean) ? $this->dispatch() : null; + } + + /** + * Dispatch the job chain unless the given truth test passes. + * + * @param bool|\Closure $boolean + * @return \Illuminate\Foundation\Bus\PendingDispatch|null + */ + public function dispatchUnless($boolean) + { + return ! value($boolean) ? $this->dispatch() : null; + } } diff --git a/tests/Integration/Queue/JobChainingTest.php b/tests/Integration/Queue/JobChainingTest.php index 7037625b62bf..a742e7ec142d 100644 --- a/tests/Integration/Queue/JobChainingTest.php +++ b/tests/Integration/Queue/JobChainingTest.php @@ -495,6 +495,54 @@ public function testBatchConditionable() $this->assertEquals('sync1', $batch->connection()); } + + public function testJobsAreChainedWhenDispatchIfIsTrue() + { + JobChainingTestFirstJob::withChain([ + new JobChainingTestSecondJob, + ])->dispatchIf(true); + + $this->runQueueWorkerCommand(['--stop-when-empty' => true]); + + $this->assertTrue(JobChainingTestFirstJob::$ran); + $this->assertTrue(JobChainingTestSecondJob::$ran); + } + + public function testJobsAreNotChainedWhenDispatchIfIsFalse() + { + JobChainingTestFirstJob::withChain([ + new JobChainingTestSecondJob, + ])->dispatchIf(false); + + $this->runQueueWorkerCommand(['--stop-when-empty' => true]); + + $this->assertFalse(JobChainingTestFirstJob::$ran); + $this->assertFalse(JobChainingTestSecondJob::$ran); + } + + public function testJobsAreChainedWhenDispatchUnlessIsFalse() + { + JobChainingTestFirstJob::withChain([ + new JobChainingTestSecondJob, + ])->dispatchUnless(false); + + $this->runQueueWorkerCommand(['--stop-when-empty' => true]); + + $this->assertTrue(JobChainingTestFirstJob::$ran); + $this->assertTrue(JobChainingTestSecondJob::$ran); + } + + public function testJobsAreNotChainedWhenDispatchUnlessIsTrue() + { + JobChainingTestFirstJob::withChain([ + new JobChainingTestSecondJob, + ])->dispatchUnless(true); + + $this->runQueueWorkerCommand(['--stop-when-empty' => true]); + + $this->assertFalse(JobChainingTestFirstJob::$ran); + $this->assertFalse(JobChainingTestSecondJob::$ran); + } } class JobChainingTestFirstJob implements ShouldQueue From e63cea8d3b6013cf607f2ff2c142c7794bc37182 Mon Sep 17 00:00:00 2001 From: James <61766491+lioneaglesolutions@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:17:44 +1000 Subject: [PATCH 11/35] fill empty test (#49632) --- tests/Mail/MailMailableTest.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/Mail/MailMailableTest.php b/tests/Mail/MailMailableTest.php index f7f1eae7a7fb..8e17cce973a6 100644 --- a/tests/Mail/MailMailableTest.php +++ b/tests/Mail/MailMailableTest.php @@ -1133,6 +1133,38 @@ public function build() public function testAssertHasSubject() { + Container::getInstance()->instance('mailer', new class + { + public function render() + { + // + } + }); + + $mailable = new class() extends Mailable + { + public function build() + { + // + } + }; + + try { + $mailable->assertHasSubject('Foo Subject'); + $this->fail(); + } catch (AssertionFailedError $e) { + $this->assertSame("Did not see expected text [Foo Subject] in email subject.\nFailed asserting that false is true.", $e->getMessage()); + } + + $mailable = new class() extends Mailable + { + public function build() + { + $this->subject('Foo Subject'); + } + }; + + $mailable->assertHasSubject('Foo Subject'); } public function testMailableHeadersGetSent() From 784bf76726b16763e172202923dc3d3df55c10cf Mon Sep 17 00:00:00 2001 From: James <61766491+lioneaglesolutions@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:51:31 +1000 Subject: [PATCH 12/35] [11.x] Add additional context to Mailable assertion messages (#49631) * add recipient type to message * fix tests --- src/Illuminate/Mail/Mailable.php | 6 +++--- tests/Mail/MailMailableTest.php | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 7bdf38ad8541..4016ee5a210e 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -1231,7 +1231,7 @@ public function assertTo($address, $name = null) PHPUnit::assertTrue( $this->hasTo($address, $name), - "Did not see expected recipient [{$recipient}] in email recipients." + "Did not see expected recipient [{$recipient}] in email 'to' recipients." ); return $this; @@ -1264,7 +1264,7 @@ public function assertHasCc($address, $name = null) PHPUnit::assertTrue( $this->hasCc($address, $name), - "Did not see expected recipient [{$recipient}] in email recipients." + "Did not see expected recipient [{$recipient}] in email 'cc' recipients." ); return $this; @@ -1285,7 +1285,7 @@ public function assertHasBcc($address, $name = null) PHPUnit::assertTrue( $this->hasBcc($address, $name), - "Did not see expected recipient [{$recipient}] in email recipients." + "Did not see expected recipient [{$recipient}] in email 'bcc' recipients." ); return $this; diff --git a/tests/Mail/MailMailableTest.php b/tests/Mail/MailMailableTest.php index 8e17cce973a6..9c21f8b06dc8 100644 --- a/tests/Mail/MailMailableTest.php +++ b/tests/Mail/MailMailableTest.php @@ -61,7 +61,7 @@ public function render() $mailable->assertHasTo('taylor@laravel.com', 'Taylor Otwell'); $this->fail(); } catch (AssertionFailedError $e) { - $this->assertSame("Did not see expected recipient [taylor@laravel.com (Taylor Otwell)] in email recipients.\nFailed asserting that false is true.", $e->getMessage()); + $this->assertSame("Did not see expected recipient [taylor@laravel.com (Taylor Otwell)] in email 'to' recipients.\nFailed asserting that false is true.", $e->getMessage()); } $mailable = new WelcomeMailableStub; @@ -107,7 +107,7 @@ public function render() if (! is_string($address)) { $address = json_encode($address); } - $this->assertSame("Did not see expected recipient [{$address}] in email recipients.\nFailed asserting that false is true.", $e->getMessage()); + $this->assertSame("Did not see expected recipient [{$address}] in email 'to' recipients.\nFailed asserting that false is true.", $e->getMessage()); } } } @@ -146,7 +146,7 @@ public function render() $mailable->assertHasCc('taylor@laravel.com', 'Taylor Otwell'); $this->fail(); } catch (AssertionFailedError $e) { - $this->assertSame("Did not see expected recipient [taylor@laravel.com (Taylor Otwell)] in email recipients.\nFailed asserting that false is true.", $e->getMessage()); + $this->assertSame("Did not see expected recipient [taylor@laravel.com (Taylor Otwell)] in email 'cc' recipients.\nFailed asserting that false is true.", $e->getMessage()); } $mailable = new WelcomeMailableStub; @@ -204,7 +204,7 @@ public function render() if (! is_string($address)) { $address = json_encode($address); } - $this->assertSame("Did not see expected recipient [{$address}] in email recipients.\nFailed asserting that false is true.", $e->getMessage()); + $this->assertSame("Did not see expected recipient [{$address}] in email 'cc' recipients.\nFailed asserting that false is true.", $e->getMessage()); } } } @@ -243,7 +243,7 @@ public function render() $mailable->assertHasBcc('taylor@laravel.com', 'Taylor Otwell'); $this->fail(); } catch (AssertionFailedError $e) { - $this->assertSame("Did not see expected recipient [taylor@laravel.com (Taylor Otwell)] in email recipients.\nFailed asserting that false is true.", $e->getMessage()); + $this->assertSame("Did not see expected recipient [taylor@laravel.com (Taylor Otwell)] in email 'bcc' recipients.\nFailed asserting that false is true.", $e->getMessage()); } $mailable = new WelcomeMailableStub; @@ -301,7 +301,7 @@ public function render() if (! is_string($address)) { $address = json_encode($address); } - $this->assertSame("Did not see expected recipient [{$address}] in email recipients.\nFailed asserting that false is true.", $e->getMessage()); + $this->assertSame("Did not see expected recipient [{$address}] in email 'bcc' recipients.\nFailed asserting that false is true.", $e->getMessage()); } } } From 140248749f461b87426773513306eb4ba86d1303 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 11 Jan 2024 13:46:55 -0600 Subject: [PATCH 13/35] flush context on all log channels, just not default --- src/Illuminate/Log/LogManager.php | 16 ++++++++++++++++ src/Illuminate/Queue/QueueServiceProvider.php | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 60498f4ef06d..15df806d55e6 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -501,6 +501,22 @@ public function sharedContext() return $this->sharedContext; } + /** + * Flush the log context on all currently resolved channels. + * + * @return $this + */ + public function withoutContext() + { + foreach ($this->channels as $channel) { + if (method_exists($channel, 'withoutContext')) { + $channel->withoutContext(); + } + } + + return $this; + } + /** * Flush the shared context. * diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index 2f94d28a13ce..2bcd16c2ff1f 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -198,7 +198,7 @@ protected function registerWorker() }; $resetScope = function () use ($app) { - if (method_exists($app['log']->driver(), 'withoutContext')) { + if (method_exists($app['log'], 'withoutContext')) { $app['log']->withoutContext(); } From e75374205ffc4379a1398df713649a368002e48f Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Thu, 11 Jan 2024 19:47:33 +0000 Subject: [PATCH 14/35] Update facade docblocks --- src/Illuminate/Support/Facades/Log.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Log.php b/src/Illuminate/Support/Facades/Log.php index 1fb2cfca082b..37e03961ebd5 100755 --- a/src/Illuminate/Support/Facades/Log.php +++ b/src/Illuminate/Support/Facades/Log.php @@ -9,6 +9,7 @@ * @method static \Psr\Log\LoggerInterface driver(string|null $driver = null) * @method static \Illuminate\Log\LogManager shareContext(array $context) * @method static array sharedContext() + * @method static \Illuminate\Log\LogManager withoutContext() * @method static \Illuminate\Log\LogManager flushSharedContext() * @method static string|null getDefaultDriver() * @method static void setDefaultDriver(string $name) @@ -26,7 +27,6 @@ * @method static void log(mixed $level, string $message, array $context = []) * @method static void write(string $level, \Illuminate\Contracts\Support\Arrayable|\Illuminate\Contracts\Support\Jsonable|\Illuminate\Support\Stringable|array|string $message, array $context = []) * @method static \Illuminate\Log\Logger withContext(array $context = []) - * @method static \Illuminate\Log\Logger withoutContext() * @method static void listen(\Closure $callback) * @method static \Psr\Log\LoggerInterface getLogger() * @method static \Illuminate\Contracts\Events\Dispatcher getEventDispatcher() From 8bb98e39b6dea70bc0a2e8fea51eb4ed55f6ef8b Mon Sep 17 00:00:00 2001 From: Frankie Jarrett Date: Thu, 11 Jan 2024 14:33:23 -0600 Subject: [PATCH 15/35] dispatchIf() and dispatchUnless() for batches (#49639) --- src/Illuminate/Bus/PendingBatch.php | 22 +++++++ tests/Bus/BusPendingBatchTest.php | 98 +++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index 60ff3884c8b8..b9622f8cc064 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -344,4 +344,26 @@ protected function dispatchExistingBatch($batch) new BatchDispatched($batch) ); } + + /** + * Dispatch the batch if the given truth test passes. + * + * @param bool|\Closure $boolean + * @return \Illuminate\Bus\Batch|null + */ + public function dispatchIf($boolean) + { + return value($boolean) ? $this->dispatch() : null; + } + + /** + * Dispatch the batch unless the given truth test passes. + * + * @param bool|\Closure $boolean + * @return \Illuminate\Bus\Batch|null + */ + public function dispatchUnless($boolean) + { + return ! value($boolean) ? $this->dispatch() : null; + } } diff --git a/tests/Bus/BusPendingBatchTest.php b/tests/Bus/BusPendingBatchTest.php index 7cd5f7e3a80e..6a6e9186e686 100644 --- a/tests/Bus/BusPendingBatchTest.php +++ b/tests/Bus/BusPendingBatchTest.php @@ -88,4 +88,102 @@ public function test_batch_is_deleted_from_storage_if_exception_thrown_during_ba $pendingBatch->dispatch(); } + + public function test_batch_is_dispatched_when_dispatchif_is_true() + { + $container = new Container; + + $eventDispatcher = m::mock(Dispatcher::class); + $eventDispatcher->shouldReceive('dispatch')->once(); + $container->instance(Dispatcher::class, $eventDispatcher); + + $job = new class + { + use Batchable; + }; + + $pendingBatch = new PendingBatch($container, new Collection([$job])); + + $repository = m::mock(BatchRepository::class); + $repository->shouldReceive('store')->once()->andReturn($batch = m::mock(stdClass::class)); + $batch->shouldReceive('add')->once()->andReturn($batch = m::mock(Batch::class)); + + $container->instance(BatchRepository::class, $repository); + + $result = $pendingBatch->dispatchIf(true); + + $this->assertInstanceOf(Batch::class, $result); + } + + public function test_batch_is_not_dispatched_when_dispatchif_is_false() + { + $container = new Container; + + $eventDispatcher = m::mock(Dispatcher::class); + $eventDispatcher->shouldNotReceive('dispatch'); + $container->instance(Dispatcher::class, $eventDispatcher); + + $job = new class + { + use Batchable; + }; + + $pendingBatch = new PendingBatch($container, new Collection([$job])); + + $repository = m::mock(BatchRepository::class); + $container->instance(BatchRepository::class, $repository); + + $result = $pendingBatch->dispatchIf(false); + + $this->assertNull($result); + } + + public function test_batch_is_dispatched_when_dispatchunless_is_false() + { + $container = new Container; + + $eventDispatcher = m::mock(Dispatcher::class); + $eventDispatcher->shouldReceive('dispatch')->once(); + $container->instance(Dispatcher::class, $eventDispatcher); + + $job = new class + { + use Batchable; + }; + + $pendingBatch = new PendingBatch($container, new Collection([$job])); + + $repository = m::mock(BatchRepository::class); + $repository->shouldReceive('store')->once()->andReturn($batch = m::mock(stdClass::class)); + $batch->shouldReceive('add')->once()->andReturn($batch = m::mock(Batch::class)); + + $container->instance(BatchRepository::class, $repository); + + $result = $pendingBatch->dispatchUnless(false); + + $this->assertInstanceOf(Batch::class, $result); + } + + public function test_batch_is_not_dispatched_when_dispatchunless_is_true() + { + $container = new Container; + + $eventDispatcher = m::mock(Dispatcher::class); + $eventDispatcher->shouldNotReceive('dispatch'); + $container->instance(Dispatcher::class, $eventDispatcher); + + $job = new class + { + use Batchable; + }; + + $pendingBatch = new PendingBatch($container, new Collection([$job])); + + $repository = m::mock(BatchRepository::class); + $container->instance(BatchRepository::class, $repository); + + $result = $pendingBatch->dispatchUnless(true); + + $this->assertNull($result); + } } From dbce9d05c940a4b3e669709d1b7f8792a48fba62 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 11 Jan 2024 16:12:00 -0600 Subject: [PATCH 16/35] flush shared context --- src/Illuminate/Queue/QueueServiceProvider.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Queue/QueueServiceProvider.php b/src/Illuminate/Queue/QueueServiceProvider.php index 2bcd16c2ff1f..478352ae7e76 100755 --- a/src/Illuminate/Queue/QueueServiceProvider.php +++ b/src/Illuminate/Queue/QueueServiceProvider.php @@ -198,6 +198,8 @@ protected function registerWorker() }; $resetScope = function () use ($app) { + $app['log']->flushSharedContext(); + if (method_exists($app['log'], 'withoutContext')) { $app['log']->withoutContext(); } From e68a840bbf764d275894b267d31302c6bbb498fe Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Sat, 13 Jan 2024 01:15:33 +1100 Subject: [PATCH 17/35] Revert parameter name change (#49659) --- src/Illuminate/Auth/Access/Gate.php | 12 ++++++------ src/Illuminate/Contracts/Auth/Access/Gate.php | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index c757714c28cc..1f0a72007e9d 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -320,25 +320,25 @@ public function after(callable $callback) /** * Determine if all of the given abilities should be granted for the current user. * - * @param iterable|string $abilities + * @param iterable|string $ability * @param array|mixed $arguments * @return bool */ - public function allows($abilities, $arguments = []) + public function allows($ability, $arguments = []) { - return $this->check($abilities, $arguments); + return $this->check($ability, $arguments); } /** * Determine if any of the given abilities should be denied for the current user. * - * @param iterable|string $abilities + * @param iterable|string $ability * @param array|mixed $arguments * @return bool */ - public function denies($abilities, $arguments = []) + public function denies($ability, $arguments = []) { - return ! $this->allows($abilities, $arguments); + return ! $this->allows($ability, $arguments); } /** diff --git a/src/Illuminate/Contracts/Auth/Access/Gate.php b/src/Illuminate/Contracts/Auth/Access/Gate.php index 1e8b8f87041b..eb605d8279fd 100644 --- a/src/Illuminate/Contracts/Auth/Access/Gate.php +++ b/src/Illuminate/Contracts/Auth/Access/Gate.php @@ -59,20 +59,20 @@ public function after(callable $callback); /** * Determine if all of the given abilities should be granted for the current user. * - * @param iterable|string $abilities + * @param iterable|string $ability * @param array|mixed $arguments * @return bool */ - public function allows($abilities, $arguments = []); + public function allows($ability, $arguments = []); /** * Determine if any of the given abilities should be denied for the current user. * - * @param iterable|string $abilities + * @param iterable|string $ability * @param array|mixed $arguments * @return bool */ - public function denies($abilities, $arguments = []); + public function denies($ability, $arguments = []); /** * Determine if all of the given abilities should be granted for the current user. From 7dff807a162a8559062a1452ee98edf8c92acd3b Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Fri, 12 Jan 2024 14:16:03 +0000 Subject: [PATCH 18/35] Update facade docblocks --- src/Illuminate/Support/Facades/Gate.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Facades/Gate.php b/src/Illuminate/Support/Facades/Gate.php index 0e7ca7431237..4423a1d6a0fb 100644 --- a/src/Illuminate/Support/Facades/Gate.php +++ b/src/Illuminate/Support/Facades/Gate.php @@ -13,8 +13,8 @@ * @method static \Illuminate\Auth\Access\Gate policy(string $class, string $policy) * @method static \Illuminate\Auth\Access\Gate before(callable $callback) * @method static \Illuminate\Auth\Access\Gate after(callable $callback) - * @method static bool allows(iterable|string $abilities, array|mixed $arguments = []) - * @method static bool denies(iterable|string $abilities, array|mixed $arguments = []) + * @method static bool allows(iterable|string $ability, array|mixed $arguments = []) + * @method static bool denies(iterable|string $ability, array|mixed $arguments = []) * @method static bool check(iterable|string $abilities, array|mixed $arguments = []) * @method static bool any(iterable|string $abilities, array|mixed $arguments = []) * @method static bool none(iterable|string $abilities, array|mixed $arguments = []) From 534872c3fdc6dcea2bd3728b44f9302b952e5cab Mon Sep 17 00:00:00 2001 From: AJ <60591772+devajmeireles@users.noreply.github.com> Date: Fri, 12 Jan 2024 11:18:14 -0300 Subject: [PATCH 19/35] [10.x] Printing Name of The Method that Calls `ensureIntlExtensionIsInstalled` in `Number` class. (#49660) * code * formatting according to style-ci * moving the logic for inside the if condition * Update Number.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Support/Number.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Number.php b/src/Illuminate/Support/Number.php index f034a66a8eec..b6f06178a1e4 100644 --- a/src/Illuminate/Support/Number.php +++ b/src/Illuminate/Support/Number.php @@ -266,7 +266,9 @@ public static function useLocale(string $locale) protected static function ensureIntlExtensionIsInstalled() { if (! extension_loaded('intl')) { - throw new RuntimeException('The "intl" PHP extension is required to use this method.'); + $method = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function']; + + throw new RuntimeException('The "intl" PHP extension is required to use the ['.$method.'] method.'); } } } From 47af503723a8e59f4dbe6bbfab78dc92d5344f33 Mon Sep 17 00:00:00 2001 From: Anas Morahhib Date: Fri, 12 Jan 2024 18:17:46 +0100 Subject: [PATCH 20/35] Update pagination tailwind.blade.php (#49665) --- src/Illuminate/Pagination/resources/views/tailwind.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Pagination/resources/views/tailwind.blade.php b/src/Illuminate/Pagination/resources/views/tailwind.blade.php index 489b6b5da2ed..aee2ad28e1d1 100644 --- a/src/Illuminate/Pagination/resources/views/tailwind.blade.php +++ b/src/Illuminate/Pagination/resources/views/tailwind.blade.php @@ -40,7 +40,7 @@
- + {{-- Previous Page Link --}} @if ($paginator->onFirstPage()) From f812cf90326e5957584255593c86e85171cce1e9 Mon Sep 17 00:00:00 2001 From: Piotr Adamczyk Date: Sat, 13 Jan 2024 19:42:08 +0100 Subject: [PATCH 21/35] [10.x] feat: add base argument to Stringable->toInteger() (#49670) * feat: add base argument to Stringable->toInteger() * fix: StyleCi --- src/Illuminate/Support/Stringable.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index c89abb01e41c..144cbb8c5537 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -1281,11 +1281,12 @@ public function toString() /** * Get the underlying string value as an integer. * + * @param int $base * @return int */ - public function toInteger() + public function toInteger($base = 10) { - return intval($this->value); + return intval($this->value, $base); } /** From 6d2f90b66c6977fc1a19bedbf2a531cfedf28d15 Mon Sep 17 00:00:00 2001 From: Su Date: Sun, 14 Jan 2024 01:44:41 +0700 Subject: [PATCH 22/35] [10.x]: Remove unused class ShouldBeUnique when make a job (#49669) --- src/Illuminate/Foundation/Console/stubs/job.queued.stub | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/stubs/job.queued.stub b/src/Illuminate/Foundation/Console/stubs/job.queued.stub index bc67adcf4790..9a7cec52a433 100644 --- a/src/Illuminate/Foundation/Console/stubs/job.queued.stub +++ b/src/Illuminate/Foundation/Console/stubs/job.queued.stub @@ -3,7 +3,6 @@ namespace {{ namespace }}; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; From c7d5e0ee29b799ea66117be5c36f6b7efc1ca33d Mon Sep 17 00:00:00 2001 From: Milwad <98118400+milwad-dev@users.noreply.github.com> Date: Sun, 14 Jan 2024 20:08:40 +0330 Subject: [PATCH 23/35] [10.x] Add tests for Eloquent methods (#49673) * Create EloquentModelLoadMaxTest.php * Create EloquentModelLoadMinTest.php * Create EloquentModelLoadSumTest.php --- .../Database/EloquentModelLoadMaxTest.php | 104 ++++++++++++++++++ .../Database/EloquentModelLoadMinTest.php | 104 ++++++++++++++++++ .../Database/EloquentModelLoadSumTest.php | 103 +++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 tests/Integration/Database/EloquentModelLoadMaxTest.php create mode 100644 tests/Integration/Database/EloquentModelLoadMinTest.php create mode 100644 tests/Integration/Database/EloquentModelLoadSumTest.php diff --git a/tests/Integration/Database/EloquentModelLoadMaxTest.php b/tests/Integration/Database/EloquentModelLoadMaxTest.php new file mode 100644 index 000000000000..cf6a5d7bd8c7 --- /dev/null +++ b/tests/Integration/Database/EloquentModelLoadMaxTest.php @@ -0,0 +1,104 @@ +increments('id'); + }); + + Schema::create('related1s', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('base_model_id'); + $table->integer('number'); + }); + + Schema::create('related2s', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('base_model_id'); + $table->integer('number'); + }); + + BaseModel::create(); + + Related1::create(['base_model_id' => 1, 'number' => 10]); + Related1::create(['base_model_id' => 1, 'number' => 11]); + Related2::create(['base_model_id' => 1, 'number' => 12]); + Related2::create(['base_model_id' => 1, 'number' => 13]); + } + + public function testLoadMaxSingleRelation() + { + $model = BaseModel::first(); + + DB::enableQueryLog(); + + $model->loadMax('related1', 'number'); + + $this->assertCount(1, DB::getQueryLog()); + $this->assertEquals(11, $model->related1_max_number); + } + + public function testLoadMaxMultipleRelations() + { + $model = BaseModel::first(); + + DB::enableQueryLog(); + + $model->loadMax(['related1', 'related2'], 'number'); + + $this->assertCount(1, DB::getQueryLog()); + $this->assertEquals(11, $model->related1_max_number); + $this->assertEquals(13, $model->related2_max_number); + } +} + +class BaseModel extends Model +{ + public $timestamps = false; + + protected $guarded = []; + + public function related1() + { + return $this->hasMany(Related1::class); + } + + public function related2() + { + return $this->hasMany(Related2::class); + } +} + +class Related1 extends Model +{ + public $timestamps = false; + + protected $fillable = ['base_model_id', 'number']; + + public function parent() + { + return $this->belongsTo(BaseModel::class); + } +} + +class Related2 extends Model +{ + public $timestamps = false; + + protected $fillable = ['base_model_id', 'number']; + + public function parent() + { + return $this->belongsTo(BaseModel::class); + } +} diff --git a/tests/Integration/Database/EloquentModelLoadMinTest.php b/tests/Integration/Database/EloquentModelLoadMinTest.php new file mode 100644 index 000000000000..b63e2ec2dc47 --- /dev/null +++ b/tests/Integration/Database/EloquentModelLoadMinTest.php @@ -0,0 +1,104 @@ +increments('id'); + }); + + Schema::create('related1s', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('base_model_id'); + $table->integer('number'); + }); + + Schema::create('related2s', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('base_model_id'); + $table->integer('number'); + }); + + BaseModel::create(); + + Related1::create(['base_model_id' => 1, 'number' => 10]); + Related1::create(['base_model_id' => 1, 'number' => 11]); + Related2::create(['base_model_id' => 1, 'number' => 12]); + Related2::create(['base_model_id' => 1, 'number' => 13]); + } + + public function testLoadMinSingleRelation() + { + $model = BaseModel::first(); + + DB::enableQueryLog(); + + $model->loadMin('related1', 'number'); + + $this->assertCount(1, DB::getQueryLog()); + $this->assertEquals(10, $model->related1_min_number); + } + + public function testLoadMinMultipleRelations() + { + $model = BaseModel::first(); + + DB::enableQueryLog(); + + $model->loadMin(['related1', 'related2'], 'number'); + + $this->assertCount(1, DB::getQueryLog()); + $this->assertEquals(10, $model->related1_min_number); + $this->assertEquals(12, $model->related2_min_number); + } +} + +class BaseModel extends Model +{ + public $timestamps = false; + + protected $guarded = []; + + public function related1() + { + return $this->hasMany(Related1::class); + } + + public function related2() + { + return $this->hasMany(Related2::class); + } +} + +class Related1 extends Model +{ + public $timestamps = false; + + protected $fillable = ['base_model_id', 'number']; + + public function parent() + { + return $this->belongsTo(BaseModel::class); + } +} + +class Related2 extends Model +{ + public $timestamps = false; + + protected $fillable = ['base_model_id', 'number']; + + public function parent() + { + return $this->belongsTo(BaseModel::class); + } +} diff --git a/tests/Integration/Database/EloquentModelLoadSumTest.php b/tests/Integration/Database/EloquentModelLoadSumTest.php new file mode 100644 index 000000000000..0e4e5fa84b8d --- /dev/null +++ b/tests/Integration/Database/EloquentModelLoadSumTest.php @@ -0,0 +1,103 @@ +increments('id'); + }); + + Schema::create('related1s', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('base_model_id'); + $table->integer('number'); + }); + + Schema::create('related2s', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('base_model_id'); + $table->integer('number'); + }); + + BaseModel::create(); + + Related1::create(['base_model_id' => 1, 'number' => 10]); + Related1::create(['base_model_id' => 1, 'number' => 11]); + Related2::create(['base_model_id' => 1, 'number' => 12]); + } + + public function testLoadSumSingleRelation() + { + $model = BaseModel::first(); + + DB::enableQueryLog(); + + $model->loadSum('related1', 'number'); + + $this->assertCount(1, DB::getQueryLog()); + $this->assertEquals(21, $model->related1_sum_number); + } + + public function testLoadSumMultipleRelations() + { + $model = BaseModel::first(); + + DB::enableQueryLog(); + + $model->loadSum(['related1', 'related2'], 'number'); + + $this->assertCount(1, DB::getQueryLog()); + $this->assertEquals(21, $model->related1_sum_number); + $this->assertEquals(12, $model->related2_sum_number); + } +} + +class BaseModel extends Model +{ + public $timestamps = false; + + protected $guarded = []; + + public function related1() + { + return $this->hasMany(Related1::class); + } + + public function related2() + { + return $this->hasMany(Related2::class); + } +} + +class Related1 extends Model +{ + public $timestamps = false; + + protected $fillable = ['base_model_id', 'number']; + + public function parent() + { + return $this->belongsTo(BaseModel::class); + } +} + +class Related2 extends Model +{ + public $timestamps = false; + + protected $fillable = ['base_model_id', 'number']; + + public function parent() + { + return $this->belongsTo(BaseModel::class); + } +} From fc0b6876ab29927a6d664d796b5c05dc70ca045e Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 15 Jan 2024 16:53:03 +0100 Subject: [PATCH 24/35] Implement draft workflow (#49683) --- .github/workflows/pull-requests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index 18b32b3261a9..050ad42f7479 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -8,5 +8,7 @@ permissions: pull-requests: write jobs: + draft: + uses: laravel/.github/.github/workflows/pull-requests.yml@main uneditable: uses: laravel/.github/.github/workflows/pull-requests.yml@main From 024442ddb828c0db8beb422a931f7c6a35670046 Mon Sep 17 00:00:00 2001 From: AJ <60591772+devajmeireles@users.noreply.github.com> Date: Mon, 15 Jan 2024 12:56:04 -0300 Subject: [PATCH 25/35] code (#49681) --- src/Illuminate/Support/Number.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Support/Number.php b/src/Illuminate/Support/Number.php index b6f06178a1e4..7719055f6224 100644 --- a/src/Illuminate/Support/Number.php +++ b/src/Illuminate/Support/Number.php @@ -144,12 +144,12 @@ public static function fileSize(int|float $bytes, int $precision = 0, ?int $maxP } /** - * Convert the number to its human readable equivalent. + * Convert the number to its human-readable equivalent. * - * @param int $number + * @param int|float $number * @param int $precision * @param int|null $maxPrecision - * @return string + * @return bool|string */ public static function abbreviate(int|float $number, int $precision = 0, ?int $maxPrecision = null) { @@ -157,12 +157,13 @@ public static function abbreviate(int|float $number, int $precision = 0, ?int $m } /** - * Convert the number to its human readable equivalent. + * Convert the number to its human-readable equivalent. * - * @param int $number + * @param int|float $number * @param int $precision * @param int|null $maxPrecision - * @return string + * @param bool $abbreviate + * @return bool|string */ public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null, bool $abbreviate = false) { @@ -182,13 +183,13 @@ public static function forHumans(int|float $number, int $precision = 0, ?int $ma } /** - * Convert the number to its human readable equivalent. + * Convert the number to its human-readable equivalent. * - * @param int $number + * @param int|float $number * @param int $precision * @param int|null $maxPrecision * @param array $units - * @return string + * @return string|false */ protected static function summarize(int|float $number, int $precision = 0, ?int $maxPrecision = null, array $units = []) { From c1e78c4ef1631a7c9c81ce22ac00d49b3bbce4dd Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 15 Jan 2024 17:01:20 +0100 Subject: [PATCH 26/35] Update pull-requests.yml --- .github/workflows/pull-requests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index 050ad42f7479..2aa858fb68e0 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -8,7 +8,5 @@ permissions: pull-requests: write jobs: - draft: - uses: laravel/.github/.github/workflows/pull-requests.yml@main - uneditable: + pull-requests: uses: laravel/.github/.github/workflows/pull-requests.yml@main From 11dd6449c3647f41e7c20c0e6dbc1b38b93b6992 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Tue, 16 Jan 2024 00:13:50 +0800 Subject: [PATCH 27/35] [10.x] Test Improvements (#49679) Signed-off-by: Mior Muhammad Zaki --- tests/Support/ConfigurationUrlParserTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/ConfigurationUrlParserTest.php b/tests/Support/ConfigurationUrlParserTest.php index 9035d08a45b6..22edc49810fe 100644 --- a/tests/Support/ConfigurationUrlParserTest.php +++ b/tests/Support/ConfigurationUrlParserTest.php @@ -135,7 +135,7 @@ public static function databaseUrls() ], ], 'query params from URL are used as extra params' => [ - 'url' => 'mysql://foo:bar@localhost/database?charset=UTF-8', + 'mysql://foo:bar@localhost/database?charset=UTF-8', [ 'driver' => 'mysql', 'database' => 'database', From 9fec940b5c5382136beb25954ecca060337bb535 Mon Sep 17 00:00:00 2001 From: Phil Bates Date: Mon, 15 Jan 2024 18:52:32 +0000 Subject: [PATCH 28/35] [10.x] Officially support floats in trans_choice (#49693) This already works fine with no further changes needed, so I'm not sure if there's a reason that floats were never officially supported. This is how it is currently, which you can see works perfectly fine: Given: // lang/en/foo.php return [ 'hours' => 'A total of :hours hour|A total of :hours hours', ]; Then: trans_choice('foo.hours', 1, ['hours' => 1]) === 'A total of 1 hour' trans_choice('foo.hours', 1.0, ['hours' => 1.0]) === 'A total of 1 hour' trans_choice('foo.hours', 1.1, ['hours' => 1.1]) === 'A total of 1.1 hours' trans_choice('foo.hours', 0.9, ['hours' => 0.9]) === 'A total of 0.9 hours' However, when running phpstan & larastan on a Laravel project that passes a float to trans_choice when wanting to display text similar to those examples ("A total of X hour[s]") it results in an error because the only documented allowed types are \Countable|int|array. Co-authored-by: Phil Bates --- src/Illuminate/Contracts/Translation/Translator.php | 2 +- src/Illuminate/Foundation/helpers.php | 2 +- .../Translation/PotentiallyTranslatedString.php | 2 +- src/Illuminate/Translation/Translator.php | 2 +- tests/Translation/TranslationTranslatorTest.php | 12 +++++++++++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Contracts/Translation/Translator.php b/src/Illuminate/Contracts/Translation/Translator.php index 6eae4915d5a1..ded1a8b864f9 100644 --- a/src/Illuminate/Contracts/Translation/Translator.php +++ b/src/Illuminate/Contracts/Translation/Translator.php @@ -18,7 +18,7 @@ public function get($key, array $replace = [], $locale = null); * Get a translation according to an integer value. * * @param string $key - * @param \Countable|int|array $number + * @param \Countable|int|float|array $number * @param array $replace * @param string|null $locale * @return string diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index e4c15edca725..c698bbdfaa8e 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -929,7 +929,7 @@ function trans($key = null, $replace = [], $locale = null) * Translates the given message based on a count. * * @param string $key - * @param \Countable|int|array $number + * @param \Countable|int|float|array $number * @param array $replace * @param string|null $locale * @return string diff --git a/src/Illuminate/Translation/PotentiallyTranslatedString.php b/src/Illuminate/Translation/PotentiallyTranslatedString.php index f46db3522429..efcccca28331 100644 --- a/src/Illuminate/Translation/PotentiallyTranslatedString.php +++ b/src/Illuminate/Translation/PotentiallyTranslatedString.php @@ -57,7 +57,7 @@ public function translate($replace = [], $locale = null) /** * Translates the string based on a count. * - * @param \Countable|int|array $number + * @param \Countable|int|float|array $number * @param array $replace * @param string|null $locale * @return $this diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index f9f8b49cb11c..634a102d54c7 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -183,7 +183,7 @@ public function get($key, array $replace = [], $locale = null, $fallback = true) * Get a translation according to an integer value. * * @param string $key - * @param \Countable|int|array $number + * @param \Countable|int|float|array $number * @param array $replace * @param string|null $locale * @return string diff --git a/tests/Translation/TranslationTranslatorTest.php b/tests/Translation/TranslationTranslatorTest.php index 8601f1493ea7..07ec429aab77 100755 --- a/tests/Translation/TranslationTranslatorTest.php +++ b/tests/Translation/TranslationTranslatorTest.php @@ -123,7 +123,7 @@ public function testGetMethodProperlyLoadsAndRetrievesItemForGlobalNamespace() $this->assertSame('breeze bar', $t->get('foo.bar', ['foo' => 'bar'])); } - public function testChoiceMethodProperlyLoadsAndRetrievesItem() + public function testChoiceMethodProperlyLoadsAndRetrievesItemForAnInt() { $t = $this->getMockBuilder(Translator::class)->onlyMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->willReturn('line'); @@ -133,6 +133,16 @@ public function testChoiceMethodProperlyLoadsAndRetrievesItem() $t->choice('foo', 10, ['replace']); } + public function testChoiceMethodProperlyLoadsAndRetrievesItemForAFloat() + { + $t = $this->getMockBuilder(Translator::class)->onlyMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); + $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->willReturn('line'); + $t->setSelector($selector = m::mock(MessageSelector::class)); + $selector->shouldReceive('choose')->once()->with('line', 1.2, 'en')->andReturn('choiced'); + + $t->choice('foo', 1.2, ['replace']); + } + public function testChoiceMethodProperlyCountsCollectionsAndLoadsAndRetrievesItem() { $t = $this->getMockBuilder(Translator::class)->onlyMethods(['get'])->setConstructorArgs([$this->getLoader(), 'en'])->getMock(); From 4d8c49fee5fefc8edb76d0abe60478b9451f17f9 Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Mon, 15 Jan 2024 18:53:10 +0000 Subject: [PATCH 29/35] Update facade docblocks --- src/Illuminate/Support/Facades/Lang.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Lang.php b/src/Illuminate/Support/Facades/Lang.php index cdaad3d0fd16..a341b5fab640 100755 --- a/src/Illuminate/Support/Facades/Lang.php +++ b/src/Illuminate/Support/Facades/Lang.php @@ -6,7 +6,7 @@ * @method static bool hasForLocale(string $key, string|null $locale = null) * @method static bool has(string $key, string|null $locale = null, bool $fallback = true) * @method static string|array get(string $key, array $replace = [], string|null $locale = null, bool $fallback = true) - * @method static string choice(string $key, \Countable|int|array $number, array $replace = [], string|null $locale = null) + * @method static string choice(string $key, \Countable|int|float|array $number, array $replace = [], string|null $locale = null) * @method static void addLines(array $lines, string $locale, string $namespace = '*') * @method static void load(string $namespace, string $group, string $locale) * @method static \Illuminate\Translation\Translator handleMissingKeysUsing(callable|null $callback) From 8d4eaebc25d4349368d326f5fff80e15a0ffdd1d Mon Sep 17 00:00:00 2001 From: Michael Nabil <46572405+michaelnabil230@users.noreply.github.com> Date: Tue, 16 Jan 2024 02:22:35 +0200 Subject: [PATCH 30/35] Use a static function (#49696) --- src/Illuminate/Console/GeneratorCommand.php | 4 ++-- src/Illuminate/Database/Console/PruneCommand.php | 2 +- src/Illuminate/Foundation/Console/Kernel.php | 2 +- src/Illuminate/Foundation/Events/DiscoverEvents.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Console/GeneratorCommand.php b/src/Illuminate/Console/GeneratorCommand.php index f061dc67d384..efb349166b7f 100644 --- a/src/Illuminate/Console/GeneratorCommand.php +++ b/src/Illuminate/Console/GeneratorCommand.php @@ -249,7 +249,7 @@ protected function possibleModels() { $modelPath = is_dir(app_path('Models')) ? app_path('Models') : app_path(); - return collect((new Finder)->files()->depth(0)->in($modelPath)) + return collect(Finder::create()->files()->depth(0)->in($modelPath)) ->map(fn ($file) => $file->getBasename('.php')) ->sort() ->values() @@ -269,7 +269,7 @@ protected function possibleEvents() return []; } - return collect((new Finder)->files()->depth(0)->in($eventPath)) + return collect(Finder::create()->files()->depth(0)->in($eventPath)) ->map(fn ($file) => $file->getBasename('.php')) ->sort() ->values() diff --git a/src/Illuminate/Database/Console/PruneCommand.php b/src/Illuminate/Database/Console/PruneCommand.php index 2cb0a603ef79..23875d1187b9 100644 --- a/src/Illuminate/Database/Console/PruneCommand.php +++ b/src/Illuminate/Database/Console/PruneCommand.php @@ -126,7 +126,7 @@ protected function models() throw new InvalidArgumentException('The --models and --except options cannot be combined.'); } - return collect((new Finder)->in($this->getPath())->files()->name('*.php')) + return collect(Finder::create()->in($this->getPath())->files()->name('*.php')) ->map(function ($model) { $namespace = $this->laravel->getNamespace(); diff --git a/src/Illuminate/Foundation/Console/Kernel.php b/src/Illuminate/Foundation/Console/Kernel.php index 227f7caea513..7b19b42fa61b 100644 --- a/src/Illuminate/Foundation/Console/Kernel.php +++ b/src/Illuminate/Foundation/Console/Kernel.php @@ -340,7 +340,7 @@ protected function load($paths) $namespace = $this->app->getNamespace(); - foreach ((new Finder)->in($paths)->files() as $file) { + foreach (Finder::create()->in($paths)->files() as $file) { $command = $this->commandClassFromFile($file, $namespace); if (is_subclass_of($command, Command::class) && diff --git a/src/Illuminate/Foundation/Events/DiscoverEvents.php b/src/Illuminate/Foundation/Events/DiscoverEvents.php index b285759d2188..a4728c2ef3ed 100644 --- a/src/Illuminate/Foundation/Events/DiscoverEvents.php +++ b/src/Illuminate/Foundation/Events/DiscoverEvents.php @@ -29,7 +29,7 @@ class DiscoverEvents public static function within($listenerPath, $basePath) { $listeners = collect(static::getListenerEvents( - (new Finder)->files()->in($listenerPath), $basePath + Finder::create()->files()->in($listenerPath), $basePath )); $discoveredEvents = []; From 7cbdae560f66df62e02b8e0ced23459af105b88c Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 16 Jan 2024 15:41:20 +0100 Subject: [PATCH 31/35] Revert "[10.x] Improve numeric comparison for custom casts" (#49702) --- .../Eloquent/Concerns/HasAttributes.php | 2 +- ...DatabaseEloquentModelCustomCastingTest.php | 27 ------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 029d45637c63..991f06434a5b 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -2101,7 +2101,7 @@ public function originalIsEquivalent($key) } return is_numeric($attribute) && is_numeric($original) - && BigDecimal::of($attribute)->isEqualTo($original); + && strcmp((string) $attribute, (string) $original) === 0; } /** diff --git a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php index bfa3d533514b..8bbdb68c0271 100644 --- a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php +++ b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php @@ -169,33 +169,6 @@ public function testDeviableCasts() $this->assertSame((new Decimal('320.988'))->getValue(), $model->price->getValue()); } - public function testDirtyOnCustomNumericCasts() - { - $model = new TestEloquentModelWithCustomCast; - $model->price = '123.00'; - $model->save(); - - $this->assertFalse($model->isDirty()); - - $model->price = '123.00'; - $this->assertFalse($model->isDirty('price')); - - $model->price = '123.0'; - $this->assertFalse($model->isDirty('price')); - - $model->price = '123'; - $this->assertFalse($model->isDirty('price')); - - $model->price = '00123.00'; - $this->assertFalse($model->isDirty('price')); - - $model->price = '123.4000'; - $this->assertTrue($model->isDirty('price')); - - $model->price = '123.0004'; - $this->assertTrue($model->isDirty('price')); - } - public function testSerializableCasts() { $model = new TestEloquentModelWithCustomCast; From 03eabd50cf00206bf043f49794f73158fe302b1c Mon Sep 17 00:00:00 2001 From: Kieran Date: Tue, 16 Jan 2024 15:08:28 +0000 Subject: [PATCH 32/35] [10.x] Add exit code to queue:clear, and queue:forget commands (#49707) * [10.x] Add exit code to queue:clear, and queue:forget commands * Update ClearCommand.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Queue/Console/ClearCommand.php | 2 ++ src/Illuminate/Queue/Console/ForgetFailedCommand.php | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Console/ClearCommand.php b/src/Illuminate/Queue/Console/ClearCommand.php index 6f3e8dc3bf9d..8f4187bcac77 100644 --- a/src/Illuminate/Queue/Console/ClearCommand.php +++ b/src/Illuminate/Queue/Console/ClearCommand.php @@ -57,6 +57,8 @@ public function handle() $this->components->info('Cleared '.$count.' '.Str::plural('job', $count).' from the ['.$queueName.'] queue'); } else { $this->components->error('Clearing queues is not supported on ['.(new ReflectionClass($queue))->getShortName().']'); + + return 1; } return 0; diff --git a/src/Illuminate/Queue/Console/ForgetFailedCommand.php b/src/Illuminate/Queue/Console/ForgetFailedCommand.php index 22d87d32b128..fce7803ccda7 100644 --- a/src/Illuminate/Queue/Console/ForgetFailedCommand.php +++ b/src/Illuminate/Queue/Console/ForgetFailedCommand.php @@ -25,7 +25,7 @@ class ForgetFailedCommand extends Command /** * Execute the console command. * - * @return void + * @return int|null */ public function handle() { @@ -33,6 +33,8 @@ public function handle() $this->components->info('Failed job deleted successfully.'); } else { $this->components->error('No failed job matches the given ID.'); + + return 1; } } } From 94d0fd7b74c47d1cb51aa09dad125a415412e445 Mon Sep 17 00:00:00 2001 From: Jan Stolle Date: Tue, 16 Jan 2024 16:11:13 +0100 Subject: [PATCH 33/35] Allow StreamInterface as raw HTTP Client body (#49705) * Allow StreamInterface as raw HTTP Client body Since the body payload is passed through to Guzzle, which in turn can handle Streams as well, this extends the versatility of the HTTP Client * Update PendingRequest.php --------- Co-authored-by: Taylor Otwell --- src/Illuminate/Http/Client/PendingRequest.php | 4 ++-- tests/Http/HttpClientTest.php | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 78e361feffad..28defb4d9607 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -78,7 +78,7 @@ class PendingRequest /** * The raw body for the request. * - * @var string + * @var \Psr\Http\Message\StreamInterface|string */ protected $pendingBody; @@ -259,7 +259,7 @@ public function baseUrl(string $url) /** * Attach a raw body to the request. * - * @param string $content + * @param \Psr\Http\Message\StreamInterface|string $content * @param string $contentType * @return $this */ diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index df4f7165373c..6b790aa06534 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -6,6 +6,7 @@ use GuzzleHttp\Middleware; use GuzzleHttp\Promise\PromiseInterface; use GuzzleHttp\Psr7\Response as Psr7Response; +use GuzzleHttp\Psr7\Utils; use GuzzleHttp\TransferStats; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Support\Arrayable; @@ -357,6 +358,26 @@ public function testSendRequestBodyWithManyAmpersands() $this->factory->withBody($body, 'text/plain')->send('post', 'http://foo.com/api'); } + public function testSendStreamRequestBody() + { + $string = 'Look at me, i am a stream!!'; + $resource = fopen('php://temp', 'w'); + fwrite($resource, $string); + rewind($resource); + $body = Utils::streamFor($resource); + + $fakeRequest = function (Request $request) use ($string) { + self::assertSame($string, $request->body()); + self::assertContains('text/plain', $request->header('Content-Type')); + + return ['my' => 'response']; + }; + + $this->factory->fake($fakeRequest); + + $this->factory->withBody($body, 'text/plain')->send('post', 'http://foo.com/api'); + } + public function testUrlsCanBeStubbedByPath() { $this->factory->fake([ From d056aabc2caffcdbf21927d464ecc1a6d145e401 Mon Sep 17 00:00:00 2001 From: taylorotwell Date: Tue, 16 Jan 2024 15:11:48 +0000 Subject: [PATCH 34/35] Update facade docblocks --- src/Illuminate/Support/Facades/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php index 6a445e078055..4c0cbd915eda 100644 --- a/src/Illuminate/Support/Facades/Http.php +++ b/src/Illuminate/Support/Facades/Http.php @@ -27,7 +27,7 @@ * @method static void flushMacros() * @method static mixed macroCall(string $method, array $parameters) * @method static \Illuminate\Http\Client\PendingRequest baseUrl(string $url) - * @method static \Illuminate\Http\Client\PendingRequest withBody(string $content, string $contentType = 'application/json') + * @method static \Illuminate\Http\Client\PendingRequest withBody(\Psr\Http\Message\StreamInterface|string $content, string $contentType = 'application/json') * @method static \Illuminate\Http\Client\PendingRequest asJson() * @method static \Illuminate\Http\Client\PendingRequest asForm() * @method static \Illuminate\Http\Client\PendingRequest attach(string|array $name, string|resource $contents = '', string|null $filename = null, array $headers = []) From da31969bd35e6ee0bbcd9e876f88952dc754b012 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Jan 2024 09:23:58 -0600 Subject: [PATCH 35/35] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 930c406f7ebf..a352be0fc7bb 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -40,7 +40,7 @@ class Application extends Container implements ApplicationContract, CachesConfig * * @var string */ - const VERSION = '10.40.0'; + const VERSION = '10.41.0'; /** * The base path for the Laravel installation.