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

Sylius Feature Flag Bundle Plugin Laravel Package

em411/sylius-feature-flag-bundle-plugin

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package and its base bundle. The plugin is a Sylius-facing layer on top of em411/feature-flag-bundle (an ajgarlag/feature-flag-bundle fork), so both must be present:

    composer require em411/sylius-feature-flag-bundle-plugin
    
  2. Register both bundles in config/bundles.php, base bundle first:

    return [
        // ...
        Ajgarlag\FeatureFlagBundle\FeatureFlagBundle::class => ['all' => true],
        Em411\SyliusFeatureFlagPlugin\Em411SyliusFeatureFlagPlugin::class => ['all' => true],
    ];
    
  3. Import the admin routing into config/routes.yaml (or a dedicated file in config/routes/), pointing at the plugin’s routing file as the README shows.

  4. Create the table. Run bin/console doctrine:schema:update --force in dev (or generate/execute a migration). Then bin/console cache:clear.

  5. First use case — a kill switch. From the Sylius admin, open the new Feature Flags grid, create a flag with a code you already reference in code (e.g. checkout.new_payment_step), leave it enabled with an empty value, and wrap the new behaviour in a check against that code. Disabling it from the admin immediately restores the old path — no deploy required.

If your Sylius version complains about a missing resource, also map the entity under sylius.resources in config/packages/_sylius.yaml and re-run the schema step.

Implementation Patterns

Two-layer flags: code default + DB override. Declare a safe default in code with the base bundle’s attribute, then let admins override it from the grid:

#[AsFeature('checkout.new_payment_step')]
final class NewPaymentStep
{
    // ...
}

Because the Doctrine-backed provider is registered at a high priority, a DB row with the same code wins over the @AsFeature attribute. This is the pattern to prefer: ship every flag with a code-defined default so production never depends on a row existing, then use the admin only for operational overrides.

Inject the flag manager where you need decisions. The base bundle exposes a manager service; inject it (constructor or action argument) rather than reading the DB directly. That keeps your code agnostic to whether a flag came from attributes, the database, or a test provider:

public function __construct(private FeatureFlagManagerInterface $flags) {}

public function __invoke(): Response
{
    if ($this->flags->isEnabled('checkout.new_payment_step')) {
        // new path
    }
    // old path
}

(Confirm the exact method name/Twig function against the base bundle’s API — this plugin only adds the admin resource and Doctrine provider.)

Use value for configuration, not just booleans. The value column is the ideal place for percentages, variant names, or JSON blobs:

$value = $this->flags->getValue('pricing.show_b2b_prices');
$config = json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR);

Wrap the decode and fall back to a hardcoded default — flags are edited by humans and a malformed JSON string should never break a page.

Seed flags in fixtures/migrations. For flags that must exist on fresh installs (e.g. a flag your templates read without a fallback), create the row in a Doctrine fixture or a migration rather than relying on manual admin entry.

Keep flag codes in a constants class. One PHP file listing every code (Flags::CHECKOUT_NEW_PAYMENT_STEP) prevents typos across @AsFeature, templates, and admin rows, and gives you a grep target when cleaning up dead flags.

Templating. For Twig-heavy storefront customisations, use the base bundle’s Twig helper (feature_flag(...) style) or pass a boolean from the controller, so the UI stays testable without hitting Doctrine in every template render.

Gotchas and Tips

  • Priority inversion surprises. A @AsFeature declaring enabled: true in code is overridden by a disabled DB row. If a feature is unexpectedly off, check the admin grid before you debug the code. Conversely, deleting a row silently reverts to the code default — that is the intended emergency-reset behaviour, not a bug.
  • Schema step is mandatory. The bundle adds a Doctrine entity; forgetting the migration means the admin grid 500s on the first request. Add the schema generation to your deployment checklist, not just to local setup.
  • Permissions in the admin. The new resource is ACL-protected like any Sylius resource. Grant the relevant admin roles permission to view/manage feature flags, otherwise super-admins see the grid and other admins get 403s.
  • Route/firewall placement. Import the routing under the admin prefix used by your app so the sylius_admin firewall applies. Importing it at the root will leave the grid unauthenticated.
  • Query cost. The Doctrine provider reads flags through the entity manager; on high-traffic storefronts that can mean a query per request. Decorate the provider or wrap the manager with a request-scoped cache (or a compiled/array provider in prod) if profiling shows it matters.
  • value is a string column. Booleans, numbers, and JSON all round-trip as strings. Type-juggle explicitly at the boundary and never rely on === true.
  • Stack age. The package targets PHP 7.4–8.1 and Symfony 4.4 with Sylius 1.8+. If you are on PHP 8.2+/Symfony 6, expect friction — pin the version and test the bundle boot carefully on your actual stack.
  • Low adoption / zero dependents. Pin the exact version in composer.json and keep the upgrade path in mind: the fallback to @AsFeature defaults means you can remove the package later without losing every flag, provided you have not built code that assumes DB rows exist.
  • Testing. Swap in the base bundle’s array/in-memory provider during tests rather than creating rows, and reset the manager between tests when asserting both enabled and disabled paths.
  • Extension points. If the stock grid is too thin (e.g. you want grouping or audit info), override the grid configuration/templates via normal Sylius resource overrides, and keep the entity unchanged so the bundle’s provider keeps working.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style