Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Laravel/ApiPlatformProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,7 @@ public function register(): void
Console\InstallCommand::class,
Console\Maker\MakeStateProcessorCommand::class,
Console\Maker\MakeStateProviderCommand::class,
Console\Maker\MakeFilterCommand::class,
OpenApiCommand::class,
]);
}
Expand Down
29 changes: 11 additions & 18 deletions src/Laravel/Console/Maker/AbstractMakeStateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace ApiPlatform\Laravel\Console\Maker;

use ApiPlatform\Laravel\Console\Maker\Utils\AppServiceProviderTagger;
use ApiPlatform\Laravel\Console\Maker\Utils\StateAppServiceProviderTagger;
use ApiPlatform\Laravel\Console\Maker\Utils\StateTemplateGenerator;
use ApiPlatform\Laravel\Console\Maker\Utils\StateTypeEnum;
use ApiPlatform\Laravel\Console\Maker\Utils\SuccessMessageTrait;
Expand All @@ -28,7 +28,7 @@ abstract class AbstractMakeStateCommand extends Command
public function __construct(
private readonly Filesystem $filesystem,
private readonly StateTemplateGenerator $stateTemplateGenerator,
private readonly AppServiceProviderTagger $appServiceProviderTagger,
private readonly StateAppServiceProviderTagger $stateAppServiceProviderTagger,
) {
parent::__construct();
}
Expand All @@ -38,7 +38,13 @@ public function __construct(
*/
public function handle(): int
{
$stateName = $this->askForStateName();
$stateType = $this->getStateType()->name;
$stateName = $this->ask(\sprintf('Choose a class name for your state %s (e.g. <fg=yellow>AwesomeState%s</>)', strtolower($stateType), ucfirst($stateType)));
if (null === $stateName || '' === $stateName) {
$this->error('[ERROR] The name argument cannot be blank.');

return self::FAILURE;
}

$directoryPath = base_path('app/State/');
$this->filesystem->ensureDirectoryExists($directoryPath);
Expand All @@ -57,25 +63,12 @@ public function handle(): int
return self::FAILURE;
}

$this->appServiceProviderTagger->addTagToServiceProvider($stateName, $this->getStateType());
$this->stateAppServiceProviderTagger->addTagToServiceProvider($stateName, $this->getStateType());

$this->writeSuccessMessage($filePath, $this->getStateType());
$this->writeSuccessMessage($filePath, \sprintf('State %s', ucfirst($this->getStateType()->name)));

return self::SUCCESS;
}

protected function askForStateName(): string
{
do {
$stateType = $this->getStateType()->name;
$stateName = $this->ask(\sprintf('Choose a class name for your state %s (e.g. <fg=yellow>AwesomeState%s</>)', strtolower($stateType), ucfirst($stateType)));
if (empty($stateName)) {
$this->error('[ERROR] This value cannot be blank.');
}
} while (empty($stateName));

return $stateName;
}

abstract protected function getStateType(): StateTypeEnum;
}
73 changes: 73 additions & 0 deletions src/Laravel/Console/Maker/MakeFilterCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Laravel\Console\Maker;

use ApiPlatform\Laravel\Console\Maker\Utils\FilterAppServiceProviderTagger;
use ApiPlatform\Laravel\Console\Maker\Utils\FilterTemplateGenerator;
use ApiPlatform\Laravel\Console\Maker\Utils\SuccessMessageTrait;
use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Filesystem\Filesystem;

