DimaLondon
@DimaLondon

Как вставить вложенный HTML в League\CommonMark для Laravel?

Я перелопатил код вей библиотеки League\CommonMark но не нашел внятного примера. Очень запутанно.

Задача: есть тег типа |attach_photo_123_456| либо |attach_video_789_380|
где, к примеру, первое:
1) надо отобразить фото
2) прикрепленное к публикации с ID=123
3) у которого ID=456

У меня все получилось (скрипт ниже). Но получилось вставить только изображение. А мне надо изображение, обрамленное ссылкой. Чтоб по нему можно было кликнуть и открылось POP окно с увеличенным размером.

То же самое для VIDEO. Там будет скриншот, обрамленный DIV с определенным классом. При клике по DIV вместо скриншота JS потом вставит код видео-плеера.

Сейчас у меня получилось так:

Тут я подключаю и вызываю парсер:
<?php

declare(strict_types=1);

namespace App\Commonmark\Extensions\Blog;

use League\CommonMark\Environment\EnvironmentBuilderInterface;
use League\CommonMark\Extension\ExtensionInterface;
use League\CommonMark\Parser\InlineParserContext;

final class AttachMediaExtension implements ExtensionInterface
{
    public function register(EnvironmentBuilderInterface $environment): void
    {
        $environment->addInlineParser(new AttachMediaParser());
    }
}


и парсер строки для вставки медиафайла:

<?php

declare(strict_types=1);

namespace App\Commonmark\Extensions\Blog;

use App\Models\Blog\Posts\BlogPost;
use Str;

use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
use League\CommonMark\Parser\Inline\InlineParserInterface;
use League\CommonMark\Parser\Inline\InlineParserMatch;
use League\CommonMark\Parser\InlineParserContext;

use League\CommonMark\Renderer\NodeRendererInterface;

class AttachMediaParser implements InlineParserInterface
{
    private const REGEX = '\|attach\-(photo|video|gif|audio)\-(\d+)\-(\d+)\|';
    
    public function getMatchDefinition(): InlineParserMatch
    {
        return InlineParserMatch::regex(self::REGEX);
    }
        
    public function parse(InlineParserContext $inlineContext): bool
    {
        $match = $inlineContext->getFullMatch();
        $matches = $inlineContext->getMatches();
        
        $type = $matches[1] ?? null; // тип медиафайла
        $postId = $matches[2] ?? null; // ID поста
        $mediaId = $matches[3] ?? null; // ID файла
        
        if (!empty($type) && !empty($postId) && !empty($mediaId)) {
            $post = BlogPost::find($postId);
            if (!empty($post)) {
                switch($type)
                {
                    case 'photo':
                        $photo = $post->photos->keyBy('id')->get($mediaId, null);
                        if (!empty($photo)) {
                            $url = $photo->prev()->url();
                            
                            $image = new Image($url);
                            $image->data->set('attributes/class', 'w-100');
                            
                            $inlineContext->getCursor()->advanceBy($inlineContext->getFullMatchLength());
                            $inlineContext->getContainer()->appendChild($image);
                        }
                        break;
                    case 'video':
                        break;
                    case 'gif':
                        break;                    
                    case 'audio':
                        break;
                }
            }
        }
        
        return true;
    }
}

Работает изумительно и быстро, если вставлять просто картинку. Но как вложить тег изображения в тег ссылки?
Теоретически, надо создать рендер, помещенный внутрь парсера, как это написано в документации? Но там же написано, что это медленнее, т.к. после этого обработка будет производиться снова. И чем больше вложенностей, тем медленнее.
  • Вопрос задан
  • 70 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