solidframe/symfony
SolidFrame for Symfony integrates the SolidFrame framework with Symfony, providing streamlined configuration, service wiring, and reusable building blocks so developers can scaffold maintainable PHP applications faster with less boilerplate.
First, calibrate the framework mismatch. Despite living in the same Composer namespace, this is a Symfony bridge. There is no Laravel service provider, no config/ publish tag, no package discovery entry. It exists to register SolidFrame services into a Symfony ContainerBuilder via a bundle (Bundle + DependencyInjection\Extension), hook HttpKernel events for routing/middleware, and dispatch through Symfony\Contracts\EventDispatcher\EventDispatcherInterface. Your day-to-day leverage depends entirely on whether you operate a Symfony service at all — in a pure Laravel app this package is inert.
Where to look first, in this order:
composer.json — the type field (symfony-bundle vs plain library), the PHP floor, and the symfony/* constraints. A hard pin on symfony/http-kernel is a blocker for anything on a different minor.DependencyInjection/*Extension.php — this is the actual public surface. The Configuration tree tells you the real config keys the README will never document.Resources/config/services.* — what is registered, what is public, what is tagged. This answers "what can I autowire?" faster than any docs.Minimal wiring (verify each step against the actual package):
composer require solidframe/symfony:0.1.0 # exact pin, not ^0.1
// config/bundles.php
return [
// ...
SolidFrame\Symfony\SolidFrameBundle::class => ['all' => true],
];
# config/packages/solidframe.yaml
solidframe:
# keys come from the bundle's Configuration tree — read it, don't guess
Then prove the bridge works with the smallest possible assertion: inject one SolidFrame service into a trivial controller and hit it.
final class ProbeController extends AbstractController
{
public function __invoke(SomeSolidFrameService $svc): Response
{
return new Response(get_class($svc));
}
}
If bin/console debug:autowiring solidframe returns nothing after registration, the bundle did not expose what you think it did — stop and read the extension class before writing more code.
First real use case: pick one SolidFrame handler (a command/query handler, not infrastructure) and consume it via constructor injection in a Symfony controller or message handler. That single path exercises container bridging, autowiring, and config presets simultaneously — the three things the package claims to do.
Consume by injection, never by $container->get(). Symfony privatises services by default and the bundle may have made SolidFrame services private intentionally. Constructor injection survives private visibility, container lookups do not. Treat ->get() as a test-only escape hatch (test.service_container).
Own the seam with your own aliases. Don't let SolidFrame interfaces leak into 200 files. In your app's services.yaml, alias SolidFrame contracts to your own interfaces:
services:
App\Contract\OrderPlacer: '@SolidFrame\...\PlaceOrderHandler'
Swapping the implementation later is then one line, which is the correct posture for a 0.1.0 dependency.
Keep SolidFrame's framework-agnostic core separate from this bridge. If you ever need the same services in a Laravel app, do not try to boot SolidFrameBundle there — Laravel ships Symfony components (http-foundation, console, process) but not the HttpKernel/bundle/compiler-pass machinery the bridge relies on. Instead depend on the underlying SolidFrame package directly and bind it in a Laravel service provider:
public function register(): void
{
$this->app->bind(OrderHandler::class, SolidFrameOrderHandler::class);
}
The Symfony bridge then becomes infrastructure for the Symfony service only, and the shared core is the reuse point. This is the pattern that keeps the dependency from becoming a platform commitment.
Event dispatcher integration. SolidFrame side events arrive at Symfony's dispatcher, so listeners are ordinary Symfony listeners — autoconfigured with #[AsEventListener], or tagged explicitly. Set priority deliberately; a 0.x bridge may register its own listeners and you'll be competing for the same event. Check debug:event-dispatcher before assuming order.
Routing/middleware hooks. Treat these as kernel.request/kernel.response subscribers rather than something analogous to Laravel middleware. Position matters relative to the firewall: a SolidFrame middleware that touches the session or token must be registered after Symfony\Component\Security\Http\Firewall. If the bundle registers the hook with a fixed priority, override the tag priority in your own config rather than forking.
Test-friendly bootstrapping is the highest-value feature. Use KernelTestCase and override services in config/services_test.yaml. Add one container-compile test to your suite:
public function testContainerCompiles(): void
{
self::bootKernel();
$this->assertTrue(self::getContainer()->has(OrderPlacer::class));
}
This catches a category of failure (missing alias, broken factory) that only otherwise appears at deploy time.
Config preset pattern. Keep the bundle's presets in config/packages/solidframe.yaml and put only environment-driven overrides in .env-referenced parameters. Never interpolate %env()% inside a compiler pass — it resolves at compile time and will bake a stale value into the cached container.
The mismatch is the headline gotcha. Half the "integration tips" you'd normally apply — autodiscovery, php artisan vendor:publish, facade binding, migration publishing — simply don't exist here. Budget a day for a competent Symfony developer, and if the team is Laravel-only, either assign someone with Symfony kernel experience or accept that debugging this package will be slow.
Pin exactly and forbid auto-merges. "solidframe/symfony": "0.1.0" — not ^0.1. A 0.x minor is allowed to break, and with a single release and zero stars there is no evidence of API discipline. Require a human to read the diff on every bump; a realistic estimate is 2–4 hours per release until the API settles.
No Flex recipe almost certainly exists. A zero-star package won't have one, so nothing is auto-registered. You wire config/bundles.php and the YAML by hand, and you should write that down in your repo's README because the next developer will assume composer require was the whole job.
Container cache is the first place breakage shows up. 0.x bridges commonly register closures or factories that fail under cache:warmup. If a fresh dev environment works but a built image doesn't, run bin/console cache:clear && bin/console cache:warmup in the failing environment before debugging anything else.
Diagnosis commands, in order of usefulness:
bin/console about
bin/console debug:container --tag=solidframe # what got tagged
bin/console debug:autowiring solidframe # what you can inject
bin/console debug:event-dispatcher | grep -i solid
bin/console lint:container # compile-time type errors
lint:container is the one Laravel developers never reach for and it earns its keep here — it resolves argument types at compile time and surfaces the wiring errors the bridge is most likely to produce.
Extension alias vs bundle name. The YAML root key is the extension's getAlias(), which is frequently not the bundle name (solidframe_symfony, solid_frame, etc.). If your config is silently ignored, that's why — a wrong root key is a no-op, not an error.
Private services. If debug:container shows the service but injection fails, it's an alias or visibility problem, not a registration one. Fix with an explicit alias in your own services.yaml; don't patch the package.
Long-running workers. Symfony Runtime (FrankenPHP worker mode, RoadRunner) keeps the container alive across requests. Any SolidFrame service holding request state in a property is now a leak — the same class of bug as Laravel Octane. Audit singletons before scaling horizontally.
Removal must be tested in the spike. Unregister the bundle, delete the YAML, composer remove, clear var/cache. If the package published anything (routes, migrations, parameters via prependExtension) confirm it's gone. Unclean removal is the failure mode that makes a cheap dependency expensive.
Named exit owner. With one maintainer and one release, assume abandonment is possible and pre-agree who forks or replaces it. The realistic trigger will be a Symfony major the package never supports — by then the core-plus-adapter split described above should make replacement a days-not-months job.
Bottom line for a Laravel shop: this is not a Laravel package and shouldn't be trialled in a Laravel request path. Its legitimate use is a Symfony service in a polyglot estate, or as a reference implementation of how to wire SolidFrame into a container you then mirror by hand in a Laravel service provider. Evaluate it there, at an exact pin, behind your own alias — and treat the first production use as a canary, not a commitment.
How can I help you explore Laravel packages today?