Skip to content

Commit f979990

Browse files
committed
Merge branch '11.x' into 12.x
Signed-off-by: Mior Muhammad Zaki <[email protected]>
2 parents 18b7533 + 43bcb81 commit f979990

23 files changed

+809
-78
lines changed

.github/workflows/databases.yml

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -293,53 +293,53 @@ jobs:
293293
DB_USERNAME: SA
294294
DB_PASSWORD: Forge123
295295

296-
# mssql_2017:
297-
# runs-on: ubuntu-20.04
298-
# timeout-minutes: 5
299-
300-
# services:
301-
# sqlsrv:
302-
# image: mcr.microsoft.com/mssql/server:2017-latest
303-
# env:
304-
# ACCEPT_EULA: Y
305-
# SA_PASSWORD: Forge123
306-
# ports:
307-
# - 1433:1433
308-
309-
# strategy:
310-
# fail-fast: true
311-
312-
# name: SQL Server 2017
313-
314-
# steps:
315-
# - name: Checkout code
316-
# uses: actions/checkout@v4
317-
318-
# - name: Setup PHP
319-
# uses: shivammathur/setup-php@v2
320-
# with:
321-
# php-version: 8.3
322-
# extensions: dom, curl, libxml, mbstring, zip, pcntl, sqlsrv, pdo, pdo_sqlsrv, odbc, pdo_odbc, :php-psr
323-
# tools: composer:v2
324-
# coverage: none
325-
326-
# - name: Set Framework version
327-
# run: composer config version "12.x-dev"
328-
329-
# - name: Install dependencies
330-
# uses: nick-fields/retry@v3
331-
# with:
332-
# timeout_minutes: 5
333-
# max_attempts: 5
334-
# command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress
335-
336-
# - name: Execute tests
337-
# run: vendor/bin/phpunit tests/Integration/Database
338-
# env:
339-
# DB_CONNECTION: sqlsrv
340-
# DB_DATABASE: master
341-
# DB_USERNAME: SA
342-
# DB_PASSWORD: Forge123
296+
mssql_2017:
297+
runs-on: ubuntu-22.04
298+
timeout-minutes: 5
299+
300+
services:
301+
sqlsrv:
302+
image: mcr.microsoft.com/mssql/server:2017-latest
303+
env:
304+
ACCEPT_EULA: Y
305+
SA_PASSWORD: Forge123
306+
ports:
307+
- 1433:1433
308+
309+
strategy:
310+
fail-fast: true
311+
312+
name: SQL Server 2017
313+
314+
steps:
315+
- name: Checkout code
316+
uses: actions/checkout@v4
317+
318+
- name: Setup PHP
319+
uses: shivammathur/setup-php@v2
320+
with:
321+
php-version: 8.3
322+
extensions: dom, curl, libxml, mbstring, zip, pcntl, sqlsrv, pdo, pdo_sqlsrv, odbc, pdo_odbc, :php-psr
323+
tools: composer:v2
324+
coverage: none
325+
326+
- name: Set Framework version
327+
run: composer config version "12.x-dev"
328+
329+
- name: Install dependencies
330+
uses: nick-fields/retry@v3
331+
with:
332+
timeout_minutes: 5
333+
max_attempts: 5
334+
command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress
335+
336+
- name: Execute tests
337+
run: vendor/bin/phpunit tests/Integration/Database
338+
env:
339+
DB_CONNECTION: sqlsrv
340+
DB_DATABASE: master
341+
DB_USERNAME: SA
342+
DB_PASSWORD: Forge123
343343

344344
sqlite:
345345
runs-on: ubuntu-24.04

