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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/BackpackServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class BackpackServiceProvider extends ServiceProvider
app\Console\Commands\CreateUser::class,
app\Console\Commands\PublishBackpackMiddleware::class,
app\Console\Commands\PublishView::class,
app\Console\Commands\Upgrade\UpgradeCommand::class,
app\Console\Commands\Addons\RequireDevTools::class,
app\Console\Commands\Addons\RequireEditableColumns::class,
app\Console\Commands\Addons\RequirePro::class,
Expand Down
18 changes: 18 additions & 0 deletions src/app/Console/Commands/Upgrade/Concerns/ExtractsFirstInteger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Backpack\CRUD\app\Console\Commands\Upgrade\Concerns;

trait ExtractsFirstInteger
{
/**
* Extract the first integer occurrence from the given string.
*/
protected function extractFirstInteger(string $value): ?int
{
if (preg_match('/(\d+)/', $value, $matches)) {
return (int) $matches[1];
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Backpack\CRUD\app\Console\Commands\Upgrade\Concerns;

use Backpack\CRUD\app\Console\Commands\Upgrade\UpgradeContext;

/**
* @mixin \Backpack\CRUD\app\Console\Commands\Upgrade\Step
*/
trait InteractsWithCrudControllers
{
/**
* Filter a list of file paths.
*/
protected function filterCrudControllerPaths(array $paths, ?callable $contentsValidator = null): array
{
if (empty($paths)) {
return [];
}

$filtered = [];

foreach ($paths as $path) {
if (! $this->isCrudControllerPath($path)) {
continue;
}

$contents = $this->context()->readFile($path);

if ($contents === null) {
continue;
}

if ($contentsValidator !== null && $contentsValidator($contents, $path) !== true) {
continue;
}

$filtered[] = $path;
}

return $filtered;
}

protected function isCrudControllerPath(string $path): bool
{
return str_contains($path, 'CrudController');
}

abstract protected function context(): UpgradeContext;
}
78 changes: 78 additions & 0 deletions src/app/Console/Commands/Upgrade/Step.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Backpack\CRUD\app\Console\Commands\Upgrade;

use Backpack\CRUD\app\Console\Commands\Upgrade\Concerns\ExtractsFirstInteger;

abstract class Step
{
use ExtractsFirstInteger;

public function __construct(protected UpgradeContext $context)
{
}

abstract public function title(): string;

public function description(): ?string
{
return null;
}

abstract public function run(): StepResult;

protected function context(): UpgradeContext
{
return $this->context;
}

public function canFix(StepResult $result): bool
{
return false;
}

public function fixMessage(StepResult $result): string
{
return 'Apply automatic fix?';
}

public function fix(StepResult $result): StepResult
{
return StepResult::skipped('No automatic fix available.');
}

public function isBlocking(): bool
{
return false;
}

/**
* Build a preview of items with an optional formatter and overflow message.
*
* @param array<int, mixed> $items
* @param callable|null $formatter
* @return array<int, string>
*/
protected function previewList(
array $items,
int $limit = 10,
?callable $formatter = null,
?string $overflowMessage = null
): array {
if (empty($items)) {
return [];
}

$formatter ??= static fn ($item): string => '- '.(string) $item;
$preview = array_slice($items, 0, $limit);
$details = array_map($formatter, $preview);

$remaining = count($items) - count($preview);

if ($remaining > 0) {
$details[] = sprintf($overflowMessage ?? '... %d more item(s) omitted.', $remaining);
}

return $details;
}
}
34 changes: 34 additions & 0 deletions src/app/Console/Commands/Upgrade/StepResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Backpack\CRUD\app\Console\Commands\Upgrade;

class StepResult
{
public function __construct(
public readonly StepStatus $status,
public readonly string $summary,
public readonly array $details = [],
public readonly array $context = []
) {
}

public static function success(string $summary, array $details = [], array $context = []): self
{
return new self(StepStatus::Passed, $summary, $details, $context);
}

public static function warning(string $summary, array $details = [], array $context = []): self
{
return new self(StepStatus::Warning, $summary, $details, $context);
}

public static function failure(string $summary, array $details = [], array $context = []): self
{
return new self(StepStatus::Failed, $summary, $details, $context);
}

public static function skipped(string $summary, array $details = [], array $context = []): self
{
return new self(StepStatus::Skipped, $summary, $details, $context);
}
}
41 changes: 41 additions & 0 deletions src/app/Console/Commands/Upgrade/StepStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Backpack\CRUD\app\Console\Commands\Upgrade;

enum StepStatus: string
{
case Passed = 'passed';
case Warning = 'warning';
case Failed = 'failed';
case Skipped = 'skipped';

public function label(): string
{
return match ($this) {
self::Passed => 'done',
self::Warning => 'warn',
self::Failed => 'fail',
self::Skipped => 'skip',
};
}

public function color(): string
{
return match ($this) {
self::Passed => 'green',
self::Warning => 'yellow',
self::Failed => 'red',
self::Skipped => 'gray',
};
}

public function isFailure(): bool
{
return $this === self::Failed;
}

public function isWarning(): bool
{
return $this === self::Warning;
}
}
Loading