tempestphp / tempest-framework

The PHP framework that gets out of your way 🌊
https://tempestphp.com
MIT License
1.13k stars 80 forks source link

Markdown views #27

Open brendt opened 9 months ago

brendt commented 9 months ago

It might be interesting to support markdown views that are wrapped in a dedicated MarkdownView class; the markdown will be rendered and be automatically be put into this view.

return view('post-1.md')->extends('base.view.php');
# Title

Body

…
aidan-casey commented 9 months ago

@brendt do you intend to introduce our own markdown parser or leverage a dependency?

brendt commented 9 months ago

Definitely league/commonmark 👍

yassiNebeL commented 9 months ago

Note, that the helper view function is returning a GenericView.

It might be interesting to support markdown views that are wrapped in a dedicated MarkdownView class

I use league/commonmark :


use League\CommonMark\MarkdownConverter;

class MarkdownView implements View
{
        use isView;
}

with this🔝 , you can choose between those solutions:

  1. Call the CommonMarkConverter inside the constructor.
  2. Override the render method.

that's pretty neat, let me know if you have another solution regarding this.

yassiNebeL commented 9 months ago

@brendt I saw RenderedView which has no responsibility!

I did this, so please let me know if I'm good to create a PR regarding the view


declare(strict_types=1);

namespace Tempest\View;

use League\CommonMark\CommonMarkConverter;
use Tempest\AppConfig;

final class MarkdownView implements View
{
    use IsView {
        IsView::__construct as private initializeView;
        render as private renderView;
    }

    public function __construct(
        private CommonMarkConverter $markdownConverter,
        string $path,
        array $params = []
    ) {
        $this->initializeView($path, $params);
    }

    private function render(AppConfig $appConfig): string
    {
        $markdownContent = $this->renderView($appConfig);
        return $this->markdownConverter->convertToHtml($markdownContent);
    }
}

This is a decoupled way, which make it more flexible and following the principle of dependency injection.

use League\CommonMark\CommonMarkConverter;

// Assuming $markdownConverter is already instantiated elsewhere
$markdownConverter = new CommonMarkConverter();

$path = '/path/to/post-1.md';
$params = ['param1' => 'value1', 'param2' => 'value2'];

$markdownView = new MarkdownView($markdownConverter, $path, $params);

available for any further information!

brendt commented 9 months ago

This will actually need some more refactoring. Right now a view renders itself — not ideal. We could move that rendering logic to somewhere else. At the moment, it's the router that renders the view:

    private function createResponse(Response|View $input): Response
    {
        if ($input instanceof View) {
            return response($input->render($this->appConfig));
        }

        return $input;
    }

We could extract "view rendering" into a separate class that's used by the router whenever the controller response is a view. This class could then also check on whether the view is a markdown view, and use commonmark to parse it. In the end, a View object should be nothing more than a data object, it shouldn't know how to render itself, and a Markdown view just happens to be an implementation of View that the ViewRenderer (or whatever we call it) knows how to render

aidan-casey commented 9 months ago

@brendt - I really like the idea of something else handling the rendering. To some degree the API response objects in #39 could become "views" in the sense of purely data, but could be serialized according to the accepts header.

yassiNebeL commented 7 months ago

@brendt I saw RenderedView which has no responsibility!

I did this, so please let me know if I'm good to create a PR regarding the view

declare(strict_types=1);

namespace Tempest\View;

use League\CommonMark\CommonMarkConverter;
use Tempest\AppConfig;

final class MarkdownView implements View
{
    use IsView {
        IsView::__construct as private initializeView;
        render as private renderView;
    }

    public function __construct(
        private CommonMarkConverter $markdownConverter,
        string $path,
        array $params = []
    ) {
        $this->initializeView($path, $params);
    }

    private function render(AppConfig $appConfig): string
    {
        $markdownContent = $this->renderView($appConfig);
        return $this->markdownConverter->convertToHtml($markdownContent);
    }
}

This is a decoupled way, which make it more flexible and following the principle of dependency injection.

use League\CommonMark\CommonMarkConverter;

// Assuming $markdownConverter is already instantiated elsewhere
$markdownConverter = new CommonMarkConverter();

$path = '/path/to/post-1.md';
$params = ['param1' => 'value1', 'param2' => 'value2'];

$markdownView = new MarkdownView($markdownConverter, $path, $params);

available for any further information!

I'm planing to submit a PR addressing this issue, however, before proceeding I'd like to confirm whether it's necessary to check the presence of code blocks within the markdown file. Naturally this can be done using tempest\highlight

Could you please share your thoughts on this @brendt?

WendellAdriel commented 6 months ago

@yassiNebeL are you working on this already? Is there anything I could help with?

yassiNebeL commented 6 months ago

AFAIK, the Response class need to be refactored, I asked @brendt regarding this on discord and he said that will happens right after tempest/core.

Definitely, I'm working on that issue and would appreciate any suggestions.

WendellAdriel commented 6 months ago

Nice, let’s sync on this @yassiNebeL! @brendt do we already have a definition on what’s going to change in the responses and how they’ll work? If not, I have some ideas I can share and we can discuss.

brendt commented 6 months ago

@WendellAdriel I need to dive into it again, but it'll probably be another week. I wanna finish some of the last things for tempest/console first, and then shift my focus back to the web part.

WendellAdriel commented 6 months ago

Got it! Thanks @brendt! I’ll keep an eye on this to help when needed!