Markdown Extra w PHP

Z okazji odświeżenia wyglądu bloga, postanowiłem wprowadzić kilka drobnych zmian w samym jego kodzie. Jedną z nich było usunięcie CKEditora i zmiana składni treści wpisów na Markdown. Oto, jak osiągnąłem ten efekt.

Zamiana HTML na Markdown

Ponieważ pierwszą i najważeniejszą rzeczą było przekształcenie składni już istniejących wpisów (a tych było ponad 80), musiałem w miarę bezboleśnie poradzić sobie z tym tematem. Zacznę zatem pokrótce od narzędzi, których użyłem.

Pierwszym krokiem przy przekształcaniu HTML uzyskanego z CKEditora było pozbycie się encji HTML. Ręczne poprawki nie wchodziły w grę, więc musiałem znaleźć lepsze wyjście. Jako edytora tekstu używam od jakiegoś czasu Atoma i pomocne okazało się zainstalowanie dodatku html-entities. Służy on, jak się nietrudno domyślić, do kodowania i dekodowania encji. Po instalacji, wystarczy znaleźć polecenie „HTML Entities: Decode” ([ctrl]+[shift]+p, d, e, c, o, [enter]).

Drugi krok to przekształcenie HTML na Markdown. W tym celu pomocna okazała się aplikacja online to-markdown. W lewej zakładce wklejamy kod HTML, a w prawej od razu otrzymujemy wynikowy kod Markdown. Proste i szybkie. Po tej zamianie każdy wpis musiałem jeszcze ręcznie dostosować (głównie chodziło o bloki kodu), jednak zajmowało to dosłownie chwilę.

Instalacja parserów Markdown i SmartyPants

Po stronie kodu bloga za to musiałem wprowadzić mechanizm, który umożliwiłby przekształcenie Markdown z powrotem na HTML. Pomocne przy tym są dwie paczki zawierające potrzebne nam parsery: php-markdown oraz php-smartypants. Pierwsza z nich zzajmuje się przetłumaczeniem składni Markdown na HTML, druga zaś automatycznie poprawi nam znaki interpunkcyjne, np. zamieni cudzysłowy zwykłe na drukarskie, czy przekształci ciąg trzech kropek na znak wielokropka.

Zaczynamy od ich zainstalowania w projekcie. Z linii komend dodajemy paczki do Composera:

composer require michelf/php-markdown michelf/php-smartypants

W momencie pisania tego wpisu, druga z instalowanych paczek jest wydana tylko jako wersja beta. Composer może więc odmówić zainstalowania jej ze względu na brak wersji stabilnej. Poradzić sobie z tym można zezwalając na instalowanie wersji beta lub ręcznie edytując plik composer.json i podając aktualną wersję rozwojową paczki:

{
    "require": {
        "michelf/php-markdown": "1.6.0",
        "michelf/php-smartypants": "1.6.x-dev"
    }
}

i następnie instalując wszystkie paczki:

composer install

Parsowanie Markdown

Zamiana Markdown na HTML jest bajecznie prosta. Wystarczy, że użyjemy następującego kodu:

use Michelf\MarkdownExtra;

// gdzieś wewnątrz kodu:
$outputHTML = MarkdownExtra::defaultTransform($inputMarkdown);

Jest oczywiście możliwość uzyskania kontroli nad sposobem parsowania, np. wyłączenie pewnych dodatkowych funkcji oferowanych przez Markdown Extra, ale takimi rzeczami zajmował się nie będę, a zainteresowanych odsyłam do dokumentacji narzędzia.

Poprawki interpunkcji

Domyślna zamiana jest równie prosta, jak w poprzednim przypadku, jednak dla tekstów w języku polskim pojawia się pewien problem. Otóż domyślny zestaw znaków interpunkcyjnych jest charakterystyczny dla języka angielskiego. Jak wiadomo, cudzysłowy drukarskie w języku angielskim są pisane w indeksie górnym, podczas gdy po polsku, cudzysłów otwierający jest w indeksie dolnym. Dla kodu HTML efekt jest taki, że używany innego kodu Unicode dla otwierającego cudzysłowu.

Zacznijmy zatem od skonfigurowania narzędzia.

use Michelf\SmartyPantsTypographer;

// gdzieś wewnątrz kodu:
$parser = new SmartyPantsTypographer();
$parser->smart_doublequote_open = "„";

Od tego momentu obiekt $parser jest skonfigurowany tak, by cudzysłowy otwierające były charakterystyczne dla języka polskiego. Teraz wystarczy przetworzyć tekst:

$outputHTML = $parser->transform($outputHTML);

Filtr

Ponieważ zamiana Markdown na HTML jest używana w wielu miejscach, całe przetwarzanie postanowiłem zawrzeć w jednym miejscu, a mianowicie w klasie filtra, który może zostać wstrzyknięty gdzie trzeba. W najogólniejszej postaci, filtr taki wygląda następująco:

namespace Dominikmarczuk\Filter;

use Michelf\MarkdownExtra;
use Michelf\SmartyPantsTypographer;

class MarkdownToHTML
{
    private $smartyPants;

    public function __construct()
    {
        $this->smartyPants = new SmartyPantsTypographer();
        $this->smartyPants->smart_doublequote_open = "„";
    }

    public function filter($inputMarkdown)
    {
        $outputHTML = MarkdownExtra::defaultTransform($inputMarkdown);
        $outputHTML = $this->smartyPants->transform($outputHTML);

        return $outputHTML;
    }
}

Jak już wspomniałem, powyższy filtr można wstrzyknąć w miejsce, gdzie operujemy na pobranych z bazy tekstach ze składnią Markdown i przekształcić je jednym wywołaniem do pożądanej postaci HTML. W ten właśnie sposób (a w zasadzie w sposób analogiczny, gdzyż na potrzeby przykładów w niniejszym wpisie dokonałem drobnych uproszczeń) przekształcony został kod mojego bloga.


Komentarze

PCC

2016-04-14, 09:42

Jakie są podstawowe różnice między Markdown a CKEditor? Nigdy wcześniej z tego nie korzystałem.

Dominik

2016-04-15, 18:46

Podstawowe różnice są trzy: sposób wprowadzania tekstu, zapisywany format i jego przetwrzanie podczas wyświetlania. CKEditor umożliwia edycję wyglądu już wyrenderowanego HTML, tak, jakbyś pisał w Wordzie. Markdown zaś wymaga korzystania ze specjalnej składni czytelnej dla człowieka, ale jednak niebędącej kodem HTML. CKEditor "pod maską" tworzy wynikowy kod HTML i to ten kod HTML trafia do bazy danych. Markdown przed zapisaniem nie jest przetwarzany, a do bazy trafia dokładnie taki kod, jaki ręcznie wpiszesz. Wreszcie wyświetlanie kodu stworzonego przez CKEditor (a więc gotowego HTML) nie wymaga żadnego przetwarzania, podczas gdy Markdown musi zostać sparsowany, aby przed wyświetleniem przekształcić go na wynikowy kod HTML.


Napisz komentarz


Szukaj wpisów


Chmura tagów