On this page
Upgrading Gacela
From 1.21 to 2.0
Gacela 2.0 raises the PHP floor, moves to gacela-project/container 2.x, removes three deprecated aliases, and makes
undeclared pillar accessors visible to static analysis. Version 1.21.0 is the final 1.x release, and its documentation
is kept as an archive at /docs/1.x.
Before upgrading
Prepare the application while it still runs on 1.21:
composer require gacela-project/gacela:^1.21
vendor/bin/gacela doctor
vendor/bin/gacela cache:clearRun the test suite with error_reporting(E_ALL) so Gacela deprecations are visible. Search explicitly for the trait
removal, which cannot emit a use-time deprecation:
rg "DocBlockResolverAwareTrait" src/Then require the new major:
composer require gacela-project/gacela:^2.0Requirements
- PHP is now 8.3 or newer, up from 8.1.
gacela-project/containeris now^2.0.2.- Symfony development integrations support
^7.0 || ^8.0; projects pinned to Symfony 6 must upgrade.
Removed APIs
| Removed in 2.0 | Replacement |
|---|---|
AbstractDependencyProvider |
AbstractProvider |
GacelaConfig::addMappingInterface() |
GacelaConfig::addBinding() |
DocBlockResolverAwareTrait |
ServiceResolverAwareTrait |
Rename dependency providers completely
Change the class, parent, and filename:
-// src/MyModule/MyModuleDependencyProvider.php
-final class MyModuleDependencyProvider extends AbstractDependencyProvider
+// src/MyModule/MyModuleProvider.php
+final class MyModuleProvider extends AbstractProviderThe filename matters because Gacela discovers pillars by convention. A class renamed without its file silently stops
resolving. Running doctor on 1.21 detects the mismatch before the old resolver is removed.
provideModuleDependencies() remains the imperative registration method. #[Provides] remains the attribute-first
alternative.
Rename bindings and the resolver trait
-$config->addMappingInterface(MyInterface::class, MyImplementation::class);
+$config->addBinding(MyInterface::class, MyImplementation::class);
-use Gacela\Framework\DocBlockResolverAwareTrait;
+use Gacela\Framework\ServiceResolverAwareTrait;Both are mechanical renames with the same behavior.
Declare pillar accessors
The PHPStan suppression for undeclared magic accessors is gone. Declare each accessor with #[ServiceMap]:
use Gacela\Framework\ServiceResolver\ServiceMap;
use Gacela\Framework\ServiceResolverAwareTrait;
#[ServiceMap(method: 'getFacade', className: BillingFacade::class)]
final class BillingController
{
use ServiceResolverAwareTrait;
}A @method BillingFacade getFacade() annotation still helps IDEs, but runtime resolution through docblocks or scanned
use statements is deprecated in 2.0 and will be removed in 3.0. Add the attribute even when retaining the docblock.
Psalm users must register the 2.0 plugin separately from the existing XInclude:
<plugins>
<pluginClass class="Gacela\Psalm\Plugin"/>
</plugins>Container compatibility
Gacela's container now decorates the final 2.x container and continues to implement ContainerInterface. Code
type-hinting the concrete inner container should accept its interface instead:
-function configure(\Gacela\Container\Container $container): void
+function configure(\Gacela\Container\ContainerInterface $container): voidModule containers are now scopes of one application container. App-wide configuration is walked once per bootstrap, while Provider registrations and instances remain isolated per module scope.
Other targeted changes
ConsoleFacade::getContainerStats()andConsoleFactory::getContainerStats()now return a final readonlyContainerStatsobject, not an array. Use properties such asregisteredServicesandprocessMemoryBytes, plusprocessMemoryFormatted(); this replaces the misleadingmemoryUsageFormatted()name.CacheWarmedEvent::failedCount()now counts actual resolution failures. Use the newskippedCount()for pillar classes a module simply does not contain.- Typed class constants on
AbstractSetupGacelaandConfigInterfacecan expose incompatible overrides at compile time. Gacela::resetCache()no longer clears a cache backend registered throughCacheableConfig::setStorage().
New in 2.0
GacelaConfig::loadDefinitions()loads wiring from arrays, PHP files, or JSON files.GacelaConfig::afterResolving()runs idempotent callbacks after top-level container resolution.GacelaConfig::tag()groups services into lazy iterables.Gacela\Framework\Attribute\Injectis the preferred import and supports constructor parameters, properties, and setters.#[Lazy]is honored byAbstractFactory::make(); native lazy behavior requires PHP 8.4 and falls back safely to eager construction on 8.3.- Dependency-tree output now follows applied bindings and marks nodes as
binding,instance,autowired, orunresolvable.
After migration, run the test suite, PHPStan or Psalm, and vendor/bin/gacela doctor --strict.
Moving on to 2.1
2.1 is a drop-in upgrade from 2.0: no removed APIs, no signature changes, no configuration to rewrite.
composer require gacela-project/gacela:^2.1Two things are worth picking up deliberately:
- Static analysis now runs the architecture rules under Psalm as well as PHPStan, each as its own suppressible issue class. Psalm users get the full rule set from the plugin they already register, and both analysers gain a second cross-module check that resolves a call's receiver by type. Expect new findings on the first run.
cache:warmexits non-zero when a warmup fails. A deploy step that ignored the exit code was silently green before, and will start failing on the problems it was already printing.
Two fixes change behavior you may have worked around: ttl: 0 means "no expiry" in InMemoryCacheStorage as it always
did in FileCache, and resolution hooks registered in gacela.php now fire inside module scopes as well as at the app
level.
Moving on to 2.2
2.2 is a drop-in upgrade from 2.1: no removed APIs, no signature changes, no configuration to rewrite.
composer require gacela-project/gacela:^2.2Everything new is opt-in: a config schema, a module dependency rules file, module doubles in tests, published scaffolding stubs, and the Symfony bundle and Laravel provider. Three things are worth knowing before the upgrade:
- The Symfony and Laravel bridges now actually reach your vendor directory.
.gitattributesstripped both from the dist archive and their namespaces sat inautoload-dev, so nothing underGacela\SymfonyBridgeorGacela\LaravelBridgewas installable before 2.2. If you copied bridge classes into your project or pinned a path repository to work around that, drop the workaround and register the bundle or provider instead. - PHPStan users on phpstan/extension-installer (opens in a new tab) get Gacela's rules
automatically from this release on. A project that deliberately ran without
phpstan-gacela.neonwill see new findings on the first run; opt out per package viaextra."phpstan/extension-installer".ignore. - A
#[ServiceMap]accessor whose mapped class the analysing process cannot autoload is now typed instead of silently falling back tomixed, so PHPStan may report calls it previously ignored.