9.3 API: Migrate DataProvider to StateProvider

This step migrates API Platform 2.x DataProviders and DataPersisters to API Platform 4.x StateProviders and StateProcessors.

When to skip this step:

  • Your plugin doesn't have custom DataProvider or DataPersister classes

When to do this step:

  • You have custom DataProvider classes in src/DataProvider/

  • You have custom DataPersister classes in src/DataPersister/

Overview of Changes

API Platform 4.x replaced DataProviders and DataPersisters with a unified State system:

API Platform 2.x
API Platform 4.x

CollectionDataProviderInterface

ProviderInterface (collections)

ItemDataProviderInterface

ProviderInterface (items)

DataPersisterInterface

ProcessorInterface

DataTransformerInterface

Some → SerializerContextBuilder

Key changes:

  • New interfaces and namespaces

  • Different method signatures

  • Explicit linking to operations (no more supports() method)

  • Organized directory structure

1. Identify Files to Migrate

Check if you have DataProviders:

Check if you have DataPersisters:

2. Migrate DataProvider to StateProvider

Directory Structure

Follow Sylius conventions for organization:

Old structure:

New structure:

Pattern: StateProvider/{Section}/{Resource}/{Type}Provider.php

  • Section: Shop or Admin

  • Resource: Entity name (singular)

  • Type: CollectionProvider or ItemProvider

Example Migration

Before (API Platform 2.x):

src/DataProvider/GetAdsBannersDataProvider.php:

After (API Platform 4.x):

src/StateProvider/Shop/Banner/CollectionProvider.php:

Key Changes:

  1. Namespace: DataProviderStateProvider\Shop\Banner

  2. Class name: GetAdsBannersDataProviderCollectionProvider

  3. Interface: ContextAwareCollectionDataProviderInterfaceProviderInterface

  4. Method: getCollection()provide()

  5. Removed: supports() method - no longer needed

  6. Removed: $class parameter - no longer needed

  7. Added: Operation $operation parameter

  8. Class modifiers: Added final readonly

  9. PHPDoc: Added @implements ProviderInterface<BannerInterface>

3. Update Service Registration

Before:

config/services/dataProvider/dataProvider.xml:

After:

config/services/stateProvider/stateProvider.xml:

Changes:

  1. Service ID: Follow pattern {vendor}.{plugin}.state_provider.{section}.{resource}.{type}

  2. Class: Updated to new namespace

  3. Removed: $class argument (resource class parameter)

  4. Tag: api_platform.collection_data_providerapi_platform.state_provider

  5. Priority: Added priority="10"

In API Platform 4.x, you must explicitly link providers to operations.

config/api_resources/resources/shop/Banner.xml:

Before (implicit):

After (explicit):

Add the provider="{service_id}" attribute to link your StateProvider to the operation.

5. Migrate DataPersister to StateProcessor (if applicable)

If you have DataPersisters, migrate them similarly:

Before:

After:

Service registration:

Link to operation:

6. Remove Old Files

After migration is complete and tested:

7. Validate Changes

Clear the cache:

Verify routes are registered:

Verify StateProvider is registered:

Test API endpoints:

Common Patterns

Pattern: Item Provider

For getting a single item:

Pattern: Using URI Variables

Access path parameters via $uriVariables:

Pattern: Using Filters

Access query parameters via $context['filters']:

Important Notes

  1. No supports() method: Linking is now explicit via provider attribute

  2. Remove $class parameter: Resource class is obtained from $operation->getClass()

  3. readonly classes: Follow Sylius convention with final readonly class

  4. Return types:

    • Collections: array

    • Items: object|null

    • Processors: mixed

  5. Service ID format: {vendor}.{plugin}.state_provider.{section}.{resource}.{type}

  6. Priority: Use priority="10" in service tags

Reference

For more examples, check Sylius core StateProviders:

Last updated

Was this helpful?