Files
FendxPHP/fendx-framework/fendx-cli/src/Generator/ControllerGenerator.php

437 lines
14 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Fendx\CLI\Generator;
class ControllerGenerator extends CodeGenerator
{
protected function loadTemplates(): void
{
$this->templates = [
'controller' => $this->getControllerTemplate(),
'method' => $this->getMethodTemplate(),
'api_controller' => $this->getApiControllerTemplate(),
'resource_controller' => $this->getResourceControllerTemplate()
];
}
public function generate(string $name, array $options = []): bool
{
if (!$this->validateName($name)) {
return false;
}
$className = $this->getClassName($name) . 'Controller';
$type = $options['type'] ?? 'basic';
$resource = $options['resource'] ?? null;
$api = $options['api'] ?? false;
$methods = $options['methods'] ?? [];
$subNamespace = 'Controller';
if ($api) {
$subNamespace .= '\\Api';
}
$path = $this->getNamespacePath($subNamespace);
$namespace = $this->getFullNamespace($subNamespace);
if (!$this->createDirectory($path)) {
return false;
}
$content = $this->generateController($className, $namespace, $type, $resource, $methods, $options);
$filePath = $path . '/' . $className . '.php';
if (!$this->createFile($filePath, $content)) {
return false;
}
$this->showMessage('success', "Controller '{$className}' generated successfully!");
// 生成路由提示
$this->showRouteHint($className, $resource, $api);
return true;
}
private function generateController(string $className, string $namespace, string $type, ?string $resource, array $methods, array $options): string
{
switch ($type) {
case 'api':
return $this->generateApiController($className, $namespace, $resource, $methods, $options);
case 'resource':
return $this->generateResourceController($className, $namespace, $resource, $options);
default:
return $this->generateBasicController($className, $namespace, $methods, $options);
}
}
private function generateBasicController(string $className, string $namespace, array $methods, array $options): string
{
$useStatements = [];
$classMethods = '';
if (empty($methods)) {
$methods = ['index'];
}
foreach ($methods as $method) {
$classMethods .= $this->generateMethod($method, $options);
if (in_array($method, ['request', 'response'])) {
$useStatements[] = 'use Fendx\\Web\\Request\\Request;';
$useStatements[] = 'use Fendx\\Web\\Response\\Response;';
}
}
$useStatements = array_unique($useStatements);
$useBlock = empty($useStatements) ? '' : implode("\n", $useStatements) . "\n\n";
return $this->renderTemplate('controller', [
'namespace' => $namespace,
'use_block' => $useBlock,
'class_name' => $className,
'methods' => $classMethods
]);
}
private function generateApiController(string $className, string $namespace, ?string $resource, array $methods, array $options): string
{
$useStatements = [
'use Fendx\\Core\\Annotation\\Controller;',
'use Fendx\\Web\\Annotation\\GetRoute;',
'use Fendx\\Web\\Annotation\\PostRoute;',
'use Fendx\\Web\\Annotation\\PutRoute;',
'use Fendx\\Web\\Annotation\\DeleteRoute;',
'use Fendx\\Web\\Request\\Request;',
'use Fendx\\Web\\Response\\Response;'
];
$classMethods = '';
$resourceName = $resource ?: strtolower(str_replace('Controller', '', $className));
if (empty($methods)) {
$methods = ['index', 'show', 'store', 'update', 'destroy'];
}
foreach ($methods as $method) {
$classMethods .= $this->generateApiMethod($method, $resourceName, $options);
}
return $this->renderTemplate('api_controller', [
'namespace' => $namespace,
'use_block' => implode("\n", $useStatements) . "\n\n",
'class_name' => $className,
'resource_name' => $resourceName,
'methods' => $classMethods
]);
}
private function generateResourceController(string $className, string $namespace, ?string $resource, array $options): string
{
$useStatements = [
'use Fendx\\Core\\Annotation\\Controller;',
'use Fendx\\Web\\Annotation\\GetRoute;',
'use Fendx\\Web\\Annotation\\PostRoute;',
'use Fendx\\Web\\Annotation\\PutRoute;',
'use Fendx\\Web\\Annotation\\DeleteRoute;',
'use Fendx\\Web\\Request\\Request;',
'use Fendx\\Web\\Response\\Response;'
];
$resourceName = $resource ?: strtolower(str_replace('Controller', '', $className));
$modelClass = $this->getClassName($resourceName);
$modelNamespace = $this->getFullNamespace('Model');
$classMethods = $this->generateResourceMethods($resourceName, $modelClass, $modelNamespace, $options);
return $this->renderTemplate('resource_controller', [
'namespace' => $namespace,
'use_block' => implode("\n", $useStatements) . "\n\n",
'class_name' => $className,
'resource_name' => $resourceName,
'model_class' => $modelClass,
'model_namespace' => $modelNamespace,
'methods' => $classMethods
]);
}
private function generateMethod(string $method, array $options): string
{
$methodName = $method;
$parameters = '';
$body = '';
$docBlock = '';
switch ($method) {
case 'index':
$docBlock = $this->generateDocBlock([], 'array');
$body = ' // TODO: Implement index method' . "\n" . ' return [];';
break;
case 'show':
$docBlock = $this->generateDocBlock(['id' => 'int'], 'array');
$parameters = 'int $id';
$body = ' // TODO: Implement show method' . "\n" . ' return [];';
break;
case 'create':
$docBlock = $this->generateDocBlock([], 'array');
$body = ' // TODO: Implement create method' . "\n" . ' return [];';
break;
case 'store':
$docBlock = $this->generateDocBlock(['request' => 'Request'], 'array');
$parameters = 'Request $request';
$useStatements[] = 'use Fendx\\Web\\Request\\Request;';
$body = ' // TODO: Implement store method' . "\n" . ' return [];';
break;
case 'edit':
$docBlock = $this->generateDocBlock(['id' => 'int'], 'array');
$parameters = 'int $id';
$body = ' // TODO: Implement edit method' . "\n" . ' return [];';
break;
case 'update':
$docBlock = $this->generateDocBlock(['id' => 'int', 'request' => 'Request'], 'array');
$parameters = 'int $id, Request $request';
$useStatements[] = 'use Fendx\\Web\\Request\\Request;';
$body = ' // TODO: Implement update method' . "\n" . ' return [];';
break;
case 'destroy':
$docBlock = $this->generateDocBlock(['id' => 'int'], 'bool');
$parameters = 'int $id';
$body = ' // TODO: Implement destroy method' . "\n" . ' return true;';
break;
default:
$docBlock = $this->generateDocBlock([], 'mixed');
$body = ' // TODO: Implement ' . $method . ' method' . "\n" . ' return null;';
}
return $this->renderTemplate('method', [
'doc_block' => $docBlock,
'method_name' => $methodName,
'parameters' => $parameters,
'body' => $body
]);
}
private function generateApiMethod(string $method, string $resourceName, array $options): string
{
$methodName = $method;
$route = '';
$parameters = '';
$body = '';
$httpMethod = '';
switch ($method) {
case 'index':
$route = "/{$resourceName}";
$httpMethod = 'GetRoute';
$docBlock = $this->generateDocBlock([], 'array');
$body = ' $data = []; // TODO: Fetch data from database' . "\n" . ' return Response::success($data);';
break;
case 'show':
$route = "/{$resourceName}/{id}";
$httpMethod = 'GetRoute';
$parameters = 'int $id';
$docBlock = $this->generateDocBlock(['id' => 'int'], 'array');
$body = ' $data = []; // TODO: Fetch item by id' . "\n" . ' return Response::success($data);';
break;
case 'store':
$route = "/{$resourceName}";
$httpMethod = 'PostRoute';
$parameters = 'Request $request';
$docBlock = $this->generateDocBlock(['request' => 'Request'], 'array');
$body = ' $data = $request->all();' . "\n" . ' // TODO: Store data to database' . "\n" . ' return Response::success($data, \'Resource created successfully\');';
break;
case 'update':
$route = "/{$resourceName}/{id}";
$httpMethod = 'PutRoute';
$parameters = 'int $id, Request $request';
$docBlock = $this->generateDocBlock(['id' => 'int', 'request' => 'Request'], 'array');
$body = ' $data = $request->all();' . "\n" . ' // TODO: Update item by id' . "\n" . ' return Response::success($data, \'Resource updated successfully\');';
break;
case 'destroy':
$route = "/{$resourceName}/{id}";
$httpMethod = 'DeleteRoute';
$parameters = 'int $id';
$docBlock = $this->generateDocBlock(['id' => 'int'], 'array');
$body = ' // TODO: Delete item by id' . "\n" . ' return Response::success(null, \'Resource deleted successfully\');';
break;
default:
return '';
}
return <<<PHP
#[{$httpMethod}('{$route}')]
public function {$methodName}({$parameters}): array
{
{$body}
}
PHP;
}
private function generateResourceMethods(string $resourceName, string $modelClass, string $modelNamespace, array $options): string
{
$methods = '';
// Index method
$methods .= <<<PHP
#[GetRoute('/{$resourceName}')]
public function index(): array
{
\$items = {$modelClass}::all();
return Response::success(\$items);
}
PHP;
// Show method
$methods .= <<<PHP
#[GetRoute('/{$resourceName}/{id}')]
public function show(int \$id): array
{
\$item = {$modelClass}::find(\$id);
if (!\$item) {
return Response::error(404, '{$modelClass} not found');
}
return Response::success(\$item);
}
PHP;
// Store method
$methods .= <<<PHP
#[PostRoute('/{$resourceName}')]
public function store(Request \$request): array
{
\$data = \$request->all();
\$item = {$modelClass}::create(\$data);
return Response::success(\$item, '{$modelClass} created successfully');
}
PHP;
// Update method
$methods .= <<<PHP
#[PutRoute('/{$resourceName}/{id}')]
public function update(int \$id, Request \$request): array
{
\$item = {$modelClass}::find(\$id);
if (!\$item) {
return Response::error(404, '{$modelClass} not found');
}
\$data = \$request->all();
\$item->update(\$data);
return Response::success(\$item, '{$modelClass} updated successfully');
}
PHP;
// Destroy method
$methods .= <<<PHP
#[DeleteRoute('/{$resourceName}/{id}')]
public function destroy(int \$id): array
{
\$item = {$modelClass}::find(\$id);
if (!\$item) {
return Response::error(404, '{$modelClass} not found');
}
\$item->delete();
return Response::success(null, '{$modelClass} deleted successfully');
}
PHP;
return $methods;
}
private function showRouteHint(string $className, ?string $resource, bool $api): void
{
$controllerName = str_replace('Controller', '', $className);
$this->output->writeln('');
$this->output->writeln('<comment>Route registration hint:</comment>');
if ($api) {
$this->output->writeln("Add this to your routes configuration:");
$this->output->writeln("<info>\$router->mount('/api', function(\$router) {");
$this->output->writeln(" \$router->registerController(new {$this->getFullNamespace('Controller\\Api')}\\{$className}());");
$this->output->writeln("});</info>");
} else {
$this->output->writeln("Add this to your routes configuration:");
$this->output->writeln("<info>\$router->registerController(new {$this->getFullNamespace('Controller')}\\{$className}());</info>");
}
}
private function getControllerTemplate(): string
{
return <<<PHP
<?php
declare(strict_types=1);
namespace {{namespace}};
{{use_block}}class {{class_name}}
{
{{methods}}
}
PHP;
}
private function getMethodTemplate(): string
{
return <<<PHP
{{doc_block}}
public function {{method_name}}({{parameters}})
{
{{body}}
}
PHP;
}
private function getApiControllerTemplate(): string
{
return <<<PHP
<?php
declare(strict_types=1);
namespace {{namespace}};
{{use_block}}#[Controller('/api')]
class {{class_name}}
{
{{methods}}
}
PHP;
}
private function getResourceControllerTemplate(): string
{
return <<<PHP
<?php
declare(strict_types=1);
namespace {{namespace}};
{{use_block}}#[Controller('/api')]
class {{class_name}}
{
{{methods}}
}
PHP;
}
}