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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions docs/guide/upgrade.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
# Upgrading from 9.x to 10.x

## The upgrade command

Sharp 10 comes with an upgrade command that replaces and notifies for deprecated and removed code. You can run it with

```bash
php artisan sharp:upgrade app/Sharp
```

Where `app/Sharp` is the path of your sharp code.

## Updating Dependencies

You should update the following dependencies in your `composer.json` file:
- `inertiajs/inertia-laravel` to `^3.0` (cf. https://inertiajs.com/docs/v3/getting-started/upgrade-guide)

## Deprecated methods
## Deprecated methods

### Forms

#### Upload `setImageCompactThumbnail()` has not impact and can be removed
#### Upload `setImageCompactThumbnail()` has no impact and can be removed
```php
\Code16\Sharp\Form\Fields\SharpFormUploadField::make('upload')
->setImageCompactThumbnail() // [!code --]
```

## Removed methods
## Removed classes and methods

Several features and methods that were deprecated in Sharp 9.0 have been removed to clean up the codebase.

Expand All @@ -34,7 +44,7 @@ Several features and methods that were deprecated in Sharp 9.0 have been removed
- The legacy `$formValidatorClass` property handling in `SharpForm` was removed. Implement the `SharpForm::rules()` and `SharpForm::messages()` methods instead (cf. [Building form](building-form#input-validation)). Along with this removal, the following classes have been removed:
- `\Code16\Sharp\Form\Validator\SharpFormRequest`
- `\Code16\Sharp\Form\Validator\SharpValidator`
- `\Code16\Sharp\Http\Middleware\Api\BindSharpValidationResolver`
- `\Code16\Sharp\Http\Middleware\Api\BindSharpValidationResolver` (remove this from config)
- In `SharpFormUploadField`, the following deprecated methods were removed:
```php
\Code16\Sharp\Form\Fields\SharpFormUploadField::make('upload')
Expand Down Expand Up @@ -66,7 +76,7 @@ Several features and methods that were deprecated in Sharp 9.0 have been removed
### Show
- The `configureMultiformAttribute()` method in `SharpShow` was removed. It's not used by sharp.

### Renamed classes
### Filters

The following classes have been renamed / moved:

Expand Down
97 changes: 97 additions & 0 deletions src/Console/UpgradeCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

namespace Code16\Sharp\Console;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

class UpgradeCommand extends Command
{
protected $signature = 'sharp:upgrade {--dry-run : Run Rector in dry-run mode} {path}';
protected $description = 'Upgrade Sharp to current major version';

public function handle()
{
$directories = [
base_path($this->argument('path')),
];

$replacements = [
'/->setCropRatio\s*\(/' => '->setImageCropRatio(',
'/->shouldOptimizeImage\s*\(/' => '->setImageOptimize(',
'/->setTransformable\s*\(/' => '->setImageTransformable(',
'/->setFileFilterImages\s*\(/' => '->setImageOnly(',
'/->setFileFilter\s*\(/' => '->setAllowedExtensions(',
'/->withSingleField\s*\(/' => '->withField(',

'/Code16\\\\Sharp\\\\EntityList\\\\Filters\\\\EntityList([A-Za-z]+Filter)/' => 'Code16\\Sharp\\Filters\\\\$1',
'/Code16\\\\Sharp\\\\Utils\\\\Filters\\\\([A-Za-z]+Filter)/' => 'Code16\\Sharp\\Filters\\\\$1',

'/\bEntityList(CheckFilter|DateRangeFilter|DateRangeRequiredFilter|SelectFilter|SelectMultipleFilter|SelectRequiredFilter)\b/' => '$1',
];

$detections = [
'currentSharpRequest()' => '/currentSharpRequest\s*\(/',
'SharpAuthenticationCheckHandler' => '/SharpAuthenticationCheckHandler/',
'SharpFormRequest' => '/SharpFormRequest/',
'BindSharpValidationResolver' => '/BindSharpValidationResolver/',
'SharpFormAutocompleteField' => '/SharpFormAutocompleteField::make\s*\(/',
'->setWidthOnSmallScreens()' => '/setWidthOnSmallScreens\s*\(/',
'->setWidthOnSmallScreensFill()' => '/setWidthOnSmallScreensFill\s*\(/',
'->configureMultiformAttribute()' => '/configureMultiformAttribute\s*\(/',
'->setDisplayFormat()' => '/setDisplayFormat\s*\(/',
'getMultiforms()' => '/getMultiforms\s*\(/',
];

$changedFilesCount = 0;
$isDryRun = $this->option('dry-run');

foreach ($directories as $directory) {
if (! File::exists($directory)) {
continue;
}

$files = File::allFiles($directory);

foreach ($files as $file) {
if ($file->getExtension() !== 'php') {
continue;
}

$filePath = $file->getPathname();
$originalContent = File::get($filePath);
$content = $originalContent;

foreach ($replacements as $pattern => $replacement) {
$content = preg_replace($pattern, $replacement, $content);
}

foreach ($detections as $label => $pattern) {
if (preg_match($pattern, $content)) {
$this->line("The removed symbol <comment>{$label}</comment> has been detected in {$filePath}");
}
}

if ($content !== $originalContent) {
$relativePath = $file->getRelativePathname();
$changedFilesCount++;

if ($isDryRun) {
$this->line("<comment>[Dry Run]</comment> Would update: {$relativePath}");
} else {
File::put($filePath, $content);
$this->info("Updated: {$relativePath}");
}
}
}
}

$this->newLine();

if ($isDryRun) {
$this->info("Dry run complete. {$changedFilesCount} files would be updated.");
} else {
$this->info("Finished! {$changedFilesCount} files were successfully updated.");
}
}
}
3 changes: 2 additions & 1 deletion src/SharpInternalServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Code16\Sharp\Console\ReorderHandlerMakeCommand;
use Code16\Sharp\Console\ServiceProviderMakeCommand;
use Code16\Sharp\Console\ShowPageMakeCommand;
use Code16\Sharp\Console\UpgradeCommand;
use Code16\Sharp\Exceptions\SharpTokenMismatchException;
use Code16\Sharp\Form\Eloquent\Uploads\Migration\CreateUploadsMigration;
use Code16\Sharp\Form\Eloquent\Uploads\Thumbnails\SharpImageManager;
Expand All @@ -43,7 +44,6 @@
use Illuminate\Console\Events\CommandStarting;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\File;
Expand Down Expand Up @@ -161,6 +161,7 @@ private function declareConsoleCommands(): void
EntityListFilterMakeCommand::class,
ReorderHandlerMakeCommand::class,
MenuMakeCommand::class,
UpgradeCommand::class,
]);
}

Expand Down
100 changes: 100 additions & 0 deletions tests/Unit/Console/UpgradeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

use Illuminate\Support\Facades\File;

beforeEach(function () {
// 1. Define a relative path we can pass to the command's --path option
$this->testPath = 'storage/framework/testing/fake_sharp_app';

// 2. Resolve the absolute path to create our test files
$this->absoluteTestPath = base_path($this->testPath);
File::ensureDirectoryExists($this->absoluteTestPath);

// 3. Create a dummy file containing legacy Sharp syntax
$this->dummyFilePath = $this->absoluteTestPath.'/AuthorFilter.php';

$this->oldContent = <<<PHP
<?php

namespace App\Sharp\Utils\Filters;

use App\Models\User;
use Code16\Sharp\EntityList\Filters\EntityListSelectFilter;
use Code16\Sharp\Form\Fields\SharpFormUploadField;
use Code16\Sharp\Form\Layout\FormLayoutColumn;
use Code16\Sharp\Utils\Filters\DateRangeFilter;

class AuthorFilter extends EntityListSelectFilter
{
public function buildFilterConfig(): void
{
SharpFormUploadField::make()
->setCropRatio('16:9')
->shouldOptimizeImage();

new FormLayoutColumn()
->withSingleField('test');
}
}
PHP;

File::put($this->dummyFilePath, $this->oldContent);
});

afterEach(function () {
// Clean up the temporary directory after each test
File::deleteDirectory($this->absoluteTestPath);
});

it('updates sharp configuration syntax correctly', function () {
$this->artisan('sharp:upgrade', [
'--path' => $this->testPath,
])
->expectsOutputToContain('Updated: AuthorFilter.php')
->expectsOutputToContain('1 files were successfully updated.')
->assertSuccessful();

$newContent = File::get($this->dummyFilePath);

// 1. Assert namespaces were updated correctly
expect($newContent)
->toContain('use Code16\Sharp\Filters\SelectFilter;')
->toContain('use Code16\Sharp\Filters\DateRangeFilter;')
->not->toContain('Code16\Sharp\EntityList\Filters\EntityListSelectFilter')
->not->toContain('Code16\Sharp\Utils\Filters\DateRangeFilter');

// 2. Assert bare class extension was updated
expect($newContent)
->toContain('class AuthorFilter extends SelectFilter')
->not->toContain('extends EntityListSelectFilter');

// 3. Assert method calls were updated
expect($newContent)
->toContain('->withField(\'test\');')
->toContain('->setImageCropRatio(\'16:9\')')
->toContain('->setImageOptimize();')
->not->toContain('withSingleField')
->not->toContain('setCropRatio')
->not->toContain('shouldOptimizeImage');
});

it('ignores files that do not need updating', function () {
// Overwrite the dummy file with already-updated syntax
$modernContent = <<<PHP
<?php
namespace App\Sharp\Utils\Filters;
use Code16\Sharp\Filters\SelectFilter;
class AuthorFilter extends SelectFilter {}
PHP;

File::put($this->dummyFilePath, $modernContent);

// Command should report 0 files updated
$this->artisan('sharp:upgrade', [
'--path' => $this->testPath,
])
->expectsOutputToContain('0 files were successfully updated.')
->assertSuccessful();

expect(File::get($this->dummyFilePath))->toBe($modernContent);
});