lyssal/geography-bundle
A Symfony bundle for managing geography data: countries, regions, departments, cities and postal codes, with Doctrine entities, repositories and forms to build location-aware applications quickly.
Version 0.2 is a breaking release: entity definitions moved from PHP annotations to YAML, and services are no longer launched automatically. Start here before touching application code.
Install and publish config
composer require <vendor>/<package>:^0.2
php artisan vendor:publish --tag=<package>-config
Open config/<package>.php first — this is where the entity directory and service-launch toggles live now.
Create the entity directory and your first YAML entity
Annotations are gone. Each entity is a file (conventionally resources/entities/<name>.yaml) containing its fields, types, and relations. Check the package's stubs/ or examples/ directory for the canonical schema before writing one by hand — the shape changed, not just the format.
Register services explicitly In 0.1 services booted on their own. In 0.2 you opt in, typically by registering the package's service provider plus your own bindings:
// bootstrap/providers.php
return [
// ...
<Vendor>\<Package>\Providers\<Package>ServiceProvider::class,
];
If entities need services injected at runtime, call the launcher/trait from a boot method or a dedicated EntityServiceProvider. Nothing happens by default — silence, not errors, is the failure mode.
Verify before building
php artisan <package>:validate # or :list / :debug if that's what the package ships
php artisan tinker --execute="dump(app(<Registry>::class)->all());"
First end-to-end use case: one YAML entity + one explicitly launched service + one route returning it. Get that green before migrating a real domain model.
One YAML file per entity, committed. Treat them as first-class source files: code review them, diff them, and keep field ordering stable so merges stay readable. Avoid deeply nested relations in a single file — split aggregates.
Explicit service registration lives in one place. Create app/Providers/<Package>ServiceProvider.php that registers every service the package should know about, and keep it out of AppServiceProvider. When you need conditional launching (e.g. only in non-production or only for specific entity types), gate it there rather than scattering if checks through feature code.
Collection/tagged registration works better than individual binds for extensibility. Register an array of services under a tag and resolve them as a collection, so adding a service is a one-line change and tests can substitute a partial set.
Feature-test the wiring, not just the YAML. Unit-test the YAML loader for shape, but add a feature test that boots the provider and asserts the resolved service is the expected instance. That test is what catches the 0.1→0.2 breakage class, where services simply aren't there.
Migration from 0.1 annotations: write a one-off script or command that reflects over the old annotated classes and emits YAML, then delete the annotations and run the package's validator side by side. Keep the generated YAML under version control and hand-edit from there — don't regenerate on every build.
Fixture strategy for tests: store YAML fixtures in tests/Fixtures/entities/ and point the config's entity path at them per test using config()->set() before the provider boots. This is the fastest way to assert edge cases without polluting the real entity directory.
CI: add a lint step for YAML (a plain yamllint or a php artisan <package>:validate job) plus a check that no @-annotation entity classes remain. Cheap and catches most of the migration drift.
null. If a feature behaves as if a service is absent, dump app()->getLoadedProviders() and app()->getBindings() before reading the code.yes/no/on/off become booleans under the common YAML 1.1 parsers; unquoted dates become DateTime objects; 0123 becomes octal. Quote anything that is semantically a string, especially entity identifiers and enum values.--strict-style linting or a parser configured to reject duplicates; a duplicated relation key is otherwise invisible.php artisan config:clear alone won't do it — look for a package-specific :clear/:reload command and wire it into your deploy script.config:cache doesn't cover custom YAML loading. Anything read at boot with file_get_contents bypasses Laravel's config cache and hits the filesystem on every request. Cache the parsed result in a singleton or a prebuilt PHP array in production.boot() method that runs before your bindings are registered gives you unresolvable dependencies. Register in register(), launch in boot(), or use $this->app->booted(...) for ordering-sensitive setup.^0.2 and read the changelog before each minor bump.How can I help you explore Laravel packages today?