Skip to content

Commit c74c93f

Browse files
committed
Merge branch 'release/0.9.17'
2 parents c625498 + caf8557 commit c74c93f

File tree

7 files changed

+693
-6
lines changed

7 files changed

+693
-6
lines changed

.version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"strategy": "semver",
33
"major": 0,
44
"minor": 9,
5-
"patch": 16,
5+
"patch": 17,
66
"build": 0
77
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<?php
2+
3+
namespace Neuron\Mvc\Cli\Commands\Schema;
4+
5+
use Neuron\Cli\Commands\Command;
6+
use Neuron\Mvc\Database\MigrationManager;
7+
use Neuron\Mvc\Database\SchemaExporter;
8+
use Neuron\Data\Settings\Source\Yaml;
9+
10+
/**
11+
* CLI command for exporting database schema to YAML
12+
* Similar to Rails' rake db:schema:dump
13+
*/
14+
class DumpCommand extends Command
15+
{
16+
/**
17+
* @inheritDoc
18+
*/
19+
public function getName(): string
20+
{
21+
return 'db:schema:dump';
22+
}
23+
24+
/**
25+
* @inheritDoc
26+
*/
27+
public function getDescription(): string
28+
{
29+
return 'Export database schema to YAML file for reference';
30+
}
31+
32+
/**
33+
* @inheritDoc
34+
*/
35+
public function configure(): void
36+
{
37+
$this->addOption( 'output', 'o', true, 'Output file path (default: db/schema.yaml)' );
38+
$this->addOption( 'config', null, true, 'Path to configuration directory' );
39+
}
40+
41+
/**
42+
* @inheritDoc
43+
*/
44+
public function execute(): int
45+
{
46+
// Get configuration
47+
$configPath = $this->input->getOption( 'config', $this->findConfigPath() );
48+
49+
if( !$configPath || !is_dir( $configPath ) )
50+
{
51+
$this->output->error( 'Configuration directory not found: ' . ($configPath ?: 'none specified') );
52+
$this->output->info( 'Use --config to specify the configuration directory' );
53+
return 1;
54+
}
55+
56+
// Load settings
57+
$settings = $this->loadSettings( $configPath );
58+
$basePath = dirname( $configPath );
59+
60+
// Create manager
61+
$manager = new MigrationManager( $basePath, $settings );
62+
63+
// Determine output file path
64+
$outputPath = $this->input->getOption( 'output' );
65+
if( !$outputPath )
66+
{
67+
// Check if there's a configured schema file path
68+
if( $settings )
69+
{
70+
$outputPath = $settings->get( 'migrations', 'schema_file' );
71+
}
72+
73+
// Default to db/schema.yaml
74+
if( !$outputPath )
75+
{
76+
$outputPath = 'db/schema.yaml';
77+
}
78+
}
79+
80+
// Resolve relative paths
81+
if( !str_starts_with( $outputPath, '/' ) )
82+
{
83+
$outputPath = $basePath . '/' . $outputPath;
84+
}
85+
86+
try
87+
{
88+
$this->output->info( 'Exporting database schema...' );
89+
90+
// Create schema exporter
91+
$exporter = new SchemaExporter(
92+
$manager->getPhinxConfig(),
93+
$manager->getEnvironment(),
94+
$manager->getMigrationTable()
95+
);
96+
97+
// Export to file
98+
if( $exporter->exportToFile( $outputPath ) )
99+
{
100+
$this->output->newLine();
101+
$this->output->success( 'Schema exported successfully to: ' . $outputPath );
102+
return 0;
103+
}
104+
else
105+
{
106+
$this->output->newLine();
107+
$this->output->error( 'Failed to write schema file: ' . $outputPath );
108+
return 1;
109+
}
110+
}
111+
catch( \Exception $e )
112+
{
113+
$this->output->error( 'Error exporting schema: ' . $e->getMessage() );
114+
115+
if( $this->input->hasOption( 'verbose' ) || $this->input->hasOption( 'v' ) )
116+
{
117+
$this->output->write( $e->getTraceAsString() );
118+
}
119+
120+
return 1;
121+
}
122+
}
123+
124+
/**
125+
* Load settings from config directory
126+
*
127+
* @param string $configPath
128+
* @return Yaml|null
129+
*/
130+
private function loadSettings( string $configPath ): ?Yaml
131+
{
132+
$configFile = $configPath . '/neuron.yaml';
133+
134+
if( !file_exists( $configFile ) )
135+
{
136+
return null;
137+
}
138+
139+
try
140+
{
141+
return new Yaml( $configFile );
142+
}
143+
catch( \Exception $e )
144+
{
145+
$this->output->warning( 'Could not load configuration: ' . $e->getMessage() );
146+
return null;
147+
}
148+
}
149+
150+
/**
151+
* Try to find the configuration directory
152+
*
153+
* @return string|null
154+
*/
155+
private function findConfigPath(): ?string
156+
{
157+
$locations = [
158+
getcwd() . '/config',
159+
dirname( getcwd() ) . '/config',
160+
dirname( getcwd(), 2 ) . '/config',
161+
];
162+
163+
foreach( $locations as $location )
164+
{
165+
if( is_dir( $location ) )
166+
{
167+
return $location;
168+
}
169+
}
170+
171+
return null;
172+
}
173+
}

