Resource factories are used on Create operations to instantiate your resource.
By default, a resource factory is defined to your resource Sylius\Component\Resource\Factory\Factory
.
It has a createNew
method with no arguments.
If you are using Symfony autowiring, you can inject the resource factory using the right variable name.
namespace App;
use Sylius\Resource\Factory\FactoryInterface;
final class MyService
{
public function __construct(
private FactoryInterface $bookFactory,
) {}
}
In this example, the app.factory.book
will be injected in your $bookFactory
You can find the variable name using this debug command:
$ bin/console debug:autowiring app.factory.book
// src/Factory/BookFactory.php
declare(strict_types=1);
namespace App\Factory;
use App\Entity\Book;
use Sylius\Resource\Factory\FactoryInterface;
final class BookFactory implements FactoryInterface
{
public function createNew(): Book
{
$book = new Book();
$book->setCreatedAt(new \DateTimeImmutable());
return $book;
}
}
Configure your factory
# config/services.yaml
services:
App\Factory\BookFactory:
decorates: 'app.factory.book'
// src/Factory/BookFactory.php
declare(strict_types=1);
namespace App\Factory;
use App\Entity\Book;
use Sylius\Resource\Factory\FactoryInterface;
use Symfony\Component\Security\Core\Security;
final class BookFactory implements FactoryInterface
{
public function __construct(private Security $security)
{
}
public function createNew(): Book
{
return new Book();
}
public function createWithCreator(): Book
{
$book = $this->createNew();
$book->setCreator($this->security->getUser());
return $book;
}
}
Use it on your create operation
// src/Entity/Book.php
declare(strict_types=1);
namespace App\Entity\Book;
use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Create;
use Sylius\Resource\Model\ResourceInterface;
#[AsResource]
#[Create(
path: 'authors/{authorId}/books',
factoryMethod: 'createWithCreator',
)]
class Book implements ResourceInterface
{
}
You can pass arguments to your factory method.
3 variables are available:
request
: to retrieve data from the request viaSymfony\Component\HttpFoundation\Request
token
: to retrieve data from the authentication token viaSymfony\Component\Security\Core\Authentication\Token\TokenInterface
user
: to retrieve data from the logged-in user viaSymfony\Component\Security\Core\User\UserInterface
It uses the Symfony expression language component.
// src/Factory/BookFactory.php
declare(strict_types=1);
namespace App\Factory;
use App\Entity\Book;
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;
use Sylius\Resource\Factory\FactoryInterface;
final class BookFactory implements FactoryInterface
{
public function __construct(private RepositoryInterface $authorRepository)
{
}
public function createNew(): Book
{
return new Book();
}
public function createForAuthor(string $authorId): Book
{
$book = $this->createNew();
$author = $this->authorRepository->find($authorId);
$book->setAuthor($author);
return $book;
}
}
Use it on your create operation
// src/Entity/Book.php
declare(strict_types=1);
namespace App\Entity\Book;
use Sylius\Resource\Model\ResourceInterface;
use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Create;
#[AsResource]
#[Create(
path: 'authors/{authorId}/books',
factoryMethod: 'createForAuthor',
factoryArguments: ['authorId' => "request.attributes.get('authorId')"],
)]
class Book implements ResourceInterface
{
}
You can use a factory without declaring it on services.yaml
.
// src/Entity/Book.php
declare(strict_types=1);
namespace App\Entity\Book;
use App\Factory\BookFactory;
use Sylius\Resource\Model\ResourceInterface;
use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Create;
#[AsResource]
#[Create(
path: 'authors/{authorId}/books',
# Here we declared the factory to use with its fully classified class name
factory: BookFactory::class,
factoryMethod: 'createForAuthor',
factoryArguments: ['authorId' => "request.attributes.get('authorId')"],
)]
class Book implements ResourceInterface
{
}
// src/Factory/BookFactory.php
declare(strict_types=1);
namespace App\Factory;
use App\Entity\Book;
final class BookFactory
{
public static function create(): Book
{
return new Book();
}
}
// src/Entity/Book.php
declare(strict_types=1);
namespace App\Entity\Book;
use App\Factory\BookFactory;
use Sylius\Resource\Metadata\AsResource;
use Sylius\Resource\Metadata\Create;
use Sylius\Resource\Model\ResourceInterface
#[AsResource]
#[Create(
factory: [BookFactory::class, 'create'],
)]
class Book implements ResourceInterface
{
}