Skip to content

Commit

Permalink
Remove Doctrine/DBAL dependency. Add enum mapper for SQLite.
Browse files Browse the repository at this point in the history
  • Loading branch information
TheDoctor0 committed Apr 20, 2024
1 parent 65d1f1b commit 5bd255d
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 115 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ You can install the package via composer:
composer require thedoctor0/laravel-factory-generator --dev
```

For Laravel 8.x and 9.x check the [v1.3.2](https://github.com/TheDoctor0/laravel-factory-generator/tree/laravel-9).

For Laravel 6.x and 7.x check the [v1.2.5](https://github.com/TheDoctor0/laravel-factory-generator/tree/laravel-7).

## Usage
Expand Down
9 changes: 4 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@
],
"license": "MIT",
"require": {
"php": ">=7.4",
"illuminate/support": "^8.0|^9.0|^10.0|^11.0",
"illuminate/console": "^8.0|^9.0|^10.0|^11.0",
"illuminate/filesystem": "^8.0|^9.0|^10.0|^11.0",
"doctrine/dbal": "^2.9|^2.10|^3.0"
"php": "^8.1",
"illuminate/support": "^10.0|^11.0",
"illuminate/console": "^10.0|^11.0",
"illuminate/filesystem": "^10.0|^11.0"
},
"autoload": {
"psr-4": {
Expand Down
109 changes: 24 additions & 85 deletions src/Console/GenerateFactoryCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Eloquent\Model;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Illuminate\Database\Eloquent\Relations\Relation;
Expand All @@ -38,10 +38,6 @@ class GenerateFactoryCommand extends Command
*/
protected $description = 'Generate test factories for models';

protected Filesystem $files;

protected Factory $view;

protected string $dir;

protected ?string $namespace;
Expand All @@ -52,19 +48,26 @@ class GenerateFactoryCommand extends Command

protected array $properties = [];

/**
* @throws \Doctrine\DBAL\DBALException
*/
public function __construct(Filesystem $files, Factory $view)
public function __construct(public Filesystem $files, public Factory $view)
{
parent::__construct();
}

$this->files = $files;
$this->view = $view;
protected function getArguments(): array
{
return [
['model', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Which models to include', []],
];
}

if (! Type::hasType('customEnum')) {
Type::addType('customEnum', EnumType::class);
}
protected function getOptions(): array
{
return [
['dir', 'D', InputOption::VALUE_OPTIONAL, 'The model directory'],
['force', 'F', InputOption::VALUE_NONE, 'Overwrite any existing model factory'],
['namespace', 'N', InputOption::VALUE_OPTIONAL, 'Model Namespace'],
['recursive', 'R', InputOption::VALUE_NONE, 'Generate model factory recursively']
];
}

public function handle(): void
Expand Down Expand Up @@ -107,23 +110,6 @@ public function handle(): void
}
}

protected function getArguments(): array
{
return [
['model', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Which models to include', []],
];
}

protected function getOptions(): array
{
return [
['dir', 'D', InputOption::VALUE_OPTIONAL, 'The model directory'],
['force', 'F', InputOption::VALUE_NONE, 'Overwrite any existing model factory'],
['namespace', 'N', InputOption::VALUE_OPTIONAL, 'Model Namespace'],
['recursive', 'R', InputOption::VALUE_NONE, 'Generate model factory recursively']
];
}

protected function generateFactory(string $model): ?string
{
if (! $this->existsClassOrTrait($model)) {
Expand Down Expand Up @@ -198,51 +184,26 @@ protected function loadModels(array $models = []): array
}, $this->files->allFiles($this->dir));
}

/**
* @throws \Doctrine\DBAL\DBALException
*/
protected function getPropertiesFromTable(Model $model): void
{
$table = $model->getConnection()->getTablePrefix() . $model->getTable();

try {
$schema = $model->getConnection()->getDoctrineSchemaManager();
} catch (Exception $exception) {
$class = get_class($model);
$driver = $model->getConnection()->getDriverName();

if (in_array($driver, ['mysql', 'pgsql', 'sqlite'])) {
$this->error("Database driver ($driver) for $class model is not configured properly!");
} else {
$this->warn("Database driver ($driver) for $class model is not supported.");
}

return;
}

$database = null;

if (Str::contains($table, '.')) {
[$database, $table] = explode('.', $table);
}

$this->registerCustomTypes($schema);

$columns = $schema->listTableColumns($table, $database);
$schema = Schema::connection($database);
$columns = $schema->getColumns($table);

if (! $columns) {
return;
}

foreach ($columns as $column) {
$field = $column->getName();
$nullable = !$column->getNotnull();

if (in_array($field, $model->getDates(), true)) {
$type = 'datetime';
} else {
$type = $column->getType()->getName();
}
$field = $column['name'];
$nullable = $column['nullable'];
$type = $column['type_name'];

if ($this->isFieldFakeable($field, $model)) {
$this->setProperty($model, $field, $type, $nullable);
Expand Down Expand Up @@ -293,7 +254,7 @@ protected function getPropertiesFromMethods(Model $model): void
}
}

protected function setProperty(Model $model, string $field, string $type, bool $nullable = false ): void
protected function setProperty(Model $model, string $field, string $type, bool $nullable = false): void
{
if ($enumValues = EnumValues::get($model, $field)) {
$enumValues = implode("', '", $enumValues);
Expand Down Expand Up @@ -342,9 +303,7 @@ protected function factoryClass(Relation $relation): string

protected function fakerPrefix(string $type, bool $nullable = false): string
{
return version_compare($this->laravel->version(), '9.18.0', '>=')
? (!$nullable ? "fake()->$type" : "fake()->optional()->$type")
: (!$nullable ? "\$this->faker->$type" : "\$this->faker->optional()->$type");
return !$nullable ? "fake()->$type" : "fake()->optional()->$type";
}

protected function isFieldFakeable(string $field, Model $model): bool
Expand Down Expand Up @@ -456,26 +415,6 @@ protected function formatPath(string ...$paths): string
return implode(DIRECTORY_SEPARATOR, $paths);
}

/**
* @throws \Doctrine\DBAL\DBALException
*/
protected function registerCustomTypes(AbstractSchemaManager $schema): void
{
$platform = $schema->getDatabasePlatform();

if (! $platform) {
return;
}

$platform->registerDoctrineTypeMapping('enum', 'customEnum');
$platformName = $platform->getName();
$customTypes = $this->laravel['config']->get("ide-helper.custom_db_types.$platformName", []);

foreach ($customTypes as $typeName => $doctrineTypeName) {
$platform->registerDoctrineTypeMapping($typeName, $doctrineTypeName);
}
}

protected function getFileStructureDiff(string $class): array
{
if ($this->namespace) {
Expand Down
2 changes: 1 addition & 1 deletion src/Database/EnumMysql.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function values(): ?array
");

$type = DB::connection($this->connection)
->select(is_string($query) ? $query : $query->getValue(DB::connection()->getQueryGrammar()));
->select($query->getValue(DB::connection()->getQueryGrammar()));

preg_match_all("/'([^']+)'/", $type[0]->Type, $matches);

Expand Down
2 changes: 1 addition & 1 deletion src/Database/EnumPgsql.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function values(): ?array
");

$type = DB::connection($this->connection)
->select(is_string($query) ? $query : $query->getValue(DB::connection()->getQueryGrammar()));
->select($query->getValue(DB::connection()->getQueryGrammar()));

if (! count($type)) {
return null;
Expand Down
31 changes: 31 additions & 0 deletions src/Database/EnumSqlite.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace TheDoctor0\LaravelFactoryGenerator\Database;

use Illuminate\Support\Facades\DB;

class EnumSqlite extends EnumDriver
{
public function values(): ?array
{
$query = DB::raw("
SELECT sql FROM sqlite_schema
WHERE tbl_name = '{$this->table}'
");

$type = DB::connection($this->connection)
->select($query->getValue(DB::connection()->getQueryGrammar()));

preg_match_all("/check \(\"{$this->field}\" in \((.+?)\)\)/", $type[0]->sql, $matches);

if (isset($matches[1][0])) {
return collect(explode(',', $matches[1][0]))->map(function ($value) {
return trim(trim($value), "'");
})->toArray();
}

return null;
}
}
4 changes: 4 additions & 0 deletions src/Database/EnumValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ protected function values(Model $model, string $field): ?array
return (new EnumPgsql($model, $field))->values();
}

if ($driver === 'sqlite') {
return (new EnumSqlite($model, $field))->values();
}

return null;
}
}
23 changes: 0 additions & 23 deletions src/Types/EnumType.php

This file was deleted.

0 comments on commit 5bd255d

Please sign in to comment.