-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #478 from hydephp/add-blade-support-for-markdown
Add inline Blade support to markdown
- Loading branch information
Showing
6 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
--- | ||
label: "Advanced Markdown" | ||
priority: 26 | ||
category: "Digging Deeper" | ||
--- | ||
|
||
# Advanced Markdown | ||
|
||
## Introduction | ||
|
||
Since HydePHP makes heavy use of Markdown there are some extra features and helpers | ||
created just for Hyde to make using Markdown even easier! | ||
|
||
## Blade Support | ||
|
||
Since Hyde v0.30.x you can use Laravel Blade in Markdown files! | ||
|
||
### Using Blade in Markdown | ||
|
||
To use Blade in your Markdown files, simply use the Blade shortcode directive, | ||
followed by your desired Blade string. | ||
|
||
#### Standard syntax | ||
|
||
```markdown | ||
[Blade]: {{ "Hello World!" }} // Will render: 'Hello World!' | ||
``` | ||
|
||
#### Blade includes | ||
|
||
Only single-line shortcode directives are supported. If you need to use multi-line Blade code, | ||
use an `@include` directive to render a more complex Blade template. | ||
You can pass data to includes by specifying an array to the second argument. | ||
|
||
```markdown | ||
[Blade]: @include("hello-world") | ||
[Blade]: @include("hello", ["name" => "World"]) | ||
``` | ||
|
||
### Enabling Blade-supported Markdown | ||
It's disabled by default since it allows arbitrary PHP to run, which could be a security risk, | ||
depending on your setup. However, if your Markdown is trusted, and you know it's safe, | ||
you can enable it in the `config/markdown.php` file. | ||
|
||
```php | ||
// torchlight! {"lineNumbers": false} | ||
'enable_blade' => true, | ||
``` | ||
|
||
#### Limitations | ||
|
||
All shortcodes must be the first word on a new line. | ||
For example, using a space before the `[Blade]:` will intentionally cause it to not render. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
namespace Hyde\Framework\Services; | ||
|
||
use Illuminate\Support\Facades\Blade; | ||
|
||
/** | ||
* Markdown Processor to render Laravel Blade within Markdown files. | ||
* | ||
* Works on a line-by-line basis by searching for a line starting with the directive. | ||
* The preprocessor expands the directive to an HTML comment. The post-processor parses it. | ||
* | ||
* @example: [Blade]: {{ time() }} | ||
* @example: [Blade]: @include('path/to/view.blade.php') | ||
* | ||
* @see \Tests\Feature\Services\BladeDownServiceTest | ||
*/ | ||
class BladeDownService | ||
{ | ||
protected string $html; | ||
protected string $output; | ||
|
||
protected array $pageData = []; | ||
|
||
public function __construct(string $html, ?array $pageData = []) | ||
{ | ||
$this->html = $html; | ||
$this->pageData = $pageData; | ||
} | ||
|
||
public function process(): self | ||
{ | ||
$this->output = implode("\n", array_map(function ($line) { | ||
return $this->lineStartsWithDirective($line) | ||
? $this->processLine($line) | ||
: $line; | ||
}, explode("\n", $this->html))); | ||
|
||
return $this; | ||
} | ||
|
||
public function get(): string | ||
{ | ||
return $this->output; | ||
} | ||
|
||
public static function render(string $html, ?array $pageData = []): string | ||
{ | ||
return (new static(static::preprocess($html), $pageData))->process()->get(); | ||
} | ||
|
||
public static function preprocess(string $markdown): string | ||
{ | ||
return implode("\n", array_map(function ($line) { | ||
return str_starts_with(strtolower($line), strtolower('[Blade]:')) | ||
? '<!-- HYDE'.trim(htmlentities($line)).' -->' | ||
: $line; | ||
}, explode("\n", $markdown))); | ||
} | ||
|
||
protected function lineStartsWithDirective(string $line): bool | ||
{ | ||
return str_starts_with(strtolower($line), '<!-- hyde[blade]:'); | ||
} | ||
|
||
protected function processLine(string $line): string | ||
{ | ||
return Blade::render( | ||
substr(substr(html_entity_decode($line), 18), 0, -4), | ||
$this->pageData | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
namespace Tests\Feature\Services; | ||
|
||
use Hyde\Framework\Services\BladeDownService; | ||
use Tests\TestCase; | ||
|
||
/** | ||
* Class BladeDownServiceTest. | ||
* | ||
* @covers \Hyde\Framework\Services\BladeDownService | ||
*/ | ||
class BladeDownServiceTest extends TestCase | ||
{ | ||
// Test it renders Blade echo syntax | ||
public function test_it_renders_blade_echo_syntax() | ||
{ | ||
$this->assertEquals('Hello World!', BladeDownService::render('[Blade]: {{ "Hello World!" }}')); | ||
} | ||
|
||
// Test it renders Blade within multiline Markdown | ||
public function test_it_renders_blade_within_multiline_markdown() | ||
{ | ||
$this->assertEquals( | ||
"Foo\nHello World!\nBar", | ||
|
||
BladeDownService::render("Foo\n[Blade]: {{ 'Hello World!' }}\nBar") | ||
); | ||
} | ||
|
||
// Test it renders Blade views | ||
public function test_it_renders_blade_views() | ||
{ | ||
file_put_contents(resource_path( | ||
'views/hello.blade.php' | ||
), 'Hello World!'); | ||
|
||
$this->assertEquals('Hello World!', BladeDownService::render('[Blade]: @include("hello")')); | ||
|
||
unlink(resource_path('views/hello.blade.php')); | ||
} | ||
|
||
// Test directive is case-insensitive | ||
public function test_directive_is_case_insensitive() | ||
{ | ||
$this->assertEquals('Hello World!', BladeDownService::render('[blade]: {{ "Hello World!" }}')); | ||
} | ||
|
||
// Test directive is ignored if it's not at the start of a line | ||
public function test_directive_is_ignored_if_it_is_not_at_the_start_of_a_line() | ||
{ | ||
$this->assertEquals('Example: [Blade]: {{ "Hello World!" }}', | ||
BladeDownService::render('Example: [Blade]: {{ "Hello World!" }}')); | ||
} | ||
|
||
// Test it renders Blade echo syntax with variables | ||
public function test_it_renders_blade_echo_syntax_with_variables() | ||
{ | ||
$this->assertEquals('Hello World!', BladeDownService::render('[Blade]: {{ $foo }}', ['foo' => 'Hello World!'])); | ||
} | ||
|
||
// Test it renders Blade views with variables | ||
public function test_it_renders_blade_views_with_variables() | ||
{ | ||
file_put_contents(resource_path( | ||
'views/hello.blade.php' | ||
), 'Hello {{ $name }}!'); | ||
|
||
$this->assertEquals('Hello John!', BladeDownService::render('[Blade]: @include("hello", ["name" => "John"])')); | ||
|
||
unlink(resource_path('views/hello.blade.php')); | ||
} | ||
} |