Installation
composer require bitecodes/factrine-bundle
Add the bundle to config/bundles.php:
return [
// ...
BiteCodes\FactrineBundle\FactrineBundle::class => ['all' => true],
];
Basic Configuration
Define a factory class for your entity (e.g., UserFactory):
namespace App\Factory;
use BiteCodes\FactrineBundle\Factory\FactoryInterface;
use App\Entity\User;
class UserFactory implements FactoryInterface
{
public function create(array $data = []): User
{
$user = new User();
$user->setName($data['name'] ?? 'Default Name');
$user->setEmail($data['email'] ?? 'default@example.com');
return $user;
}
}
Register the Factory
Configure the factory in config/packages/factrine.yaml:
factrine:
factories:
App\Entity\User: App\Factory\UserFactory
First Use Case Generate a user entity in a controller or service:
use BiteCodes\FactrineBundle\Factory\FactoryManager;
class UserController extends AbstractController
{
public function createUser(FactoryManager $factoryManager)
{
$user = $factoryManager->create('App\Entity\User', ['name' => 'John Doe']);
// Use $user...
}
}
Dynamic Data Generation Use factories to generate test data or mock entities:
$users = [];
for ($i = 0; $i < 10; $i++) {
$users[] = $factoryManager->create('App\Entity\User', [
'name' => "User $i",
'email' => "user$i@example.com"
]);
}
Integration with Fixtures
Combine with doctrine/doctrine-fixtures-bundle for bulk data loading:
# config/packages/doctrine.yaml
doctrine:
orm:
entity_managers:
default:
mappings:
App:
is_bundle: false
type: annotation
dir: "%kernel.project_dir%/src/Entity"
prefix: "App\Entity"
alias: App
Dependency Injection
Inject FactoryManager into services for reusable factory logic:
class UserService
{
public function __construct(private FactoryManager $factoryManager) {}
public function createDefaultUser(): User
{
return $this->factoryManager->create('App\Entity\User');
}
}
Custom Factory Logic Extend factory methods for complex scenarios:
class UserFactory implements FactoryInterface
{
public function createAdmin(array $data = []): User
{
$user = $this->create($data);
$user->setRoles(['ROLE_ADMIN']);
return $user;
}
}
Factory Inheritance Reuse base factories for related entities:
class PostFactory implements FactoryInterface
{
public function create(array $data = []): Post
{
$post = new Post();
$post->setTitle($data['title'] ?? 'Untitled Post');
$post->setContent($data['content'] ?? 'No content');
$post->setAuthor($data['author'] ?? $this->createDefaultAuthor());
return $post;
}
private function createDefaultAuthor(): User
{
return $this->factoryManager->create('App\Entity\User');
}
}
Circular Dependencies
Avoid circular references in factory logic (e.g., UserFactory creating Post which requires User).
Solution: Use lazy-loading or mock objects during initialization.
Missing Factory Configuration
Forgetting to register factories in factrine.yaml will throw FactoryNotFoundException.
Solution: Verify the factories key in config and entity namespace alignment.
Overriding Default Data Hardcoding values in factories may lead to inconsistent test data. Solution: Use configurable defaults or pass data dynamically.
Entity Manager Conflicts
Factories may use the wrong EntityManager if not explicitly set.
Solution: Bind EntityManagerInterface to the correct manager in DI container.
Performance with Large Datasets
Generating thousands of entities without persistence can consume memory.
Solution: Batch inserts or use EntityManager::flush() periodically.
Enable Factory Logging
Add debug logging in config/packages/monolog.yaml:
monolog:
handlers:
factrine:
type: stream
path: "%kernel.logs_dir%/factrine.log"
level: debug
channels: ["factrine"]
Then log factory creation:
$this->logger->debug('Created entity', ['entity' => $entity]);
Validate Factory Output Use assertions to verify factory output:
$user = $factoryManager->create('App\Entity\User');
assert($user instanceof User);
assert(!empty($user->getEmail()));
Custom Factory Resolvers
Override FactoryManager to add logic for resolving factories:
class CustomFactoryManager extends FactoryManager
{
protected function resolveFactory(string $entityClass): FactoryInterface
{
if ($entityClass === 'App\Entity\Admin') {
return new AdminFactory();
}
return parent::resolveFactory($entityClass);
}
}
Event-Driven Factories Trigger events after factory creation:
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class UserFactory implements FactoryInterface
{
public function __construct(private EventDispatcherInterface $dispatcher) {}
public function create(array $data = []): User
{
$user = new User();
// ... set properties
$this->dispatcher->dispatch(new UserCreatedEvent($user));
return $user;
}
}
Dynamic Factory Selection Use runtime conditions to select factories:
$factory = $factoryManager->create(
$entityClass,
$data,
$environment === 'test' ? 'TestFactory' : null
);
Hybrid Factories
Combine with existing tools like Faker:
use Faker\Factory as Faker;
class UserFactory implements FactoryInterface
{
public function create(array $data = []): User
{
$faker = Faker::create();
$user = new User();
$user->setName($data['name'] ?? $faker->name);
$user->setEmail($data['email'] ?? $faker->email);
return $user;
}
}
How can I help you explore Laravel packages today?