src/Mvc/Cli/Provider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,11 @@ public static function register( Registry $registry ): void
6161
'db:seed',
6262
'Neuron\\Mvc\\Cli\\Commands\\Migrate\\SeedCommand'
6363
);
64+
65+
// Schema export commands
66+
$registry->register(
67+
'db:schema:dump',
68+
'Neuron\\Mvc\\Cli\\Commands\\Schema\\DumpCommand'
69+
);
6470
}
6571
}

src/Mvc/Database/MigrationManager.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,56 @@ public function ensureSeedsDirectory(): bool
262262
return true;
263263
}
264264

265+
/**
266+
* Get schema file path
267+
*
268+
* @return string
269+
*/
270+
public function getSchemaFilePath(): string
271+
{
272+
$path = $this->getSetting( 'migrations', 'schema_file', 'db/schema.yaml' );
273+
274+
return $this->resolvePath( $path );
275+
}
276+
277+
/**
278+
* Check if auto-dump schema is enabled
279+
*
280+
* @return bool
281+
*/
282+
public function isAutoDumpSchemaEnabled(): bool
283+
{
284+
return (bool)$this->getSetting( 'migrations', 'auto_dump_schema', false );
285+
}
286+
287+
/**
288+
* Dump database schema to YAML file
289+
*
290+
* @param string|null $outputPath Optional output path (uses configured path if null)
291+
* @return bool Success status
292+
*/
293+
public function dumpSchema( ?string $outputPath = null ): bool
294+
{
295+
try
296+
{
297+
$exporter = new SchemaExporter(
298+
$this->getPhinxConfig(),
299+
$this->getEnvironment(),
300+
$this->getMigrationTable()
301+
);
302+
303+
$path = $outputPath ?? $this->getSchemaFilePath();
304+
305+
return $exporter->exportToFile( $path );
306+
}
307+
catch( \Exception $e )
308+
{
309+
// Log error but don't fail the migration
310+
error_log( "Failed to dump schema: " . $e->getMessage() );
311+
return false;
312+
}
313+
}
314+
265315
/**
266316
* Execute a Phinx command
267317
*
@@ -305,6 +355,12 @@ public function execute( string $command, array $arguments = [] ): array
305355
$result = "All migrations have been run\n";
306356
}
307357

358+
// Auto-dump schema if enabled and not a fake migration
359+
if( !$fake && $this->isAutoDumpSchemaEnabled() )
360+
{
361+
$this->dumpSchema();
362+
}
363+
308364
return [0, $result];
309365

310366
case 'rollback':
@@ -321,6 +377,12 @@ public function execute( string $command, array $arguments = [] ): array
321377
$result = "Rollback completed successfully\n";
322378
}
323379

380+
// Auto-dump schema if enabled and not a fake rollback
381+
if( !$fake && $this->isAutoDumpSchemaEnabled() )
382+
{
383+
$this->dumpSchema();
384+
}
385+
324386
return [0, $result];
325387

326388
case 'status':

0 commit comments

Comments
 (0)