This directory builds larafly by example, a bilingual (EN + ES) book teaching
LaraFly by walking through the samples/lumen project chapter by chapter. It
mirrors fireflyframework-pyfly/book/'s architecture (WeasyPrint -> PDF, a
hand-rolled EPUB3 assembler, python-markdown with custom directives), renamed
and re-tokened for LaraFly/PHP/Laravel.
This is a Python toolchain, isolated from the PHP monorepo: book/.venv/
and book/dist/ (the generated PDF/EPUB) are gitignored and never committed.
Only the sources — book.yaml, build/*.py, theme/*.css, art/,
src/ (EN), src-es/ (ES), tests/ — are tracked.
Published PDF and EPUB editions (English + Español)
are rebuilt with the MkDocs site after every successful main CI run. GitHub releases also carry the
books built from their tag. Each download set includes SHA256SUMS and a build-info.json source commit.
The first build needs network access (to install the Python deps) and a native cairo + pango stack (WeasyPrint's rendering backend). Every build after that is fully offline.
# 1. Create the venv (Python 3.12 preferred; this repo used 3.13 — 3.12 was not
# installed on the build machine, and WeasyPrint has no 3.12-specific pin).
python3.12 -m venv book/.venv # or: python3.13 -m venv book/.venv
book/.venv/bin/pip install -r book/build/requirements.txt
# 2. macOS only: WeasyPrint links against cairo/pango via ctypes at runtime.
brew install cairo pangobook/build/run.sh sets DYLD_FALLBACK_LIBRARY_PATH to Homebrew's lib/ so
WeasyPrint finds libcairo/libpango without any manual export. On Linux,
install the equivalent packages (e.g. apt install libcairo2 libpango-1.0-0 libpangoft2-1.0-0)
and run.sh's DYLD_FALLBACK_LIBRARY_PATH export is a no-op (Linux uses the
system loader path instead).
bash book/build/run.sh # English -> book/dist/larafly-by-example.{pdf,epub}
bash book/build/run.sh --config book.es.yaml # Spanish -> book/dist/larafly-by-example-es.{pdf,epub}book/dist/ is created on demand and is gitignored — nobody commits a
generated PDF/EPUB.
To run the same pipeline as CI, including the book tests, PHP listing checks, both editions,
the PDF text-boundary check, the strict MkDocs build and site/downloads/ packaging:
bash scripts/build-docs.shA fenced ```php block is linted with the real PHP CLI (php -l, via a temp
file — no execution) unless it carries a <!-- source: … --> marker. A marked
block is a verbatim excerpt of the repository file it names — a fragment that
does not parse on its own — and is checked by line-for-line comparison in
DocsCodeIsRealTest instead. Every listing in src/ and in src-es/
carries one marker or the other, and both directories are named in
DocsCodeAudit::AUDITED, so every marked block in either edition is held to the
comparison:
book/.venv/bin/python book/build/verify_code.py book/src --require-provenance
book/.venv/bin/python book/build/verify_code.py book/src-es --require-provenanceExits non-zero and prints FAIL <file>:<line> ... for any listing that fails to
parse, and — with --require-provenance — for any php listing carrying
neither marker.
cd book && ../book/.venv/bin/python -m pytest -qCovers the Markdown extension (::: figure, ::: listing, admonitions), the
EPUB3/OCF assembler, and the PHP-listing extractor/linter.
book/
book.yaml # EN manifest: title/author/rights, front matter, parts/chapters
book.es.yaml # ES manifest (manuscript_dir: src-es)
build/
build.py # orchestrates: manifest -> items -> EpubBuilder + render_pdf
md.py # Markdown -> XHTML: ::: figure / ::: listing directives,
# note/tip/warning/laravel admonitions, codehilite
epub.py # stdlib-only EPUB3 (OCF) zip assembler
pdf.py # WeasyPrint HTML -> PDF
gen_cover.py # validates canonical art; --render rasterizes outlined SVGs
verify_code.py # fenced ```php listings: `php -l`, except `source:` ones
run.sh # sets DYLD_FALLBACK_LIBRARY_PATH, execs build.py
requirements.txt # pinned: weasyprint, markdown, pygments, pyyaml, pytest, cairosvg
theme/
tokens.css # CSS custom properties (palette)
book.css # shared screen/EPUB styles
print.css # @page rules, running heads, page-break control (PDF only)
pygments.css # syntax-highlighting token colors
art/
cover{,-es}.{svg,png} # canonical localized front covers
back-cover{,-es}.{svg,png} # canonical localized back covers
PROVENANCE.md # source and delivered artwork hashes
figures/ # inline-SVG diagrams referenced by ::: figure
openers/ # reserved for future per-chapter opener art (empty)
src/ # EN manuscript (Markdown)
00-front/ # title/copyright/dedication/preface/conventions
00-quickstart.md # "Build Lumen step by step" quick start
01..13a-*.md # the sixteen chapters, 4A, 10A and 13A included (Parts I-IV)
90-appendix-a-laravel.md # Laravel -> LaraFly cheat-sheet
94-glossary.md # glossary
src-es/ # ES manuscript, same structure/filenames
tests/
test_md.py, test_epub.py, test_verify_code.py
- Code listings: real chapters use a plain fenced block with the language
tag
php, e.g.```php. These are both syntax-highlighted (via Pygments) and linted byverify_code.py. A custom::: listing <label> | <caption>block directive is also available (ported from PyFly) for listings that need a file-name tab and a numbered caption baked into the HTML. - Figures:
::: figure <path.svg> | <caption>inlines an SVG (or embeds a raster image as a data URI) so it renders crisply in both the EPUB and the print PDF. - Callouts:
!!! note,!!! tip,!!! warning(admonition extension), and LaraFly's own!!! laravel "..."— a Laravel-parity callout that maps a LaraFly concept directly to its native Laravel equivalent (this replaces PyFly's!!! springcallout).
The manuscript is structurally complete in both languages: a five-file front matter, a "Build Lumen step by step" quick start, sixteen chapters across four parts —
- Part I — Foundations: Why LaraFly, Dependency Injection & Auto-Configuration, Configuration/Profiles/Secrets, Your First HTTP API
- Part II — Modelling & Persisting the Domain: Persistence & Repositories, Domain-Driven Design
- Part III — Coordinating & Securing the Application: CQRS, Event-Driven
Architecture & the Transactional Outbox, Transactions & the
#[Transactional]proxy, Security, OAuth2 and OpenID Connect - Part IV — Observability, Testing & Delivery: Observability/Actuator, Testing, the CLI & the Zero-Reflection Cache, Feature Flags
— plus Appendix A (Laravel → LaraFly cheat-sheet) and a Glossary. Every
chapter walks the real samples/lumen project. Every fenced ```php listing
in src/ and in src-es/ carries either a source: marker naming the
repository file it was excerpted from — compared line for line by the
repository's own documentation guard — or an illustrative: marker saying it is
the reader's own code, which is the kind php -l checks. Both editions build to
book/dist/ as PDF + EPUB.
The two editions are the same book, line for line. Every chapter file has
the same sections in the same order at the same line numbers, and every php
listing and every source:-marked excerpt in the Spanish edition is the English
one character for character — identifiers, config keys, endpoint paths and HTTP
transcripts are never translated. What a Spanish fence does translate is the
trailing comment on a shell or tree listing: that is prose the reader reads, not
code they run, and no php or source: block carries one. The repository's own
prose guard derives both halves of that parity — the per-chapter sizes, and the
blocks themselves, byte for byte — and fails the build the moment one edition
stops matching the other.
The English and Spanish manifests select their own front/back SVG and PNG files
under art/. See artwork provenance for the canonical brand
kit source and delivered asset hashes. The SVG typography is outlined; the build
needs no author-machine fonts for the covers.
book/.venv/bin/python book/build/gen_cover.pyThis validates all four SVG/PNG pairs without modifying them. Use an explicit
--render only to rasterize the checked-in SVGs again. The book build fails if a
configured PNG is missing. Covers fill the PDF trim without running text; EPUB
editions include accessible front/back documents and localized navigation.
Book-only editions can be published separately under books-* tags and must not
be marked as the latest framework release. Keep the book source commit and asset
checksums with the edition. A book-only edition does not change framework package
versions or replace the assets attached to an existing framework version.