Skip to content

Commit

Permalink
Merge pull request #1738 from hydephp/includes-facade-improvements
Browse files Browse the repository at this point in the history
[2.x] Includes facade improvements
  • Loading branch information
caendesilva authored Jun 26, 2024
2 parents 8de4d37 + befd302 commit ebdcb91
Show file tree
Hide file tree
Showing 6 changed files with 511 additions and 50 deletions.
23 changes: 23 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ This serves two purposes:
- Minor: The documentation article component now supports disabling the semantic rendering using a falsy value in https://github.com/hydephp/develop/pull/1566
- Minor: Changed the default build task message to make it more concise in https://github.com/hydephp/develop/pull/1659
- Minor: Data collection files are now validated for syntax errors during discovery in https://github.com/hydephp/develop/pull/1732
- Minor: Methods in the `Includes` facade now return `HtmlString` objects instead of `string` in https://github.com/hydephp/develop/pull/1738. For more information, see below.
- Minor: `Includes::path()` and `Includes::get()` methods now normalizes paths to be basenames to match the behaviour of the other include methods in https://github.com/hydephp/develop/pull/1738. This means that nested directories are no longer supported, as you should use a data collection for that.
- The `hasFeature` method on the Hyde facade and HydeKernel now only accepts a Feature enum value instead of a string for its parameter.
- Changed how the documentation search is generated, to be an `InMemoryPage` instead of a post-build task.
- Media asset files are now copied using the new build task instead of the deprecated `BuildService::transferMediaAssets()` method.
- Calling the `Include::path()` method will no longer create the includes directory in https://github.com/hydephp/develop/pull/1707
- Calling the `DataCollection` methods will no longer create the data collections directory in https://github.com/hydephp/develop/pull/1732
- Markdown includes are now converted to HTML using the custom HydePHP Markdown service, meaning they now support full GFM spec and custom Hyde features like colored blockquotes and code block filepath labels in https://github.com/hydephp/develop/pull/1738
- Markdown returned from includes are now trimmed of trailing whitespace and newlines in https://github.com/hydephp/develop/pull/1738

### Deprecated
- for soon-to-be removed features.
Expand Down Expand Up @@ -221,6 +225,25 @@ For example, if you triggered the media transfer with a build service method cal
(new TransferMediaAssets())->run();
```

### Includes facade changes

The following methods in the `Includes` facade now return `HtmlString` objects instead of `string`:

- `Includes::html()`
- `Includes::blade()`
- `Includes::markdown()`

- This means that you no longer need to use `{!! !!}` to render the output of these methods in Blade templates, instead just use `{{ }}`.
- If you have used the return value of these methods in custom code, you may need to adjust your code to work with the new return type.

For more information, see the RFC that proposed this change: https://github.com/hydephp/develop/issues/1734
The RFC was implemented in https://github.com/hydephp/develop/pull/1738

#### Remember to escape output if necessary

**Note:** Remember that this means that includes are **no longer escaped** by default, so make sure to escape the output if necessary, for example if the content is user-generated.
- (Use `{{ e(Includes::html('foo')) }}` instead of `{{ Includes::html('foo') }}` to escape the output, matching the previous behavior.)

### DataCollection API changes

The DataCollection feature has been reworked to improve the developer experience and make it more consistent with the rest of the API.
Expand Down
10 changes: 9 additions & 1 deletion docs/digging-deeper/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ Includes::markdown('example') === Includes::markdown('example.md');

All methods will return `null` if the file does not exist.
However, you can supply a default value as the second argument to be used instead.
Remember that Markdown and Blade defaults will still be rendered to HTML.
Remember that Markdown and Blade defaults will also be rendered to HTML.

Includes are particularly useful in Blade views, as you can echo them directly. You do not need to import the namespace, as it is already aliased.

```blade
<footer>
{{ Includes::markdown('footer.md') }}
</footer>
```

```php
use Hyde\Support\Includes;
Expand Down
2 changes: 2 additions & 0 deletions packages/framework/src/Framework/Services/MarkdownService.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Hyde\Facades\Config;
use Hyde\Facades\Features;
use Hyde\Markdown\Models\MarkdownDocument;
use Hyde\Framework\Concerns\Internal\SetsUpMarkdownConverter;
use Hyde\Pages\DocumentationPage;
use Hyde\Markdown\MarkdownConverter;
Expand Down Expand Up @@ -186,6 +187,7 @@ public function hasFeature(string $feature): bool
protected function determineIfTorchlightAttributionShouldBeInjected(): bool
{
return ! $this->isDocumentationPage()
&& ! (isset($this->pageClass) && $this->pageClass === MarkdownDocument::class)
&& Config::getBool('torchlight.attribution.enabled', true)
&& str_contains($this->html, 'Syntax highlighted by torchlight.dev');
}
Expand Down
100 changes: 61 additions & 39 deletions packages/framework/src/Support/Includes.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
namespace Hyde\Support;

