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

How To Bundle Laravel Package

kjonski/how-to-bundle

A Laravel/PHP package for bundling reusable how-to content and step-by-step guides into your application, making instructions easier to organize, publish, and maintain. Simple to integrate and lightweight.

View on GitHub
Deep Wiki
Context7

Getting Started

kjonski/how-to-bundle is not a Composer-installable library — it's a tutorial repository that walks through preparing a reusable Symfony bundle, step by step. There is no composer require step; you consume it by cloning it and reading it.

git clone https://github.com/kjonski/how-to-bundle
cd how-to-bundle
git log --oneline --reverse   # if history is present, this is the actual tutorial

Look first at, in this order:

  1. The README — it frames the intended learning path.
  2. composer.json — note "type": "symfony-bundle", the PSR-4 autoload mapping, and any extra block. This is the contract that makes a bundle installable.
  3. The bundle entry class (e.g. SomethingBundle.php) at the namespace root — this is what the Symfony kernel registers.
  4. DependencyInjection/ — the Extension subclass and the Configuration tree. This is where 90% of real-world bundle bugs live.

First use case: you have application code in a Laravel or Symfony app that you want to extract into something reusable. Use this repo as a checklist for the shape of that extraction: entry class → DI extension → configuration schema → services definition → tests.

Since you're a Laravel developer, be explicit about the mismatch: this repo teaches Symfony bundle mechanics. In Laravel the analogue is a package with a ServiceProvider, mergeConfigFrom(), publishes(), and extra.laravel.providers for auto-discovery. Read the Symfony version for the concepts (config schema, prepend/merge semantics, compile-time wiring), then translate.

Implementation Patterns

Follow the commits, not the files. Tutorial repos are most useful as a diff sequence. Check out each commit and read the change in isolation; that's the "step-by-step" the description promises.

The skeleton to replicate (Symfony side):

src/
  AcmeWidgetBundle.php            # extends Bundle
  DependencyInjection/
    AcmeWidgetExtension.php       # extends Extension, loads services
    Configuration.php             # TreeBuilder root = 'acme_widget'
  Resources/config/services.yaml

Key wiring details that make it work:

  • AcmeWidgetExtension::load() receives $configs and must call $this->processConfiguration(new Configuration(), $configs).
  • The extension alias must match the config root node. AcmeWidgetExtension → acme_widget. Mismatch here produces the classic "There is no extension able to load the configuration for …" error.
  • Bundle::getContainerExtension() reflects on the class name to find the extension; overriding it is only needed for non-standard naming.
  • $container->prependExtensionConfig() in Bundle::build() or in the extension's prepend() is how you inject sane defaults without stomping on the app's own config.

Composer metadata is part of the tutorial and worth copying verbatim:

{
  "type": "symfony-bundle",
  "autoload": { "psr-4": { "Acme\\WidgetBundle\\": "src/" } },
  "extra": { "branch-alias": { "dev-main": "1.0-dev" } }
}

Without type: symfony-bundle, Flex won't offer a recipe and tooling won't treat it as a bundle.

Integration tips for a Laravel developer translating this:

Symfony bundle concept Laravel equivalent
Extension::load() ServiceProvider::register()
Configuration tree config/widget.php + mergeConfigFrom()
Resources/config/services.yaml container bindings / singletons array
prependExtensionConfig() mergeConfigFrom() + $this->app->scoped() defaults
Bundle auto-registration extra.laravel.providers
Flex recipe php artisan vendor:publish

Workflow that actually pays off: scaffold the bundle in a packages/acme/widget directory, add it to the host app's repositories as a path (Composer) or symlink (Laravel), and iterate with a live autoload rather than tagging releases. Only composer tag once the config schema and public service IDs are stable — those are your BC surface.

Test it from a host app, not in isolation. A bundle with no consumer is untested. At minimum, boot a kernel with the bundle registered and assert the container compiles and your service is reachable by its public alias. bin/console lint:container is the cheapest smoke test.

Gotchas and Tips

  • Don't composer require kjonski/how-to-bundle. It's a tutorial, not a dependency. If you want to fork it as a starting point, fork it and change the namespace, package name, and license headers — otherwise you'll ship someone else's tutorial as your vendor code.
  • 11 stars, no release cadence. Treat it as reading material pinned to a specific commit. There's no guarantee it tracks Symfony 6/7 conventions (service configs moved from Resources/config/ to config/ in Symfony 4.2+, and the old path is deprecated/removed in recent versions). Verify every snippet against the Symfony docs for your target version before copying.
  • Extension alias vs. bundle name. The single most common failure when following this kind of tutorial. Acme\WidgetBundle\DependencyInjection\AcmeWidgetExtension implies alias acme_widget; your config/packages/acme_widget.yaml root key must match exactly. Use debug:config acme_widget to confirm the alias is registered.
  • Config tree strictness. TreeBuilder with ->addDefaultsIfNotSet() and ->children() will throw on unknown keys. Add ->ignoreExtraKeys(false) only if you genuinely need forward compatibility; otherwise strict is better for catching typos in consumer config.
  • Service visibility. Everything in a bundle's services.yaml is private by default since Symfony 4. Services you intend consumers to fetch via $container->get() need an explicit public alias. Prefer constructor injection and keep almost nothing public.
  • Compiler passes over runtime conditionals. If the tutorial shows if ($config['enabled']) inside a service, that's a smell — do it at compile time via a CompilerPass or by conditionally loading the service file in load().
  • Debugging commands worth memorizing: bin/console debug:container --tag=…, debug:config <alias>, lint:container, lint:yaml config/. In a bundle context, debug:container --env-vars also helps confirm that env placeholders in your config schema resolve.
  • Extension points to leave open: a CompilerPass registered in Bundle::build(), a tagged-interface convention for consumers to extend behaviour, and prepend() for defaults. These are what separate a usable bundle from a hardcoded one.
  • Watch for missing tests/CI. A tutorial repo usually has neither. Budget time for writing your own functional test kernel — it's the thing that will actually catch regressions when you upgrade Symfony or Laravel majors.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings