Commit 54f3002f authored by Dillenn Terumalai's avatar Dillenn Terumalai
Browse files

// WIP

parent 8988fdc1
......@@ -43,6 +43,14 @@ class InterfaceMakeCommand extends GeneratorCommand
$stub = '/stubs/interface.model.stub';
}
if ($this->option('base')) {
$stub = '/stubs/interface.base.stub';
}
if ($this->option('extend')) {
$stub = '/stubs/interface.extend.stub';
}
$stub = $stub ?? '/stubs/interface.plain.stub';
return $this->resolveStubPath($stub);
......@@ -83,15 +91,15 @@ class InterfaceMakeCommand extends GeneratorCommand
*/
protected function buildClass($name)
{
$controllerNamespace = $this->getNamespace($name);
$replace = [];
if ($this->option('model')) {
$replace = $this->buildModelReplacements($replace);
}
$replace["use {$controllerNamespace}\Controller;\n"] = '';
if ($this->option('extend')) {
$replace['{{ interface }}'] = $this->parseInterface($this->option('extend'));
}
return str_replace(
array_keys($replace), array_values($replace), parent::buildClass($name)
......@@ -141,6 +149,23 @@ class InterfaceMakeCommand extends GeneratorCommand
return $this->qualifyModel($model);
}
/**
* Get the fully-qualified interface name.
*
* @param string $interface
* @return string
*
* @throws InvalidArgumentException
*/
protected function parseInterface(string $interface)
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $interface)) {
throw new InvalidArgumentException('Interface name contains invalid characters.');
}
return $this->qualifyClass($interface);
}
/**
* Get the console command options.
*
......@@ -149,7 +174,9 @@ class InterfaceMakeCommand extends GeneratorCommand
protected function getOptions()
{
return [
['force', null, InputOption::VALUE_NONE, 'Create the interface even if the interface already exists'],
['force', null, InputOption::VALUE_NONE, 'Create the interface even if the interface already exists.'],
['base', null, InputOption::VALUE_NONE, 'Create the generic base repository interface.'],
['extend', 'e', InputOption::VALUE_OPTIONAL, 'Generate a repository interface which extends the given interface.'],
['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a repository interface for the given model.']
];
}
......
<?php
namespace Dterumal\RepositoryArtisan\Console;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;
class RepositoryControllerMakeCommand extends GeneratorCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $name = 'make:repository-controller';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new repository controller';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Class';
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub(): string
{
$stub = '/stubs/controller.repository.stub';
return $this->resolveStubPath($stub);
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath(string $stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Http\Controllers';
}
/**
* Build the class with the given name.
*
* Remove the base controller import if we are already in the base namespace.
*
* @param string $name
* @return string
* @throws FileNotFoundException
*/
protected function buildClass($name)
{
$controllerNamespace = $this->getNamespace($name);
$replace = [];
$replace = $this->buildModelAndRequestsAndInterfaceReplacements($replace);
$replace["use {$controllerNamespace}\Controller;\n"] = '';
return str_replace(
array_keys($replace), array_values($replace), parent::buildClass($name)
);
}
/**
* Build the model replacement values.
*
* @param array $replace
* @return array
*/
protected function buildModelAndRequestsAndInterfaceReplacements(array $replace)
{
$modelClass = $this->parseModel($this->option('model'));
$interface = $this->parseInterface($this->option('interface'));
$storeRequestClass = 'App\Http\Requests\Store'.$this->option('model').'Request';
$updateRequestClass = 'App\Http\Requests\Update'.$this->option('model').'Request';
if (! class_exists($modelClass)) {
if ($this->confirm("A {$modelClass} model does not exist. Do you want to generate it?", true)) {
$this->call('make:model', ['name' => $modelClass]);
}
}
if (! interface_exists($interface)) {
if ($this->confirm("A {$interface} interface does not exist. Do you want to generate it?", true)) {
$this->call('make:interface', [
'name' => $interface,
'--model' => $modelClass,
'--extend' => 'BaseRepository'
]);
}
}
if (! class_exists($storeRequestClass)) {
if ($this->confirm("A {$storeRequestClass} request does not exist. Do you want to generate it?", true)) {
$this->call('make:request', ['name' => $storeRequestClass]);
}
}
if (! class_exists($updateRequestClass)) {
if ($this->confirm("A {$updateRequestClass} request does not exist. Do you want to generate it?", true)) {
$this->call('make:request', ['name' => $updateRequestClass]);
}
}
return array_merge($replace, [
'{{ namespacedModel }}' => $modelClass,
'{{namespacedModel}}' => $modelClass,
'{{ model }}' => class_basename($modelClass),
'{{model}}' => class_basename($modelClass),
'{{ modelVariable }}' => lcfirst(class_basename($modelClass)),
'{{modelVariable}}' => lcfirst(class_basename($modelClass)),
'{{ modelPlural }}' => Str::plural(lcfirst(class_basename($modelClass))),
'{{modelPlural}}' => Str::plural(lcfirst(class_basename($modelClass))),
'{{ namespacedStoreRequest }}' => $storeRequestClass,
'{{namespacedStoreRequest}}' => $storeRequestClass,
'{{ storeRequest }}' => class_basename($storeRequestClass),
'{{storeRequest}}' => class_basename($storeRequestClass),
'{{ namespacedUpdateRequest }}' => $updateRequestClass,
'{{namespacedUpdateRequest}}' => $updateRequestClass,
'{{ updateRequest }}' => class_basename($updateRequestClass),
'{{updateRequest}}' => class_basename($updateRequestClass),
'{{ namespacedInterface }}' => $interface,
'{{namespacedInterface}}' => $interface,
'{{ interface }}' => class_basename($interface),
'{{interface}}' => class_basename($interface),
]);
}
/**
* Get the fully-qualified model class name.
*
* @param string $model
* @return string
*
* @throws InvalidArgumentException
*/
protected function parseModel(string $model)
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
throw new InvalidArgumentException('Model name contains invalid characters.');
}
return $this->qualifyModel($model);
}
/**
* Get the fully-qualified interface name.
*
* @param string $interface
* @return string
*
* @throws InvalidArgumentException
*/
protected function parseInterface(string $interface)
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $interface)) {
throw new InvalidArgumentException('Interface name contains invalid characters.');
}
return $this->qualifyInterface($interface);
}
/**
* Qualify the given model class base name.
*
* @param string $model
* @return string
*/
protected function qualifyInterface(string $model)
{
$model = ltrim($model, '\\/');
$model = str_replace('/', '\\', $model);
$rootNamespace = $this->rootNamespace();
if (Str::startsWith($model, $rootNamespace)) {
return $model;
}
return is_dir(app_path('Contracts'))
? $rootNamespace.'Contracts\\'.$model
: $rootNamespace.$model;
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['force', null, InputOption::VALUE_NONE, 'Create the interface even if the interface already exists.'],
['interface', 'i', InputOption::VALUE_REQUIRED, 'The given interface to use in the controller'],
['model', 'm', InputOption::VALUE_REQUIRED, 'The given model to use in the controller.']
];
}
}
......@@ -2,7 +2,6 @@
namespace Dterumal\RepositoryArtisan\Console;
use Illuminate\Console\Command;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Support\Str;
......@@ -51,6 +50,10 @@ class RepositoryMakeCommand extends GeneratorCommand
$stub = str_replace('.stub', '.interface.stub', $stub);
}
if ($this->option('base') && ! is_null($stub) && $this->option('model')) {
$stub = str_replace('.stub', '.base.stub', $stub);
}
$stub = $stub ?? '/stubs/repository.plain.stub';
return $this->resolveStubPath($stub);
......@@ -91,8 +94,6 @@ class RepositoryMakeCommand extends GeneratorCommand
*/
protected function buildClass($name)
{
$repositoryNamespace = $this->getNamespace($name);
$replace = [];
if ($this->option('model')) {
......@@ -103,7 +104,9 @@ class RepositoryMakeCommand extends GeneratorCommand
$replace = $this->buildInterfaceReplacements($replace);
}
$replace["use {$repositoryNamespace}\Controller;\n"] = '';
if ($this->option('base')) {
$replace = $this->buildBaseInterfaceReplacements($replace);
}
return str_replace(
array_keys($replace), array_values($replace), parent::buildClass($name)
......@@ -149,6 +152,45 @@ class RepositoryMakeCommand extends GeneratorCommand
]);
}
/**
* Build the model replacement values.
*
* @param array $replace
* @return array
*/
protected function buildBaseInterfaceReplacements(array $replace)
{
$interfaceClass = 'BaseRepository';
$modelClass = null;
if ($this->option('model')) {
$modelClass = $this->parseModel($this->option('model'));
}
if (! interface_exists($interfaceClass)) {
if ($this->confirm("A {$interfaceClass} interface does not exist. Do you want to generate it?", true)) {
if ($modelClass) {
$this->call('make:interface', [
'name' => $interfaceClass,
'--model' => $modelClass
]);
} else {
$this->call('make:interface', [
'name' => $interfaceClass
]);
}
}
}
return array_merge($replace, [
'{{ namespacedInterface }}' => $interfaceClass,
'{{namespacedInterface}}' => $interfaceClass,
'{{ interface }}' => class_basename($interfaceClass),
'{{interface}}' => class_basename($interfaceClass)
]);
}
/**
* Build the model replacement values.
*
......@@ -241,6 +283,7 @@ class RepositoryMakeCommand extends GeneratorCommand
{
return [
['force', null, InputOption::VALUE_NONE, 'Create the repository even if the repository already exists.'],
['base', null, InputOption::VALUE_NONE, 'Create a repository class which implements the base repository interface.'],
['interface', 'i', InputOption::VALUE_OPTIONAL, 'Generate a repository class which implements the given interface.'],
['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a repository class for the given model.']
];
......
<?php
namespace {{ namespace }};
use {{ namespacedInterface }};
use {{ namespacedStoreRequest }};
use {{ namespacedUpdateRequest }};
use {{ namespacedModel }};
use Illuminate\Http\Request;
use Inertia\Inertia;
class {{ class }} extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse|\Inertia\Response
*/
public function index(Request $request)
{
return $request->wantsJson()
? response()->json(app({{ interface }}::class)->get())
: Inertia::render('Path/To/Page', [
'{{ modelPlural }}' => app({{ interface }}::class)->all($request),
]);
}
/**
* Store a newly created resource in storage.
*
* @param \{{ namespacedStoreRequest }} $request
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
public function store({{ storeRequest }} $request)
{
$validated = $request->validated();
${{ modelVariable }} = app({{ interface }}::class)->store($validated);
return $request->wantsJson()
? response()->json(${{ modelVariable }})
: back()->with('{{ modelVariable }}-stored');
}
/**
* Display the specified resource.
*
* @param \Illuminate\Http\Request $request
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return \Illuminate\Http\JsonResponse|\Inertia\Response
*/
public function show(Request $request, {{ model }} ${{ modelVariable }})
{
return $request->wantsJson()
? response()->json(app({{ interface }}::class)->find(${{ modelVariable }}))
: Inertia::render('Path/To/Page', [
'{{ modelVariable }}' => app({{ interface }}::class)->find(${{ modelVariable }})
]);
}
/**
* Update the specified resource in storage.
*
* @param \{{ namespacedUpdateRequest }} $request
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
public function update({{ updateRequest }} $request, {{ model }} ${{ modelVariable }})
{
$validated = $request->validated();
${{ modelVariable }} = app({{ interface }}::class)->update($validated, ${{ modelVariable }});
return $request->wantsJson()
? response()->json(${{ modelVariable }})
: back()->with('{{ modelVariable }}-updated');
}
/**
* Remove the specified resource from storage.
*
* @param \Illuminate\Http\Request $request
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
public function destroy(Request $request, {{ model }} ${{ modelVariable }})
{
if (${{ modelVariable }}->trashed()) {
$isDeleted = app({{ interface }}::class)->destroy(${{ modelVariable }});
return $request->wantsJson()
? response()->json($isDeleted)
: back()->with('{{ modelVariable }}-removed');
}
$isDeleted = app({{ interface }}::class)->delete(${{ modelVariable }});
return $request->wantsJson()
? response()->json($isDeleted)
: back()->with('{{ modelVariable }}-deleted');
}
}
\ No newline at end of file
<?php
namespace {{ namespace }};
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
interface BaseRepository
{
/**
* Returns a paginated listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function all(Request $request): LengthAwarePaginator;
/**
* Returns a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get(Request $request): Collection;
/**
* Store a newly created resource in storage.
*
* @param array $request
* @return \Illuminate\Database\Eloquent\Model
*/
public function store(array $request): Model;
/**
* Display the specified resource.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function find(Model $model): Model;
/**
* Update the specified resource in storage.
*
* @param array $request
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function update(array $request, Model $model): Model;
/**
* Delete the specified resource in storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return bool
*/
public function delete(Model $model): bool;
/**
* Remove the specified resource from storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return bool
*/
public function destroy(Model $model): bool;
}
\ No newline at end of file
<?php
namespace {{ namespace }};
interface {{ class }} extends {{ interface }}
{
//
}
\ No newline at end of file
......@@ -4,15 +4,26 @@ namespace {{ namespace }};
use {{ namespacedModel }};
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request;
interface {{ class }}
{
/**
* Returns a paginated listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator;
*/
public function all(Request $request): LengthAwarePaginator;
/**
* Returns a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Database\Eloquent\Collection
*/
public function all(): Collection;
public function get(Request $request): Collection;
/**
* Store a newly created resource in storage.
......@@ -39,6 +50,14 @@ interface {{ class }}
*/
public function update(array $request, {{ model }} ${{ modelVariable }}): {{ model }};
/**
* Delete the specified resource in storage.
*