hosmelq / laravel-anydoc
Laravel integration for converting documents to GitHub-Flavored Markdown with Anydoc.
Requires
- php: ^8.4
- ext-anydoc: ^0.1.0
- illuminate/filesystem: ^12.0 || ^13.0
- illuminate/http: ^12.0 || ^13.0
- illuminate/support: ^12.0 || ^13.0
- spatie/laravel-package-tools: ^1.93
- thecodingmachine/safe: ^3.4
Requires (Dev)
- ergebnis/composer-normalize: ^2.52
- larastan/larastan: ^3.10
- laravel/pint: ^1.30
- orchestra/pest-plugin-testbench: ^4.1
- orchestra/testbench: ^10.0 || ^11.1
- pestphp/pest: ^4.7
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- rector/rector: ^2.6
- shipmonk/composer-dependency-analyser: ^1.8
- spaze/phpstan-disallowed-calls: ^4.14
- thecodingmachine/phpstan-safe-rule: ^1.4
- ticketswap/phpstan-error-formatter: ^1.3
- tomasvotruba/type-coverage: ^2.3
This package is auto-updated.
Last update: 2026-08-10 22:20:36 UTC
README
Laravel Anydoc provides a fluent Laravel API for converting Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF files to GitHub-Flavored Markdown. It also provides access to Anydoc's structured document model.
Requirements
- PHP 8.4+
- Laravel 12.x or 13.x
- ext-anydoc 0.1.x
Installation
Install the native extension with PIE:
pie install hosmelq/ext-anydoc
Then install the Laravel package via Composer:
composer require hosmelq/laravel-anydoc
Laravel discovers the package automatically. There are no configuration files, migrations, or other assets to publish.
Basic Usage
Convert a local file to Markdown:
use HosmelQ\Anydoc\Laravel\Facades\Anydoc; $markdown = Anydoc::file('report.docx')->markdown();
Uploaded files are also supported:
$markdown = Anydoc::file($uploadedFile)->markdown();
Convert directly from bytes:
$bytes = file_get_contents('report.docx'); $markdown = Anydoc::bytes($bytes)->markdown();
CSV has no content signature, so CSV bytes require an explicit format:
use HosmelQ\Anydoc\Laravel\Enums\Format; use HosmelQ\Anydoc\Laravel\Facades\Anydoc; $bytes = file_get_contents('data.csv'); $markdown = Anydoc::bytes($bytes, Format::Csv)->markdown();
Laravel Filesystem Disks
Use disk to convert a file stored on a Laravel filesystem disk:
use HosmelQ\Anydoc\Laravel\Facades\Anydoc; $markdown = Anydoc::disk('s3') ->file('documents/report.docx') ->markdown();
Omit the disk name to use Laravel's default filesystem disk:
$markdown = Anydoc::disk() ->file('documents/report.docx') ->markdown();
Disk and uploaded-file inputs are read into memory before conversion. All conversions are synchronous.
Structured Documents
Call document instead of markdown to access Anydoc's readonly document model:
use HosmelQ\Anydoc\Laravel\Facades\Anydoc; $document = Anydoc::file('presentation.pptx')->document(); $blocks = $document->blocks; $notes = $document->notes; $assets = $document->assets;
The document model includes blocks, inline content, lists, tables, notes, and embedded assets.
PDF supports Markdown conversion only. Calling document for a PDF throws an
Anydoc\Exception\UnsupportedException.
Supported Formats
| Format | Extensions |
|---|---|
| CSV | .csv |
| EPUB | .epub |
| Excel | .xls, .xlsb, .xlsm, .xlsx |
| OpenDocument | .odp, .ods, .odt |
.pdf |
|
| PowerPoint | .pot, .pps, .ppsm, .ppsx, .ppt, .pptm, .pptx |
| Rich Text Format | .rtf |
| Word | .doc, .docm, .docx |
Use the Format enum when you need to specify a format explicitly:
use HosmelQ\Anydoc\Laravel\Enums\Format; use HosmelQ\Anydoc\Laravel\Facades\Anydoc; $markdown = Anydoc::bytes($bytes, Format::Docx)->markdown();
The enum exposes these cases:
Format::Csv; Format::Doc; Format::Docx; Format::Epub; Format::Odp; Format::Ods; Format::Odt; Format::Pdf; Format::Ppt; Format::Pptx; Format::Rtf; Format::Xlsx;
Macro-enabled and legacy extensions are normalized to their corresponding
formats. For example, .docm resolves to Format::Docx, .pptm resolves to
Format::Pptx, and .xls resolves to Format::Xlsx.
Format Detection
Formats may be detected from bytes, extensions, or paths:
use HosmelQ\Anydoc\Laravel\Facades\Anydoc; $fromBytes = Anydoc::formatFromBytes($bytes); $fromExtension = Anydoc::formatFromExtension('.DOCX'); $fromPath = Anydoc::formatFromPath('documents/report.docx');
Each method returns a Format enum case or null when the format is not
recognized. Extension detection is case-insensitive and accepts an optional
leading dot.
Uploaded files are detected from their contents, with the original filename used as a fallback. Filesystem objects are detected from their contents, with their path used as a fallback.
Dependency Injection
The Anydoc contract may be injected instead of using the facade:
use HosmelQ\Anydoc\Laravel\Contracts\Anydoc; final class ConvertDocument { public function __construct( private Anydoc $anydoc, ) {} public function handle(string $path): string { return $this->anydoc->file($path)->markdown(); } }
The package registers the contract as a singleton backed by the Anydoc manager.
Error Handling
Native conversion errors extend Anydoc\Exception\ConvertException:
use Anydoc\Exception\ConvertException; use Anydoc\Exception\PanicException; use HosmelQ\Anydoc\Laravel\Facades\Anydoc; try { $markdown = Anydoc::file('report.docx')->markdown(); } catch (ConvertException $exception) { report($exception); } catch (PanicException $exception) { report($exception); }
Concrete conversion exceptions include:
EncryptedExceptionIoExceptionMalformedExceptionMissingPartExceptionResourceLimitExceptionUnsupportedException
Filesystem sources may also throw Laravel filesystem exceptions when their
contents cannot be read. PanicException represents a panic from the native
Rust library and does not extend ConvertException.
Testing
Use fake to test application code without reading files or running a conversion:
use HosmelQ\Anydoc\Laravel\Facades\Anydoc; Anydoc::fake([ 'markdown' => '# Converted document', ]); $markdown = Anydoc::file('report.docx')->markdown(); Anydoc::assertConvertedToMarkdown( fn ($conversion): bool => $conversion->input === 'report.docx', );
Fake responses may also be closures:
Anydoc::fake([ 'markdown' => fn ($conversion): string => "# {$conversion->input}", ]);
The fake provides the following assertions and inspection methods:
Anydoc::assertConverted(); Anydoc::assertConvertedTimes(2); Anydoc::assertConvertedToDocument(); Anydoc::assertConvertedToMarkdown(); Anydoc::assertNotConverted(fn ($conversion): bool => false); Anydoc::assertNothingConverted(); $conversions = Anydoc::conversions();
Assertion and filtering callbacks receive a recorded conversion containing its
disk, format, input, output type, and source type. A callback matches when it
returns true.
A conversion is recorded when markdown or document is called, not when the
pending conversion is created. The default fake Markdown response is an empty
string. Document conversions require a configured Anydoc\Document response.
Running the Test Suite
composer test
Changelog
See CHANGELOG.md for a list of changes.
Contributing
Pull requests are welcome. Please run the test suite before submitting changes.
License
The MIT License (MIT). Please see License File for more information.