The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
Api

Console Commands

Symfony console commands provided by the API Components Bundle for managing users, cleaning up data, and generating component entities.

Most commands use the silverback:api-components: prefix. Run them via the Symfony console:

php bin/console silverback:api-components:<command>

In a Docker Compose setup, prefix with the service name:

docker compose exec api php bin/console silverback:api-components:<command>

user:create

Create a user account directly from the command line, without going through the registration API. Useful for creating the first admin on a fresh installation before the front-end is set up.

php bin/console silverback:api-components:user:create

The command prompts interactively for username, email, and password. You can also pass them as positional arguments:

php bin/console silverback:api-components:user:create alice alice@example.com s3cr3t --admin

Options

OptionDescription
--adminCreate with ROLE_ADMIN
--super-adminCreate with ROLE_SUPER_ADMIN
--inactiveCreate as disabled (cannot log in until enabled)
--overwriteUpdate the user if they already exist instead of erroring

Without --admin or --super-admin, the user is created with ROLE_USER only.

refresh-tokens:expire

Expire all refresh tokens, or all tokens for a specific user. Use this to force re-login after a security incident or account change.

# Expire all tokens for all users
php bin/console silverback:api-components:refresh-tokens:expire

# Expire tokens for one user (by username)
php bin/console silverback:api-components:refresh-tokens:expire alice

# Expire by email instead of username
php bin/console silverback:api-components:refresh-tokens:expire alice@example.com --field email

clean-orphaned

Scan every ComponentGroup and AbstractComponent in the database and delete any that are no longer attached to any layout, page, or parent component.

php bin/console silverback:api-components:clean-orphaned

Run this after bulk deletions or data migrations to keep the database tidy. The command outputs a progress bar and reports how many orphaned records were removed.


Maker Commands

These commands use the standard make: prefix from Symfony MakerBundle and are only registered when MakerBundle is installed.

generate-fixtures

Walk the live database and output a complete AbstractCwaScaffold-compatible PHP class. Useful for capturing a known-good database state as a reproducible fixture, or as a starting point after setting up a site through the admin UI.

php bin/console silverback:api-components:generate-fixtures

By default the class is written to src/DataFixtures/GeneratedScaffold.php. Pass --output to change the path:

php bin/console silverback:api-components:generate-fixtures --output src/DataFixtures/MyScaffold.php

The generated class extends AbstractCwaScaffold and reproduces:

  • All layouts, pages, and page data records with their routes
  • ComponentGroups and their allowedComponents
  • ComponentPositions — including pageDataPosition calls for template pages
  • Components with all public PHP entity properties, uiComponent, and uiClassNames
  • Nested closures for parent/child page and page data relationships

After generation, review the file and run php bin/console doctrine:fixtures:load to reload the captured state. See Data Fixtures for the full builder API reference.


Maker Commands

These commands use the standard make: prefix from Symfony MakerBundle and are only registered when MakerBundle is installed.

make:api-component

Generate a new AbstractComponent entity with the correct namespace, attributes, and optional behaviour traits wired up automatically.

php bin/console make:api-component

The command prompts interactively for the class name and which behaviours to add. You can also pass everything as arguments:

php bin/console make:api-component HeroBlock --timestamped --publishable

Options

  • --timestamped — Add #[Timestamped]: generates createdAt / updatedAt columns via TimestampedTrait
  • --publishable — Add #[Publishable]: wires up the draft/publish lifecycle via PublishableTrait
  • --uploadable — Add #[Uploadable]: includes a $file property and UploadableTrait for file handling

Example output (with all three flags)

#[Silverback\Timestamped]
#[Silverback\Publishable]
#[Silverback\Uploadable]
#[ApiResource]
#[ORM\Entity]
class HeroBlock extends AbstractComponent
{
    use TimestampedTrait;
    use PublishableTrait;
    use UploadableTrait;

    #[Silverback\UploadableField(adapter: 'local')]
    public ?File $file = null;
}

After generation, run make:migration and review the generated SQL before executing it — the traits add columns and (for publishable) self-referencing foreign keys.

make:page-data

Generate a new AbstractPageData entity with typed properties pre-wired, plus console output showing the matching nuxt.config snippet and fixture stub.

php bin/console make:page-data

The command prompts interactively for the class name and properties. You can pass everything inline:

php bin/console make:page-data ConferenceData --properties headline:?string body:?string heroImage:?string

Properties are defined as name:type pairs. Nullable types use the ? prefix.

Example output

#[ApiResource]
#[ORM\Entity]
class ConferenceData extends AbstractPageData
{
    #[ORM\Column(nullable: true)]
    public ?string $headline;

    #[ORM\Column(nullable: true)]
    public ?string $body;

    #[ORM\Column(nullable: true)]
    public ?string $heroImage;
}

After generation the command prints:

  • The nuxt.config.ts cwa.pageData.ConferenceData.properties snippet to add human-readable labels for the admin picker
  • A fixture scaffold stub: $cwa->pageData(new ConferenceData(), template: 'my-template')
  • ->pageDataPosition(ConferenceData::class, 'propertyName') calls for each property, ready to paste into a template group

After generation, run make:migration and review the generated SQL before executing it.

make:cwa-scaffold

Generate a starter AbstractCwaScaffold subclass pre-wired with a layout, a home page, and commented-out nav link stubs.

php bin/console make:cwa-scaffold

The command prompts interactively for the class name, layout reference key, and layout UI component name. You can pass everything inline:

php bin/console make:cwa-scaffold AppScaffold --layout-ref main --layout-component Primary

Options

OptionDefaultDescription
--layout-refmainReference key passed to $cwa->layout()
--layout-componentCwaLayoutPrimaryLayout UI suffix (e.g. Primary → stores CwaLayoutPrimary)

Example output

class AppScaffold extends AbstractCwaScaffold
{
    public function build(CwaFixtureBuilder $cwa): void
    {
        $navGroup = $cwa->layout('main', 'Primary')
            ->group('top');

        $cwa->page('home', 'PrimaryPageTemplate', layout: 'main', route: '/', routeName: 'home-page',
            configure: fn (PageBuilder $page) => $page
                ->title('Home')
                ->group('primary')
        );

        // $navGroup->add(...) — nav links go here after routes exist
    }
}

After generation the command prints the config/services.yaml snippet to register the class as a Doctrine fixture:

App\DataFixtures\AppScaffold:
    tags: [doctrine.fixture.orm]

Then run php bin/console doctrine:fixtures:load to seed the database. See Data Fixtures for the full builder API.

make:rename-component

Generate a Doctrine migration to rename a CWA component type. Use this when you need to rename a PHP entity class that is already stored in the database — it updates the discriminator column (dtype) in abstract_component and replaces old collection IRIs in component_group.allowed_components.

php bin/console make:rename-component

The command prompts interactively for the old and new class names, FQCNs, and dtype values (defaulting to lowercase class names):

php bin/console make:rename-component HtmlContent RichText

What it does

  1. Generates a Doctrine migration class at src/Migrations/RenameComponentHtmlContentToRichText.php
  2. The migration updates abstract_component.dtype and component_group.allowed_components in the database
  3. After generation, the command prints any ComponentGroup records whose allowedComponents array references the old IRI — these need front-end updates too

Front-end checklist (printed after generation)

  1. Rename the Vue component file from the old name to the new name
  2. Update any imports or registrations referencing the old name
  3. Run php bin/console doctrine:migrations:migrate
Run make:migration and review the generated SQL before executing. The migration is written for you — do not skip the review step.