update controllers logic
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Sync Laravel models from CodeIgniter 4 *Model.php siblings (mass-assignment parity).
|
||||
*
|
||||
* Updates only:
|
||||
* - protected $fillable ← CI protected $allowedFields (order preserved)
|
||||
* - public $timestamps ← CI protected $useTimestamps
|
||||
*
|
||||
* Does NOT overwrite $table / $primaryKey (schemas may diverge: e.g. flag vs current_flag).
|
||||
*
|
||||
* Skips Laravel: Teacher (extends User), Communication, EventCharge, ClassModel, Calendar aliases.
|
||||
*
|
||||
* Usage (from app_laravel directory):
|
||||
* php tools/sync_fillable_from_codeigniter.php
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
const NL = "\n";
|
||||
|
||||
$laravelRoot = dirname(__DIR__);
|
||||
$workspaceRoot = dirname($laravelRoot);
|
||||
$ciModelsDir = $workspaceRoot.DIRECTORY_SEPARATOR.'app_codeigniter'.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'Models';
|
||||
$laravelModelsDir = $laravelRoot.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'Models';
|
||||
|
||||
if (! is_dir($ciModelsDir)) {
|
||||
fwrite(STDERR, "CI models dir not found: {$ciModelsDir}".NL);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** CI Model basename => Laravel model basename */
|
||||
$manualCiToLaravel = [
|
||||
'FlagModel.php' => 'CurrentFlag.php',
|
||||
];
|
||||
|
||||
/** Laravel files skipped (aliases / inheritance) */
|
||||
$skipLaravelBasenames = [
|
||||
'Teacher.php',
|
||||
'Communication.php',
|
||||
'EventCharge.php',
|
||||
'ClassModel.php',
|
||||
'Calendar.php',
|
||||
];
|
||||
|
||||
function ciFileToLaravelFile(string $ciBasename, array $manual): ?string
|
||||
{
|
||||
if (isset($manual[$ciBasename])) {
|
||||
return $manual[$ciBasename];
|
||||
}
|
||||
if (! preg_match('/^(.+)Model\.php$/', $ciBasename, $m)) {
|
||||
return null;
|
||||
}
|
||||
$base = $m[1];
|
||||
if ($base === 'Parent' || $base === 'Class') {
|
||||
return $base.'Model.php';
|
||||
}
|
||||
|
||||
return $base.'.php';
|
||||
}
|
||||
|
||||
function extractFirstBracketArray(string $src, string $needle): ?string
|
||||
{
|
||||
$pos = strpos($src, $needle);
|
||||
if ($pos === false) {
|
||||
return null;
|
||||
}
|
||||
$pos += strlen($needle);
|
||||
$len = strlen($src);
|
||||
while ($pos < $len && ctype_space($src[$pos])) {
|
||||
$pos++;
|
||||
}
|
||||
if ($pos >= $len || $src[$pos] !== '[') {
|
||||
return null;
|
||||
}
|
||||
$start = $pos;
|
||||
$depth = 0;
|
||||
for ($i = $pos; $i < $len; $i++) {
|
||||
$c = $src[$i];
|
||||
if ($c === '[') {
|
||||
$depth++;
|
||||
} elseif ($c === ']') {
|
||||
$depth--;
|
||||
if ($depth === 0) {
|
||||
return substr($src, $start, $i - $start + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
function parseQuotedStringsFromArrayLiteral(string $arrayLiteral): array
|
||||
{
|
||||
$out = [];
|
||||
if (! preg_match_all("/'((?:\\\\'|[^'])*)'/", $arrayLiteral, $m)) {
|
||||
return $out;
|
||||
}
|
||||
foreach ($m[1] as $raw) {
|
||||
$out[] = str_replace("\\'", "'", $raw);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/** Render inner array only: [\n 'a',\n ] */
|
||||
function renderFillableArray(array $items): string
|
||||
{
|
||||
$lines = [];
|
||||
foreach ($items as $item) {
|
||||
$escaped = addcslashes($item, "\\'");
|
||||
$lines[] = " '".$escaped."',";
|
||||
}
|
||||
|
||||
return "[\n".implode("\n", $lines)."\n ]";
|
||||
}
|
||||
|
||||
function replaceFillableBlock(string $laravel, string $newArrayLiteral): string
|
||||
{
|
||||
$re = '/protected\s+\$fillable\s*=\s*\[[\s\S]*?\];/m';
|
||||
if (! preg_match($re, $laravel)) {
|
||||
return $laravel;
|
||||
}
|
||||
|
||||
return preg_replace($re, 'protected $fillable = '.$newArrayLiteral.';', $laravel, 1);
|
||||
}
|
||||
|
||||
function replaceTimestampsLine(string $laravel, bool $useTimestamps): string
|
||||
{
|
||||
$line = $useTimestamps
|
||||
? ' public $timestamps = true;'
|
||||
: ' public $timestamps = false;';
|
||||
|
||||
if (preg_match('/public\s+\$timestamps\s*=\s*(true|false)\s*;/', $laravel)) {
|
||||
return preg_replace(
|
||||
'/public\s+\$timestamps\s*=\s*(true|false)\s*;/',
|
||||
$line,
|
||||
$laravel,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
// Insert after class opening brace line (first line after "class X extends Y")
|
||||
return preg_replace(
|
||||
'/(class\s+\w+[^\n]*\n\{[\t ]*\n)/',
|
||||
'$1'.$line.NL.NL,
|
||||
$laravel,
|
||||
1
|
||||
) ?: preg_replace('/(class\s+\w+[^\n]*\n\{)/', '$1'.NL.$line, $laravel, 1);
|
||||
}
|
||||
|
||||
$updated = 0;
|
||||
$skipped = 0;
|
||||
$missing = [];
|
||||
|
||||
foreach (glob($ciModelsDir.DIRECTORY_SEPARATOR.'*Model.php') ?: [] as $ciPath) {
|
||||
$ciBasename = basename($ciPath);
|
||||
$laravelBasename = ciFileToLaravelFile($ciBasename, $manualCiToLaravel);
|
||||
if ($laravelBasename === null) {
|
||||
continue;
|
||||
}
|
||||
if (in_array($laravelBasename, $skipLaravelBasenames, true)) {
|
||||
fwrite(STDERR, "Skip (alias/base): {$laravelBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$lvPath = $laravelModelsDir.DIRECTORY_SEPARATOR.$laravelBasename;
|
||||
if (! is_file($lvPath)) {
|
||||
$missing[] = $laravelBasename.' (from '.$ciBasename.')';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$ciSrc = (string) file_get_contents($ciPath);
|
||||
$lvSrc = (string) file_get_contents($lvPath);
|
||||
|
||||
$useTs = true;
|
||||
if (preg_match('/protected\s+\$useTimestamps\s*=\s*(true|false)\s*;/', $ciSrc, $tm)) {
|
||||
$useTs = $tm[1] === 'true';
|
||||
}
|
||||
|
||||
$allowedBody = extractFirstBracketArray($ciSrc, 'protected $allowedFields = ');
|
||||
if ($allowedBody === null) {
|
||||
fwrite(STDERR, "No allowedFields in {$ciBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields = parseQuotedStringsFromArrayLiteral($allowedBody);
|
||||
if ($fields === []) {
|
||||
fwrite(STDERR, "Empty allowedFields in {$ciBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! preg_match('/protected\s+\$fillable\s*=\s*\[/', $lvSrc)) {
|
||||
fwrite(STDERR, "No \$fillable array in {$laravelBasename} — add manually".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$rendered = renderFillableArray($fields);
|
||||
$newLv = replaceFillableBlock($lvSrc, $rendered);
|
||||
$newLv = replaceTimestampsLine($newLv, $useTs);
|
||||
|
||||
if ($newLv === $lvSrc) {
|
||||
fwrite(STDERR, "Unchanged: {$laravelBasename}".NL);
|
||||
$skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
file_put_contents($lvPath, $newLv);
|
||||
fwrite(STDOUT, "Updated {$laravelBasename}".NL);
|
||||
$updated++;
|
||||
}
|
||||
|
||||
fwrite(STDOUT, NL.'Done. Updated: '.$updated.', skipped: '.$skipped.NL);
|
||||
if ($missing !== []) {
|
||||
fwrite(STDERR, 'Missing Laravel files ('.count($missing).'): '.implode(', ', array_slice($missing, 0, 20)).(count($missing) > 20 ? '…' : '').NL);
|
||||
|
||||
exit(2);
|
||||
}
|
||||
Reference in New Issue
Block a user