diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml
index 359877d89f72..8dcfa62b65c0 100644
--- a/.github/workflows/releases.yml
+++ b/.github/workflows/releases.yml
@@ -18,7 +18,7 @@ jobs:
outputs:
version: ${{ steps.version.outputs.version }}
- notes: ${{ steps.cleaned-notes.outputs.release-notes }}
+ notes: ${{ steps.cleaned-notes.outputs.notes }}
steps:
- name: Checkout repository
@@ -90,10 +90,11 @@ jobs:
- name: Cleanup release notes
id: cleaned-notes
run: |
- NOTES="${{ steps.generated-notes.outputs.release-notes }}"
- NOTES=$(echo $NOTES | sed '/## What/d')
- NOTES=$(echo $NOTES | sed '/## New Contributors/,$d')
- echo "release-notes=${NOTES}" >> "$GITHUB_OUTPUT"
+ RELEASE_NOTES=$(echo $RELEASE_NOTES | sed '/## What/d')
+ RELEASE_NOTES=$(echo $RELEASE_NOTES | sed '/## New Contributors/,$d')
+ echo "notes=${RELEASE_NOTES}" >> "$GITHUB_OUTPUT"
+ env:
+ RELEASE_NOTES: ${{ steps.generated-notes.outputs.release-notes }}
- name: Create release
uses: softprops/action-gh-release@v2
@@ -102,7 +103,7 @@ jobs:
with:
tag_name: v${{ steps.version.outputs.version }}
name: v${{ steps.version.outputs.version }}
- body: ${{ steps.cleaned-notes.outputs.release-notes }}
+ body: ${{ steps.cleaned-notes.outputs.notes }}
target_commitish: ${{ github.ref_name }}
make_latest: 'legacy'
diff --git a/src/Illuminate/Database/DetectsLostConnections.php b/src/Illuminate/Database/DetectsLostConnections.php
index 622545bdcb4d..3c1f7a927dc7 100644
--- a/src/Illuminate/Database/DetectsLostConnections.php
+++ b/src/Illuminate/Database/DetectsLostConnections.php
@@ -19,6 +19,7 @@ protected function causedByLostConnection(Throwable $e)
return Str::contains($message, [
'server has gone away',
+ 'Server has gone away',
'no connection to the server',
'Lost connection',
'is dead or not enabled',
diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php
index d9a453359d23..e8c25101361b 100644
--- a/src/Illuminate/Database/Eloquent/Factories/Factory.php
+++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php
@@ -240,9 +240,9 @@ public function createOneQuietly($attributes = [])
*/
public function createMany(int|iterable|null $records = null)
{
- if (is_null($records)) {
- $records = $this->count ?? 1;
- }
+ $records ??= ($this->count ?? 1);
+
+ $this->count = null;
if (is_numeric($records)) {
$records = array_fill(0, $records, []);
diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
index 7a90dc998cc0..ef17cce6371c 100755
--- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
+++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
@@ -784,7 +784,7 @@ public function findOr($id, $columns = ['*'], ?Closure $callback = null)
* @param mixed $operator
* @param mixed $value
* @param string $boolean
- * @return \Illuminate\Database\Eloquent\Model|static
+ * @return \Illuminate\Database\Eloquent\Model|static|null
*/
public function firstWhere($column, $operator = null, $value = null, $boolean = 'and')
{
@@ -795,7 +795,7 @@ public function firstWhere($column, $operator = null, $value = null, $boolean =
* Execute the query and get the first result.
*
* @param array $columns
- * @return mixed
+ * @return \Illuminate\Database\Eloquent\Model|static|null
*/
public function first($columns = ['*'])
{
diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
index 70dd922b20b0..2f3dc31fef60 100644
--- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
+++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
@@ -320,7 +320,7 @@ public function updateOrCreate(array $attributes, array $values = [])
* @param mixed $operator
* @param mixed $value
* @param string $boolean
- * @return \Illuminate\Database\Eloquent\Model|static
+ * @return \Illuminate\Database\Eloquent\Model|static|null
*/
public function firstWhere($column, $operator = null, $value = null, $boolean = 'and')
{
@@ -331,7 +331,7 @@ public function firstWhere($column, $operator = null, $value = null, $boolean =
* Execute the query and get the first related model.
*
* @param array $columns
- * @return mixed
+ * @return \Illuminate\Database\Eloquent\Model|static|null
*/
public function first($columns = ['*'])
{
diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php
index 48876cd9c072..60c00de993ad 100755
--- a/src/Illuminate/Foundation/Application.php
+++ b/src/Illuminate/Foundation/Application.php
@@ -591,6 +591,10 @@ public function storagePath($path = '')
return $this->joinPaths($this->storagePath ?: $_ENV['LARAVEL_STORAGE_PATH'], $path);
}
+ if (isset($_SERVER['LARAVEL_STORAGE_PATH'])) {
+ return $this->joinPaths($this->storagePath ?: $_SERVER['LARAVEL_STORAGE_PATH'], $path);
+ }
+
return $this->joinPaths($this->storagePath ?: $this->basePath('storage'), $path);
}
diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php
index 7b9ab9a56d6c..2a956830df98 100755
--- a/src/Illuminate/Translation/Translator.php
+++ b/src/Illuminate/Translation/Translator.php
@@ -262,6 +262,16 @@ protected function makeReplacements($line, array $replace)
$shouldReplace = [];
foreach ($replace as $key => $value) {
+ if ($value instanceof Closure) {
+ $line = preg_replace_callback(
+ '/<'.$key.'>(.*?)<\/'.$key.'>/',
+ fn ($args) => $value($args[1]),
+ $line
+ );
+
+ continue;
+ }
+
if (is_object($value) && isset($this->stringableHandlers[get_class($value)])) {
$value = call_user_func($this->stringableHandlers[get_class($value)], $value);
}
diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php
index f46ebc3213f2..cc3c78504554 100644
--- a/tests/Database/DatabaseEloquentFactoryTest.php
+++ b/tests/Database/DatabaseEloquentFactoryTest.php
@@ -129,14 +129,30 @@ public function test_basic_model_can_be_created()
$users = FactoryTestUserFactory::new()->createMany(2);
$this->assertInstanceOf(Collection::class, $users);
$this->assertCount(2, $users);
+ $this->assertInstanceOf(FactoryTestUser::class, $users->first());
$users = FactoryTestUserFactory::times(2)->createMany();
$this->assertInstanceOf(Collection::class, $users);
$this->assertCount(2, $users);
+ $this->assertInstanceOf(FactoryTestUser::class, $users->first());
+
+ $users = FactoryTestUserFactory::times(2)->createMany();
+ $this->assertInstanceOf(Collection::class, $users);
+ $this->assertCount(2, $users);
+ $this->assertInstanceOf(FactoryTestUser::class, $users->first());
+
+ $users = FactoryTestUserFactory::times(3)->createMany([
+ ['name' => 'Taylor Otwell'],
+ ['name' => 'Jeffrey Way'],
+ ]);
+ $this->assertInstanceOf(Collection::class, $users);
+ $this->assertCount(2, $users);
+ $this->assertInstanceOf(FactoryTestUser::class, $users->first());
$users = FactoryTestUserFactory::new()->createMany();
$this->assertInstanceOf(Collection::class, $users);
$this->assertCount(1, $users);
+ $this->assertInstanceOf(FactoryTestUser::class, $users->first());
$users = FactoryTestUserFactory::times(10)->create();
$this->assertCount(10, $users);
diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php
index 1d92d5e6e1b0..1a1858298300 100755
--- a/tests/Routing/RoutingUrlGeneratorTest.php
+++ b/tests/Routing/RoutingUrlGeneratorTest.php
@@ -779,7 +779,7 @@ public function testSignedUrl()
$this->assertTrue($url->hasValidSignature($request));
- $request = Request::create($url->signedRoute('foo').'?tempered=true');
+ $request = Request::create($url->signedRoute('foo').'?tampered=true');
$this->assertFalse($url->hasValidSignature($request));
}
@@ -827,7 +827,7 @@ public function testSignedRelativeUrl()
$this->assertTrue($url->hasValidSignature($request, false));
- $request = Request::create($url->signedRoute('foo', [], null, false).'?tempered=true');
+ $request = Request::create($url->signedRoute('foo', [], null, false).'?tampered=true');
$this->assertFalse($url->hasValidSignature($request, false));
}
@@ -906,7 +906,7 @@ public function testSignedUrlWithKeyResolver()
$this->assertTrue($url->hasValidSignature($request));
- $request = Request::create($url->signedRoute('foo').'?tempered=true');
+ $request = Request::create($url->signedRoute('foo').'?tampered=true');
$this->assertFalse($url->hasValidSignature($request));
diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php
index 1f4ab12ad738..f8a7770e136a 100755
--- a/tests/Support/SupportStrTest.php
+++ b/tests/Support/SupportStrTest.php
@@ -12,11 +12,13 @@
class SupportStrTest extends TestCase
{
- public function testStringCanBeLimitedByWords()
+ public function testStringCanBeLimitedByWords(): void
{
$this->assertSame('Taylor...', Str::words('Taylor Otwell', 1));
$this->assertSame('Taylor___', Str::words('Taylor Otwell', 1, '___'));
$this->assertSame('Taylor Otwell', Str::words('Taylor Otwell', 3));
+ $this->assertSame('Taylor Otwell', Str::words('Taylor Otwell', -1, '...'));
+ $this->assertSame('', Str::words('', 3, '...'));
}
public function testStringCanBeLimitedByWordsNonAscii()
@@ -114,11 +116,13 @@ public function testStringApa()
$this->assertSame(' ', Str::apa(' '));
}
- public function testStringWithoutWordsDoesntProduceError()
+ public function testStringWithoutWordsDoesntProduceError(): void
{
$nbsp = chr(0xC2).chr(0xA0);
$this->assertSame(' ', Str::words(' '));
$this->assertEquals($nbsp, Str::words($nbsp));
+ $this->assertSame(' ', Str::words(' '));
+ $this->assertSame("\t\t\t", Str::words("\t\t\t"));
}
public function testStringAscii()
@@ -265,7 +269,7 @@ public function testStrBefore()
$this->assertSame('han', Str::before('han2nah', 2));
}
- public function testStrBeforeLast()
+ public function testStrBeforeLast(): void
{
$this->assertSame('yve', Str::beforeLast('yvette', 'tte'));
$this->assertSame('yvet', Str::beforeLast('yvette', 't'));
@@ -276,6 +280,10 @@ public function testStrBeforeLast()
$this->assertSame('yv0et', Str::beforeLast('yv0et0te', '0'));
$this->assertSame('yv0et', Str::beforeLast('yv0et0te', 0));
$this->assertSame('yv2et', Str::beforeLast('yv2et2te', 2));
+ $this->assertSame('', Str::beforeLast('', 'test'));
+ $this->assertSame('', Str::beforeLast('yvette', 'yvette'));
+ $this->assertSame('laravel', Str::beforeLast('laravel framework', ' '));
+ $this->assertSame('yvette', Str::beforeLast("yvette\tyv0et0te", "\t"));
}
public function testStrBetween()
diff --git a/tests/Translation/TranslationTranslatorTest.php b/tests/Translation/TranslationTranslatorTest.php
index 07ec429aab77..86c8948ef94f 100755
--- a/tests/Translation/TranslationTranslatorTest.php
+++ b/tests/Translation/TranslationTranslatorTest.php
@@ -257,6 +257,42 @@ public function testGetJsonReplacesWithStringable()
);
}
+ public function testTagReplacements()
+ {
+ $t = new Translator($this->getLoader(), 'en');
+
+ $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]);
+ $t->getLoader()->shouldReceive('load')->once()->with('en', 'We have some nice documentation', '*')->andReturn([]);
+
+ $this->assertSame(
+ 'We have some nice documentation',
+ $t->get(
+ 'We have some nice documentation',
+ [
+ 'docs-link' => fn ($children) => "$children",
+ ]
+ )
+ );
+ }
+
+ public function testTagReplacementsHandleMultipleOfSameTag()
+ {
+ $t = new Translator($this->getLoader(), 'en');
+
+ $t->getLoader()->shouldReceive('load')->once()->with('en', '*', '*')->andReturn([]);
+ $t->getLoader()->shouldReceive('load')->once()->with('en', 'bold something else also bold', '*')->andReturn([]);
+
+ $this->assertSame(
+ 'bold something else also bold',
+ $t->get(
+ 'bold something else also bold',
+ [
+ 'bold-this' => fn ($children) => "$children",
+ ]
+ )
+ );
+ }
+
public function testDetermineLocalesUsingMethod()
{
$t = new Translator($this->getLoader(), 'en');