bfg/doc
A Laravel/PHP documentation package from BFG that helps generate and organize project documentation, making it easy to browse and maintain reference docs alongside your codebase.
Because this package has a single star and no dependents, treat the first ten minutes as an audit rather than a normal install. Pin the exact version you evaluate — do not use ^1.0.
composer require bfg/doc:1.x.y # exact version, note it in your PR description
Then, in order:
composer.json in vendor/bfg/doc first. Check the require block for the PHP and illuminate/* constraints. If it declares laravel/framework: ^8.0 and you are on Laravel 11, stop and decide whether a fork is cheaper than adoption.src/ before running anything. With one star, the source is the documentation. Look for the service provider (auto-discovery or manual registration), the config/ file name, any database/migrations/ stubs, and whether routes/views are shipped.php artisan vendor:publish --provider="Bfg\Doc\DocServiceProvider"
# or, if tags are defined:
php artisan vendor:publish --tag=doc-config
php artisan vendor:publish --tag=doc-migrations
php artisan migrate on a scratch database and inspect the resulting schema. Column names and index choices tell you more about intended usage than the README will.First use case: the lowest-risk integration is read-only. Point the package at an existing documents table or a small Storage disk folder, render one listing, and verify the query path before you let it write anything. Once the read path is understood, add a single create flow behind a feature flag.
If the README is empty or aspirational, budget an hour to write your own usage note in the repo wiki the day you adopt it. You will be the only source of documentation for your team.
Wrap it, don't scatter it. Create one application-level service (App\Services\DocumentService) that owns every call into the package. Models, controllers, and jobs talk to your service. When the package is abandoned — a realistic outcome at one star — you replace one file instead of grepping fifty.
final class DocumentService
{
public function __construct(private DocumentRepository $docs) {}
public function attach(Model $owner, UploadedFile $file, array $meta = []): Document
{
return DB::transaction(function () use ($owner, $file, $meta) {
$path = $file->store("documents/{$owner->getKey()}", 'documents');
return $this->docs->create([
'owner_type' => $owner->getMorphClass(),
'owner_id' => $owner->getKey(),
'path' => $path,
'name' => $file->getClientOriginalName(),
'mime' => $file->getMimeType(),
'size' => $file->getSize(),
...$meta,
]);
});
}
}
Keep the polymorphic shape if it exists. If the package ships documentable_type / documentable_id, preserve it exactly rather than adding your own user_id columns. It lets you attach documents to invoices, tickets, and users with one table, and it keeps future package upgrades from breaking your schema.
Isolate the storage disk. Register a dedicated disk (private, not public) and reference it by name in config. Never let the package fall back to the default disk — the day someone changes FILESYSTEM_DISK in .env, every stored document path breaks silently.
// config/filesystems.php
'documents' => [
'driver' => 's3',
'root' => 'tenant-' . tenant('id') . '/documents',
// ...
],
Serve downloads through a controller, not a URL. Even if the package exposes a route, add your own authorization check in front of it:
public function download(Document $document)
{
$this->authorize('view', $document);
return Storage::disk($document->disk)->download($document->path, $document->name);
}
Enforce validation at the edge. File size, MIME type, and extension checks belong in a FormRequest, not in the package's config file — config is global, and you will eventually need a 50MB upload for one tenant and 5MB for everyone else.
'file' => ['required', 'file', 'max:10240', 'mimes:pdf,docx,xlsx,png'],
Test with Storage::fake() and an in-memory database. Because there is no community test suite behind this package, your own suite is the regression net. A single feature test covering upload → list → download → delete will catch nearly every breaking change an upgrade introduces.
Introduce a thin adapter if the API is thin. If the package is essentially a model plus a migration, do not fight it — subclass or use its trait, and add the behaviour you need (versioning, soft deletes, virus scanning) in your own layer so a later replacement is a no-op.
composer require against a VCS path is cheap insurance."bfg/doc": "1.2.3" in composer.json, and put a comment in the PR explaining why. A caret range on an unmaintained package is a supply-chain decision you did not consciously make.DB::transaction cannot roll back a file write. Upload first, insert second, and schedule a nightly reconciliation job that deletes files with no row and flags rows with no file. Do the delete in the opposite order: soft-delete the record, remove the file, then hard-delete in a queued job.users table created in 2014 and you publish today, the foreign key may run before users exists. Rename the published migration file to reorder it.php artisan config:cache freezes package config at build time. If the package reads an env var inside a class rather than in config/doc.php, you will see stale values in production that never appear locally. Grep env( in vendor/bfg/doc/src — any hit is a latent bug.routes/web.php. Check with php artisan route:list --path=doc.vendor/ diffing is your changelog. Since no release notes are likely, diff vendor/bfg/doc between versions before upgrading. git diff --no-index on the vendor directory after composer update shows exactly what moved.php artisan config:clear && route:clear, confirm the provider is listed in bootstrap/providers.php (Laravel 11) or config/app.php (10 and below), confirm the published migration actually ran (php artisan migrate:status), and log a call to the package's entry point to verify it is invoked at all.Document model with a morph relation and a storage disk. Write down what that migration looks like while the package is fresh in your head — it turns an emergency into an afternoon.How can I help you explore Laravel packages today?