Skip to content

Commit

Permalink
Merge pull request flipboxstudio#63 from joelhy/feat/make-factory
Browse files Browse the repository at this point in the history
feat: add 'php artisan make:factory' support
  • Loading branch information
joelhy authored Nov 5, 2019
2 parents 288b522 + 6b7c1df commit 06e229a
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 62 deletions.
93 changes: 93 additions & 0 deletions src/LumenGenerator/Console/FactoryMakeCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

namespace Flipbox\LumenGenerator\Console;

use Symfony\Component\Console\Input\InputOption;

class FactoryMakeCommand extends GeneratorCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:factory';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new model factory';

/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Factory';

/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return __DIR__.'/stubs/factory.stub';
}

/**
* Build the class with the given name.
*
* @param string $name
* @return string
*/
protected function buildClass($name)
{
$namespaceModel = $this->option('model')
? $this->qualifyClass($this->option('model'))
: trim($this->rootNamespace(), '\\').'\\Model';

$model = class_basename($namespaceModel);

return str_replace(
[
'NamespacedDummyModel',
'DummyModel',
],
[
$namespaceModel,
$model,
],
parent::buildClass($name)
);
}

/**
* Get the destination class path.
*
* @param string $name
* @return string
*/
protected function getPath($name)
{
$name = str_replace(
['\\', '/'], '', $this->argument('name')
);

return $this->laravel->databasePath()."/factories/{$name}.php";
}

/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['model', 'm', InputOption::VALUE_OPTIONAL, 'The name of the model'],
];
}
}
165 changes: 103 additions & 62 deletions src/LumenGenerator/Console/GeneratorCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace Flipbox\LumenGenerator\Console;

use Illuminate\Support\Str;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputArgument;