use Hyde\Hyde;
use Hyde\Facades\Filesystem;
use Illuminate\Support\HtmlString;
use Hyde\Markdown\Models\MarkdownDocument;
use Hyde\Markdown\Models\Markdown;
use Illuminate\Support\Facades\Blade;

use function trim;
use function basename;
use function file_exists;
use function file_get_contents;

/**
* The Includes facade provides a simple way to access partials in the includes directory.
Expand All @@ -32,80 +34,100 @@ class Includes
*/
public static function path(?string $filename = null): string
{
return $filename === null
? Hyde::path(static::$includesDirectory)
: Hyde::path(static::$includesDirectory.'/'.$filename);
if ($filename === null) {
return Hyde::path(static::$includesDirectory);
}

return Hyde::path(static::$includesDirectory.'/'.static::normalizePath($filename));
}

/**
* Get the raw contents of a partial file in the includes directory.
*
* @param string $filename The name of the partial file, including the extension.
* @param string|null $default The default value to return if the partial is not found.
* @return string|null The contents of the partial file, or the default value if not found.
* @return string|null The raw contents of the partial file, or the default value if not found.
*/
public static function get(string $filename, ?string $default = null): ?string
{
$path = static::path($filename);

if (! file_exists($path)) {
return $default;
}

return file_get_contents($path);
return static::getInclude(fn (string $contents): string => $contents, $filename, $default);
}

/**
* Get the HTML contents of a partial file in the includes directory.
*
* @param string $filename The name of the partial file, with or without the extension.
* @param string|null $default The default value to return if the partial is not found.
* @return string|null The raw contents of the partial file, or the default value if not found.
* @return HtmlString|null The contents of the partial file, or the default value if not found.
*/
public static function html(string $filename, ?string $default = null): ?string
public static function html(string $filename, ?string $default = null): ?HtmlString
{
$path = static::path(basename($filename, '.html').'.html');

if (! file_exists($path)) {
return $default === null ? null : $default;
}

return file_get_contents($path);
return static::getInclude([static::class, 'renderHtml'], $filename, $default, '.html');
}

/**
* Get the rendered Markdown of a partial file in the includes directory.
* Get the rendered Blade of a partial file in the includes directory.
*
* @param string $filename The name of the partial file, with or without the extension.
* @param string|null $default The default value to return if the partial is not found.
* @return string|null The rendered contents of the partial file, or the default value if not found.
* @return HtmlString|null The rendered contents of the partial file, or the default value if not found.
*/
public static function markdown(string $filename, ?string $default = null): ?string
public static function blade(string $filename, ?string $default = null): ?HtmlString
{
$path = static::path(basename($filename, '.md').'.md');

if (! file_exists($path)) {
return $default === null ? null : Markdown::render($default);
}

return Markdown::render(file_get_contents($path));
return static::getInclude([static::class, 'renderBlade'], $filename, $default, '.blade.php');
}

/**
* Get the rendered Blade of a partial file in the includes directory.
* Get the rendered Markdown of a partial file in the includes directory.
*
* @param string $filename The name of the partial file, with or without the extension.
* @param string|null $default The default value to return if the partial is not found.
* @return string|null The rendered contents of the partial file, or the default value if not found.
* @return HtmlString|null The rendered contents of the partial file, or the default value if not found.
*/
public static function blade(string $filename, ?string $default = null): ?string
public static function markdown(string $filename, ?string $default = null): ?HtmlString
{
$path = static::path(basename($filename, '.blade.php').'.blade.php');
return static::getInclude([static::class, 'renderMarkdown'], $filename, $default, '.md');
}

if (! file_exists($path)) {
return $default === null ? null : Blade::render($default);
/** @param callable(string): (\Illuminate\Support\HtmlString|string) $method */
protected static function getInclude(callable $method, string $filename, ?string $default, string $extension = ''): HtmlString|string|null
{
$path = static::normalizePath($filename, $extension);
$contents = static::getFileContents(static::path($path));

if ($contents === null && $default === null) {
return null;
}

return $method($contents ?? $default);
}

protected static function normalizePath(string $filename, string $extension = ''): string
{
return basename($filename, $extension).$extension;
}

protected static function getFileContents(string $path): ?string
{
if (! Filesystem::exists($path)) {
return null;
}

return Blade::render(file_get_contents($path));
return Filesystem::get($path);
}

protected static function renderHtml(string $html): HtmlString
{
return new HtmlString($html);
}

protected static function renderBlade(string $blade): HtmlString
{
return new HtmlString(Blade::render($blade));
}

protected static function renderMarkdown(string $markdown): HtmlString
{
return new HtmlString(trim(Markdown::render($markdown, MarkdownDocument::class)));
}
}
Loading

0 comments on commit ebdcb91

Please sign in to comment.