final class MakeFilterCommand extends Command
{
use SuccessMessageTrait;

protected $signature = 'make:filter';
protected $description = 'Creates an API Platform filter';

public function __construct(
private readonly Filesystem $filesystem,
private readonly FilterTemplateGenerator $filterTemplateGenerator,
private readonly FilterAppServiceProviderTagger $filterAppServiceProviderTagger,
) {
parent::__construct();
}

/**
* @throws FileNotFoundException
*/
public function handle(): int
{
$nameArgument = $this->ask('Choose a class name for your filter (e.g. <fg=yellow>AwesomeFilter</>)');
if (null === $nameArgument || '' === $nameArgument) {
$this->error('[ERROR] The name argument cannot be blank.');

return self::FAILURE;
}

$directoryPath = base_path('app/Filter/');
$this->filesystem->ensureDirectoryExists($directoryPath);

$filePath = $this->filterTemplateGenerator->getFilePath($directoryPath, $nameArgument);
if ($this->filesystem->exists($filePath)) {
$this->error(\sprintf('[ERROR] The file "%s" can\'t be generated because it already exists.', $filePath));

return self::FAILURE;
}

$this->filterTemplateGenerator->generate($filePath, $nameArgument);
if (!$this->filesystem->exists($filePath)) {
$this->error(\sprintf('[ERROR] The file "%s" could not be created.', $filePath));

return self::FAILURE;
}

$this->filterAppServiceProviderTagger->addTagToServiceProvider($nameArgument);

$this->writeSuccessMessage($filePath, 'Eloquent Filter');

return self::SUCCESS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace {{ namespace }};

use ApiPlatform\Metadata\Parameter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

final class {{ class_name }} implements FilterInterface
{
/**
* @param Builder<Model> $builder
* @param array<string, mixed> $context
*/
public function apply(Builder $builder, mixed $values, Parameter $parameter, array $context = []): Builder
{
// TODO: make your awesome query using the $builder
// return $builder->
}
}
74 changes: 74 additions & 0 deletions src/Laravel/Console/Maker/Utils/FilterAppServiceProviderTagger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Laravel\Console\Maker\Utils;

use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Filesystem\Filesystem;

final readonly class FilterAppServiceProviderTagger
{
/** @var string */
private const APP_SERVICE_PROVIDER_PATH = 'Providers/AppServiceProvider.php';

/** @var string */
private const FILTER_INTERFACE_USE_STATEMENT = 'use ApiPlatform\Laravel\Eloquent\Filter\FilterInterface;';

public function __construct(private Filesystem $filesystem)
{
}

/**
* @throws FileNotFoundException
*/
public function addTagToServiceProvider(string $filterName): void
{
$appServiceProviderPath = app_path(self::APP_SERVICE_PROVIDER_PATH);
if (!$this->filesystem->exists($appServiceProviderPath)) {
throw new \RuntimeException('The AppServiceProvider is missing!');
}

$serviceProviderContent = $this->filesystem->get($appServiceProviderPath);

$this->addUseStatements($serviceProviderContent, $filterName);
$this->addTag($serviceProviderContent, $filterName, $appServiceProviderPath);
}

private function addUseStatements(string &$content, string $filterName): void
{
$useStatements = [self::FILTER_INTERFACE_USE_STATEMENT, \sprintf('use App\\Filter\\%s;', $filterName)];
$statementsString = implode("\n", $useStatements)."\n";

$content = preg_replace(
'/^(namespace\s[^;]+;\s*)/m',
"$1\n$statementsString",
$content,
1
);
}

private function addTag(string &$content, string $filterName, string $serviceProviderPath): void
{
$tagStatement = \sprintf("\n\n\t\t\$this->app->tag(%s::class, FilterInterface::class);", $filterName);

if (!str_contains($content, $tagStatement)) {
$content = preg_replace(
'/(public function register\(\)[^{]*{)(.*?)(\s*}\s*})/s',
"$1$2$tagStatement$3",
$content
);

$this->filesystem->put($serviceProviderPath, $content);
}
}
}
50 changes: 50 additions & 0 deletions src/Laravel/Console/Maker/Utils/FilterTemplateGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Laravel\Console\Maker\Utils;

use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Filesystem\Filesystem;

final readonly class FilterTemplateGenerator
{
public function __construct(private Filesystem $filesystem)
{
}

public function getFilePath(string $directoryPath, string $filterFileName): string
{
return \sprintf('%s%s.php', $directoryPath, $filterFileName);
}

/**
* @throws FileNotFoundException
*/
public function generate(string $pathLink, string $filterName): void
{
$namespace = 'App\\Filter';
$template = $this->filesystem->get(
\sprintf(
'%s/Resources/skeleton/EloquentFilter.php.tpl',
\dirname(__DIR__),
)
);

$content = strtr($template, [
'{{ namespace }}' => $namespace,
'{{ class_name }}' => $filterName,
]);

$this->filesystem->put($pathLink, $content);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Filesystem\Filesystem;

final readonly class AppServiceProviderTagger
final readonly class StateAppServiceProviderTagger
{
/** @var string */
private const APP_SERVICE_PROVIDER_PATH = 'Providers/AppServiceProvider.php';
Expand Down
6 changes: 2 additions & 4 deletions src/Laravel/Console/Maker/Utils/SuccessMessageTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@

trait SuccessMessageTrait
{
private function writeSuccessMessage(string $filePath, StateTypeEnum $stateTypeEnum): void
private function writeSuccessMessage(string $filePath, string $customText): void
{
$stateText = strtolower($stateTypeEnum->name);

$this->newLine();
$this->line(' <bg=green;fg=white> </>');
$this->line(' <bg=green;fg=white> Success! </>');
$this->line(' <bg=green;fg=white> </>');
$this->newLine();
$this->line('<fg=blue>created</>: <fg=white;options=underscore>'.$filePath.'</>');
$this->newLine();
$this->line("Next: Open your new state $stateText class and start customizing it.");
$this->line("Next: Open your new $customText class and start customizing it.");
}
}
Loading
Loading