All Docs

Custom Adapters

Replace the Liquid engine or PDF renderer with your own implementation.

SferaDoc’s template engine and PDF engine are both pluggable via behaviour adapters.


Custom Template Engine

The default template engine uses solid (Liquid). Replace it by implementing SferaDoc.TemplateEngine.Adapter.

Behaviour

defmodule SferaDoc.TemplateEngine.Adapter do
  @callback parse(body :: String.t()) ::
              {:ok, parsed :: term()} | {:error, term()}

  @callback render(parsed :: term(), assigns :: map()) ::
              {:ok, html :: String.t()} | {:error, term()}
end

Example

defmodule MyApp.EExEngine do
  @behaviour SferaDoc.TemplateEngine.Adapter

  @impl true
  def parse(body) do
    # EEx compiles at parse time
    {:ok, EEx.compile_string(body)}
  end

  @impl true
  def render(compiled, assigns) do
    html = EEx.eval_compiled(compiled, assigns: assigns)
    {:ok, html}
  rescue
    e -> {:error, e}
  end
end

Configure:

config :sfera_doc, :template_engine,
  adapter: MyApp.EExEngine

Custom PDF Engine

The default PDF engine uses chromic_pdf. Replace it by implementing SferaDoc.PdfEngine.Adapter.

Behaviour

defmodule SferaDoc.PdfEngine.Adapter do
  @callback render(html :: String.t(), opts :: keyword()) ::
              {:ok, binary()} | {:error, term()}
end

Example

defmodule MyApp.WkHtmlToPdf do
  @behaviour SferaDoc.PdfEngine.Adapter

  @impl true
  def render(html, _opts) do
    with {:ok, path} <- Temp.path(%{suffix: ".pdf"}),
         :ok <- write_html_and_convert(html, path),
         {:ok, binary} <- File.read(path) do
      {:ok, binary}
    end
  end

  defp write_html_and_convert(html, output_path) do
    input = Temp.path!(%{suffix: ".html"})
    File.write!(input, html)
    case System.cmd("wkhtmltopdf", [input, output_path]) do
      {_, 0} -> :ok
      {reason, _} -> {:error, reason}
    end
  end
end

Configure:

config :sfera_doc, :pdf_engine,
  adapter: MyApp.WkHtmlToPdf

Store Adapter

See Store Adapters for implementing a custom template store.

Object Store Adapter

See PDF Caching for implementing a custom object store.