Files
Epicnabbo-Catalogus-Updated…/Optimized Atomcms daily updated/vendor/filament/upgrade/bin/filament-v4
T
2025-11-25 22:42:56 +01:00

350 lines
12 KiB
PHP

#!/usr/bin/env php
<?php
use function Termwind\{ask, render};
require 'vendor/autoload.php';
render(<<<'HTML'
<div>
<div class="space-y-1">
<div class="py-1 px-3 bg-amber-600 text-amber-50">
<strong>Filament v4</strong> Upgrade
</div>
<div>
Welcome to the <strong>Filament v4</strong> upgrade process!
<br />
This script will attempt to handle most of the breaking changes for you.
<br />
If you have any questions, please reach out to us on <a href="https://filamentphp.com/discord" class="underline font-bold">Discord</a> or <a href="https://github.com/filamentphp/filament/discussions/new?category=q-a" class="underline font-bold">GitHub</a>.
</div>
<div>
To begin, please ensure that you are using a version control system such as Git.
<br />
We will make changes directly to your files, and you will need to be able to revert them if something goes wrong.
<br />
<strong>Please commit any changes you have made to your project before continuing.</strong>
</div>
</div>
<br />
</div>
HTML);
require __DIR__ . '/../src/check-compatibility.php';
$directories = $argv[1] ?? ask(<<<HTML
<div>
Please provide a comma-separated list of directories containing Filament code to upgrade (e.g. <strong>app</strong>, <strong>app-modules</strong>, <strong>src</strong>).
<br />
<span class="bg-amber-600 text-amber-50 mr-1">
You can skip this if you have a normal Laravel app structure:
</span>
</div>
HTML) ?: 'app';
render(<<<HTML
<p class="bg-green-600 text-green-50">
Starting upgrade...
</p>
HTML);
$rectorScriptPath = implode(DIRECTORY_SEPARATOR, ['vendor', 'bin', 'rector']);
foreach (explode(',', $directories) as $directory) {
$directory = trim($directory);
$directory = trim($directory, DIRECTORY_SEPARATOR);
render(<<<HTML
<p>
Start processing <strong>/{$directory}</strong> to fix code affected by breaking changes.
</p>
HTML);
exec("{$rectorScriptPath} process {$directory} --config vendor/filament/upgrade/src/rector.php --clear-cache");
render(<<<HTML
<p class="pt-2">
Finished processing <strong>/{$directory}</strong>.
</p>
HTML);
}
$requireCommands = [];
foreach (json_decode(file_get_contents('composer.json'), true)['require'] as $package => $version) {
if ($package === 'filament/upgrade') {
continue;
}
if (! str_starts_with($package, 'filament/')) {
continue;
}
if ($package === 'filament/spatie-laravel-translatable-plugin') {
$requireCommands[] = "composer remove filament/spatie-laravel-translatable-plugin -W --no-update";
$requireCommands[] = "composer require lara-zeus/spatie-translatable -W --no-update";
continue;
}
$isWindows = str_starts_with(php_uname(), 'Windows');
if (! $isWindows) {
$requireCommands[] = "composer require {$package}:\"^4.0\" -W --no-update";
} else {
$requireCommands[] = "composer require {$package}:\"~4.0\" -W --no-update";
}
}
$requireCommandsHtml = implode("</strong><br /><strong>", $requireCommands);
// Suggest commands for third-party Filament plugins that have v4-compatible releases
$thirdPartyCommands = [];
try {
// Prefer shared cache generated by check-compatibility.php
$shared = $GLOBALS['FILAMENT_UPGRADE_PACKAGIST'] ?? null;
// Fallback detection if cache is not available
if ($shared === null || empty($shared['plugins'])) {
$composer = json_decode(file_get_contents('composer.json'), true);
$deps = $composer['require'] ?? [];
$allPackages = array_keys($deps);
$plugins = array_filter($allPackages, function ($plugin) {
if (str_starts_with($plugin, 'filament/')) {
return false;
}
try {
$composerPath = "vendor/{$plugin}/composer.json";
if (! file_exists($composerPath)) {
return false;
}
$composerContent = file_get_contents($composerPath);
$composer = json_decode($composerContent, true);
if (! $composer || ! is_array($composer)) {
return false;
}
$requires = $composer['require'] ?? [];
foreach ($requires as $key => $value) {
if (str_starts_with($key, 'filament/')) {
return true;
}
}
} catch (Throwable $exception) {}
return false;
});
// Create a minimal shared structure to continue without extra HTTP (none yet cached though)
$shared = [
'plugins' => array_values($plugins),
'compatibility' => [],
'versions' => [],
];
}
$plugins = $shared['plugins'] ?? [];
$isWindows = str_starts_with(php_uname(), 'Windows');
foreach ($plugins as $plugin) {
// Try to reuse computed compatibility first
$compatibility = $shared['compatibility'][$plugin] ?? null; // ['version' => string, 'isPrerelease' => bool]
// If not computed, try to evaluate using cached versions arrays (no HTTP)
if ($compatibility === null) {
$stableVersions = $shared['versions'][$plugin]['stable'] ?? [];
foreach ($stableVersions as $checkingVersion) {
$requires = $checkingVersion['require'] ?? [];
foreach ($requires as $dep => $constraint) {
if (!str_starts_with($dep, 'filament/')) {
continue;
}
if (preg_match("/\^\s*4(?:\.|$)|~\s*4(?:\.|$)|>=\s*4(?:\.|$)/", (string) $constraint)) {
$compatibility = [
'version' => (string) ($checkingVersion['version'] ?? ''),
'isPrerelease' => false,
];
break;
}
}
}
if ($compatibility === null) {
$devVersions = $shared['versions'][$plugin]['dev'] ?? [];
foreach ($devVersions as $checkingVersion) {
$requires = $checkingVersion['require'] ?? [];
foreach ($requires as $dep => $constraint) {
if (!str_starts_with($dep, 'filament/')) {
continue;
}
if (preg_match("/\^\s*4(?:\.|$)|~\s*4(?:\.|$)|>=\s*4(?:\.|$)/", (string) $constraint)) {
$compatibility = [
'version' => (string) ($checkingVersion['version'] ?? ''),
'isPrerelease' => true,
];
break;
}
}
}
}
}
// As a last resort, if we still don't have compatibility and there are no cached versions, do HTTP queries
if ($compatibility === null && empty($shared['versions'][$plugin])) {
try {
$url = "https://repo.packagist.org/p2/{$plugin}.json";
$json = @file_get_contents($url);
if ($json) {
$data = json_decode($json, true);
$versions = $data['packages'][$plugin] ?? [];
$shared['versions'][$plugin]['stable'] = $versions;
foreach ($versions as $checkingVersion) {
$requires = $checkingVersion['require'] ?? [];
foreach ($requires as $dep => $constraint) {
if (!str_starts_with($dep, 'filament/')) {
continue;
}
if (preg_match("/\^\s*4(?:\.|$)|~\s*4(?:\.|$)|>=\s*4(?:\.|$)/", (string) $constraint)) {
$compatibility = [
'version' => (string) ($checkingVersion['version'] ?? ''),
'isPrerelease' => false,
];
break;
}
}
}
}
if ($compatibility === null) {
$devUrl = "https://repo.packagist.org/p2/{$plugin}~dev.json";
$devJson = @file_get_contents($devUrl);
if ($devJson) {
$devData = json_decode($devJson, true);
$devVersions = $devData['packages'][$plugin] ?? [];
$shared['versions'][$plugin]['dev'] = $devVersions;
foreach ($devVersions as $checkingVersion) {
$requires = $checkingVersion['require'] ?? [];
foreach ($requires as $dep => $constraint) {
if (!str_starts_with($dep, 'filament/')) {
continue;
}
if (preg_match("/\^\s*4(?:\.|$)|~\s*4(?:\.|$)|>=\s*4(?:\.|$)/", (string) $constraint)) {
$compatibility = [
'version' => (string) ($checkingVersion['version'] ?? ''),
'isPrerelease' => true,
];
break;
}
}
}
}
}
} catch (Throwable $exception) {
// ignore
}
}
if ($compatibility !== null) {
// Persist back for other consumers during this run
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['compatibility'][$plugin] = $compatibility;
$version = ltrim($compatibility['version'], 'v');
$isPrerelease = $compatibility['isPrerelease'];
if ($version === 'unknown') {
// Skip suggesting install command for plugins with unknown version (e.g., private/non-Packagist)
continue;
}
$constraint = null;
if (! $isPrerelease) {
// Prefer using major.minor for pre-v1 packages to avoid ^0.0 or ~0.0
if (preg_match('/^(\d+)\.(\d+)/', $version, $m)) {
$major = (int) $m[1];
$minor = (int) $m[2];
if ($major === 0) {
// For 0.x.y, constrain to the minor series, e.g. ^0.12 or ~0.12
$constraint = $isWindows ? "~0.{$minor}" : "^0.{$minor}";
} else {
// For 1.x and above, stick to major series, e.g. ^4.0 or ~4.0
$constraint = $isWindows ? "~{$major}.0" : "^{$major}.0";
}
} elseif (preg_match('/^(\d+)/', $version, $m)) {
// Fallback: if only a major could be parsed
$major = (int) $m[1];
$constraint = $isWindows ? "~{$major}.0" : "^{$major}.0";
}
}
if ($constraint === null) {
$constraint = $version;
}
$thirdPartyCommands[] = "composer require {$plugin}:\"{$constraint}\" -W --no-update";
}
}
} catch (Throwable $exception) {
// If anything goes wrong, we just won't print third-party suggestions
}
$thirdPartyCommandsHtml = $thirdPartyCommands ? '<br />' . implode("</strong><br /><strong>", $thirdPartyCommands) : '';
render(<<<HTML
<div>
<span class="bg-green-600 text-green-50">
Now you're ready to update your Composer dependencies!
</span>
<br /> <br />
First require new versions of Filament packages:
<br />
<strong>{$requireCommandsHtml}{$thirdPartyCommandsHtml}</strong>
<br /> <br />
And then run:
<br />
<strong>composer update</strong>
<br /> <br />
If you have any questions, please reach out to us on <a href="https://filamentphp.com/discord" class="underline font-bold">Discord</a> or <a href="https://github.com/filamentphp/filament/discussions/new?category=q-a" class="underline font-bold">GitHub</a>.
</div>
HTML);