update project
This commit is contained in:
+84
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "orchestra/canvas-core",
|
||||
"description": "Code Generators Builder for Laravel Applications and Packages",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
},
|
||||
{
|
||||
"name": "Mior Muhammad Zaki",
|
||||
"email": "crynobone@gmail.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Canvas\\Core\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Canvas\\Core\\Tests\\": "tests/",
|
||||
"Workbench\\App\\": "workbench/app/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"composer-runtime-api": "^2.2",
|
||||
"composer/semver": "^3.0",
|
||||
"illuminate/console": "^13.0",
|
||||
"illuminate/support": "^13.0",
|
||||
"orchestra/sidekick": "~1.1.23|~1.2.20"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/framework": "^13.0",
|
||||
"laravel/pint": "^1.24",
|
||||
"mockery/mockery": "^1.6.10",
|
||||
"orchestra/testbench-core": "^11.0",
|
||||
"phpstan/phpstan": "^2.1.17",
|
||||
"phpunit/phpunit": "^11.5.50|^12.5.8|^13.0.0",
|
||||
"symfony/yaml": "^7.4|^8.0"
|
||||
},
|
||||
"config": {
|
||||
"audit": {
|
||||
"ignore": {
|
||||
"GHSA-78fx-h6xr-vch4": "Affected component is not in use"
|
||||
}
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"support": {
|
||||
"issues": "https://github.com/orchestral/canvas/issues"
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Orchestra\\Canvas\\Core\\LaravelServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@clear",
|
||||
"@prepare"
|
||||
],
|
||||
"clear": "@php vendor/bin/testbench package:purge-skeleton --ansi",
|
||||
"prepare": "@php vendor/bin/testbench package:discover --ansi",
|
||||
"lint": [
|
||||
"@php vendor/bin/pint --ansi --parallel",
|
||||
"@php vendor/bin/phpstan analyse --verbose --ansi"
|
||||
],
|
||||
"test": "@php vendor/bin/phpunit -c ./ --color",
|
||||
"ci": [
|
||||
"@composer audit",
|
||||
"@prepare",
|
||||
"@lint",
|
||||
"@test"
|
||||
]
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Actions;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
class DumpComposerAutoloads
|
||||
{
|
||||
/**
|
||||
* Construct a new action.
|
||||
*/
|
||||
public function __construct(
|
||||
protected string $workingPath
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Handle the action.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
app('canvas.composer')
|
||||
->setWorkingPath($this->workingPath)
|
||||
->dumpAutoloads();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Actions;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
class ModifyComposer
|
||||
{
|
||||
/**
|
||||
* Construct a new action.
|
||||
*/
|
||||
public function __construct(
|
||||
protected string $workingPath
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Handle the action.
|
||||
*
|
||||
* @param callable(array):array $callback
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function handle(callable $callback): void
|
||||
{
|
||||
$composerFile = join_paths($this->workingPath, 'composer.json');
|
||||
|
||||
if (! file_exists($composerFile)) {
|
||||
throw new RuntimeException("Unable to locate `composer.json` file at [{$this->workingPath}].");
|
||||
}
|
||||
|
||||
$composer = json_decode((string) file_get_contents($composerFile), true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
$composer = \call_user_func($callback, $composer);
|
||||
|
||||
file_put_contents(
|
||||
$composerFile,
|
||||
json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Actions;
|
||||
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Orchestra\Sidekick\Env;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
class WriteEnvironmentVariables
|
||||
{
|
||||
/**
|
||||
* Construct a new action instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public Filesystem $filesystem,
|
||||
public string|false|null $filename,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Handle the action.
|
||||
*
|
||||
* @param array<string, mixed> $variables
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
public function handle(array $variables, bool $overwrite = false): void
|
||||
{
|
||||
if (! \is_string($this->filename)) {
|
||||
throw new FileNotFoundException;
|
||||
}
|
||||
|
||||
$this->writeVariables($variables, $this->filename, $overwrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an array of key-value pairs to the environment file.
|
||||
*
|
||||
* @laravel-overrides
|
||||
*
|
||||
* @param array<string, mixed> $variables
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
protected function writeVariables(array $variables, string $filename, bool $overwrite = false): void
|
||||
{
|
||||
if ($this->filesystem->missing($filename)) {
|
||||
throw new FileNotFoundException("The file [{$filename}] does not exist.");
|
||||
}
|
||||
|
||||
$lines = explode(PHP_EOL, $this->filesystem->get($filename));
|
||||
|
||||
foreach ($variables as $key => $value) {
|
||||
$lines = $this->addVariableToEnvContents($key, $value, $lines, $overwrite);
|
||||
}
|
||||
|
||||
$this->filesystem->put($filename, implode(PHP_EOL, $lines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a variable to the environment file contents.
|
||||
*
|
||||
* @laravel-overrides
|
||||
*/
|
||||
protected function addVariableToEnvContents(string $key, mixed $value, array $envLines, bool $overwrite): array
|
||||
{
|
||||
$prefix = explode('_', $key)[0].'_';
|
||||
$lastPrefixIndex = -1;
|
||||
|
||||
$shouldQuote = \is_string($value) && preg_match('/^[a-zA-z0-9]+$/', $value) === 0;
|
||||
|
||||
$lineToAddVariations = [
|
||||
$key.'='.(\is_string($value) ? '"'.addslashes($value).'"' : Env::encode($value)),
|
||||
$key.'='.(\is_string($value) ? "'".addslashes($value)."'" : Env::encode($value)),
|
||||
$key.'='.Env::encode($value),
|
||||
];
|
||||
|
||||
$lineToAdd = $shouldQuote ? $lineToAddVariations[0] : $lineToAddVariations[2];
|
||||
|
||||
if ($value === '') {
|
||||
$lineToAdd = $key.'=';
|
||||
}
|
||||
|
||||
foreach ($envLines as $index => $line) {
|
||||
if (str_starts_with($line, $prefix)) {
|
||||
$lastPrefixIndex = $index;
|
||||
}
|
||||
|
||||
if (\in_array($line, $lineToAddVariations)) {
|
||||
// This exact line already exists, so we don't need to add it again.
|
||||
return $envLines;
|
||||
}
|
||||
|
||||
if ($line === $key.'=') {
|
||||
// If the value is empty, we can replace it with the new value.
|
||||
$envLines[$index] = $lineToAdd;
|
||||
|
||||
return $envLines;
|
||||
}
|
||||
|
||||
if (str_starts_with($line, $key.'=')) {
|
||||
if (! $overwrite) {
|
||||
return $envLines;
|
||||
}
|
||||
|
||||
$envLines[$index] = $lineToAdd;
|
||||
|
||||
return $envLines;
|
||||
}
|
||||
}
|
||||
|
||||
if ($lastPrefixIndex === -1) {
|
||||
if (\count($envLines) && $envLines[\count($envLines) - 1] !== '') {
|
||||
$envLines[] = '';
|
||||
}
|
||||
|
||||
return array_merge($envLines, [$lineToAdd]);
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
\array_slice($envLines, 0, $lastPrefixIndex + 1),
|
||||
[$lineToAdd],
|
||||
\array_slice($envLines, $lastPrefixIndex + 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Commands;
|
||||
|
||||
use Illuminate\Console\GeneratorCommand as Command;
|
||||
use Orchestra\Canvas\Core\Concerns;
|
||||
use Orchestra\Canvas\Core\Contracts\GeneratesCode;
|
||||
|
||||
/**
|
||||
* @property string|null $name
|
||||
* @property string|null $description
|
||||
*/
|
||||
abstract class GeneratorCommand extends Command implements GeneratesCode
|
||||
{
|
||||
use Concerns\CodeGenerator;
|
||||
use Concerns\TestGenerator;
|
||||
use Concerns\UsesGeneratorOverrides;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function qualifyModel(string $model)
|
||||
{
|
||||
return $this->qualifyModelUsingCanvas($model);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function userProviderModel()
|
||||
{
|
||||
return $this->userProviderModelUsingCanvas();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function viewPath($path = '')
|
||||
{
|
||||
return $this->viewPathUsingCanvas($path);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function possibleModels()
|
||||
{
|
||||
return $this->possibleModelsUsingCanvas();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function possibleEvents()
|
||||
{
|
||||
return $this->possibleEventsUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Commands;
|
||||
|
||||
use Illuminate\Console\MigrationGeneratorCommand as Command;
|
||||
use Orchestra\Canvas\Core\Concerns\MigrationGenerator;
|
||||
|
||||
/**
|
||||
* @property string|null $name
|
||||
* @property string|null $description
|
||||
*/
|
||||
abstract class MigrationGeneratorCommand extends Command
|
||||
{
|
||||
use MigrationGenerator;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function createBaseMigration($table)
|
||||
{
|
||||
return $this->createBaseMigrationUsingCanvas($table);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function migrationExists($table)
|
||||
{
|
||||
return $this->migrationExistsUsingCanvas($table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Concerns;
|
||||
|
||||
use Illuminate\Console\Concerns\CreatesMatchingTest;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait CodeGenerator
|
||||
{
|
||||
use CreatesUsingGeneratorPreset;
|
||||
|
||||
/**
|
||||
* Generate code.
|
||||
*/
|
||||
public function generateCode(): bool
|
||||
{
|
||||
$name = $this->getNameInput();
|
||||
$force = $this->hasOption('force') && $this->option('force') === true;
|
||||
|
||||
$className = $this->qualifyClass($name);
|
||||
$path = $this->getPath($this->qualifyClass($name));
|
||||
|
||||
// First we need to ensure that the given name is not a reserved word within the PHP
|
||||
// language and that the class name will actually be valid. If it is not valid we
|
||||
// can error now and prevent from polluting the filesystem using invalid files.
|
||||
if ($this->isReservedName($name)) {
|
||||
$this->components->error(\sprintf('The name "%s" is reserved by PHP.', $name));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next, 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 (! $force && $this->alreadyExists($name)) {
|
||||
return $this->codeAlreadyExists($className, $path);
|
||||
}
|
||||
|
||||
// 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->sortImports($this->generatingCode($this->buildClass($className), $className))
|
||||
);
|
||||
|
||||
if (\in_array(CreatesMatchingTest::class, class_uses_recursive($this))) {
|
||||
$this->handleTestCreationUsingCanvas($path);
|
||||
}
|
||||
|
||||
return tap($this->codeHasBeenGenerated($className, $path), function ($exitCode) use ($className, $path) {
|
||||
$this->afterCodeHasBeenGenerated($className, $path);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle generating code.
|
||||
*/
|
||||
public function generatingCode(string $stub, string $className): string
|
||||
{
|
||||
return $stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Code already exists.
|
||||
*/
|
||||
public function codeAlreadyExists(string $className, string $path): bool
|
||||
{
|
||||
$this->components->error(
|
||||
\sprintf(
|
||||
'%s [%s] already exists!', $this->type, Str::after($path, $this->generatorPreset()->basePath().DIRECTORY_SEPARATOR)
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Code successfully generated.
|
||||
*/
|
||||
public function codeHasBeenGenerated(string $className, string $path): bool
|
||||
{
|
||||
$this->components->info(
|
||||
\sprintf(
|
||||
'%s [%s] created successfully.', $this->type, Str::after($path, $this->generatorPreset()->basePath().DIRECTORY_SEPARATOR)
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run after code successfully generated.
|
||||
*/
|
||||
public function afterCodeHasBeenGenerated(string $className, string $path): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Concerns;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Orchestra\Canvas\Core\PresetManager;
|
||||
use Orchestra\Canvas\Core\Presets\Preset;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
trait CreatesUsingGeneratorPreset
|
||||
{
|
||||
/**
|
||||
* Add the standard command options for generating with preset.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function addGeneratorPresetOptions()
|
||||
{
|
||||
$message = 'to running the command';
|
||||
|
||||
if (property_exists($this, 'type') && ! empty($this->type)) {
|
||||
$message = 'when generating '.Str::lower($this->type);
|
||||
}
|
||||
|
||||
$this->getDefinition()->addOption(new InputOption(
|
||||
'preset',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
\sprintf('Preset used %s', $message),
|
||||
null,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the generator preset.
|
||||
*/
|
||||
protected function generatorPreset(): Preset
|
||||
{
|
||||
/** @var string|null $preset */
|
||||
$preset = $this->option('preset');
|
||||
|
||||
return $this->laravel->make(PresetManager::class)->driver($preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator preset source path.
|
||||
*/
|
||||
protected function getGeneratorSourcePath(): string
|
||||
{
|
||||
return $this->generatorPreset()->sourcePath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Concerns;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
trait MigrationGenerator
|
||||
{
|
||||
use CreatesUsingGeneratorPreset;
|
||||
|
||||
/**
|
||||
* Create a base migration file for the table.
|
||||
*/
|
||||
protected function createBaseMigrationUsingCanvas(string $table): string
|
||||
{
|
||||
return $this->laravel->make('migration.creator')->create(
|
||||
"create_{$table}_table", $this->generatorPreset()->migrationPath()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a migration for the table already exists.
|
||||
*/
|
||||
protected function migrationExistsUsingCanvas(string $table): bool
|
||||
{
|
||||
return \count($this->files->glob(
|
||||
join_paths($this->generatorPreset()->migrationPath(), '*_*_*_*_create_'.$table.'_table.php')
|
||||
)) !== 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Concerns;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
trait ResolvesPresetStubs
|
||||
{
|
||||
/**
|
||||
* Resolve the fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveStubPath($stub)
|
||||
{
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
return $preset->hasCustomStubPath() && file_exists($customPath = join_paths($preset->basePath(), trim($stub, '/')))
|
||||
? $customPath
|
||||
: $this->resolveDefaultStubPath($stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return $stub;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Concerns;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait TestGenerator
|
||||
{
|
||||
use CreatesUsingGeneratorPreset;
|
||||
|
||||
/**
|
||||
* Create the matching test case if requested.
|
||||
*/
|
||||
protected function handleTestCreationUsingCanvas(string $path): bool
|
||||
{
|
||||
if (! $this->option('test') && ! $this->option('pest')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sourcePath = $this->generatorPreset()->sourcePath();
|
||||
|
||||
return $this->call('make:test', array_merge([
|
||||
'name' => Str::of($path)->after($sourcePath)->beforeLast('.php')->append('Test')->replace('\\', '/'),
|
||||
'--pest' => $this->option('pest'),
|
||||
], array_filter([
|
||||
'--preset' => $this->hasOption('preset') ? $this->option('preset') : null,
|
||||
]))) == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Concerns;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Orchestra\Canvas\Core\Presets\Preset;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
trait UsesGeneratorOverrides
|
||||
{
|
||||
/**
|
||||
* Qualify the given model class base name.
|
||||
*/
|
||||
protected function qualifyModelUsingCanvas(string $model): string
|
||||
{
|
||||
$model = ltrim($model, '\\/');
|
||||
|
||||
$model = str_replace('/', '\\', $model);
|
||||
|
||||
if (str_starts_with($model, $this->rootNamespace())) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
return $this->generatorPreset()->modelNamespace().$model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*/
|
||||
protected function getPathUsingCanvas(string $name): string
|
||||
{
|
||||
$name = Str::replaceFirst($this->rootNamespace(), '', $name);
|
||||
|
||||
return join_paths($this->getGeneratorSourcePath(), str_replace('\\', '/', $name).'.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*/
|
||||
protected function rootNamespaceUsingCanvas(): string
|
||||
{
|
||||
return $this->generatorPreset()->rootNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the default guard's user provider.
|
||||
*/
|
||||
protected function userProviderModelUsingCanvas(?string $guard = null): ?string
|
||||
{
|
||||
return $this->generatorPreset()->userProviderModel($guard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first view directory path from the application configuration.
|
||||
*/
|
||||
protected function viewPathUsingCanvas(string $path = ''): string
|
||||
{
|
||||
$views = $this->generatorPreset()->viewPath();
|
||||
|
||||
return join_paths($views, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of possible model names.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
protected function findAvailableModelsUsingCanvas(): array
|
||||
{
|
||||
$sourcePath = $this->generatorPreset()->sourcePath();
|
||||
|
||||
$modelPath = is_dir(join_paths($sourcePath, 'Models')) ? join_paths($sourcePath, 'Models') : $sourcePath;
|
||||
|
||||
return collect((new Finder)->files()->depth(0)->in($modelPath))
|
||||
->map(fn ($file) => $file->getBasename('.php'))
|
||||
->sort()
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of possible model names.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*
|
||||
* @deprecated 10.1.0 Use `findAvailableModelsUsingCanvas()` instead.
|
||||
*/
|
||||
protected function possibleModelsUsingCanvas(): array
|
||||
{
|
||||
return $this->findAvailableModelsUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of possible event names.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
protected function possibleEventsUsingCanvas(): array
|
||||
{
|
||||
$eventPath = join_paths($this->generatorPreset()->sourcePath(), 'Events');
|
||||
|
||||
if (! is_dir($eventPath)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return collect((new Finder)->files()->depth(0)->in($eventPath))
|
||||
->map(fn ($file) => $file->getBasename('.php'))
|
||||
->sort()
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function rootNamespace();
|
||||
|
||||
/**
|
||||
* Resolve the generator preset.
|
||||
*/
|
||||
abstract protected function generatorPreset(): Preset;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Contracts;
|
||||
|
||||
interface GeneratesCode
|
||||
{
|
||||
/**
|
||||
* Handle generating code.
|
||||
*/
|
||||
public function generatingCode(string $stub, string $className): string;
|
||||
|
||||
/**
|
||||
* Code already exists.
|
||||
*/
|
||||
public function codeAlreadyExists(string $className, string $path): bool;
|
||||
|
||||
/**
|
||||
* Code successfully generated.
|
||||
*/
|
||||
public function codeHasBeenGenerated(string $className, string $path): bool;
|
||||
|
||||
/**
|
||||
* Run after code successfully generated.
|
||||
*/
|
||||
public function afterCodeHasBeenGenerated(string $className, string $path): void;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core;
|
||||
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Composer;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class LaravelServiceProvider extends ServiceProvider implements DeferrableProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind('canvas.composer', static fn () => new Composer(new Filesystem));
|
||||
|
||||
$this->app->singleton(PresetManager::class, static fn ($app) => new PresetManager($app));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
* @return array<int, class-string>
|
||||
*/
|
||||
public function provides(): array
|
||||
{
|
||||
return [
|
||||
PresetManager::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core;
|
||||
|
||||
use Illuminate\Support\Manager;
|
||||
|
||||
class PresetManager extends Manager
|
||||
{
|
||||
/**
|
||||
* The default driver name.
|
||||
*/
|
||||
protected string $defaultPreset = 'laravel';
|
||||
|
||||
/**
|
||||
* Create "laravel" driver.
|
||||
*/
|
||||
public function createLaravelDriver(): Presets\Laravel
|
||||
{
|
||||
/** @phpstan-ignore argument.type */
|
||||
return new Presets\Laravel($this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default driver name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultDriver($name)
|
||||
{
|
||||
$this->defaultPreset = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default driver name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultDriver()
|
||||
{
|
||||
return $this->defaultPreset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Presets;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
class Laravel extends Preset
|
||||
{
|
||||
/**
|
||||
* Preset name.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return 'laravel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the base working directory.
|
||||
*/
|
||||
public function basePath(): string
|
||||
{
|
||||
return $this->app->basePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the source directory.
|
||||
*/
|
||||
public function sourcePath(): string
|
||||
{
|
||||
return $this->app->basePath('app');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the testing directory.
|
||||
*/
|
||||
public function testingPath(): string
|
||||
{
|
||||
return $this->app->basePath('tests');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the resource directory.
|
||||
*/
|
||||
public function resourcePath(): string
|
||||
{
|
||||
return $this->app->resourcePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the view directory.
|
||||
*/
|
||||
public function viewPath(): string
|
||||
{
|
||||
return $this->app->make('config')->get('view.paths')[0] ?? $this->app->resourcePath('views');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the factory directory.
|
||||
*/
|
||||
public function factoryPath(): string
|
||||
{
|
||||
return $this->app->databasePath('factories');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the migration directory.
|
||||
*/
|
||||
public function migrationPath(): string
|
||||
{
|
||||
return $this->app->databasePath('migrations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the seeder directory.
|
||||
*/
|
||||
public function seederPath(): string
|
||||
{
|
||||
if (is_dir($seederPath = $this->app->databasePath('seeds'))) {
|
||||
return $seederPath;
|
||||
}
|
||||
|
||||
return $this->app->databasePath('seeders');
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset namespace.
|
||||
*/
|
||||
public function rootNamespace(): string
|
||||
{
|
||||
return $this->app->getNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Command namespace.
|
||||
*/
|
||||
public function commandNamespace(): string
|
||||
{
|
||||
return "{$this->rootNamespace()}Console\Commands\\";
|
||||
}
|
||||
|
||||
/**
|
||||
* Model namespace.
|
||||
*/
|
||||
public function modelNamespace(): string
|
||||
{
|
||||
return is_dir(join_paths($this->sourcePath(), 'Models')) ? "{$this->rootNamespace()}Models\\" : $this->rootNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider namespace.
|
||||
*/
|
||||
public function providerNamespace(): string
|
||||
{
|
||||
return "{$this->rootNamespace()}Providers\\";
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing namespace.
|
||||
*/
|
||||
public function testingNamespace(): string
|
||||
{
|
||||
return 'Tests\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Database factory namespace.
|
||||
*/
|
||||
public function factoryNamespace(): string
|
||||
{
|
||||
return 'Database\Factories\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Database seeder namespace.
|
||||
*/
|
||||
public function seederNamespace(): string
|
||||
{
|
||||
return 'Database\Seeders\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset has custom stub path.
|
||||
*/
|
||||
public function hasCustomStubPath(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Core\Presets;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use LogicException;
|
||||
|
||||
abstract class Preset
|
||||
{
|
||||
/**
|
||||
* Construct a new preset.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected Application $app
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Check if preset name equal to $name.
|
||||
*/
|
||||
public function is(string $name): bool
|
||||
{
|
||||
return $this->name() === $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the default guard's user provider.
|
||||
*
|
||||
* @return class-string|null
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function userProviderModel(?string $guard = null): ?string
|
||||
{
|
||||
/** @var \Illuminate\Contracts\Config\Repository $config */
|
||||
$config = $this->app->make('config');
|
||||
|
||||
$guard = $guard ?: $config->get('auth.defaults.guard');
|
||||
|
||||
if (\is_null($provider = $config->get("auth.guards.{$guard}.provider"))) {
|
||||
throw new LogicException(\sprintf('The [%s] guard is not defined in your "auth" configuration file.', $guard));
|
||||
}
|
||||
|
||||
return $config->get("auth.providers.{$provider}.model");
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset name.
|
||||
*/
|
||||
abstract public function name(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the base working directory.
|
||||
*/
|
||||
abstract public function basePath(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the source directory.
|
||||
*/
|
||||
abstract public function sourcePath(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the testing directory.
|
||||
*/
|
||||
abstract public function testingPath(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the resource directory.
|
||||
*/
|
||||
abstract public function resourcePath(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the view directory.
|
||||
*/
|
||||
abstract public function viewPath(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the factory directory.
|
||||
*/
|
||||
abstract public function factoryPath(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the migration directory.
|
||||
*/
|
||||
abstract public function migrationPath(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the seeder directory.
|
||||
*/
|
||||
abstract public function seederPath(): string;
|
||||
|
||||
/**
|
||||
* Preset namespace.
|
||||
*/
|
||||
abstract public function rootNamespace(): string;
|
||||
|
||||
/**
|
||||
* Command namespace.
|
||||
*/
|
||||
abstract public function commandNamespace(): string;
|
||||
|
||||
/**
|
||||
* Model namespace.
|
||||
*/
|
||||
abstract public function modelNamespace(): string;
|
||||
|
||||
/**
|
||||
* Provider namespace.
|
||||
*/
|
||||
abstract public function providerNamespace(): string;
|
||||
|
||||
/**
|
||||
* Testing namespace.
|
||||
*/
|
||||
abstract public function testingNamespace(): string;
|
||||
|
||||
/**
|
||||
* Database factory namespace.
|
||||
*/
|
||||
abstract public function factoryNamespace(): string;
|
||||
|
||||
/**
|
||||
* Database seeder namespace.
|
||||
*/
|
||||
abstract public function seederNamespace(): string;
|
||||
|
||||
/**
|
||||
* Preset has custom stub path.
|
||||
*/
|
||||
abstract public function hasCustomStubPath(): bool;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
define('CANVAS_WORKING_PATH', $workingPath = getcwd());
|
||||
define('TESTBENCH_WORKING_PATH', $workingPath);
|
||||
|
||||
require $_composer_autoload_path ?? __DIR__.'/vendor/autoload.php';
|
||||
|
||||
$config = Orchestra\Testbench\Foundation\Config::loadFromYaml(
|
||||
workingPath: $workingPath,
|
||||
defaults: [
|
||||
'providers' => [],
|
||||
'dont-discover' => [],
|
||||
],
|
||||
);
|
||||
|
||||
$commander = new Orchestra\Canvas\Console\Commander($config->getAttributes(), $workingPath);
|
||||
|
||||
$commander->handle();
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "orchestra/canvas",
|
||||
"description": "Code Generators for Laravel Applications and Packages",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
},
|
||||
{
|
||||
"name": "Mior Muhammad Zaki",
|
||||
"email": "crynobone@gmail.com"
|
||||
}
|
||||
],
|
||||
"bin": [
|
||||
"canvas"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Canvas\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Canvas\\Tests\\": "tests/",
|
||||
"Illuminate\\Tests\\Integration\\Generators\\": "workbench/tests/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"composer-runtime-api": "^2.2",
|
||||
"composer/semver": "^3.0",
|
||||
"illuminate/console": "^13.0.0",
|
||||
"illuminate/database": "^13.0.0",
|
||||
"illuminate/filesystem": "^13.0.0",
|
||||
"illuminate/support": "^13.0.0",
|
||||
"orchestra/canvas-core": "^11.0.0",
|
||||
"orchestra/sidekick": "~1.1.23|~1.2.20",
|
||||
"orchestra/testbench-core": "^11.0.0",
|
||||
"symfony/yaml": "^7.4.0|^8.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/framework": "^13.0.0",
|
||||
"laravel/pint": "^1.24",
|
||||
"mockery/mockery": "^1.6.10",
|
||||
"phpstan/phpstan": "^2.1.14",
|
||||
"phpunit/phpunit": "^11.5.50|^12.5.8|^13.0.0"
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": {
|
||||
"laravel/framework": "source",
|
||||
"*": "auto"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Orchestra\\Canvas\\LaravelServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@clear",
|
||||
"@prepare"
|
||||
],
|
||||
"clear": "@php vendor/bin/testbench package:purge-skeleton --ansi",
|
||||
"prepare": "@php vendor/bin/testbench package:discover --ansi",
|
||||
"lint": [
|
||||
"@php vendor/bin/pint --ansi --parallel",
|
||||
"@php vendor/bin/phpstan analyse --verbose"
|
||||
],
|
||||
"test": [
|
||||
"@composer dump-autoload",
|
||||
"@php vendor/bin/phpunit --no-coverage --no-configuration --bootstrap vendor/autoload.php --color ./tests ./workbench/tests"
|
||||
],
|
||||
"sync": "@php bin/sync",
|
||||
"ci": [
|
||||
"@composer audit",
|
||||
"@prepare",
|
||||
"@lint",
|
||||
"@test"
|
||||
]
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Canvas
|
||||
{
|
||||
/**
|
||||
* Make Preset from configuration.
|
||||
*
|
||||
* @param array<string, mixed> $config
|
||||
*/
|
||||
public static function preset(array $config, string $basePath): Presets\Preset
|
||||
{
|
||||
/** @var array<string, mixed> $configuration */
|
||||
$configuration = Arr::except($config, 'preset');
|
||||
|
||||
/** @var string|class-string<\Orchestra\Canvas\Presets\Preset> $preset */
|
||||
$preset = $config['preset'] ?? 'laravel';
|
||||
|
||||
/** @phpstan-ignore return.type */
|
||||
return match (true) {
|
||||
$preset === 'package' => new Presets\Package($configuration, $basePath),
|
||||
$preset === 'laravel' => new Presets\Laravel($configuration, $basePath),
|
||||
class_exists($preset) => new $preset($configuration, $basePath),
|
||||
default => throw new InvalidArgumentException(\sprintf('Unable to resolve %s preset', $preset)),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Orchestra\Canvas\Core\PresetManager;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
use function Orchestra\Sidekick\join_paths;
|
||||
|
||||
class CanvasServiceProvider extends ServiceProvider implements DeferrableProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->callAfterResolving(PresetManager::class, static function ($manager, $app) {
|
||||
$manager->extend('canvas', fn ($app) => new GeneratorPreset($app));
|
||||
|
||||
$manager->setDefaultDriver('canvas');
|
||||
});
|
||||
|
||||
$this->app->singleton('orchestra.canvas', static function (Application $app) {
|
||||
$workingPath = \defined('CANVAS_WORKING_PATH') ? CANVAS_WORKING_PATH : $app->basePath();
|
||||
|
||||
$filesystem = $app->make('files');
|
||||
|
||||
$config = ['preset' => 'laravel'];
|
||||
|
||||
if (file_exists(join_paths($workingPath, 'canvas.yaml'))) {
|
||||
$config = Yaml::parseFile(join_paths($workingPath, 'canvas.yaml'));
|
||||
} else {
|
||||
Arr::set($config, 'testing.extends', [
|
||||
'unit' => 'PHPUnit\Framework\TestCase',
|
||||
'feature' => 'Tests\TestCase',
|
||||
]);
|
||||
|
||||
$config['namespace'] = rescue(fn () => rtrim($app->getNamespace(), '\\'), null, false);
|
||||
}
|
||||
|
||||
return Canvas::preset($config, $workingPath);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
Console\GeneratorMakeCommand::class,
|
||||
Console\PresetMakeCommand::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function provides()
|
||||
{
|
||||
return [
|
||||
'orchestra.canvas',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\MigrationGenerator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Queue/Console/BatchesTableCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:queue-batches-table', description: 'Create a migration for the batches database table', aliases: ['queue:batches-table'])]
|
||||
class BatchesTableCommand extends \Illuminate\Queue\Console\BatchesTableCommand
|
||||
{
|
||||
use MigrationGenerator;
|
||||
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'make:queue-batches-table';
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a base migration file for the table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createBaseMigration($table)
|
||||
{
|
||||
return $this->createBaseMigrationUsingCanvas($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a migration for the table already exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
#[\Override]
|
||||
protected function migrationExists($table)
|
||||
{
|
||||
return $this->migrationExistsUsingCanvas($table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\MigrationGenerator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Cache/Console/CacheTableCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:cache-table', description: 'Create a migration for the cache database table', aliases: ['cache:table'])]
|
||||
class CacheTableCommand extends \Illuminate\Cache\Console\CacheTableCommand
|
||||
{
|
||||
use MigrationGenerator;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a base migration file for the table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createBaseMigration($table)
|
||||
{
|
||||
return $this->createBaseMigrationUsingCanvas($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a migration for the table already exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
#[\Override]
|
||||
protected function migrationExists($table)
|
||||
{
|
||||
return $this->migrationExistsUsingCanvas($table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/CastMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:cast', description: 'Create a new custom Eloquent cast class')]
|
||||
class CastMakeCommand extends \Illuminate\Foundation\Console\CastMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ChannelMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:channel', description: 'Create a new channel class')]
|
||||
class ChannelMakeCommand extends \Illuminate\Foundation\Console\ChannelMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ClassMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:class', description: 'Create a new class')]
|
||||
class ClassMakeCommand extends \Illuminate\Foundation\Console\ClassMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Illuminate\Contracts\Console\Kernel as ConsoleKernel;
|
||||
use Illuminate\Foundation\Application as LaravelApplication;
|
||||
use Illuminate\Support\Collection;
|
||||
use Orchestra\Canvas\CanvasServiceProvider;
|
||||
use Orchestra\Canvas\Core\Concerns\CreatesUsingGeneratorPreset;
|
||||
use Orchestra\Canvas\LaravelServiceProvider;
|
||||
use Symfony\Component\Console\Command\Command as SymfonyCommand;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Commander extends \Orchestra\Testbench\Console\Commander
|
||||
{
|
||||
/** {@inheritDoc} */
|
||||
protected string $environmentFile = '.env';
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected array $providers = [];
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
protected function resolveApplicationCallback()
|
||||
{
|
||||
return static function ($app) {
|
||||
$app->register(CanvasServiceProvider::class);
|
||||
};
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
public function laravel()
|
||||
{
|
||||
if (! $this->app instanceof LaravelApplication) {
|
||||
$app = parent::laravel();
|
||||
|
||||
/** @var \Illuminate\Contracts\Console\Kernel $kernel */
|
||||
$kernel = $app->make(ConsoleKernel::class);
|
||||
|
||||
$app->register(LaravelServiceProvider::class);
|
||||
|
||||
Collection::make($kernel->all())
|
||||
->reject(
|
||||
static fn (SymfonyCommand $command, string $name) => \in_array(CreatesUsingGeneratorPreset::class, class_uses_recursive($command))
|
||||
)->each(static function (SymfonyCommand $command) {
|
||||
$command->setHidden(true);
|
||||
});
|
||||
}
|
||||
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->app;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ComponentMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:component', description: 'Create a new view component class')]
|
||||
class ComponentMakeCommand extends \Illuminate\Foundation\Console\ComponentMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run after code successfully generated.
|
||||
*/
|
||||
public function afterCodeHasBeenGenerated(string $className, string $path): void
|
||||
{
|
||||
if ($this->option('view') || ! $this->option('inline')) {
|
||||
$this->writeView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first view directory path from the application configuration.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function viewPath($path = '')
|
||||
{
|
||||
return $this->viewPathUsingCanvas($path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:command', description: 'Create a new Artisan command')]
|
||||
class ConsoleMakeCommand extends \Illuminate\Foundation\Console\ConsoleMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*
|
||||
* @param string $rootNamespace
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return rtrim($this->generatorPreset()->commandNamespace(), '\\');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Routing/Console/ControllerMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:controller', description: 'Create a new controller class')]
|
||||
class ControllerMakeCommand extends \Illuminate\Routing\Console\ControllerMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Qualify the given model class base name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function qualifyModel(string $model)
|
||||
{
|
||||
return $this->qualifyModelUsingCanvas($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the replacements for a parent controller.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\Override]
|
||||
protected function buildParentReplacements()
|
||||
{
|
||||
/** @var class-string|string $parentModelClass */
|
||||
/** @phpstan-ignore argument.type */
|
||||
$parentModelClass = $this->parseModel($this->option('parent'));
|
||||
|
||||
if (! class_exists($parentModelClass) &&
|
||||
$this->components->confirm("A {$parentModelClass} model does not exist. Do you want to generate it?", true)) {
|
||||
$this->call('make:model', ['name' => $parentModelClass, '--preset' => $this->option('preset')]);
|
||||
}
|
||||
|
||||
return [
|
||||
'ParentDummyFullModelClass' => $parentModelClass,
|
||||
'{{ namespacedParentModel }}' => $parentModelClass,
|
||||
'{{namespacedParentModel}}' => $parentModelClass,
|
||||
'ParentDummyModelClass' => class_basename($parentModelClass),
|
||||
'{{ parentModel }}' => class_basename($parentModelClass),
|
||||
'{{parentModel}}' => class_basename($parentModelClass),
|
||||
'ParentDummyModelVariable' => lcfirst(class_basename($parentModelClass)),
|
||||
'{{ parentModelVariable }}' => lcfirst(class_basename($parentModelClass)),
|
||||
'{{parentModelVariable}}' => lcfirst(class_basename($parentModelClass)),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the model replacement values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\Override]
|
||||
protected function buildModelReplacements(array $replace)
|
||||
{
|
||||
/** @var class-string|string $modelClass */
|
||||
/** @phpstan-ignore argument.type */
|
||||
$modelClass = $this->parseModel($this->option('model'));
|
||||
|
||||
if (! class_exists($modelClass) && $this->components->confirm("A {$modelClass} model does not exist. Do you want to generate it?", true)) {
|
||||
$this->call('make:model', ['name' => $modelClass, '--preset' => $this->option('preset')]);
|
||||
}
|
||||
|
||||
$replace = $this->buildFormRequestReplacements($replace, $modelClass);
|
||||
|
||||
if ($this->option('requests')) {
|
||||
$namespace = $this->rootNamespace();
|
||||
$replace['{{ namespacedRequests }}'] = str_replace('App\\', $namespace, $replace['{{ namespacedRequests }}']);
|
||||
$replace['{{namespacedRequests}}'] = str_replace('App\\', $namespace, $replace['{{namespacedRequests}}']);
|
||||
}
|
||||
|
||||
return array_merge($replace, [
|
||||
'DummyFullModelClass' => $modelClass,
|
||||
'{{ namespacedModel }}' => $modelClass,
|
||||
'{{namespacedModel}}' => $modelClass,
|
||||
'DummyModelClass' => class_basename($modelClass),
|
||||
'{{ model }}' => class_basename($modelClass),
|
||||
'{{model}}' => class_basename($modelClass),
|
||||
'DummyModelVariable' => lcfirst(class_basename($modelClass)),
|
||||
'{{ modelVariable }}' => lcfirst(class_basename($modelClass)),
|
||||
'{{modelVariable}}' => lcfirst(class_basename($modelClass)),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of possible model names.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function findAvailableModels()
|
||||
{
|
||||
return $this->findAvailableModelsUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the form requests for the given model and classes.
|
||||
*
|
||||
* @param string $modelClass
|
||||
* @param string $storeRequestClass
|
||||
* @param string $updateRequestClass
|
||||
* @return array
|
||||
*/
|
||||
#[\Override]
|
||||
protected function generateFormRequests($modelClass, $storeRequestClass, $updateRequestClass)
|
||||
{
|
||||
$storeRequestClass = 'Store'.class_basename($modelClass).'Request';
|
||||
|
||||
$this->call('make:request', [
|
||||
'name' => $storeRequestClass,
|
||||
'--preset' => $this->option('preset'),
|
||||
]);
|
||||
|
||||
$updateRequestClass = 'Update'.class_basename($modelClass).'Request';
|
||||
|
||||
$this->call('make:request', [
|
||||
'name' => $updateRequestClass,
|
||||
'--preset' => $this->option('preset'),
|
||||
]);
|
||||
|
||||
return [$storeRequestClass, $updateRequestClass];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Routing/Console/EnumMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:enum', description: 'Create a new enum')]
|
||||
class EnumMakeCommand extends \Illuminate\Foundation\Console\EnumMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/EventMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:event', description: 'Create a new event class')]
|
||||
class EventMakeCommand extends \Illuminate\Foundation\Console\EventMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:exception', description: 'Create a new custom exception class')]
|
||||
class ExceptionMakeCommand extends \Illuminate\Foundation\Console\ExceptionMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\ResolvesPresetStubs;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:factory', description: 'Create a new model factory')]
|
||||
class FactoryMakeCommand extends \Illuminate\Database\Console\Factories\FactoryMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use ResolvesPresetStubs;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return join_paths(__DIR__, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full namespace for a given class, without the class name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getNamespace($name)
|
||||
{
|
||||
return rtrim($this->generatorPreset()->factoryNamespace(), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator preset source path.
|
||||
*/
|
||||
protected function getGeneratorSourcePath(): string
|
||||
{
|
||||
return $this->generatorPreset()->factoryPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess the model name from the Factory name or return a default model name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function guessModelName($name)
|
||||
{
|
||||
if (str_ends_with($name, 'Factory')) {
|
||||
$name = substr($name, 0, -7);
|
||||
}
|
||||
|
||||
return $this->qualifyModelUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the default guard's user provider.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
#[\Override]
|
||||
protected function userProviderModel()
|
||||
{
|
||||
return $this->userProviderModelUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\MigrationGenerator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Queue/Console/FailedTableCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:queue-failed-table', description: 'Create a migration for the failed queue jobs database table', aliases: ['queue:failed-table'])]
|
||||
class FailedTableCommand extends \Illuminate\Queue\Console\FailedTableCommand
|
||||
{
|
||||
use MigrationGenerator;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a base migration file for the table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createBaseMigration($table)
|
||||
{
|
||||
return $this->createBaseMigrationUsingCanvas($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a migration for the table already exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
#[\Override]
|
||||
protected function migrationExists($table)
|
||||
{
|
||||
return $this->migrationExistsUsingCanvas($table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Orchestra\Canvas\Core\Commands\GeneratorCommand;
|
||||
use Orchestra\Canvas\Core\Concerns\ResolvesPresetStubs;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
#[AsCommand(name: 'make:generator', description: 'Create a new generator command')]
|
||||
class GeneratorMakeCommand extends GeneratorCommand
|
||||
{
|
||||
use ResolvesPresetStubs;
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Generator';
|
||||
|
||||
/**
|
||||
* Replace the class name for the given stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function replaceClass($stub, $name)
|
||||
{
|
||||
$stub = parent::replaceClass($stub, $name);
|
||||
|
||||
/** @var string $command */
|
||||
$command = $this->option('command') ?: 'make:'.Str::of($name)->classBasename()->kebab()->value();
|
||||
|
||||
return str_replace(['dummy:command', '{{ command }}'], $command, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getStub()
|
||||
{
|
||||
return $this->resolveStubPath(join_paths('stubs', 'generator.stub'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return join_paths(__DIR__, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*
|
||||
* @param string $rootNamespace
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return rtrim($this->generatorPreset()->commandNamespace(), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command options.
|
||||
*
|
||||
* @return array<int, array>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the generator already exists'],
|
||||
['command', null, InputOption::VALUE_OPTIONAL, 'The terminal command that should be assigned', 'make:name'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/InterfaceMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:interface', description: 'Create a new interface')]
|
||||
class InterfaceMakeCommand extends \Illuminate\Foundation\Console\InterfaceMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/JobMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:job', description: 'Create a new job class')]
|
||||
class JobMakeCommand extends \Illuminate\Foundation\Console\JobMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/JobMiddlewareMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:job-middleware', description: 'Create a new job middleware class')]
|
||||
class JobMiddlewareMakeCommand extends \Illuminate\Foundation\Console\JobMiddlewareMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ListenerMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:listener', description: 'Create a new event listener class')]
|
||||
class ListenerMakeCommand extends \Illuminate\Foundation\Console\ListenerMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of possible event names.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function possibleEvents()
|
||||
{
|
||||
return $this->possibleEventsUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/MailMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:mail', description: 'Create a new email class')]
|
||||
class MailMakeCommand extends \Illuminate\Foundation\Console\MailMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run after code successfully generated.
|
||||
*/
|
||||
public function afterCodeHasBeenGenerated(string $className, string $path): void
|
||||
{
|
||||
if ($this->option('markdown') !== false) {
|
||||
$this->writeMarkdownTemplate();
|
||||
}
|
||||
|
||||
if ($this->option('view') !== false) {
|
||||
$this->writeView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Routing/Console/MiddlewareMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:middleware', description: 'Create a new middleware class')]
|
||||
class MiddlewareMakeCommand extends \Illuminate\Routing\Console\MiddlewareMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Commands\Command;
|
||||
use Orchestra\Canvas\Core\Concerns\CreatesUsingGeneratorPreset;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:migration', description: 'Create a new migration file')]
|
||||
class MigrateMakeCommand extends \Illuminate\Database\Console\Migrations\MigrateMakeCommand
|
||||
{
|
||||
use CreatesUsingGeneratorPreset;
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Migration';
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
if (! $preset->is('laravel')) {
|
||||
$this->input->setOption('path', $preset->migrationPath());
|
||||
$this->input->setOption('realpath', true);
|
||||
}
|
||||
|
||||
parent::handle();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ModelMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:model', description: 'Create a new Eloquent model class')]
|
||||
class ModelMakeCommand extends \Illuminate\Foundation\Console\ModelMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run after code successfully generated.
|
||||
*/
|
||||
protected function afterCodeHasBeenGenerated(): void
|
||||
{
|
||||
if ($this->option('all')) {
|
||||
$this->input->setOption('factory', true);
|
||||
$this->input->setOption('seed', true);
|
||||
$this->input->setOption('migration', true);
|
||||
$this->input->setOption('controller', true);
|
||||
$this->input->setOption('policy', true);
|
||||
$this->input->setOption('resource', true);
|
||||
}
|
||||
|
||||
if ($this->option('factory')) {
|
||||
$this->createFactory();
|
||||
}
|
||||
|
||||
if ($this->option('migration')) {
|
||||
$this->createMigration();
|
||||
}
|
||||
|
||||
if ($this->option('seed')) {
|
||||
$this->createSeeder();
|
||||
}
|
||||
|
||||
if ($this->option('controller') || $this->option('resource') || $this->option('api')) {
|
||||
$this->createController();
|
||||
}
|
||||
|
||||
if ($this->option('policy')) {
|
||||
$this->createPolicy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a model factory for the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createFactory()
|
||||
{
|
||||
$factory = Str::studly($this->getNameInput());
|
||||
|
||||
$this->call('make:factory', [
|
||||
'name' => "{$factory}Factory",
|
||||
'--model' => $this->qualifyClass($this->getNameInput()),
|
||||
'--preset' => $this->option('preset'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a migration file for the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createMigration()
|
||||
{
|
||||
$table = Str::snake(Str::pluralStudly(class_basename($this->getNameInput())));
|
||||
|
||||
if ($this->option('pivot')) {
|
||||
$table = Str::singular($table);
|
||||
}
|
||||
|
||||
$this->call('make:migration', [
|
||||
'name' => "create_{$table}_table",
|
||||
'--create' => $table,
|
||||
'--fullpath' => true,
|
||||
'--preset' => $this->option('preset'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a seeder file for the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createSeeder()
|
||||
{
|
||||
$seeder = Str::studly(class_basename($this->getNameInput()));
|
||||
|
||||
$this->call('make:seeder', [
|
||||
'name' => "{$seeder}Seeder",
|
||||
'--preset' => $this->option('preset'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a controller for the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createController()
|
||||
{
|
||||
$controller = Str::studly(class_basename($this->getNameInput()));
|
||||
|
||||
$modelName = $this->qualifyClass($this->getNameInput());
|
||||
|
||||
$this->call('make:controller', array_filter([
|
||||
'name' => "{$controller}Controller",
|
||||
'--model' => $this->option('resource') || $this->option('api') ? $modelName : null,
|
||||
'--api' => $this->option('api'),
|
||||
'--requests' => $this->option('requests') || $this->option('all'),
|
||||
'--preset' => $this->option('preset'),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a policy file for the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createPolicy()
|
||||
{
|
||||
$policy = Str::studly(class_basename($this->getNameInput()));
|
||||
|
||||
$this->call('make:policy', [
|
||||
'name' => "{$policy}Policy",
|
||||
'--model' => $this->qualifyClass($this->getNameInput()),
|
||||
'--preset' => $this->option('preset'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*
|
||||
* @param string $rootNamespace
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return rtrim($this->generatorPreset()->modelNamespace(), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Qualify the given model class base name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function qualifyModel(string $model)
|
||||
{
|
||||
return $this->qualifyModelUsingCanvas($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/NotificationMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:notification', description: 'Create a new notification class')]
|
||||
class NotificationMakeCommand extends \Illuminate\Foundation\Console\NotificationMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run after code successfully generated.
|
||||
*/
|
||||
public function afterCodeHasBeenGenerated(string $className, string $path): void
|
||||
{
|
||||
if ($this->option('markdown')) {
|
||||
$this->writeMarkdownTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\MigrationGenerator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Notifications/Console/NotificationTableCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:notifications-table', description: 'Create a migration for the notifications table', aliases: ['notifications:table'])]
|
||||
class NotificationTableCommand extends \Illuminate\Notifications\Console\NotificationTableCommand
|
||||
{
|
||||
use MigrationGenerator;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a base migration file for the table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createBaseMigration($table)
|
||||
{
|
||||
return $this->createBaseMigrationUsingCanvas($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a migration for the table already exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
#[\Override]
|
||||
protected function migrationExists($table)
|
||||
{
|
||||
return $this->migrationExistsUsingCanvas($table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ObserverMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:observer', description: 'Create a new observer class')]
|
||||
class ObserverMakeCommand extends \Illuminate\Foundation\Console\ObserverMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Qualify the given model class base name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function qualifyModel(string $model)
|
||||
{
|
||||
return $this->qualifyModelUsingCanvas($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of possible model names.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function findAvailableModels()
|
||||
{
|
||||
return $this->findAvailableModelsUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/PolicyMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:policy', description: 'Create a new policy class')]
|
||||
class PolicyMakeCommand extends \Illuminate\Foundation\Console\PolicyMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Qualify the given model class base name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function qualifyModel(string $model)
|
||||
{
|
||||
return $this->qualifyModelUsingCanvas($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the default guard's user provider.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
#[\Override]
|
||||
protected function userProviderModel()
|
||||
{
|
||||
/** @var string|null $guard */
|
||||
$guard = $this->option('guard');
|
||||
|
||||
return $this->userProviderModelUsingCanvas($guard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of possible model names.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function findAvailableModels()
|
||||
{
|
||||
return $this->findAvailableModelsUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Orchestra\Canvas\Core\Commands\GeneratorCommand;
|
||||
use Orchestra\Canvas\Core\Concerns\ResolvesPresetStubs;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use function Laravel\Prompts\select;
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
use function Orchestra\Testbench\package_path;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
#[AsCommand(name: 'preset', description: 'Create canvas.yaml for the project')]
|
||||
class PresetMakeCommand extends GeneratorCommand
|
||||
{
|
||||
use ResolvesPresetStubs;
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Preset';
|
||||
|
||||
/**
|
||||
* Interact with the user before validating the input.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function interact(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
if (\is_null($input->getArgument('name'))) {
|
||||
$input->setArgument('name', select(
|
||||
label: 'The preset type?',
|
||||
options: [
|
||||
'laravel' => 'Application',
|
||||
'package' => 'Package',
|
||||
],
|
||||
required: true,
|
||||
));
|
||||
}
|
||||
|
||||
if (\is_null($input->getOption('namespace'))) {
|
||||
$files = new Filesystem;
|
||||
$composer = $files->json(package_path('composer.json'));
|
||||
|
||||
$namespaces = Collection::make(Arr::wrap(data_get($composer, 'autoload.psr-4')))
|
||||
->keys()
|
||||
->transform(static fn ($namespace) => rtrim($namespace, '\\'))
|
||||
->mapWithKeys(static fn ($namespace) => [$namespace => $namespace]);
|
||||
|
||||
if ($namespaces->isNotEmpty()) {
|
||||
if ($namespaces->count() === 1) {
|
||||
$input->setOption('namespace', $namespaces->first());
|
||||
} else {
|
||||
$input->setOption('namespace', select(
|
||||
label: 'The root namespace for your package?',
|
||||
options: $namespaces->all(),
|
||||
required: true,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::interact($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getStub()
|
||||
{
|
||||
$name = Str::lower($this->getNameInput());
|
||||
|
||||
$stub = join_paths(__DIR__, 'stubs', 'preset');
|
||||
|
||||
return $this->files->exists("{$stub}.{$name}.stub")
|
||||
? "{$stub}.{$name}.stub"
|
||||
: "{$stub}.laravel.stub";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return join_paths($this->generatorPreset()->basePath(), 'canvas.yaml');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace(): string
|
||||
{
|
||||
/** @var string $namespace */
|
||||
$namespace = transform(
|
||||
$this->option('namespace'), static fn (string $namespace) => trim($namespace) /** @phpstan-ignore argument.type */
|
||||
);
|
||||
|
||||
if (! empty($namespace)) {
|
||||
return $namespace;
|
||||
}
|
||||
|
||||
return match ($this->argument('name')) {
|
||||
'package' => 'PackageName',
|
||||
/* 'laravel' */
|
||||
default => rtrim($this->laravel->getNamespace(), '\\'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command options.
|
||||
*
|
||||
* @return array<int, array>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['namespace', null, InputOption::VALUE_OPTIONAL, 'Root namespace'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ProviderMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:provider', description: 'Create a new service provider class')]
|
||||
class ProviderMakeCommand extends \Illuminate\Foundation\Console\ProviderMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*
|
||||
* @param string $rootNamespace
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return rtrim($this->generatorPreset()->providerNamespace(), '\\');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Illuminate\Queue\Console\TableCommand;
|
||||
use Orchestra\Canvas\Core\Concerns\MigrationGenerator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Queue/Console/TableCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:queue-table', description: 'Create a migration for the queue jobs database table', aliases: ['queue:table'])]
|
||||
class QueueTableCommand extends TableCommand
|
||||
{
|
||||
use MigrationGenerator;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a base migration file for the table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createBaseMigration($table)
|
||||
{
|
||||
return $this->createBaseMigrationUsingCanvas($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a migration for the table already exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
#[\Override]
|
||||
protected function migrationExists($table)
|
||||
{
|
||||
return $this->migrationExistsUsingCanvas($table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/RequestMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:request', description: 'Create a new form request class')]
|
||||
class RequestMakeCommand extends \Illuminate\Foundation\Console\RequestMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ResourceMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:resource', description: 'Create a new resource')]
|
||||
class ResourceMakeCommand extends \Illuminate\Foundation\Console\ResourceMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/RuleMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:rule', description: 'Create a new validation rule')]
|
||||
class RuleMakeCommand extends \Illuminate\Foundation\Console\RuleMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/ScopeMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:scope', description: 'Create a new class')]
|
||||
class ScopeMakeCommand extends \Illuminate\Foundation\Console\ScopeMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Qualify the given model class base name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function qualifyModel(string $model)
|
||||
{
|
||||
return $this->qualifyModelUsingCanvas($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Database/Console/Seeds/SeederMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:seeder', description: 'Create a new seeder class')]
|
||||
class SeederMakeCommand extends \Illuminate\Database\Console\Seeds\SeederMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator preset source path.
|
||||
*/
|
||||
protected function getGeneratorSourcePath(): string
|
||||
{
|
||||
return $this->generatorPreset()->seederPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->generatorPreset()->seederNamespace();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\MigrationGenerator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Session/Console/SessionTableCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:session-table', description: 'Create a migration for the session database table', aliases: ['session:table'])]
|
||||
class SessionTableCommand extends \Illuminate\Session\Console\SessionTableCommand
|
||||
{
|
||||
use MigrationGenerator;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a base migration file for the table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function createBaseMigration($table)
|
||||
{
|
||||
return $this->createBaseMigrationUsingCanvas($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a migration for the table already exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
#[\Override]
|
||||
protected function migrationExists($table)
|
||||
{
|
||||
return $this->migrationExistsUsingCanvas($table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Orchestra\Canvas\GeneratorPreset;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Console/TestMakeCommand.php
|
||||
*/
|
||||
#[AsCommand(name: 'make:test', description: 'Create a new test class')]
|
||||
class TestMakeCommand extends \Illuminate\Foundation\Console\TestMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the class name for the given stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function generatingCode($stub, $name)
|
||||
{
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
if (! $preset instanceof GeneratorPreset) {
|
||||
return $stub;
|
||||
}
|
||||
|
||||
$testCase = $this->option('unit')
|
||||
? $preset->canvas()->config('testing.extends.unit', 'PHPUnit\Framework\TestCase')
|
||||
: $preset->canvas()->config(
|
||||
'testing.extends.feature',
|
||||
$preset->canvas()->is('laravel') ? 'Tests\TestCase' : 'Orchestra\Testbench\TestCase'
|
||||
);
|
||||
|
||||
return $this->replaceTestCase($stub, $testCase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the model for the given stub.
|
||||
*/
|
||||
protected function replaceTestCase(string $stub, string $testCase): string
|
||||
{
|
||||
$namespaceTestCase = $testCase = str_replace('/', '\\', $testCase);
|
||||
|
||||
if (str_starts_with($testCase, '\\')) {
|
||||
$stub = str_replace('NamespacedDummyTestCase', trim($testCase, '\\'), $stub);
|
||||
} else {
|
||||
$stub = str_replace('NamespacedDummyTestCase', $namespaceTestCase, $stub);
|
||||
}
|
||||
|
||||
$stub = str_replace(
|
||||
"use {$namespaceTestCase};\nuse {$namespaceTestCase};", "use {$namespaceTestCase};", $stub
|
||||
);
|
||||
|
||||
$testCase = class_basename(trim($testCase, '\\'));
|
||||
|
||||
return str_replace('DummyTestCase', $testCase, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function resolveStubPath($stub)
|
||||
{
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
if (! $preset instanceof GeneratorPreset) {
|
||||
return parent::resolveStubPath($stub);
|
||||
}
|
||||
|
||||
return $preset->hasCustomStubPath() && file_exists($customPath = join_paths($preset->basePath(), $stub))
|
||||
? $customPath
|
||||
: $this->resolveDefaultStubPath($stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return join_paths(__DIR__, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator preset source path.
|
||||
*/
|
||||
protected function getGeneratorSourcePath(): string
|
||||
{
|
||||
return $this->generatorPreset()->testingPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
return $this->getPathUsingCanvas($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->generatorPreset()->testingNamespace();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Orchestra\Canvas\Core\Commands\GeneratorCommand;
|
||||
use Orchestra\Canvas\Core\Concerns\ResolvesPresetStubs;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
#[AsCommand(name: 'make:user-factory', description: 'Create the User factory class')]
|
||||
class UserFactoryMakeCommand extends GeneratorCommand
|
||||
{
|
||||
use ResolvesPresetStubs;
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Factory';
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getStub()
|
||||
{
|
||||
return $this->resolveStubPath(join_paths('stubs', 'user-factory.stub'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return join_paths(__DIR__, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->generatorPreset()->factoryNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator preset source path.
|
||||
*/
|
||||
protected function getGeneratorSourcePath(): string
|
||||
{
|
||||
return $this->generatorPreset()->factoryPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle generating code.
|
||||
*/
|
||||
public function generatingCode(string $stub, string $className): string
|
||||
{
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
return str_replace([
|
||||
'{{ factoryNamespace }}',
|
||||
'{{ namespacedModel }}',
|
||||
'{{ model }}',
|
||||
], [
|
||||
rtrim($preset->factoryNamespace(), '\\'),
|
||||
$preset->modelNamespace().'User',
|
||||
'User',
|
||||
], $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the desired class name from the input.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getNameInput()
|
||||
{
|
||||
return 'UserFactory';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command arguments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getArguments()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command options.
|
||||
*
|
||||
* @return array<int, array>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the generator already exists'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use Orchestra\Canvas\Core\Commands\GeneratorCommand;
|
||||
use Orchestra\Canvas\Core\Concerns\ResolvesPresetStubs;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
#[AsCommand(name: 'make:user-model', description: 'Create the User model class')]
|
||||
class UserModelMakeCommand extends GeneratorCommand
|
||||
{
|
||||
use ResolvesPresetStubs;
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Model';
|
||||
|
||||
/**
|
||||
* Build the class with the given name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
protected function buildClass($name)
|
||||
{
|
||||
$stub = parent::buildClass($name);
|
||||
|
||||
if (! InstalledVersions::isInstalled('laravel/sanctum')) {
|
||||
$stub = str_replace(
|
||||
' use HasApiTokens, HasFactory, Notifiable;'.PHP_EOL,
|
||||
' use HasFactory, Notifiable;'.PHP_EOL,
|
||||
$stub
|
||||
);
|
||||
}
|
||||
|
||||
return $stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getStub()
|
||||
{
|
||||
return $this->resolveStubPath(join_paths('stubs', 'user-model.stub'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return join_paths(__DIR__, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*/
|
||||
#[\Override]
|
||||
public function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return rtrim($this->generatorPreset()->modelNamespace(), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the desired class name from the input.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getNameInput()
|
||||
{
|
||||
return 'User';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command arguments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getArguments()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command options.
|
||||
*
|
||||
* @return array<int, array>
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the generator already exists'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Console;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Orchestra\Canvas\Core\Concerns\CodeGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\TestGenerator;
|
||||
use Orchestra\Canvas\Core\Concerns\UsesGeneratorOverrides;
|
||||
use Orchestra\Canvas\GeneratorPreset;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
use function Orchestra\Sidekick\Filesystem\join_paths;
|
||||
|
||||
#[AsCommand(name: 'make:view', description: 'Create a new view')]
|
||||
class ViewMakeCommand extends \Illuminate\Foundation\Console\ViewMakeCommand
|
||||
{
|
||||
use CodeGenerator;
|
||||
use TestGenerator {
|
||||
handleTestCreationUsingCanvas as protected handleTestCreationUsingCanvasFromTrait;
|
||||
}
|
||||
use UsesGeneratorOverrides;
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
#[\Override]
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addGeneratorPresetOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
#[\Override]
|
||||
public function handle()
|
||||
{
|
||||
/** @phpstan-ignore return.type */
|
||||
return $this->generateCode() ? self::SUCCESS : self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function resolveStubPath($stub)
|
||||
{
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
if (! $preset instanceof GeneratorPreset) {
|
||||
return parent::resolveStubPath($stub);
|
||||
}
|
||||
|
||||
return $preset->hasCustomStubPath() && file_exists($customPath = join_paths($preset->basePath(), $stub))
|
||||
? $customPath
|
||||
: $this->resolveDefaultStubPath($stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return join_paths(__DIR__, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination view path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getPath($name)
|
||||
{
|
||||
/** @var string $extension */
|
||||
/** @phpstan-ignore argument.type */
|
||||
$extension = transform($this->option('extension'), fn (string $extension) => trim($extension));
|
||||
|
||||
return $this->viewPath(
|
||||
$this->getNameInput().'.'.$extension,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first view directory path from the application configuration.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function viewPath($path = '')
|
||||
{
|
||||
return $this->viewPathUsingCanvas($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the desired view name from the input.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getNameInput()
|
||||
{
|
||||
/** @phpstan-ignore argument.type, return.type */
|
||||
return transform($this->argument('name'), function (string $name) {
|
||||
return str_replace(['\\', '.'], '/', trim($name));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the matching test case if requested.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
protected function handleTestCreationUsingCanvas($path): bool
|
||||
{
|
||||
if (! $this->option('test') && ! $this->option('pest')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
if (! $preset instanceof GeneratorPreset) {
|
||||
return $this->handleTestCreationUsingCanvasFromTrait($path);
|
||||
}
|
||||
|
||||
$namespaceTestCase = $testCase = $preset->canvas()->config(
|
||||
'testing.extends.feature',
|
||||
$preset->canvas()->is('laravel') ? 'Tests\TestCase' : 'Orchestra\Testbench\TestCase'
|
||||
);
|
||||
|
||||
$stub = $this->files->get($this->getTestStub());
|
||||
|
||||
if (Str::startsWith($testCase, '\\')) {
|
||||
$stub = str_replace('NamespacedDummyTestCase', trim($testCase, '\\'), $stub);
|
||||
} else {
|
||||
$stub = str_replace('NamespacedDummyTestCase', $namespaceTestCase, $stub);
|
||||
}
|
||||
|
||||
$contents = str_replace(
|
||||
['{{ namespace }}', '{{ class }}', '{{ name }}', 'DummyTestCase'],
|
||||
[$this->testNamespace(), $this->testClassName(), $this->testViewName(), class_basename(trim($testCase, '\\'))],
|
||||
$stub,
|
||||
);
|
||||
|
||||
$this->files->ensureDirectoryExists(\dirname($this->getTestPath()), 0755, true);
|
||||
|
||||
return $this->files->put($this->getTestPath(), $contents) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return $this->rootNamespaceUsingCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination test case path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getTestPath()
|
||||
{
|
||||
$preset = $this->generatorPreset();
|
||||
|
||||
$testPath = Str::of($this->testClassFullyQualifiedName())
|
||||
->replace('\\', DIRECTORY_SEPARATOR)
|
||||
->replaceFirst(join_paths('Tests', 'Feature'), join_paths(str_replace($preset->basePath(), '', $preset->testingPath()), 'Feature'))
|
||||
->append('Test.php')
|
||||
->value();
|
||||
|
||||
return $preset->basePath().$testPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the test stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
#[\Override]
|
||||
protected function getTestStub()
|
||||
{
|
||||
$stubName = 'view.'.($this->option('pest') ? 'pest' : 'test').'.stub';
|
||||
|
||||
return $this->resolveStubPath(join_paths('stubs', $stubName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace DummyNamespace;
|
||||
|
||||
class DummyClass
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace {{ factoryNamespace }};
|
||||
|
||||
use {{ namespacedModel }};
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use {{ namespacedModel }};
|
||||
|
||||
/**
|
||||
* @extends Factory<{{ model }}>
|
||||
*/
|
||||
class {{ factory }}Factory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var class-string<{{ model }}>
|
||||
*/
|
||||
protected $model = {{ model }}::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace DummyNamespace;
|
||||
|
||||
use Orchestra\Canvas\Core\Commands\GeneratorCommand;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand(name: 'dummy:command', description: 'Create a new class')]
|
||||
class DummyClass extends GeneratorCommand
|
||||
{
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Class';
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getStub()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default fully-qualified path to the stub.
|
||||
*
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveDefaultStubPath($stub)
|
||||
{
|
||||
return __DIR__.$stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*/
|
||||
public function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return $rootNamespace;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
test('example', function () {
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
test('example', function () {
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
preset: laravel
|
||||
|
||||
namespace: DummyNamespace
|
||||
|
||||
model:
|
||||
namespace: DummyNamespace
|
||||
@@ -0,0 +1,27 @@
|
||||
preset: package
|
||||
|
||||
namespace: DummyNamespace
|
||||
user-auth-model: App\Models\User
|
||||
|
||||
paths:
|
||||
src: src
|
||||
resource: resources
|
||||
|
||||
factory:
|
||||
path: database/factories
|
||||
|
||||
migration:
|
||||
path: database/migrations
|
||||
prefix: ''
|
||||
|
||||
console:
|
||||
namespace: DummyNamespace\Console
|
||||
|
||||
model:
|
||||
namespace: DummyNamespace\Models
|
||||
|
||||
provider:
|
||||
namespace: DummyNamespace\Providers
|
||||
|
||||
testing:
|
||||
namespace: DummyNamespace\Tests
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace {{ namespace }};
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use NamespacedDummyTestCase;
|
||||
|
||||
class {{ class }} extends DummyTestCase
|
||||
{
|
||||
/**
|
||||
* A basic feature test example.
|
||||
*/
|
||||
public function test_example(): void
|
||||
{
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace {{ namespace }};
|
||||
|
||||
use NamespacedDummyTestCase;
|
||||
|
||||
class {{ class }} extends DummyTestCase
|
||||
{
|
||||
/**
|
||||
* A basic unit test example.
|
||||
*/
|
||||
public function test_example(): void
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace {{ factoryNamespace }};
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use {{ namespacedModel }};
|
||||
|
||||
/**
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var class-string<{{ model }}>
|
||||
*/
|
||||
protected $model = {{ model }}::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace {{ namespace }};
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
#[Fillable(['name', 'email', 'password'])]
|
||||
#[Hidden(['password', 'remember_token'])]
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
it('can render', function () {
|
||||
$contents = $this->view('{{ name }}', [
|
||||
//
|
||||
]);
|
||||
|
||||
$contents->assertSee('');
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<!-- {{ quote }} -->
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace {{ namespace }};
|
||||
|
||||
use NamespacedDummyTestCase;
|
||||
use Illuminate\Foundation\Testing\Concerns\InteractsWithViews;
|
||||
|
||||
class {{ class }} extends DummyTestCase
|
||||
{
|
||||
use InteractsWithViews;
|
||||
|
||||
/**
|
||||
* A basic view test example.
|
||||
*/
|
||||
public function test_it_can_render(): void
|
||||
{
|
||||
$contents = $this->view('{{ name }}', [
|
||||
//
|
||||
]);
|
||||
|
||||
$contents->assertSee('');
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas;
|
||||
|
||||
use Orchestra\Canvas\Core\Presets\Preset;
|
||||
|
||||
use function Orchestra\Sidekick\join_paths;
|
||||
|
||||
class GeneratorPreset extends Preset
|
||||
{
|
||||
/**
|
||||
* Preset name.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return 'canvas';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the base working directory.
|
||||
*/
|
||||
public function basePath(): string
|
||||
{
|
||||
return $this->canvas()->basePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the source directory.
|
||||
*/
|
||||
public function sourcePath(): string
|
||||
{
|
||||
return $this->canvas()->sourcePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the testing directory.
|
||||
*/
|
||||
public function testingPath(): string
|
||||
{
|
||||
return $this->canvas()->testingPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the resource directory.
|
||||
*/
|
||||
public function resourcePath(): string
|
||||
{
|
||||
return $this->canvas()->resourcePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the view directory.
|
||||
*/
|
||||
public function viewPath(): string
|
||||
{
|
||||
return join_paths($this->resourcePath(), 'views');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the factory directory.
|
||||
*/
|
||||
public function factoryPath(): string
|
||||
{
|
||||
return $this->canvas()->factoryPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the migration directory.
|
||||
*/
|
||||
public function migrationPath(): string
|
||||
{
|
||||
return $this->canvas()->migrationPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the seeder directory.
|
||||
*/
|
||||
public function seederPath(): string
|
||||
{
|
||||
return $this->canvas()->seederPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset namespace.
|
||||
*/
|
||||
public function rootNamespace(): string
|
||||
{
|
||||
return $this->canvas()->rootNamespace().'\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Command namespace.
|
||||
*/
|
||||
public function commandNamespace(): string
|
||||
{
|
||||
return $this->canvas()->commandNamespace().'\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Model namespace.
|
||||
*/
|
||||
public function modelNamespace(): string
|
||||
{
|
||||
return $this->canvas()->modelNamespace().'\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider namespace.
|
||||
*/
|
||||
public function providerNamespace(): string
|
||||
{
|
||||
return $this->canvas()->providerNamespace().'\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Database factory namespace.
|
||||
*/
|
||||
public function factoryNamespace(): string
|
||||
{
|
||||
return $this->canvas()->factoryNamespace().'\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Database seeder namespace.
|
||||
*/
|
||||
public function seederNamespace(): string
|
||||
{
|
||||
return $this->canvas()->seederNamespace().'\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing namespace.
|
||||
*/
|
||||
public function testingNamespace(): string
|
||||
{
|
||||
return $this->canvas()->testingNamespace().'\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset has custom stub path.
|
||||
*/
|
||||
public function hasCustomStubPath(): bool
|
||||
{
|
||||
return ! \is_null($this->canvas()->getCustomStubPath());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
public function userProviderModel(?string $guard = null): ?string
|
||||
{
|
||||
if (\is_null($guard) || $guard === $this->app->make('config')->get('auth.defaults.guard')) {
|
||||
return $this->canvas()->config('user-auth-model')
|
||||
?? $this->canvas()->config('user-auth-provider')
|
||||
?? parent::userProviderModel($guard);
|
||||
}
|
||||
|
||||
return parent::userProviderModel($guard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get canvas preset.
|
||||
*/
|
||||
public function canvas(): Presets\Preset
|
||||
{
|
||||
return $this->app->make('orchestra.canvas');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,596 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas;
|
||||
|
||||
use Illuminate\Cache\Console\CacheTableCommand;
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Database\Console\Factories\FactoryMakeCommand;
|
||||
use Illuminate\Database\Console\Seeds\SeederMakeCommand;
|
||||
use Illuminate\Foundation\Console\CastMakeCommand;
|
||||
use Illuminate\Foundation\Console\ChannelMakeCommand;
|
||||
use Illuminate\Foundation\Console\ClassMakeCommand;
|
||||
use Illuminate\Foundation\Console\ComponentMakeCommand;
|
||||
use Illuminate\Foundation\Console\ConsoleMakeCommand;
|
||||
use Illuminate\Foundation\Console\EnumMakeCommand;
|
||||
use Illuminate\Foundation\Console\EventMakeCommand;
|
||||
use Illuminate\Foundation\Console\ExceptionMakeCommand;
|
||||
use Illuminate\Foundation\Console\InterfaceMakeCommand;
|
||||
use Illuminate\Foundation\Console\JobMakeCommand;
|
||||
use Illuminate\Foundation\Console\JobMiddlewareMakeCommand;
|
||||
use Illuminate\Foundation\Console\ListenerMakeCommand;
|
||||
use Illuminate\Foundation\Console\MailMakeCommand;
|
||||
use Illuminate\Foundation\Console\ModelMakeCommand;
|
||||
use Illuminate\Foundation\Console\NotificationMakeCommand;
|
||||
use Illuminate\Foundation\Console\ObserverMakeCommand;
|
||||
use Illuminate\Foundation\Console\PolicyMakeCommand;
|
||||
use Illuminate\Foundation\Console\ProviderMakeCommand;
|
||||
use Illuminate\Foundation\Console\RequestMakeCommand;
|
||||
use Illuminate\Foundation\Console\ResourceMakeCommand;
|
||||
use Illuminate\Foundation\Console\RuleMakeCommand;
|
||||
use Illuminate\Foundation\Console\ScopeMakeCommand;
|
||||
use Illuminate\Foundation\Console\TestMakeCommand;
|
||||
use Illuminate\Foundation\Console\ViewMakeCommand;
|
||||
use Illuminate\Notifications\Console\NotificationTableCommand;
|
||||
use Illuminate\Queue\Console\BatchesTableCommand;
|
||||
use Illuminate\Queue\Console\FailedTableCommand;
|
||||
use Illuminate\Queue\Console\TableCommand as QueueTableCommand;
|
||||
use Illuminate\Routing\Console\ControllerMakeCommand;
|
||||
use Illuminate\Routing\Console\MiddlewareMakeCommand;
|
||||
use Illuminate\Session\Console\SessionTableCommand;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
/**
|
||||
* @see https://github.com/laravel/framework/blob/11.x/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php
|
||||
*/
|
||||
class LaravelServiceProvider extends ServiceProvider implements DeferrableProvider
|
||||
{
|
||||
/**
|
||||
* Register the service provider.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->registerCastMakeCommand();
|
||||
$this->registerChannelMakeCommand();
|
||||
$this->registerClassMakeCommand();
|
||||
$this->registerComponentMakeCommand();
|
||||
$this->registerConsoleMakeCommand();
|
||||
$this->registerControllerMakeCommand();
|
||||
$this->registerEnumMakeCommand();
|
||||
$this->registerEventMakeCommand();
|
||||
$this->registerExceptionMakeCommand();
|
||||
$this->registerFactoryMakeCommand();
|
||||
$this->registerJobMakeCommand();
|
||||
$this->registerJobMiddlewareMakeCommand();
|
||||
$this->registerInterfaceMakeCommand();
|
||||
$this->registerListenerMakeCommand();
|
||||
$this->registerMailMakeCommand();
|
||||
$this->registerMiddlewareMakeCommand();
|
||||
$this->registerMigrateMakeCommand();
|
||||
$this->registerModelMakeCommand();
|
||||
$this->registerNotificationMakeCommand();
|
||||
$this->registerObserverMakeCommand();
|
||||
$this->registerPolicyMakeCommand();
|
||||
$this->registerProviderMakeCommand();
|
||||
$this->registerRequestMakeCommand();
|
||||
$this->registerResourceMakeCommand();
|
||||
$this->registerRuleMakeCommand();
|
||||
$this->registerScopeMakeCommand();
|
||||
$this->registerSeederMakeCommand();
|
||||
$this->registerTestMakeCommand();
|
||||
$this->registerViewMakeCommand();
|
||||
|
||||
$this->registerCacheTableCommand();
|
||||
$this->registerNotificationTableCommand();
|
||||
$this->registerQueueBatchesTableCommand();
|
||||
$this->registerQueueFailedTableCommand();
|
||||
$this->registerQueueTableCommand();
|
||||
$this->registerSessionTableCommand();
|
||||
|
||||
$this->registerUserFactoryMakeCommand();
|
||||
$this->registerUserModelMakeCommand();
|
||||
|
||||
$this->commands([
|
||||
Console\CastMakeCommand::class,
|
||||
Console\ChannelMakeCommand::class,
|
||||
Console\ComponentMakeCommand::class,
|
||||
Console\ConsoleMakeCommand::class,
|
||||
Console\ClassMakeCommand::class,
|
||||
Console\ControllerMakeCommand::class,
|
||||
Console\EnumMakeCommand::class,
|
||||
Console\EventMakeCommand::class,
|
||||
Console\ExceptionMakeCommand::class,
|
||||
Console\FactoryMakeCommand::class,
|
||||
Console\JobMakeCommand::class,
|
||||
Console\InterfaceMakeCommand::class,
|
||||
Console\ListenerMakeCommand::class,
|
||||
Console\MailMakeCommand::class,
|
||||
Console\MiddlewareMakeCommand::class,
|
||||
Console\MigrateMakeCommand::class,
|
||||
Console\ModelMakeCommand::class,
|
||||
Console\NotificationMakeCommand::class,
|
||||
Console\ObserverMakeCommand::class,
|
||||
Console\PolicyMakeCommand::class,
|
||||
Console\ProviderMakeCommand::class,
|
||||
Console\RequestMakeCommand::class,
|
||||
Console\ResourceMakeCommand::class,
|
||||
Console\RuleMakeCommand::class,
|
||||
Console\ScopeMakeCommand::class,
|
||||
Console\SeederMakeCommand::class,
|
||||
Console\TestMakeCommand::class,
|
||||
Console\ViewMakeCommand::class,
|
||||
|
||||
Console\BatchesTableCommand::class,
|
||||
Console\CacheTableCommand::class,
|
||||
Console\FailedTableCommand::class,
|
||||
Console\NotificationTableCommand::class,
|
||||
Console\QueueTableCommand::class,
|
||||
Console\SessionTableCommand::class,
|
||||
|
||||
Console\UserFactoryMakeCommand::class,
|
||||
Console\UserModelMakeCommand::class,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerCastMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
CastMakeCommand::class, static fn ($app) => new Console\CastMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerChannelMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ChannelMakeCommand::class, static fn ($app) => new Console\ChannelMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerClassMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ClassMakeCommand::class, static fn ($app) => new Console\ClassMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerComponentMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ComponentMakeCommand::class, static fn ($app) => new Console\ComponentMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerConsoleMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ConsoleMakeCommand::class, static fn ($app) => new Console\ConsoleMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerControllerMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ControllerMakeCommand::class, static fn ($app) => new Console\ControllerMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerEnumMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
EnumMakeCommand::class, fn ($app) => new Console\EnumMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerEventMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
EventMakeCommand::class, static fn ($app) => new Console\EventMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerExceptionMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ExceptionMakeCommand::class, static fn ($app) => new Console\ExceptionMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerFactoryMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
FactoryMakeCommand::class, static fn ($app) => new Console\FactoryMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerJobMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
JobMakeCommand::class, static fn ($app) => new Console\JobMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerJobMiddlewareMakeCommand()
|
||||
{
|
||||
$this->app->singleton(
|
||||
JobMiddlewareMakeCommand::class, static fn ($app) => new Console\JobMiddlewareMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerInterfaceMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
InterfaceMakeCommand::class, static fn ($app) => new Console\InterfaceMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerListenerMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ListenerMakeCommand::class, static fn ($app) => new Console\ListenerMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerMailMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
MailMakeCommand::class, static fn ($app) => new Console\MailMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerMiddlewareMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
MiddlewareMakeCommand::class, static fn ($app) => new Console\MiddlewareMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerMigrateMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(Console\MigrateMakeCommand::class, static function ($app) {
|
||||
// Once we have the migration creator registered, we will create the command
|
||||
// and inject the creator. The creator is responsible for the actual file
|
||||
// creation of the migrations, and may be extended by these developers.
|
||||
$creator = $app['migration.creator'];
|
||||
|
||||
$composer = $app['composer'];
|
||||
|
||||
return new Console\MigrateMakeCommand($creator, $composer);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerModelMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ModelMakeCommand::class, static fn ($app) => new Console\ModelMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerNotificationMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
NotificationMakeCommand::class, static fn ($app) => new Console\NotificationMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerObserverMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ObserverMakeCommand::class, static fn ($app) => new Console\ObserverMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerPolicyMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
PolicyMakeCommand::class, static fn ($app) => new Console\PolicyMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerProviderMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ProviderMakeCommand::class, static fn ($app) => new Console\ProviderMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerRequestMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
RequestMakeCommand::class, static fn ($app) => new Console\RequestMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerResourceMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ResourceMakeCommand::class, static fn ($app) => new Console\ResourceMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerRuleMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
RuleMakeCommand::class, static fn ($app) => new Console\RuleMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerScopeMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ScopeMakeCommand::class, static fn ($app) => new Console\ScopeMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerSeederMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
SeederMakeCommand::class, static fn ($app) => new Console\SeederMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerTestMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
TestMakeCommand::class, static fn ($app) => new Console\TestMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerViewMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
ViewMakeCommand::class, static fn ($app) => new Console\ViewMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerCacheTableCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
CacheTableCommand::class, static fn ($app) => new Console\CacheTableCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerNotificationTableCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
NotificationTableCommand::class, static fn ($app) => new Console\NotificationTableCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerQueueBatchesTableCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
BatchesTableCommand::class, static fn ($app) => new Console\BatchesTableCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerQueueFailedTableCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
FailedTableCommand::class, static fn ($app) => new Console\FailedTableCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerQueueTableCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
QueueTableCommand::class, static fn ($app) => new Console\QueueTableCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerSessionTableCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
SessionTableCommand::class, static fn ($app) => new Console\SessionTableCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerUserFactoryMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
Console\UserFactoryMakeCommand::class, static fn ($app) => new Console\UserFactoryMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the command.
|
||||
*/
|
||||
protected function registerUserModelMakeCommand(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
Console\UserModelMakeCommand::class, static fn ($app) => new Console\UserModelMakeCommand($app['files'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
* @return array<int, class-string>
|
||||
*/
|
||||
public function provides()
|
||||
{
|
||||
return [
|
||||
CastMakeCommand::class,
|
||||
Console\CastMakeCommand::class,
|
||||
ChannelMakeCommand::class,
|
||||
Console\ChannelMakeCommand::class,
|
||||
ClassMakeCommand::class,
|
||||
Console\ClassMakeCommand::class,
|
||||
ComponentMakeCommand::class,
|
||||
Console\ComponentMakeCommand::class,
|
||||
ConsoleMakeCommand::class,
|
||||
Console\ConsoleMakeCommand::class,
|
||||
ControllerMakeCommand::class,
|
||||
Console\ControllerMakeCommand::class,
|
||||
EnumMakeCommand::class,
|
||||
Console\EnumMakeCommand::class,
|
||||
EventMakeCommand::class,
|
||||
Console\EventMakeCommand::class,
|
||||
ExceptionMakeCommand::class,
|
||||
Console\ExceptionMakeCommand::class,
|
||||
FactoryMakeCommand::class,
|
||||
Console\FactoryMakeCommand::class,
|
||||
InterfaceMakeCommand::class,
|
||||
Console\InterfaceMakeCommand::class,
|
||||
JobMakeCommand::class,
|
||||
Console\JobMakeCommand::class,
|
||||
JobMiddlewareMakeCommand::class,
|
||||
Console\JobMiddlewareMakeCommand::class,
|
||||
ListenerMakeCommand::class,
|
||||
Console\ListenerMakeCommand::class,
|
||||
MailMakeCommand::class,
|
||||
Console\MailMakeCommand::class,
|
||||
MiddlewareMakeCommand::class,
|
||||
Console\MiddlewareMakeCommand::class,
|
||||
Console\MigrateMakeCommand::class,
|
||||
ModelMakeCommand::class,
|
||||
Console\ModelMakeCommand::class,
|
||||
NotificationMakeCommand::class,
|
||||
Console\NotificationMakeCommand::class,
|
||||
ObserverMakeCommand::class,
|
||||
Console\ObserverMakeCommand::class,
|
||||
PolicyMakeCommand::class,
|
||||
Console\PolicyMakeCommand::class,
|
||||
ProviderMakeCommand::class,
|
||||
Console\ProviderMakeCommand::class,
|
||||
RequestMakeCommand::class,
|
||||
Console\RequestMakeCommand::class,
|
||||
ResourceMakeCommand::class,
|
||||
Console\ResourceMakeCommand::class,
|
||||
RuleMakeCommand::class,
|
||||
Console\RuleMakeCommand::class,
|
||||
ScopeMakeCommand::class,
|
||||
Console\ScopeMakeCommand::class,
|
||||
SeederMakeCommand::class,
|
||||
Console\SeederMakeCommand::class,
|
||||
TestMakeCommand::class,
|
||||
Console\TestMakeCommand::class,
|
||||
ViewMakeCommand::class,
|
||||
Console\ViewMakeCommand::class,
|
||||
|
||||
BatchesTableCommand::class,
|
||||
Console\BatchesTableCommand::class,
|
||||
CacheTableCommand::class,
|
||||
Console\CacheTableCommand::class,
|
||||
FailedTableCommand::class,
|
||||
Console\FailedTableCommand::class,
|
||||
NotificationTableCommand::class,
|
||||
Console\NotificationTableCommand::class,
|
||||
QueueTableCommand::class,
|
||||
Console\QueueTableCommand::class,
|
||||
SessionTableCommand::class,
|
||||
Console\SessionTableCommand::class,
|
||||
|
||||
Console\UserFactoryMakeCommand::class,
|
||||
Console\UserModelMakeCommand::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Presets;
|
||||
|
||||
use function Orchestra\Sidekick\join_paths;
|
||||
|
||||
class Laravel extends Preset
|
||||
{
|
||||
/**
|
||||
* Preset name.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return 'laravel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the source directory.
|
||||
*/
|
||||
public function sourcePath(): string
|
||||
{
|
||||
return join_paths($this->basePath(), $this->config('paths.src', 'app'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset namespace.
|
||||
*/
|
||||
public function rootNamespace(): string
|
||||
{
|
||||
return $this->config['namespace'] ?? 'App';
|
||||
}
|
||||
|
||||
/**
|
||||
* Command namespace.
|
||||
*/
|
||||
public function commandNamespace(): string
|
||||
{
|
||||
return $this->config('console.namespace', $this->rootNamespace().'\Console\Commands');
|
||||
}
|
||||
|
||||
/**
|
||||
* Model namespace.
|
||||
*/
|
||||
public function modelNamespace(): string
|
||||
{
|
||||
return $this->config('model.namespace', $this->rootNamespace().'\Models');
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider namespace.
|
||||
*/
|
||||
public function providerNamespace(): string
|
||||
{
|
||||
return $this->config('provider.namespace', $this->rootNamespace().'\Providers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing namespace.
|
||||
*/
|
||||
public function testingNamespace(): string
|
||||
{
|
||||
return $this->config('testing.namespace', 'Tests');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom stub path.
|
||||
*/
|
||||
public function getCustomStubPath(): ?string
|
||||
{
|
||||
return join_paths($this->basePath(), 'stubs');
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Presets;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function Orchestra\Sidekick\join_paths;
|
||||
|
||||
class Package extends Preset
|
||||
{
|
||||
/**
|
||||
* Preset name.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return 'package';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the source directory.
|
||||
*/
|
||||
public function sourcePath(): string
|
||||
{
|
||||
return join_paths(
|
||||
$this->basePath(),
|
||||
$this->config('paths.src', 'src')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset namespace.
|
||||
*/
|
||||
public function rootNamespace(): string
|
||||
{
|
||||
$namespace = trim($this->config['namespace'] ?? '');
|
||||
|
||||
if (empty($namespace)) {
|
||||
throw new InvalidArgumentException("Please configure namespace configuration under 'canvas.yaml'");
|
||||
}
|
||||
|
||||
return $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command namespace.
|
||||
*/
|
||||
public function commandNamespace(): string
|
||||
{
|
||||
return $this->config('console.namespace', $this->rootNamespace().'\Console');
|
||||
}
|
||||
|
||||
/**
|
||||
* Model namespace.
|
||||
*/
|
||||
public function modelNamespace(): string
|
||||
{
|
||||
return $this->config('model.namespace', $this->rootNamespace());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider namespace.
|
||||
*/
|
||||
public function providerNamespace(): string
|
||||
{
|
||||
return $this->config('provider.namespace', $this->rootNamespace());
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing namespace.
|
||||
*/
|
||||
public function testingNamespace(): string
|
||||
{
|
||||
return $this->config('testing.namespace', $this->rootNamespace().'\Tests');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom stub path.
|
||||
*/
|
||||
public function getCustomStubPath(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Canvas\Presets;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
use function Orchestra\Sidekick\join_paths;
|
||||
|
||||
abstract class Preset
|
||||
{
|
||||
/**
|
||||
* Construct a new preset.
|
||||
*
|
||||
* @param array<string, mixed> $config
|
||||
*/
|
||||
public function __construct(
|
||||
protected array $config,
|
||||
protected string $basePath
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if preset name equal to $name.
|
||||
*/
|
||||
public function is(string $name): bool
|
||||
{
|
||||
return $this->name() === $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configuration.
|
||||
*
|
||||
* @param mixed|null $default
|
||||
*/
|
||||
public function config(?string $key = null, $default = null): mixed
|
||||
{
|
||||
if (\is_null($key)) {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
return Arr::get($this->config, $key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the base working directory.
|
||||
*/
|
||||
public function basePath(): string
|
||||
{
|
||||
return $this->basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the testing directory.
|
||||
*/
|
||||
public function testingPath(): string
|
||||
{
|
||||
return join_paths($this->basePath, 'tests');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the resource directory.
|
||||
*/
|
||||
public function resourcePath(): string
|
||||
{
|
||||
return join_paths(
|
||||
$this->basePath(),
|
||||
$this->config('paths.resource', 'resources')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the factory directory.
|
||||
*/
|
||||
public function factoryPath(): string
|
||||
{
|
||||
return join_paths(
|
||||
$this->basePath(),
|
||||
$this->config('factory.path', join_paths('database', 'factories'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the migration directory.
|
||||
*/
|
||||
public function migrationPath(): string
|
||||
{
|
||||
return join_paths(
|
||||
$this->basePath(),
|
||||
$this->config('migration.path', join_paths('database', 'migrations'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the seeder directory.
|
||||
*/
|
||||
public function seederPath(): string
|
||||
{
|
||||
return join_paths(
|
||||
$this->basePath(),
|
||||
$this->config('seeder.path', join_paths('database', 'seeders'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Database factory namespace.
|
||||
*/
|
||||
public function factoryNamespace(): string
|
||||
{
|
||||
return $this->config('factory.namespace', 'Database\Factories');
|
||||
}
|
||||
|
||||
/**
|
||||
* Database seeder namespace.
|
||||
*/
|
||||
public function seederNamespace(): string
|
||||
{
|
||||
return $this->config('seeder.namespace', 'Database\Seeders');
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset name.
|
||||
*/
|
||||
abstract public function name(): string;
|
||||
|
||||
/**
|
||||
* Get the path to the source directory.
|
||||
*/
|
||||
abstract public function sourcePath(): string;
|
||||
|
||||
/**
|
||||
* Preset namespace.
|
||||
*/
|
||||
abstract public function rootNamespace(): string;
|
||||
|
||||
/**
|
||||
* Command namespace.
|
||||
*/
|
||||
abstract public function commandNamespace(): string;
|
||||
|
||||
/**
|
||||
* Model namespace.
|
||||
*/
|
||||
abstract public function modelNamespace(): string;
|
||||
|
||||
/**
|
||||
* Provider namespace.
|
||||
*/
|
||||
abstract public function providerNamespace(): string;
|
||||
|
||||
/**
|
||||
* Testing namespace.
|
||||
*/
|
||||
abstract public function testingNamespace(): string;
|
||||
|
||||
/**
|
||||
* Get custom stub path.
|
||||
*/
|
||||
abstract public function getCustomStubPath(): ?string;
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "orchestra/sidekick",
|
||||
"description": "Packages Toolkit Utilities and Helpers for Laravel",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mior Muhammad Zaki",
|
||||
"email": "crynobone@gmail.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Sidekick\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/Eloquent/functions.php",
|
||||
"src/Filesystem/functions.php",
|
||||
"src/Http/functions.php",
|
||||
"src/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Sidekick\\Tests\\": "tests/",
|
||||
"App\\": "workbench/app/",
|
||||
"Database\\Factories\\": "workbench/database/factories/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"composer-runtime-api": "^2.2",
|
||||
"composer/semver": "^3.0",
|
||||
"symfony/polyfill-php83": "^1.32"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.21",
|
||||
"laravel/framework": "^10.48.29|^11.44.7|^12.1.1|^13.0",
|
||||
"laravel/pint": "^1.4",
|
||||
"mockery/mockery": "^1.5.1",
|
||||
"orchestra/testbench-core": "^8.37.0|^9.14.0|^10.2.0|^11.0",
|
||||
"phpstan/phpstan": "^2.1.14",
|
||||
"phpunit/phpunit": "^10.0|^11.0|^12.0",
|
||||
"symfony/process": "^6.0|^7.0"
|
||||
},
|
||||
"config": {
|
||||
"audit": {
|
||||
"block-insecure": false
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"lint": [
|
||||
"@php vendor/bin/pint",
|
||||
"@php vendor/bin/phpstan analyse --verbose"
|
||||
],
|
||||
"test": "@php vendor/bin/phpunit",
|
||||
"ci": [
|
||||
"@lint",
|
||||
"@test"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick\Eloquent\Concerns;
|
||||
|
||||
use function Orchestra\Sidekick\laravel_version_compare;
|
||||
|
||||
/**
|
||||
* Polyfill for Eloquent Model to get previous attributes.
|
||||
*
|
||||
* @see https://github.com/laravel/framework/pull/55729
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
if (laravel_version_compare('12.15.0', '>=')) {
|
||||
trait HasPreviousAttributes
|
||||
{
|
||||
// ...
|
||||
}
|
||||
} else {
|
||||
trait HasPreviousAttributes
|
||||
{
|
||||
/**
|
||||
* The previous state of the changed model attributes.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected $previous = [];
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
public function syncChanges()
|
||||
{
|
||||
parent::syncChanges();
|
||||
|
||||
$this->previous = array_intersect_key($this->getRawOriginal(), $this->changes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
#[\Override]
|
||||
public function discardChanges()
|
||||
{
|
||||
$this->previous = [];
|
||||
|
||||
return parent::discardChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attributes that were previously original before the model was last saved.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getPrevious()
|
||||
{
|
||||
return $this->previous;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick\Eloquent;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use WeakMap;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class Watcher
|
||||
{
|
||||
/**
|
||||
* The cache instance.
|
||||
*
|
||||
* @var \WeakMap<\Illuminate\Database\Eloquent\Model, array<string, mixed>>|null
|
||||
*/
|
||||
protected static ?WeakMap $cache = null;
|
||||
|
||||
/**
|
||||
* Get the watcher store.
|
||||
*
|
||||
* @return \WeakMap<\Illuminate\Database\Eloquent\Model, array<string, mixed>>
|
||||
*/
|
||||
public static function store(): WeakMap
|
||||
{
|
||||
/** @phpstan-ignore assign.propertyType,return.type */
|
||||
return static::$cache ??= new WeakMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a model snapshot.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function snapshot(Model $model): ?array
|
||||
{
|
||||
$original = $model->getRawOriginal();
|
||||
|
||||
$response = match (true) {
|
||||
$model->isDirty() => $original,
|
||||
isset(static::store()[$model]) => static::store()[$model],
|
||||
default => null,
|
||||
};
|
||||
|
||||
static::store()[$model] = $original;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the instance states.
|
||||
*/
|
||||
public static function flushState(): void
|
||||
{
|
||||
static::$cache = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick\Eloquent;
|
||||
|
||||
use BackedEnum;
|
||||
use Carbon\CarbonInterface;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\Concerns\AsPivot;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
use Illuminate\Support\Arr;
|
||||
use InvalidArgumentException;
|
||||
use JsonSerializable;
|
||||
use Orchestra\Sidekick\SensitiveValue;
|
||||
use Stringable;
|
||||
use Throwable;
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\column_name')) {
|
||||
/**
|
||||
* Get qualify column name from Eloquent model.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model|class-string<\Illuminate\Database\Eloquent\Model> $model
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
function column_name(Model|string $model, string $attribute): string
|
||||
{
|
||||
if (\is_string($model)) {
|
||||
$model = new $model;
|
||||
}
|
||||
|
||||
if (! $model instanceof Model) {
|
||||
throw new InvalidArgumentException(\sprintf('Given $model is not an instance of [%s].', Model::class));
|
||||
}
|
||||
|
||||
return $model->qualifyColumn($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\is_pivot_model')) {
|
||||
/**
|
||||
* Determine if the given model is a pivot model.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @template TPivotModel of (\Illuminate\Database\Eloquent\Model&\Illuminate\Database\Eloquent\Relations\Concerns\AsPivot)|\Illuminate\Database\Eloquent\Relations\Pivot
|
||||
*
|
||||
* @param TPivotModel|class-string<TPivotModel> $model
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
function is_pivot_model(Pivot|Model|string $model): bool
|
||||
{
|
||||
if (\is_string($model)) {
|
||||
$model = new $model;
|
||||
}
|
||||
|
||||
if (! $model instanceof Model) {
|
||||
throw new InvalidArgumentException(\sprintf('Given $model is not an instance of [%s|%s].', Model::class, Pivot::class));
|
||||
}
|
||||
|
||||
if ($model instanceof Pivot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return \in_array(AsPivot::class, class_uses_recursive($model), true);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\model_exists')) {
|
||||
/**
|
||||
* Check whether given $model exists.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function model_exists(mixed $model): bool
|
||||
{
|
||||
return $model instanceof Model && $model->exists === true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\model_from')) {
|
||||
/**
|
||||
* Check whether given $model exists.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model|class-string<\Illuminate\Database\Eloquent\Model> $model
|
||||
* @param array<string, mixed> $attributes
|
||||
*/
|
||||
function model_from(Model|string $model, array $attributes): Model
|
||||
{
|
||||
return $model::unguarded(function () use ($model, $attributes) {
|
||||
if (\is_string($model)) {
|
||||
$model = new $model;
|
||||
}
|
||||
|
||||
return $model->newInstance()->setRawAttributes($attributes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\model_key_type')) {
|
||||
/**
|
||||
* Check whether given $model key type.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model|class-string<\Illuminate\Database\Eloquent\Model> $model
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
function model_key_type(Model|string $model): string
|
||||
{
|
||||
if (\is_string($model)) {
|
||||
$model = new $model;
|
||||
}
|
||||
|
||||
if (! $model instanceof Model) {
|
||||
throw new InvalidArgumentException(\sprintf('Given $model is not an instance of [%s].', Model::class));
|
||||
}
|
||||
|
||||
$uses = class_uses_recursive($model);
|
||||
|
||||
if (\in_array(HasUlids::class, $uses, true)) {
|
||||
return 'ulid';
|
||||
} elseif (\in_array(HasUuids::class, $uses, true)) {
|
||||
return 'uuid';
|
||||
}
|
||||
|
||||
return $model->getKeyType();
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\model_diff')) {
|
||||
/**
|
||||
* Get attributes diff state from a model.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param array<int, string> $excludes
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
function model_diff(Model $model, array $excludes = [], bool $withTimestamps = true): array
|
||||
{
|
||||
$hiddens = $model->getHidden();
|
||||
$excludedAttributes = array_merge($excludes, $model->getAppends());
|
||||
$timestamps = [$model->getCreatedAtColumn(), $model->getUpdatedAtColumn()];
|
||||
|
||||
if (! model_exists($model) || $model->wasRecentlyCreated === true) {
|
||||
$rawChanges = $model->getAttributes();
|
||||
|
||||
$changes = model_from($model, $rawChanges)->setHidden($excludedAttributes)->attributesToArray();
|
||||
|
||||
return Arr::except(
|
||||
summarize_changes($changes, hiddens: $hiddens),
|
||||
$withTimestamps === false ? $timestamps : [$model->getUpdatedAtColumn()]
|
||||
);
|
||||
}
|
||||
|
||||
$rawChanges = $model->isDirty() ? $model->getDirty() : $model->getChanges();
|
||||
|
||||
$changes = array_intersect_key(
|
||||
model_from($model, $rawChanges)->setHidden($excludedAttributes)->setAppends([])->attributesToArray(),
|
||||
$rawChanges
|
||||
);
|
||||
|
||||
return Arr::except(
|
||||
summarize_changes($changes, hiddens: $hiddens),
|
||||
$withTimestamps === false ? $timestamps : []
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\model_snapshot')) {
|
||||
/**
|
||||
* Store a snapshot for a model and return the original attributes.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
function model_snapshot(Model $model): ?array
|
||||
{
|
||||
return Watcher::snapshot($model);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\model_state')) {
|
||||
/**
|
||||
* Get attributes original and changed state from a model.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param array<int, string> $excludes
|
||||
* @return array{0: array<string, mixed>|null, 1: array<string, mixed>}
|
||||
*/
|
||||
function model_state(Model $model, array $excludes = [], bool $withTimestamps = true): array
|
||||
{
|
||||
$changes = model_diff($model, $excludes, $withTimestamps);
|
||||
$excludedAttributes = array_merge($excludes, $model->getAppends());
|
||||
|
||||
if (! model_exists($model) || $model->wasRecentlyCreated == true) {
|
||||
return [null, $changes];
|
||||
}
|
||||
|
||||
/** @phpstan-ignore function.alreadyNarrowedType */
|
||||
$previous = method_exists($model, 'getPrevious') ? $model->getPrevious() : null;
|
||||
|
||||
if (empty($previous)) {
|
||||
$previous = Watcher::snapshot($model);
|
||||
}
|
||||
|
||||
$original = summarize_changes(
|
||||
array_intersect_key(model_from($model, $previous ?? [])->setHidden($excludedAttributes)->setAppends([])->attributesToArray(), $changes),
|
||||
hiddens: $model->getHidden(),
|
||||
);
|
||||
|
||||
return [$original, $changes];
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\normalize_value')) {
|
||||
/**
|
||||
* Normalize the given value to be store to database as scalar.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @return scalar
|
||||
*/
|
||||
function normalize_value(mixed $value): mixed
|
||||
{
|
||||
$value = match (true) {
|
||||
$value instanceof CarbonInterface => $value->toISOString(),
|
||||
$value instanceof JsonSerializable => $value->jsonSerialize(),
|
||||
$value instanceof BackedEnum => $value->value,
|
||||
default => $value,
|
||||
};
|
||||
|
||||
if (\is_object($value) && $value instanceof Stringable) {
|
||||
return (string) $value;
|
||||
} elseif (\is_object($value) || \is_array($value)) {
|
||||
try {
|
||||
return json_encode($value);
|
||||
} catch (Throwable $e) { // @phpstan-ignore catch.neverThrown
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\summarize_changes')) {
|
||||
/**
|
||||
* Get table name from Eloquent model.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param array<string, mixed> $changes
|
||||
* @param array<int, string> $hiddens
|
||||
* @return array<string, \Orchestra\Sidekick\SensitiveValue<mixed>|scalar>
|
||||
*/
|
||||
function summarize_changes(array $changes, array $hiddens = []): array
|
||||
{
|
||||
$summaries = [];
|
||||
|
||||
foreach ($changes as $attribute => $value) {
|
||||
$summaries[$attribute] = \in_array($attribute, $hiddens, true)
|
||||
? new SensitiveValue($value)
|
||||
: normalize_value($value);
|
||||
}
|
||||
|
||||
return $summaries;
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Eloquent\table_name')) {
|
||||
/**
|
||||
* Get table name from Eloquent model.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model|class-string<\Illuminate\Database\Eloquent\Model> $model
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
function table_name(Model|string $model): string
|
||||
{
|
||||
if (\is_string($model)) {
|
||||
$model = new $model;
|
||||
}
|
||||
|
||||
if (! $model instanceof Model) {
|
||||
throw new InvalidArgumentException(\sprintf('Given $model is not an instance of [%s].', Model::class));
|
||||
}
|
||||
|
||||
return $model->getTable();
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
class Env extends \Illuminate\Support\Env
|
||||
{
|
||||
/**
|
||||
* Determine if environmemt variable is available.
|
||||
*/
|
||||
public static function has(string $key): bool
|
||||
{
|
||||
return static::get($key, new UndefinedValue) instanceof UndefinedValue === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an environment value.
|
||||
*/
|
||||
public static function set(string $key, string $value): void
|
||||
{
|
||||
static::getRepository()->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget an environment variable.
|
||||
*
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function forget(string $key): bool
|
||||
{
|
||||
return static::getRepository()->clear($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward environment value.
|
||||
*
|
||||
* @param \Orchestra\Sidekick\UndefinedValue|mixed|null $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function forward(string $key, $default = new UndefinedValue)
|
||||
{
|
||||
$value = static::get($key, $default);
|
||||
|
||||
if ($value instanceof UndefinedValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::encode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode environment variable value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function encode($value)
|
||||
{
|
||||
if (\is_null($value)) {
|
||||
return '(null)';
|
||||
}
|
||||
|
||||
if (\is_bool($value)) {
|
||||
return $value === true ? '(true)' : '(false)';
|
||||
}
|
||||
|
||||
if (empty($value)) {
|
||||
return '(empty)';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick\Filesystem;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Filesystem\filename_from_classname')) {
|
||||
/**
|
||||
* Resolve filename from classname.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param class-string $className
|
||||
*/
|
||||
function filename_from_classname(string $className): string|false
|
||||
{
|
||||
if (! class_exists($className, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$classFileName = (new ReflectionClass($className))->getFileName();
|
||||
|
||||
if (
|
||||
$classFileName === false
|
||||
|| (! is_file($classFileName) && ! str_ends_with(strtolower($classFileName), '.php'))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return realpath($classFileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Filesystem\is_symlink')) {
|
||||
/**
|
||||
* Determine if the path is a symlink for both Unix and Windows environments.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function is_symlink(string $path): bool
|
||||
{
|
||||
if (\Orchestra\Sidekick\windows_os() && is_dir($path) && readlink($path) !== $path) {
|
||||
return true;
|
||||
} elseif (is_link($path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Filesystem\join_paths')) {
|
||||
/**
|
||||
* Join the given paths together.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function join_paths(?string $basePath, string ...$paths): string
|
||||
{
|
||||
foreach ($paths as $index => $path) {
|
||||
if (empty($path) && $path !== '0') {
|
||||
unset($paths[$index]);
|
||||
} else {
|
||||
$paths[$index] = DIRECTORY_SEPARATOR.ltrim($path, DIRECTORY_SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
return $basePath.implode('', $paths);
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick;
|
||||
|
||||
use ArrayAccess;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Jsonable;
|
||||
use Illuminate\Support\Fluent;
|
||||
use Illuminate\Support\Traits\ForwardsCalls;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
*
|
||||
* @implements \Illuminate\Contracts\Support\Arrayable<TKey, TValue>
|
||||
* @implements \ArrayAccess<TKey, TValue>
|
||||
*/
|
||||
abstract class FluentDecorator implements Arrayable, ArrayAccess, Jsonable, JsonSerializable
|
||||
{
|
||||
use ForwardsCalls;
|
||||
|
||||
/**
|
||||
* The Fluent instance.
|
||||
*
|
||||
* @var \Illuminate\Support\Fluent<TKey, TValue>
|
||||
*/
|
||||
protected Fluent $fluent;
|
||||
|
||||
/**
|
||||
* Create a new fluent instance.
|
||||
*
|
||||
* @param iterable<TKey, TValue> $attributes
|
||||
*/
|
||||
public function __construct($attributes = [])
|
||||
{
|
||||
$this->fluent = new Fluent($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the fluent instance to an array.
|
||||
*
|
||||
* @return array<TKey, TValue>
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->fluent->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object into something JSON serializable.
|
||||
*
|
||||
* @return array<TKey, TValue>
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the fluent instance to JSON.
|
||||
*
|
||||
* @param int $options
|
||||
* @return string
|
||||
*/
|
||||
public function toJson($options = 0)
|
||||
{
|
||||
return (string) json_encode($this->jsonSerialize(), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given offset exists.
|
||||
*
|
||||
* @param TKey $offset
|
||||
*/
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
return $this->fluent->offsetExists($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for a given offset.
|
||||
*
|
||||
* @param TKey $offset
|
||||
* @return TValue|null
|
||||
*/
|
||||
public function offsetGet($offset): mixed
|
||||
{
|
||||
return $this->fluent->offsetGet($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value at the given offset.
|
||||
*
|
||||
* @param TKey $offset
|
||||
* @param TValue $value
|
||||
*/
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
$this->fluent->offsetSet($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset the value at the given offset.
|
||||
*
|
||||
* @param TKey $offset
|
||||
*/
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
$this->fluent->offsetUnset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dynamic calls to the fluent instance to set attributes.
|
||||
*
|
||||
* @param TKey $method
|
||||
* @param array{0: ?TValue} $parameters
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
return $this->forwardDecoratedCallTo($this->fluent, $method, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically retrieve the value of an attribute.
|
||||
*
|
||||
* @param TKey $key
|
||||
* @return TValue|null
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
/** @phpstan-ignore function.alreadyNarrowedType */
|
||||
if (method_exists($this->fluent, 'value')) {
|
||||
return $this->fluent->value($key);
|
||||
}
|
||||
|
||||
return $this->fluent->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically set the value of an attribute.
|
||||
*
|
||||
* @param TKey $key
|
||||
* @param TValue $value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
{
|
||||
$this->fluent->offsetSet($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically check if an attribute is set.
|
||||
*
|
||||
* @param TKey $key
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($key)
|
||||
{
|
||||
return $this->fluent->offsetExists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically unset an attribute.
|
||||
*
|
||||
* @param TKey $key
|
||||
* @return void
|
||||
*/
|
||||
public function __unset($key)
|
||||
{
|
||||
$this->fluent->offsetUnset($key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick\Http;
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\Http\safe_int')) {
|
||||
/**
|
||||
* Convert large id higher than Number.MAX_SAFE_INTEGER to string.
|
||||
*
|
||||
* https://stackoverflow.com/questions/47188449/json-max-int-number/47188576
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function safe_int(mixed $value): mixed
|
||||
{
|
||||
$jsonMaxInt = 9007199254740991;
|
||||
|
||||
if (\is_int($value) && abs($value) >= $jsonMaxInt) {
|
||||
return (string) $value;
|
||||
} elseif (filter_var($value, FILTER_VALIDATE_INT) && abs($value) < $jsonMaxInt) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick;
|
||||
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
use Symfony\Component\Process\PhpExecutableFinder as SymfonyPhpExecutableFinder;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class PhpExecutableFinder extends SymfonyPhpExecutableFinder
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
#[\Override]
|
||||
public function find(bool $includeArgs = true): string|false
|
||||
{
|
||||
if ($herdPath = getenv('HERD_HOME')) {
|
||||
return (new ExecutableFinder)->find(name: 'php', extraDirs: [join_paths($herdPath, 'bin')]) ?? false;
|
||||
}
|
||||
|
||||
return parent::find($includeArgs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick;
|
||||
|
||||
use JsonSerializable;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*
|
||||
* @template TValue of mixed
|
||||
*/
|
||||
final class SensitiveValue implements JsonSerializable, Stringable
|
||||
{
|
||||
/**
|
||||
* Construct a new sensitive value.
|
||||
*
|
||||
* @param TValue $value
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly mixed $value
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original value.
|
||||
*
|
||||
* @return TValue
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the value for debugging.
|
||||
*/
|
||||
public function __debugInfo(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for string serialization.
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->jsonSerialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for JSON serialization.
|
||||
*/
|
||||
public function jsonSerialize(): string
|
||||
{
|
||||
return '******';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
final class UndefinedValue implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Determine if value is equivalent to "undefined" or "null".
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @phpstan-assert-if-true \Orchestra\Sidekick\UndefinedValue|null $value
|
||||
*/
|
||||
public static function equalsTo($value): bool
|
||||
{
|
||||
return $value instanceof UndefinedValue || \is_null($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for JSON serialization.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+415
@@ -0,0 +1,415 @@
|
||||
<?php
|
||||
|
||||
namespace Orchestra\Sidekick;
|
||||
|
||||
use BackedEnum;
|
||||
use Closure;
|
||||
use Composer\InstalledVersions;
|
||||
use Composer\Semver\VersionParser;
|
||||
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Support\Arr;
|
||||
use OutOfBoundsException;
|
||||
use PHPUnit\Runner\Version;
|
||||
use RuntimeException;
|
||||
use UnitEnum;
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\enum_name')) {
|
||||
/**
|
||||
* Get the proper name from enum.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
function enum_name(BackedEnum|UnitEnum $enum): string
|
||||
{
|
||||
return mb_convert_case(str_replace('_', ' ', $enum->name), MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\enum_value')) {
|
||||
/**
|
||||
* Get the proper name from enum.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @template TValue
|
||||
* @template TDefault
|
||||
*
|
||||
* @param TValue $value
|
||||
* @param TDefault|callable(TValue): TDefault $default
|
||||
* @return ($value is empty ? TDefault : mixed)
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
function enum_value(mixed $value, mixed $default = null): mixed
|
||||
{
|
||||
return match (true) {
|
||||
$value instanceof BackedEnum => $value->value,
|
||||
$value instanceof UnitEnum => $value->name,
|
||||
|
||||
default => $value ?? value($default),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\after_resolving')) {
|
||||
/**
|
||||
* Register after resolving callback.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @template TLaravel of \Illuminate\Contracts\Foundation\Application
|
||||
*
|
||||
* @param TLaravel $app
|
||||
* @param class-string|string $name
|
||||
* @param (\Closure(object, TLaravel):(mixed))|null $callback
|
||||
*/
|
||||
function after_resolving(ApplicationContract $app, string $name, ?Closure $callback = null): void
|
||||
{
|
||||
$app->afterResolving($name, $callback);
|
||||
|
||||
if ($app->resolved($name)) {
|
||||
value($callback, $app->make($name), $app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\join_paths')) {
|
||||
|
||||
/**
|
||||
* Join the given paths together.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
function join_paths(?string $basePath, string ...$paths): string
|
||||
{
|
||||
return Filesystem\join_paths($basePath, ...$paths);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\once')) {
|
||||
/**
|
||||
* Run callback only once.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param mixed $callback
|
||||
* @return \Closure():mixed
|
||||
*/
|
||||
function once($callback): Closure
|
||||
{
|
||||
$response = new UndefinedValue;
|
||||
|
||||
return function () use ($callback, &$response) {
|
||||
if ($response instanceof UndefinedValue) {
|
||||
$response = value($callback) ?? null;
|
||||
}
|
||||
|
||||
return $response;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\is_safe_callable')) {
|
||||
/**
|
||||
* Determine if the value is a callable and not a string matching an available function name.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function is_safe_callable(mixed $value): bool
|
||||
{
|
||||
if ($value instanceof Closure) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! \is_callable($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (\is_array($value)) {
|
||||
return \count($value) === 2 && array_is_list($value) && method_exists(...$value);
|
||||
}
|
||||
|
||||
return ! \is_string($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\is_symlink')) {
|
||||
/**
|
||||
* Determine if the path is a symlink for both Unix and Windows environments.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
function is_symlink(string $path): bool
|
||||
{
|
||||
return Filesystem\is_symlink($path);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\is_testbench_cli')) {
|
||||
/**
|
||||
* Determine if command executed via Testbench CLI.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function is_testbench_cli(?bool $dusk = null): bool
|
||||
{
|
||||
$usingTestbench = \defined('TESTBENCH_CORE');
|
||||
$usingTestbenchDusk = \defined('TESTBENCH_DUSK');
|
||||
|
||||
return match ($dusk) {
|
||||
false => $usingTestbench === true && $usingTestbenchDusk === false,
|
||||
true => $usingTestbench === true && $usingTestbenchDusk === true,
|
||||
default => $usingTestbench === true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\transform_relative_path')) {
|
||||
/**
|
||||
* Transform relative path.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
function transform_relative_path(string $path, string $workingPath): string
|
||||
{
|
||||
return str_starts_with($path, './')
|
||||
? rtrim($workingPath, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.mb_substr($path, 2)
|
||||
: $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\package_path')) {
|
||||
/**
|
||||
* Get the package path.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @no-named-arguments
|
||||
*
|
||||
* @param array<int, string|null>|string ...$path
|
||||
*/
|
||||
function package_path(array|string $path = ''): string
|
||||
{
|
||||
$packagePath = once(function () {
|
||||
$workingPath = realpath(match (true) {
|
||||
\defined('TESTBENCH_WORKING_PATH') => TESTBENCH_WORKING_PATH,
|
||||
Env::has('TESTBENCH_WORKING_PATH') => Env::get('TESTBENCH_WORKING_PATH'),
|
||||
default => InstalledVersions::getRootPackage()['install_path'],
|
||||
});
|
||||
|
||||
return $workingPath !== false ? $workingPath : getcwd();
|
||||
});
|
||||
|
||||
return join_paths($packagePath(), ...Arr::wrap(\func_num_args() > 1 ? \func_get_args() : $path));
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\working_path')) {
|
||||
/**
|
||||
* Get the working path.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @no-named-arguments
|
||||
*
|
||||
* @param array<int, string|null>|string ...$path
|
||||
*/
|
||||
function working_path(array|string $path = ''): string
|
||||
{
|
||||
return is_testbench_cli()
|
||||
? package_path($path)
|
||||
: base_path(join_paths(...Arr::wrap(\func_num_args() > 1 ? \func_get_args() : $path)));
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\laravel_normalize_version')) {
|
||||
/**
|
||||
* Laravel normalize version.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
*/
|
||||
function laravel_normalize_version(): string
|
||||
{
|
||||
if (! class_exists(Application::class)) {
|
||||
throw new OutOfBoundsException('Unable to verify "laravel/framework" version');
|
||||
}
|
||||
|
||||
/** @var string $version */
|
||||
$version = transform(
|
||||
Application::VERSION,
|
||||
fn (string $version) => match ($version) {
|
||||
'13.x-dev' => '13.0.0',
|
||||
default => $version,
|
||||
}
|
||||
);
|
||||
|
||||
return (new VersionParser)->normalize($version);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\phpunit_normalize_version')) {
|
||||
/**
|
||||
* PHPUnit normalize version.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
*/
|
||||
function phpunit_normalize_version(): string
|
||||
{
|
||||
if (! class_exists(Version::class)) {
|
||||
throw new OutOfBoundsException('Unable to verify "phpunit/phpunit" version');
|
||||
}
|
||||
|
||||
/** @var string $version */
|
||||
$version = transform(
|
||||
Version::id(),
|
||||
fn (string $version) => match (true) {
|
||||
str_starts_with($version, '13.0-') => '13.0.0',
|
||||
default => $version,
|
||||
}
|
||||
);
|
||||
|
||||
return (new VersionParser)->normalize($version);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\laravel_version_compare')) {
|
||||
/**
|
||||
* Laravel version compare.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @template TOperator of string|null
|
||||
*
|
||||
* @param TOperator $operator
|
||||
* @return (TOperator is null ? int : bool)
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
function laravel_version_compare(string $version, ?string $operator = null): int|bool
|
||||
{
|
||||
if (! class_exists(Application::class)) {
|
||||
return package_version_compare('laravel/framework', $version, $operator);
|
||||
}
|
||||
|
||||
$laravel = laravel_normalize_version();
|
||||
$version = (new VersionParser)->normalize($version);
|
||||
|
||||
if (\is_null($operator)) {
|
||||
return version_compare($laravel, $version);
|
||||
}
|
||||
|
||||
return version_compare($laravel, $version, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\package_version_compare')) {
|
||||
/**
|
||||
* Package version compare.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @template TOperator of string|null
|
||||
*
|
||||
* @phpstan-param TOperator $operator
|
||||
*
|
||||
* @phpstan-return (TOperator is null ? int : bool)
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
function package_version_compare(string $package, string $version, ?string $operator = null): int|bool
|
||||
{
|
||||
$prettyVersion = InstalledVersions::getPrettyVersion($package);
|
||||
|
||||
if (\is_null($prettyVersion)) {
|
||||
throw new RuntimeException(\sprintf('Unable to compare "%s" version', $package));
|
||||
}
|
||||
|
||||
$versionParser = new VersionParser;
|
||||
|
||||
$package = $versionParser->normalize($prettyVersion);
|
||||
$version = $versionParser->normalize($version);
|
||||
|
||||
if (\is_null($operator)) {
|
||||
return version_compare($package, $version);
|
||||
}
|
||||
|
||||
return version_compare($package, $version, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\phpunit_version_compare')) {
|
||||
/**
|
||||
* PHPUnit version compare.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @template TOperator of string|null
|
||||
*
|
||||
* @param TOperator $operator
|
||||
* @return (TOperator is null ? int : bool)
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
function phpunit_version_compare(string $version, ?string $operator = null): int|bool
|
||||
{
|
||||
if (! class_exists(Version::class)) {
|
||||
return package_version_compare('phpunit/phpunit', $version, $operator);
|
||||
}
|
||||
|
||||
$phpunit = phpunit_normalize_version();
|
||||
$version = (new VersionParser)->normalize($version);
|
||||
|
||||
if (\is_null($operator)) {
|
||||
return version_compare($phpunit, $version);
|
||||
}
|
||||
|
||||
return version_compare($phpunit, $version, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\php_binary')) {
|
||||
/**
|
||||
* Determine the PHP Binary.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
function php_binary(): string
|
||||
{
|
||||
return (new PhpExecutableFinder)->find(false) ?: 'php';
|
||||
}
|
||||
}
|
||||
|
||||
if (! \function_exists('Orchestra\Sidekick\windows_os')) {
|
||||
/**
|
||||
* Determine whether the current environment is Windows-based.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
function windows_os(): bool
|
||||
{
|
||||
return PHP_OS_FAMILY === 'Windows';
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "orchestra/testbench-core",
|
||||
"description": "Testing Helper for Laravel Development",
|
||||
"homepage": "https://packages.tools/testbench",
|
||||
"keywords": ["laravel", "laravel-packages", "testing", "tdd", "bdd", "dev"],
|
||||
"license": "MIT",
|
||||
"support": {
|
||||
"issues": "https://github.com/orchestral/testbench/issues",
|
||||
"source": "https://github.com/orchestral/testbench-core"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mior Muhammad Zaki",
|
||||
"email": "crynobone@gmail.com",
|
||||
"homepage": "https://github.com/crynobone"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Testbench\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Orchestra\\Testbench\\Tests\\": "tests/",
|
||||
"Workbench\\App\\": "workbench/app/",
|
||||
"Workbench\\Database\\Factories\\": "workbench/database/factories/",
|
||||
"Workbench\\Database\\Seeders\\": "workbench/database/seeders/"
|
||||
}
|
||||
},
|
||||
"bin": [
|
||||
"testbench"
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"composer-runtime-api": "^2.2",
|
||||
"orchestra/sidekick": "~1.1.23|~1.2.20",
|
||||
"symfony/deprecation-contracts": "^2.5|^3.0",
|
||||
"symfony/polyfill-php84": "^1.34.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.24",
|
||||
"laravel/framework": "^13.9.0",
|
||||
"laravel/pint": "^1.24",
|
||||
"laravel/serializable-closure": "^2.0.10",
|
||||
"mockery/mockery": "^1.6.10",
|
||||
"phpstan/phpstan": "^2.1.38",
|
||||
"phpunit/phpunit": "^11.5.50|^12.5.8|^13.0.0",
|
||||
"spatie/laravel-ray": "^1.43.6",
|
||||
"symfony/process": "^7.4.5|^8.0.5",
|
||||
"symfony/yaml": "^7.4.0|^8.0.0",
|
||||
"vlucas/phpdotenv": "^5.6.1"
|
||||
},
|
||||
"conflict": {
|
||||
"brianium/paratest": "<7.3.0|>=8.0.0",
|
||||
"laravel/framework": "<13.9.0|>=14.0.0",
|
||||
"laravel/serializable-closure": ">=2.0.0 <2.0.10|>=3.0.0",
|
||||
"nunomaduro/collision": "<8.9.0|>=9.0.0",
|
||||
"phpunit/phpunit": "<11.5.50|>=12.0.0 <12.5.8|>=13.2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcntl": "Required to use all features of the console signal trapping.",
|
||||
"brianium/paratest": "Allow using parallel testing (^7.3).",
|
||||
"fakerphp/faker": "Allow using Faker for testing (^1.23).",
|
||||
"laravel/framework": "Required for testing (^13.9.0).",
|
||||
"mockery/mockery": "Allow using Mockery for testing (^1.6).",
|
||||
"nunomaduro/collision": "Allow using Laravel style tests output and parallel testing (^8.9).",
|
||||
"orchestra/testbench-dusk": "Allow using Laravel Dusk for testing (^11.0).",
|
||||
"phpunit/phpunit": "Allow using PHPUnit for testing (^11.5.50|^12.5.8|^13.0.0).",
|
||||
"symfony/process": "Required to use Orchestra\\Testbench\\remote function (^7.4|^8.0).",
|
||||
"symfony/yaml": "Required for Testbench CLI (^7.4|^8.0).",
|
||||
"vlucas/phpdotenv": "Required for Testbench CLI (^5.6.1)."
|
||||
},
|
||||
"config": {
|
||||
"audit": {
|
||||
"ignore": []
|
||||
},
|
||||
"preferred-install": {
|
||||
"laravel/framework": "source",
|
||||
"*": "auto"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@clear",
|
||||
"@prepare"
|
||||
],
|
||||
"clear": "@php testbench package:purge-skeleton --ansi",
|
||||
"prepare": "@php testbench package:discover --ansi",
|
||||
"serve": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"@clear",
|
||||
"@putenv PHP_CLI_SERVER_WORKERS=5",
|
||||
"@php testbench serve --ansi"
|
||||
],
|
||||
"lint": [
|
||||
"@php vendor/bin/pint --ansi",
|
||||
"@php vendor/bin/phpstan analyse --verbose"
|
||||
],
|
||||
"test": [
|
||||
"@php vendor/bin/phpunit --no-coverage --no-configuration --bootstrap vendor/autoload.php --exclude-group phpunit-configuration --color tests"
|
||||
],
|
||||
"sync": [
|
||||
"@clear",
|
||||
"@php bin/sync",
|
||||
"@lint"
|
||||
],
|
||||
"sync-dev": [
|
||||
"@clear",
|
||||
"@php bin/sync --dev",
|
||||
"@lint"
|
||||
],
|
||||
"ci": [
|
||||
"@composer audit",
|
||||
"@post-autoload-dump",
|
||||
"@lint",
|
||||
"@test"
|
||||
]
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=AckfSECXIvnK5r28GVIWUAxmbBSjTsmF
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
# APP_MAINTENANCE_STORE=database
|
||||
|
||||
# PHP_CLI_SERVER_WORKERS=4
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
# DB_HOST=127.0.0.1
|
||||
# DB_PORT=3306
|
||||
# DB_DATABASE=laravel
|
||||
# DB_USERNAME=root
|
||||
# DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=cookie
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
# CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_SCHEME=null
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
@@ -0,0 +1,6 @@
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
testbench.yaml
|
||||
testbench.yaml.backup
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user