abstract class GeneratorCommand extends Command
Expand All @@ -26,7 +26,8 @@ abstract class GeneratorCommand extends Command
/**
* Create a new controller creator command instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @param \Illuminate\Filesystem\Filesystem $files
* @return void
*/
public function __construct(Filesystem $files)
{
Expand All @@ -46,108 +47,114 @@ abstract protected function getStub();
* Execute the console command.
*
* @return bool|null
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function handle()
{
$name = $this->parseName($this->getNameInput());
$name = $this->qualifyClass($this->getNameInput());

$path = $this->getPath($name);

if ($this->alreadyExists($this->getNameInput())) {
// First we will check to see if the class already exists. If it does, we don't want
// to create the class and overwrite the user's code. So, we will bail out so the
// code is untouched. Otherwise, we will continue generating this class' files.
if ((! $this->hasOption('force') ||
! $this->option('force')) &&
$this->alreadyExists($this->getNameInput())) {
$this->error($this->type.' already exists!');

return false;
}

// Next, we will generate the path to the location where this class' file should get
// written. Then, we will build the class and make the proper replacements on the
// stub files so that it gets the correctly formatted namespace and class name.
$this->makeDirectory($path);

$this->files->put($path, $this->buildClass($name));
$this->files->put($path, $this->sortImports($this->buildClass($name)));

$this->info($this->type.' created successfully.');
}

/**
* Determine if the class already exists.
* Parse the class name and format according to the root namespace.
*
* @param string $rawName
*
* @return bool
* @param string $name
* @return string
*/
protected function alreadyExists($rawName)
protected function qualifyClass($name)
{
$name = $this->parseName($rawName);
$name = ltrim($name, '\\/');

$rootNamespace = $this->rootNamespace();

if (Str::startsWith($name, $rootNamespace)) {
return $name;
}

$name = str_replace('/', '\\', $name);

return $this->files->exists($this->getPath($name));
return $this->qualifyClass(
$this->getDefaultNamespace(trim($rootNamespace, '\\')).'\\'.$name
);
}

/**
* Get the destination class path.
*
* @param string $name
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getPath($name)
protected function getDefaultNamespace($rootNamespace)
{
$name = Str::replaceFirst($this->laravel->getNamespace(), '', $name);

return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php';
return $rootNamespace;
}

/**
* Parse the name and format according to the root namespace.
*
* @param string $name
* Determine if the class already exists.
*
* @return string
* @param string $rawName
* @return bool
*/
protected function parseName($name)
protected function alreadyExists($rawName)
{
$rootNamespace = $this->laravel->getNamespace();

if (Str::startsWith($name, $rootNamespace)) {
return $name;
}

if (Str::contains($name, '/')) {
$name = str_replace('/', '\\', $name);
}

return $this->parseName($this->getDefaultNamespace(trim($rootNamespace, '\\')).'\\'.$name);
return $this->files->exists($this->getPath($this->qualifyClass($rawName)));
}

/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* Get the destination class path.
*
* @param string $name
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
protected function getPath($name)
{
return $rootNamespace;
$name = Str::replaceFirst($this->rootNamespace(), '', $name);

return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php';
}

/**
* Build the directory for the class if necessary.
*
* @param string $path
*
* @param string $path
* @return string
*/
protected function makeDirectory($path)
{
if (!$this->files->isDirectory(dirname($path))) {
if (! $this->files->isDirectory(dirname($path))) {
$this->files->makeDirectory(dirname($path), 0777, true, true);
}

return $path;
}

/**
* Build the class with the given name.
*
* @param string $name
*
* @param string $name
* @return string
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function buildClass($name)
{
Expand All @@ -159,33 +166,25 @@ protected function buildClass($name)
/**
* Replace the namespace for the given stub.
*
* @param string $stub
* @param string $name
*
* @param string $stub
* @param string $name
* @return $this
*/
protected function replaceNamespace(&$stub, $name)
{
$stub = str_replace(
'DummyNamespace',
$this->getNamespace($name),
$stub
);

$stub = str_replace(
'DummyRootNamespace',
$this->laravel->getNamespace(),
['DummyNamespace', 'DummyRootNamespace', 'NamespacedDummyUserModel'],
[$this->getNamespace($name), $this->rootNamespace(), $this->userProviderModel()],
$stub
);

return $this;
}

/**
* Get the full namespace name for a given class.
*
* @param string $name
* Get the full namespace for a given class, without the class name.
*
* @param string $name
* @return string
*/
protected function getNamespace($name)
Expand All @@ -196,9 +195,8 @@ protected function getNamespace($name)
/**
* Replace the class name for the given stub.
*
* @param string $stub
* @param string $name
*
* @param string $stub
* @param string $name
* @return string
*/
protected function replaceClass($stub, $name)
Expand All @@ -208,6 +206,25 @@ protected function replaceClass($stub, $name)
return str_replace('DummyClass', $class, $stub);
}

/**
* Alphabetically sorts the imports for the given stub.
*
* @param string $stub
* @return string
*/
protected function sortImports($stub)
{
if (preg_match('/(?P<imports>(?:use [^;]+;$\n?)+)/m', $stub, $match)) {
$imports = explode("\n", trim($match['imports']));

sort($imports);

return str_replace(trim($match['imports']), implode("\n", $imports), $stub);
}

return $stub;
}

/**
* Get the desired class name from the input.
*
Expand All @@ -218,6 +235,30 @@ protected function getNameInput()
return trim($this->argument('name'));
}

/**
* Get the root namespace for the class.
*
* @return string
*/
protected function rootNamespace()
{
return $this->laravel->getNamespace();
}

/**
* Get the model for the default guard's user provider.
*
* @return string|null
*/
protected function userProviderModel()
{
$guard = config('auth.defaults.guard');

$provider = config("auth.guards.{$guard}.provider");

return config("auth.providers.{$provider}.model");
}

/**
* Get the console command arguments.
*
Expand Down
12 changes: 12 additions & 0 deletions src/LumenGenerator/Console/stubs/factory.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Faker\Generator as Faker;
use NamespacedDummyModel;

$factory->define(DummyModel::class, function (Faker $faker) {
return [
//
];
});
Loading

0 comments on commit 06e229a

Please sign in to comment.