src/Illuminate/Console/Application.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
use Illuminate\Contracts\Container\Container;
99
use Illuminate\Contracts\Events\Dispatcher;
1010
use Illuminate\Support\ProcessUtils;
11+
use ReflectionClass;
1112
use Symfony\Component\Console\Application as SymfonyApplication;
13+
use Symfony\Component\Console\Attribute\AsCommand;
1214
use Symfony\Component\Console\Command\Command as SymfonyCommand;
1315
use Symfony\Component\Console\Exception\CommandNotFoundException;
1416
use Symfony\Component\Console\Input\ArrayInput;
@@ -238,12 +240,18 @@ protected function addToParent(SymfonyCommand $command)
238240
*/
239241
public function resolve($command)
240242
{
241-
if (is_subclass_of($command, SymfonyCommand::class) && ($commandName = $command::getDefaultName())) {
242-
foreach (explode('|', $commandName) as $name) {
243-
$this->commandMap[$name] = $command;
244-
}
243+
if (is_subclass_of($command, SymfonyCommand::class)) {
244+
$attribute = (new ReflectionClass($command))->getAttributes(AsCommand::class);
245+
246+
$commandName = ! empty($attribute) ? $attribute[0]->newInstance()->name : null;
245247

246-
return null;
248+
if (! is_null($commandName)) {
249+
foreach (explode('|', $commandName) as $name) {
250+
$this->commandMap[$name] = $command;
251+
}
252+
253+
return null;
254+
}
247255
}
248256

249257
if ($command instanceof Command) {

src/Illuminate/Foundation/Console/AboutCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ protected function gatherApplicationInformation()
183183
'Config' => static::format($this->laravel->configurationIsCached(), console: $formatCachedStatus),
184184
'Events' => static::format($this->laravel->eventsAreCached(), console: $formatCachedStatus),
185185
'Routes' => static::format($this->laravel->routesAreCached(), console: $formatCachedStatus),
186-
'Views' => static::format($this->hasPhpFiles($this->laravel->storagePath('framework/views')), console: $formatCachedStatus),
186+
'Views' => static::format($this->hasPhpFiles(config('view.compiled')), console: $formatCachedStatus),
187187
]);
188188

189189
static::addToSection('Drivers', fn () => array_filter([

src/Illuminate/Foundation/Testing/Concerns/InteractsWithTestCaseLifecycle.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
use Illuminate\Foundation\Testing\WithoutMiddleware;
2424
use Illuminate\Http\Middleware\TrustHosts;
2525
use Illuminate\Http\Middleware\TrustProxies;
26+
use Illuminate\Mail\Markdown;
2627
use Illuminate\Queue\Console\WorkCommand;
2728
use Illuminate\Queue\Queue;
2829
use Illuminate\Support\Carbon;
30+
use Illuminate\Support\EncodedHtmlString;
2931
use Illuminate\Support\Facades\Facade;
3032
use Illuminate\Support\Facades\ParallelTesting;
3133
use Illuminate\Support\Once;
@@ -171,8 +173,10 @@ protected function tearDownTheTestEnvironment(): void
171173
Component::forgetFactory();
172174
ConvertEmptyStringsToNull::flushState();
173175
Factory::flushState();
176+
EncodedHtmlString::flushState();
174177
EncryptCookies::flushState();
175178
HandleExceptions::flushState();
179+
Markdown::flushState();
176180
Migrator::withoutMigrations([]);
177181
Once::flush();
178182
PreventRequestsDuringMaintenance::flushState();

src/Illuminate/Mail/Mailable.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Illuminate\Contracts\Support\Renderable;
1414
use Illuminate\Contracts\Translation\HasLocalePreference;
1515
use Illuminate\Support\Collection;
16+
use Illuminate\Support\EncodedHtmlString;
1617
use Illuminate\Support\HtmlString;
1718
use Illuminate\Support\Str;
1819
use Illuminate\Support\Traits\Conditionable;
@@ -1371,7 +1372,7 @@ public function assertHasSubject($subject)
13711372
*/
13721373
public function assertSeeInHtml($string, $escape = true)
13731374
{
1374-
$string = $escape ? e($string) : $string;
1375+
$string = $escape ? EncodedHtmlString::convert($string, withQuote: isset($this->markdown)) : $string;
13751376

13761377
[$html, $text] = $this->renderForAssertions();
13771378

@@ -1393,7 +1394,7 @@ public function assertSeeInHtml($string, $escape = true)
13931394
*/
13941395
public function assertDontSeeInHtml($string, $escape = true)
13951396
{
1396-
$string = $escape ? e($string) : $string;
1397+
$string = $escape ? EncodedHtmlString::convert($string, withQuote: isset($this->markdown)) : $string;
13971398

13981399
[$html, $text] = $this->renderForAssertions();
13991400

@@ -1415,7 +1416,9 @@ public function assertDontSeeInHtml($string, $escape = true)
14151416
*/
14161417
public function assertSeeInOrderInHtml($strings, $escape = true)
14171418
{
1418-
$strings = $escape ? array_map(e(...), $strings) : $strings;
1419+
$strings = $escape ? array_map(function ($string) {
1420+
return EncodedHtmlString::convert($string, withQuote: isset($this->markdown));
1421+
}, $strings) : $strings;
14191422

14201423
[$html, $text] = $this->renderForAssertions();
14211424

src/Illuminate/Mail/Markdown.php

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Illuminate\Mail;
44

55
use Illuminate\Contracts\View\Factory as ViewFactory;
6+
use Illuminate\Support\EncodedHtmlString;
67
use Illuminate\Support\HtmlString;
78
use Illuminate\Support\Str;
89
use League\CommonMark\Environment\Environment;
@@ -34,6 +35,13 @@ class Markdown
3435
*/
3536
protected $componentPaths = [];
3637

38+
/**
39+
* Indicates if secure encoding should be enabled.
40+
*
41+
* @var bool
42+
*/
43+
protected static $withSecuredEncoding = false;
44+
3745
/**
3846
* Create a new Markdown renderer instance.
3947
*
@@ -59,9 +67,37 @@ public function render($view, array $data = [], $inliner = null)
5967
{
6068
$this->view->flushFinderCache();
6169

62-
$contents = $this->view->replaceNamespace(
63-
'mail', $this->htmlComponentPaths()
64-
)->make($view, $data)->render();
70+
$bladeCompiler = $this->view
71+
->getEngineResolver()
72+
->resolve('blade')
73+
->getCompiler();
74+
75+
$contents = $bladeCompiler->usingEchoFormat(
76+
'new \Illuminate\Support\EncodedHtmlString(%s)',
77+
function () use ($view, $data) {
78+
if (static::$withSecuredEncoding === true) {
79+
EncodedHtmlString::encodeUsing(function ($value) {
80+
$replacements = [
81+
'[' => '\[',
82+
'<' => '&lt;',
83+
'>' => '&gt;',
84+
];
85+
86+
return str_replace(array_keys($replacements), array_values($replacements), $value);
87+
});
88+
}
89+
90+
try {
91+
$contents = $this->view->replaceNamespace(
92+
'mail', $this->htmlComponentPaths()
93+
)->make($view, $data)->render();
94+
} finally {
95+
EncodedHtmlString::flushState();
96+
}
97+
98+
return $contents;
99+
}
100+
);
65101

66102
if ($this->view->exists($customTheme = Str::start($this->theme, 'mail.'))) {
67103
$theme = $customTheme;
@@ -72,7 +108,7 @@ public function render($view, array $data = [], $inliner = null)
72108
}
73109

74110
return new HtmlString(($inliner ?: new CssToInlineStyles)->convert(
75-
$contents, $this->view->make($theme, $data)->render()
111+
str_replace('\[', '[', $contents), $this->view->make($theme, $data)->render()
76112
));
77113
}
78114

@@ -100,20 +136,59 @@ public function renderText($view, array $data = [])
100136
* Parse the given Markdown text into HTML.
101137
*
102138
* @param string $text
139+
* @param bool $encoded
103140
* @return \Illuminate\Support\HtmlString
104141
*/
105-
public static function parse($text)
142+
public static function parse($text, bool $encoded = false)
106143
{
107-
$environment = new Environment([
144+
if ($encoded === false) {
145+
return new HtmlString(static::converter()->convert($text)->getContent());
146+
}
147+
148+
if (static::$withSecuredEncoding === true || $encoded === true) {
149+
EncodedHtmlString::encodeUsing(function ($value) {
150+
$replacements = [
151+
'[' => '\[',
152+
'<' => '\<',
153+
];
154+
155+
$html = str_replace(array_keys($replacements), array_values($replacements), $value);
156+
157+
return static::converter([
158+
'html_input' => 'escape',
159+
])->convert($html)->getContent();
160+
});
161+
}
162+
163+
$html = '';
164+
165+
try {
166+
$html = static::converter()->convert($text)->getContent();
167+
} finally {
168+
EncodedHtmlString::flushState();
169+
}
170+
171+
return new HtmlString($html);
172+
}
173+
174+
/**
175+
* Get a Markdown converter instance.
176+
*
177+
* @internal
178+
*
179+
* @param array<string, mixed> $config
180+
* @return \League\CommonMark\MarkdownConverter
181+
*/
182+
public static function converter(array $config = [])
183+
{
184+
$environment = new Environment(array_merge([
108185
'allow_unsafe_links' => false,
109-
]);
186+
], $config));
110187

111188
$environment->addExtension(new CommonMarkCoreExtension);
112189
$environment->addExtension(new TableExtension);
113190

114-
$converter = new MarkdownConverter($environment);
115-
116-
return new HtmlString($converter->convert($text)->getContent());
191+
return new MarkdownConverter($environment);
117192
}
118193

119194
/**
@@ -185,4 +260,34 @@ public function getTheme()
185260
{
186261
return $this->theme;
187262
}
263+
264+
/**
265+
* Enable secured encoding when parsing Markdown.
266+
*
267+
* @return void
268+
*/
269+
public static function withSecuredEncoding()
270+
{
271+
static::$withSecuredEncoding = true;
272+
}
273+
274+
/**
275+
* Disable secured encoding when parsing Markdown.
276+
*
277+
* @return void
278+
*/
279+
public static function withoutSecuredEncoding()
280+
{
281+
static::$withSecuredEncoding = false;
282+
}
283+
284+
/**
285+
* Flush the class's global state.
286+
*
287+
* @return void
288+
*/
289+
public static function flushState()
290+
{
291+
static::$withSecuredEncoding = false;
292+
}
188293
}

src/Illuminate/Mail/resources/views/html/button.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<table border="0" cellpadding="0" cellspacing="0" role="presentation">
1313
<tr>
1414
<td>
15-
<a href="{{ $url }}" class="button button-{{ $color }}" target="_blank" rel="noopener">{{ $slot }}</a>
15+
<a href="{{ $url }}" class="button button-{{ $color }}" target="_blank" rel="noopener">{!! $slot !!}</a>
1616
</td>
1717
</tr>
1818
</table>

src/Illuminate/Mail/resources/views/html/header.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
@if (trim($slot) === 'Laravel')
66
<img src="https://laravel.com/img/notification-logo.png" class="logo" alt="Laravel Logo">
77
@else
8-
{{ $slot }}
8+
{!! $slot !!}
99
@endif
1010
</a>
1111
</td>

0 commit comments

Comments
 (0)