packages/sql-fixture/src/FileFixtureProvider.php

1<?php
2
3declare(strict_types=1);
4
5namespace SqlFixture;
6
7use Faker\Generator;
8use Faker\Provider\Base;
9use RuntimeException;
10use SqlFixture\Hydrator\HydratorInterface;
11use SqlFixture\Platform\PlatformFactory;
12use SqlFixture\Schema\TableSchema;
13use SqlFixture\TypeMapper\TypeMapperInterface;
14
15/**
16 * Faker provider that generates fixtures from local DDL files.
17 */
18class FileFixtureProvider extends Base
19{
20    private FixtureGenerator $fixtureGenerator;
21
22    /**
23     * @var array<string, TableSchema> Table name → parsed schema cache
24     */
25    private array $schemas = [];
26
27    /**
28     * @param string $dialect SQL dialect ('mysql' or 'sqlite')
29     */
30    public function __construct(
31        Generator $faker,
32        string $ddlPath,
33        ?TypeMapperInterface $typeMapper = null,
34        ?HydratorInterface $hydrator = null,
35        string $dialect = PlatformFactory::DRIVER_MYSQL,
36    ) {
37        parent::__construct($faker);
38
39        $typeMapper ??= PlatformFactory::createTypeMapper($dialect);
40        $schemaParser = PlatformFactory::createSchemaParser($dialect);
41
42        $this->fixtureGenerator = new FixtureGenerator($faker, $typeMapper, $hydrator, $schemaParser);
43        $this->schemas = (new Provider\DdlDirectory())->loadSchemas($ddlPath, $schemaParser);
44    }
45
46    /**
47     * Generate a fixture from a DDL file.
48     *
49     * @template T of object
50     * @param string $tableName Table name (e.g., "users")
51     * @param array<string, mixed> $overrides Override values
52     * @param class-string<T>|null $className Deserialization target class
53     * @return ($className is null ? array<string, mixed> : T)
54     * @throws RuntimeException
55     */
56    public function fixture(
57        string $tableName,
58        array $overrides = [],
59        ?string $className = null,
60    ): array|object {
61        $normalizedName = strtolower($tableName);
62
63        if (!isset($this->schemas[$normalizedName])) {
64            throw new RuntimeException("Schema not found for table: {$tableName}");
65        }
66
67        return $this->fixtureGenerator->generate($this->schemas[$normalizedName], $overrides, $className);
68    }
69
70    /**
71     * Check if a table schema is loaded.
72     */
73    public function hasTable(string $tableName): bool
74    {
75        return isset($this->schemas[strtolower($tableName)]);
76    }
77
78    /**
79     * Get list of available table names.
80     *
81     * @return list<string>
82     */
83    public function getTableNames(): array
84    {
85        return array_keys($this->schemas);
86    }
87
88    /**
89     * Manually register a schema.
90     */
91    public function registerSchema(string $createTableSql): void
92    {
93        $schema = $this->fixtureGenerator->getSchemaParser()->parse($createTableSql);
94        $this->schemas[strtolower($schema->tableName)] = $schema;
95    }
96
97    /**
98     * Get the underlying fixture generator.
99     */
100    public function getFixtureGenerator(): FixtureGenerator
101    {
102        return $this->fixtureGenerator;
103    }
104}
105