# Providers

Providers retrieve data from your persistence layer.

* [Default providers](#default-providers)
  * [Custom repository method](#custom-repository-method)
  * [Custom repository arguments](#custom-repository-arguments)
* [Custom providers](#custom-providers)
* [Disable providing data](#disable-providing-data)

## Default providers

When your resource is a Doctrine entity, there's a default provider `Sylius\Component\Resource\Symfony\Request\State\Provider` which is already configured to your operations.

As it uses the Doctrine repository configured on your resource, some default repository methods are used.

| Operation   | Repository method |
| ----------- | ----------------- |
| index       | createPaginator   |
| show        | findOneBy         |
| update      | findOneBy         |
| delete      | findOneBy         |
| bulk delete | findById          |

### Custom repository method

You can customize the method to use.

{% code title="src/Entity/Customer.php" lineNumbers="true" %}

```php

declare(strict_types=1);

namespace App\Entity;

use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Show;
use Sylius\Resource\Model\ResourceInterface;

#[AsResource(
    operations: [
        new Show(
            repositoryMethod: 'findOneByEmail',
        ),
    ],
)
final class Customer implements ResourceInterface
{
    // [...]
}
```

{% endcode %}

### Custom repository arguments

You can pass arguments to your repository method.

3 variables are available:

* `request`: to retrieve data from the request via `Symfony\Component\HttpFoundation\Request`
* `token`: to retrieve data from the authentication token via `Symfony\Component\Security\Core\Authentication\Token\TokenInterface`
* `user`: to retrieve data from the logged-in user via `Symfony\Component\Security\Core\User\UserInterface`

It uses the [Symfony expression language](https://symfony.com/doc/current/components/expression_language.html) component.

{% code title="src/Entity/Customer.php" lineNumbers="true" %}

```php

declare(strict_types=1);

namespace App\Entity;

use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Show;
use Sylius\Resource\Model\ResourceInterface;

#[AsResource(
    operations: [
        new Show(
            repositoryMethod: 'findOneByEmail', 
            repositoryArguments: ['email' => "request.attributes.get('email')"],
        ),
    ],
)
final class Customer implements ResourceInterface
{
    // [...]
}
```

{% endcode %}

## Custom providers

Custom providers are useful to customize your logic to retrieve data and for an advanced usage such as an hexagonal architecture.

As an example, let's configure a `BoardGameItemProvider` on a `BoardGameResource` which is not a Doctrine entity.

{% code title="src/BoardGameBlog/Infrastructure/Sylius/State/Provider/BoardGameItemProvider.php" lineNumbers="true" %}

```php

declare(strict_types=1);

namespace App\BoardGameBlog\Infrastructure\Sylius\State\Provider;

use Sylius\Resource\State\ProviderInterface;

final class BoardGameItemProvider implements ProviderInterface
{
    public function __construct(
        private QueryBusInterface $queryBus,
    ) {
    }

    public function provide(Operation $operation, Context $context): object|array|null
    {
        $request = $context->get(RequestOption::class)?->request();
        Assert::notNull($request);

        $id = (string) $request->attributes->get('id');

        $model = $this->queryBus->ask(new FindBoardGameQuery(new BoardGameId(Uuid::fromString($id))));

        return null !== $model ? BoardGameResource::fromModel($model) : null;
    }
}
```

{% endcode %}

Use this provider on your operation.

{% code title="src/BoardGameBlog/Infrastructure/Sylius/Resource/BoardGameResource.php" lineNumbers="true" %}

```php

declare(strict_types=1);

namespace App\BoardGameBlog\Infrastructure\Sylius\Resource;

use App\BoardGameBlog\Infrastructure\Sylius\State\Provider\BoardGameItemProvider;
use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Show;
use Sylius\Resource\Model\ResourceInterface;

#[AsResource(
    operations: [
        new Show(
            provider: BoardGameItemProvider::class, 
        ),
    ],
)
final class BoardGameResource implements ResourceInterface
{
    // [...]
}
```

{% endcode %}

## Disable providing data

In some cases, you may want not to read data.

For example, in a delete operation, you can implement your custom delete processor without reading it before.

{% code title="src/BoardGameBlog/Infrastructure/Sylius/Resource/BoardGameResource.php" lineNumbers="true" %}

```php

declare(strict_types=1);

namespace App\BoardGameBlog\Infrastructure\Sylius\Resource;

use App\BoardgameBlog\Infrastructure\Sylius\State\Provider\DeleteBoardGameProcessor;
use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Delete;
use Sylius\Resource\Model\ResourceInterface;

#[AsResource(
    operations: [
        new Delete(
            processor: DeleteBoardGameProcessor::class,
            read: false,
        ),
    ],
)
final class BoardGameResource implements ResourceInterface
{
    // [...]
}
```

{% endcode %}

{% code title="src/BoardGameBlog/Infrastructure/Sylius/State/Processor/DeleteBoardGameProcessor.php" lineNumbers="true" %}

```php

namespace App\BoardGameBlog\Infrastructure\Sylius\State\Processor;

use App\BoardGameBlog\Application\Command\DeleteBoardGameCommand;
use App\BoardGameBlog\Domain\ValueObject\BoardGameId;
use App\BoardGameBlog\Infrastructure\Sylius\Resource\BoardGameResource;
use App\Shared\Application\Command\CommandBusInterface;
use Sylius\Resource\Context\Context;
use Sylius\Resource\Context\Option\RequestOption;
use Sylius\Resource\Metadata\Operation;
use Sylius\Resource\State\ProcessorInterface;
use Webmozart\Assert\Assert;

final class DeleteBoardGameProcessor implements ProcessorInterface
{
    public function __construct(
        private CommandBusInterface $commandBus,
    ) {
    }

    public function process(mixed $data, Operation $operation, Context $context): mixed
    {
        Assert::isInstanceOf($data, BoardGameResource::class);
        
        // Data is not provided in this case, so you will need to get it from the HTTP request
        $id = $context->get(RequestOption::class)?->attributes->get('id') ?? null;
        Assert::notNull($id);

        $this->commandBus->dispatch(new DeleteBoardGameCommand(new BoardGameId($id)));

        return null;
    }
}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://stack.sylius.com/resource/index/providers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
