Open source
Package Toolkit for Laravel
composer require roundly-consulting/package-toolkit-for-laravelOverview
A native, dependency-free toolkit for building Laravel packages. Extend one base service provider, describe what your package ships in a fluent builder, and every console-gated publish, load and command call is emitted for you — once. Alongside it come key-type aware schema macros, a portable, injection-safe LIKE search, validate-or-throw config accessors and a model resolver. MIT-licensed and built only on official Laravel and Symfony APIs.
What you get
Fluent package builder
Extend one base provider and declare config, migrations, views, translations, routes, commands, aliases and about output in a single chain.
Publish-only migrations
Migrations publish with ordered timestamps and republish in place — never auto-loaded, never duplicated, never written over your own.
Key-type schema macros
One config-driven bigint/uuid/ulid strategy with ownerKey(), morphKey(), polymorphicSubject() and auditable().
Strict config readers
Integer, string, enum, fixed-vocabulary and boolean readers: a value that is not set — absent, null or blank, like a host’s KEY= — takes the default, anything else invalid throws. DTO arrays and your own exception class too.
Portable, safe search
whereLikeEscaped() escapes user wildcards and uses ILIKE on Postgres, LIKE elsewhere — on query and Eloquent builders.
Idempotent by design
Gates, Blade directives and macros register once, even on a double boot — plus a PHPStan extension for the macros.
Documentation
Installation
Install via Composer — the toolkit is a library your package’s service provider builds on, with nothing to publish.
The package builder
Extend PackageServiceProvider, describe your package in configurePackage(), and let the base provider wire the rest.
Builder methods
Every Package builder method — config, migrations, translations, views, routes, commands, aliases, about and stubs — with its publish tag.
Publish-only migrations
Package migrations are never auto-loaded: they publish with ordered timestamps, republish in place, and the host runs migrate.
Bindings & observers
Bind a contract to the class named in config and attach an observer to a configurable model — from register() and boot().
Opt-in traits
Idempotent gate, Blade directive and schema-macro registration — a double boot never clobbers or double-registers anything.
Key types & schema macros
One config-driven bigint/uuid/ulid key strategy with the ownerKey(), morphKey(), polymorphicSubject() and auditable() macros.
Static analysis (PHPStan)
A bundled PHPStan extension declares the schema and query macros, so Larastan never reports them as undefined methods.
Database helpers
A DatabaseDriver enum for driver-aware branching and whereLikeEscaped() — a portable, injection-safe “contains” search.
Config validation
Strict config readers — integers, required strings, enums, fixed vocabularies and booleans, DTO arrays and your own exception class.
Model resolution
Resolve a configurable Eloquent model class with ModelResolver or ResolvesModels — a class not extending the packaged model throws.
Exceptions & retry-after
The toolkit’s exception hierarchy with its exact messages, plus the HasRetryAfter contract for rate-limit errors.
Migrating a package
Move an existing hand-wired package onto the toolkit in four steps — provider, key types, helpers, quality gate.
Testing
Load your package’s migrations explicitly in its TestCase, then test config guards, macros and directives through the public API.
Requirements
PHP 8.4+ and Laravel 12 or 13 — no other runtime dependencies. Add phpstan/extension-installer to load the PHPStan extension automatically.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.