Skip to content

Commit aff8995

Browse files
committed
Streamline options + create separate factories
1 parent 293eb78 commit aff8995

File tree

2 files changed

+87
-108
lines changed

2 files changed

+87
-108
lines changed

resources/views/factory.blade.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
/* @@var $factory \Illuminate\Database\Eloquent\Factory */
12

2-
$factory->define({{$reflection->getName()}}::class, function (Faker\Generator $faker) {
3+
use Faker\Generator as Faker;
4+
5+
$factory->define({{ $reflection->getName() }}::class, function (Faker $faker) {
36
return [
4-
@foreach($properties as $name => $property)
5-
'{{$name}}' => @if($property['faker']){!!$property['type']!!}@else'{{$property['type']}}'@endif,
6-
@endforeach
7+
@foreach($properties as $name => $property)
8+
'{{$name}}' => {!! $property !!},
9+
@endforeach
710
];
811
});
9-

src/Console/GenerateCommand.php

Lines changed: 80 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
namespace Mpociot\LaravelTestFactoryHelper\Console;
44

55
use Illuminate\Console\Command;
6-
use Illuminate\Contracts\Filesystem\FileNotFoundException;
76
use Illuminate\Database\Eloquent\Relations\Relation;
87
use Illuminate\Filesystem\Filesystem;
98
use Illuminate\Support\Str;
10-
use Symfony\Component\Console\Input\InputOption;
9+
use Symfony\Component\ClassLoader\ClassMapGenerator;
1110
use Symfony\Component\Console\Input\InputArgument;
11+
use Symfony\Component\Console\Input\InputOption;
1212
use Symfony\Component\Console\Output\OutputInterface;
13-
use Symfony\Component\ClassLoader\ClassMapGenerator;
1413

1514
class GenerateCommand extends Command
1615
{
@@ -26,11 +25,6 @@ class GenerateCommand extends Command
2625
*/
2726
protected $name = 'test-factory-helper:generate';
2827

29-
/**
30-
* @var string
31-
*/
32-
protected $filename = 'database/factories/ModelFactory.php';
33-
3428
/**
3529
* @var string
3630
*/
@@ -64,7 +58,7 @@ class GenerateCommand extends Command
6458
/**
6559
* @var
6660
*/
67-
protected $reset;
61+
protected $force;
6862

6963
/**
7064
* @param Filesystem $files
@@ -83,25 +77,32 @@ public function __construct(Filesystem $files, $view)
8377
*/
8478
public function handle()
8579
{
86-
$filename = $this->option('filename');
87-
$this->dirs = $this->option('dir');
88-
$model = $this->argument('model');
89-
$ignore = $this->option('ignore');
90-
$this->reset = $this->option('reset');
80+
$this->dir = $this->option('dir');
81+
$this->force = $this->option('force');
9182

92-
try {
93-
$this->existingFactories = $this->files->get($filename);
94-
} catch (FileNotFoundException $e) {
95-
$this->existingFactories = '';
96-
}
83+
$models = $this->loadModels($this->argument('model'));
84+
85+
foreach ($models as $model) {
86+
$filename = 'database/factories/' . class_basename($model) . 'Factory.php';
9787

98-
$result = $this->generateFactories($model, $ignore);
88+
if ($this->files->exists($filename) && !$this->force) {
89+
$this->warn('Model factory exists, use --force to overwrite: ' . $filename);
9990

100-
$written = $this->files->put('database/factories/ModelFactory.php', $result);
101-
if ($written !== false) {
102-
$this->info("Model factories were written successfully to ".$filename);
103-
} else {
104-
$this->error("Failed to write model factories to ".$filename);
91+
continue;
92+
}
93+
94+
$result = $this->generateFactory($model);
95+
96+
if ($result === false) {
97+
continue;
98+
}
99+
100+
$written = $this->files->put($filename, $result);
101+
if ($written !== false) {
102+
$this->info('Model factory created: ' . $filename);
103+
} else {
104+
$this->error('Failed to create model factory: ' . $filename);
105+
}
105106
}
106107
}
107108

@@ -126,92 +127,77 @@ protected function getArguments()
126127
protected function getOptions()
127128
{
128129
return array(
129-
array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the model factory file', $this->filename),
130-
array('dir', 'D', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The model dir', array($this->dir)),
131-
array('reset', 'R', InputOption::VALUE_NONE, 'Remove the original ModelFactory instead of appending'),
132-
array('ignore', 'I', InputOption::VALUE_OPTIONAL, 'Which models to ignore', ''),
130+
array('dir', 'D', InputOption::VALUE_OPTIONAL, 'The model directory', array($this->dir)),
131+
array('force', 'F', InputOption::VALUE_NONE, 'Overwrite any existing model factory'),
133132
);
134133
}
135134

136-
protected function generateFactories($loadModels, $ignore = '')
135+
protected function generateFactory($model)
137136
{
137+
$output = '<?php' . "\n\n";
138138

139-
if (empty($loadModels)) {
140-
$models = $this->loadModels();
141-
} else {
142-
$models = array();
143-
foreach ($loadModels as $model) {
144-
$models = array_merge($models, explode(',', $model));
139+
$this->properties = [];
140+
if (!class_exists($model)) {
141+
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
142+
$this->error("Unable to find '$model' class");
145143
}
144+
return false;
146145
}
147146

148-
$output = ($this->reset || !$this->files->exists('database/factories/ModelFactory.php')) ? '<?php'."\n\n" : $this->existingFactories;
149-
$ignore = explode(',', $ignore);
147+
try {
148+
// handle abstract classes, interfaces, ...
149+
$reflectionClass = new \ReflectionClass($model);
150150

151-
foreach ($models as $name) {
152-
if (in_array($name, $ignore)) {
153-
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
154-
$this->comment("Ignoring model '$name'");
155-
}
156-
continue;
151+
if (!$reflectionClass->isSubclassOf('Illuminate\Database\Eloquent\Model')) {
152+
return false;
157153
}
158154

159-
$this->properties = array();
160-
if (class_exists($name)) {
161-
try {
162-
// handle abstract classes, interfaces, ...
163-
$reflectionClass = new \ReflectionClass($name);
155+
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
156+
$this->comment("Loading model '$model'");
157+
}
164158

165-
if (!$reflectionClass->isSubclassOf('Illuminate\Database\Eloquent\Model')) {
166-
continue;
167-
}
159+
if (!$reflectionClass->IsInstantiable()) {
160+
// ignore abstract class or interface
161+
return false;
162+
}
168163

169-
if (!$this->reset && preg_match("/\\\$factory->define\((.*?)".preg_quote($reflectionClass->getName())."::class(.*?),/", $this->existingFactories)) {
170-
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
171-
$this->error("Model '$name' already has a factory");
172-
}
173-
continue;
174-
}
164+
$model = $this->laravel->make($model);
175165

176-
if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
177-
$this->comment("Loading model '$name'");
178-
}
166+
$this->getPropertiesFromTable($model);
167+
$this->getPropertiesFromMethods($model);
179168

180-
if (!$reflectionClass->IsInstantiable()) {
181-
// ignore abstract class or interface
182-
continue;
183-
}
184-
185-
$model = $this->laravel->make($name);
169+
$output .= $this->createFactory($model);
170+
} catch (\Exception $e) {
171+
$this->error("Exception: " . $e->getMessage() . "\nCould not analyze class $model.");
172+
}
186173

187-
$this->getPropertiesFromTable($model);
174+
return $output;
175+
}
188176

189-
$this->getPropertiesFromMethods($model);
190177

191-
$output .= $this->createFactory($name);
192-
$ignore[] = $name;
193-
} catch (\Exception $e) {
194-
$this->error("Exception: " . $e->getMessage() . "\nCould not analyze class $name.");
178+
protected function loadModels($models = [])
179+
{
180+
if (!empty($models)) {
181+
return array_map(function ($name) {
182+
if (strpos($name, '\\') !== false) {
183+
return $name;
195184
}
196-
}
197185

186+
return str_replace(
187+
[DIRECTORY_SEPARATOR, basename($this->laravel->path()) . '\\'],
188+
['\\', $this->laravel->getNamespace()],
189+
$this->dir . DIRECTORY_SEPARATOR . $name
190+
);
191+
}, $models);
198192
}
199-
return $output;
200-
}
201193

202194

203-
protected function loadModels()
204-
{
205-
$models = array();
206-
foreach ($this->dirs as $dir) {
207-
$dir = base_path() . '/' . $dir;
208-
if (file_exists($dir)) {
209-
foreach (ClassMapGenerator::createMap($dir) as $model => $path) {
210-
$models[] = $model;
211-
}
212-
}
195+
$dir = base_path($this->dir);
196+
if (!file_exists($dir)) {
197+
return [];
213198
}
214-
return $models;
199+
200+
return array_keys(ClassMapGenerator::createMap($dir));
215201
}
216202

217203
/**
@@ -251,7 +237,7 @@ protected function getPropertiesFromTable($model)
251237
$name !== $model::CREATED_AT &&
252238
$name !== $model::UPDATED_AT
253239
) {
254-
if(!method_exists($model,'getDeletedAtColumn') || (method_exists($model,'getDeletedAtColumn') && $name !== $model->getDeletedAtColumn())) {
240+
if (!method_exists($model, 'getDeletedAtColumn') || (method_exists($model, 'getDeletedAtColumn') && $name !== $model->getDeletedAtColumn())) {
255241
$this->setProperty($name, $type);
256242
}
257243
}
@@ -307,17 +293,10 @@ protected function getPropertiesFromMethods($model)
307293
*/
308294
protected function setProperty($name, $type = null)
309295
{
310-
if (!isset($this->properties[$name])) {
311-
$this->properties[$name] = array();
312-
$this->properties[$name]['type'] = 'mixed';
313-
$this->properties[$name]['faker'] = false;
314-
}
315-
if ($type !== null) {
316-
$this->properties[$name]['type'] = $type;
317-
}
296+
if ($type !== null && Str::startsWith($type, 'factory(')) {
297+
$this->properties[$name] = $type;
318298

319-
if (Str::startsWith($type,'function ()')) {
320-
$this->properties[$name]['faker'] = true;
299+
return;
321300
}
322301

323302
$fakeableTypes = [
@@ -365,13 +344,11 @@ protected function setProperty($name, $type = null)
365344
];
366345

367346
if (isset($fakeableNames[$name])) {
368-
$this->properties[$name]['faker'] = true;
369-
$this->properties[$name]['type'] = $fakeableNames[$name];
347+
$this->properties[$name] = $fakeableNames[$name];
370348
}
371349

372-
if (isset($fakeableTypes[$type]) && !$this->properties[$name]['faker']) {
373-
$this->properties[$name]['faker'] = true;
374-
$this->properties[$name]['type'] = $fakeableTypes[$type];
350+
if (isset($fakeableTypes[$type])) {
351+
$this->properties[$name] = $fakeableTypes[$type];
375352
}
376353
}
377354

0 commit comments

Comments
 (0)