Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Markdown Builder Laravel Package

davidbadura/markdown-builder

A fluent PHP library for building Markdown documents programmatically. Compose headings, paragraphs, lists, links, code blocks, and tables via a clean, chainable API, ideal for READMEs, reports, and dynamic docs in any PHP or Laravel project.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require davidbadura/markdown-builder

There is no Laravel service provider or facade to discover — it's a framework-agnostic PHP library. The practical setup is:

  1. Read composer.json first to confirm the PHP constraint against your app's version.
  2. Read src/ before the README. The surface is tiny (a builder plus a handful of element/node classes), and the source will tell you the exact method names and whether output is produced by build(), __toString(), or both.
  3. If you want it injected, bind it as a transient (new instance per document) in AppServiceProvider — the builder accumulates state, so a singleton will leak content between requests/jobs.

A first, realistic use case is generating a markdown report or changelog from data you already have:

use DavidBadura\MarkdownBuilder\MarkdownBuilder;

// Method names are illustrative — confirm the exact API in src/.
$md = (new MarkdownBuilder())
    ->addHeader('Weekly report', 1)
    ->addParagraph('Generated ' . now()->toDateString())
    ->addListing([
        'New signups: ' . $signups,
        'Churn: ' . $churn,
    ]);

Storage::disk('local')->put('reports/weekly.md', (string) $md);

Then serve it with response()->download(...) or Storage::download(...). That single flow — model data in, .md file out — is the highest-value entry point for most Laravel apps.

Implementation Patterns

Wrap the builder in a document class. Don't scatter builder calls through controllers. Create App\Support\Markdown\WeeklyReport with a build(): string method. This gives you one place to change formatting and one place to test, and it insulates the rest of the app if you later swap the package out.

Use it for data-driven exports, not static docs. If the content is fixed prose, a Blade template that emits markdown is simpler and diff-friendly. Reach for the builder when the structure is dynamic: release notes from commits, per-customer summaries, API docs from a schema, exportable record dumps.

Compose per section. Build a MarkdownBuilder per logical section (summary, table, appendix), then concatenate the rendered strings with "\n\n" between them. This keeps methods short and makes sections individually testable. It also sidesteps any internal nesting quirks.

Loop Eloquent results into lists/tables:

foreach ($orders as $order) {
    $md->addListingItem("{$order->id} — {$order->total}");
}

Batch queries first; the builder itself is cheap, but naive per-row relationship access inside the loop is not.

Schedule or queue it. A changelog or report generator belongs in an artisan command or a queued job, writing to Storage. Keep the HTTP path limited to triggering and downloading; don't generate large documents inline in a request.

Test the raw string, not rendered HTML. Snapshot the generated markdown (or assert on stable substrings). Rendering through CommonMark in tests adds a second source of failure and hides formatting regressions in the actual output.

Pipe to HTML only at the edge. If you need to display the result, run it through league/commonmark in the view layer. Never store both the markdown and the HTML and let them drift.

Gotchas and Tips

  • It's effectively unmaintained. Last release was October 2021 and the project is small. Pin the version in composer.json, and be prepared to vendor or fork it — the codebase is small enough that a fork is a realistic escape hatch. Budget for that risk before putting it on a critical path.
  • Escaping is on you. A "simple markdown builder" typically does not escape user-supplied text. If any interpolated value can contain *, _, #, `, |, or a leading -, you will get broken markup. Add your own escaper for table cells and inline text before passing values in.
  • Table cells need explicit pipe escaping. An unescaped | in a value silently shifts every subsequent column. Escape to \| and strip newlines from cell content — a newline inside a row destroys the table.
  • Blank-line handling matters. Most markdown parsers require a blank line between block-level elements (headings, lists, tables, code fences). Check the generated output before a heading or after a list; if blocks are glued together, insert separators yourself.
  • Nested list indentation is inconsistent across renderers. Prefer 4 spaces for the sub-level if you nest, and verify in the actual renderer you ship with (GitHub, CommonMark, GitLab all differ slightly on edge cases).
  • Code fences with backticks inside need a longer fence (```` vs `). If you emit code blocks from user content, use four backticks and let the content be what it is.
  • HTML passes straight through. Markdown allows raw HTML; if the output is rendered on a page, sanitize it. Do not treat this library as a sanitizer — it isn't one, and it's a builder, not a parser, so it can't validate anything coming in.
  • Check the stringify path. Confirm whether you need build(), __toString(), or an explicit render(). Calling the wrong one returns an object that silently stringifies to "" in some contexts; dump() the result during development.
  • No type safety on arguments in an older codebase. Wrap the builder in your own small class with typed methods. That's also your extension point: subclassing or decorating a wrapper is far safer than patching the library internals for a formatting tweak.
  • Debugging tip: when output looks wrong, print the raw markdown with visible characters (e.g. str_replace(' ', '·', $md)) to catch trailing-space line breaks and missing blank lines before blaming the renderer.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package