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
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,19 @@ Drops a PostgreSQL schema and all its objects:
```yaml
# config/services.yaml
services:
SharedServices\Command\Doctrine\DoctrineSchemaDropCommand: ~
SharedServices\Command\Doctrine\DoctrineSchemaDropCommand:
arguments:
- '@Doctrine\DBAL\Connection'
- ['public'] # Disallowed schema names for safety
```

Usage:
```bash
php bin/console doctrine:schema:delete <schema_name>
```

**Security Note:** You can specify disallowed schema names to prevent accidental deletion of critical schemas like `public`.

### Schema Migrations Command
Runs Doctrine migrations within a specific schema. Creates the schema if it doesn't exist:

Expand All @@ -129,13 +134,17 @@ services:
SharedServices\Command\Doctrine\DoctrineSchemaFixturesLoadCommand:
arguments:
- '@doctrine.fixtures_load_command'
- '@Doctrine\DBAL\Connection'
- ['public'] # Disallowed schema names for safety
```

Usage:
```bash
php bin/console doctrine:schema:fixtures:load <schema_name> [options]
```

**Security Note:** You can specify disallowed schema names to prevent accidental fixture loading into critical schemas like `public`.

**Note:** These commands are optional and should only be registered if you're using the corresponding Doctrine features (migrations and/or fixtures) in your project.

## Testing
Expand Down
17 changes: 15 additions & 2 deletions src/Command/Doctrine/DoctrineSchemaDropCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@

class DoctrineSchemaDropCommand extends AbstractDoctrineSchemaCommand
{
public function __construct(Connection $connection)
{
/**
* @param string[] $disallowedSchemaNames
*/
public function __construct(
Connection $connection,
private readonly array $disallowedSchemaNames = [],
) {
parent::__construct('doctrine:schema:delete', $connection);
}

Expand All @@ -22,6 +27,14 @@ protected function execute(
): int {
$schema = $this->getSchemaFromInput($input);

if (in_array($schema, $this->disallowedSchemaNames, true)) {
$output->writeln(
"<error>Command is disallowed from being called for the '$schema' schema</error>"
);

return Command::FAILURE;
}

$output->writeln("<info>Drop schema '{$schema}'...<info>");

$quotedSchema = $this->connection->quoteIdentifier($schema);
Expand Down
12 changes: 12 additions & 0 deletions src/Command/Doctrine/DoctrineSchemaFixturesLoadCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@

class DoctrineSchemaFixturesLoadCommand extends AbstractNestingDoctrineSchemaCommand
{
/**
* @param string[] $disallowedSchemaNames
*/
public function __construct(
LoadDataFixturesDoctrineCommand $parentCommand,
Connection $connection,
private readonly array $disallowedSchemaNames = [],
) {
parent::__construct('doctrine:schema:fixtures:load', $parentCommand, $connection);
}
Expand All @@ -27,6 +31,14 @@ protected function execute(
try {
$schema = $this->getSchemaFromInput($input);

if (in_array($schema, $this->disallowedSchemaNames, true)) {
$output->writeln(
"<error>Command is disallowed from being called for the '$schema' schema</error>"
);

return Command::FAILURE;
}

if (!$this->isSchemaExist($schema)) {
$output->writeln("<error>Schema '{$schema}' doesn't exist</error>");

Expand Down
16 changes: 15 additions & 1 deletion tests/Command/Doctrine/DoctrineSchemaDropCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class DoctrineSchemaDropCommandTest extends TestCase
protected function setUp(): void
{
$this->connection = $this->createMock(Connection::class);
$this->command = new DoctrineSchemaDropCommand($this->connection);
$this->command = new DoctrineSchemaDropCommand($this->connection, ['public']);
}

public function testSuccess(): void
Expand All @@ -41,4 +41,18 @@ public function testSuccess(): void

$this->assertEquals(Command::SUCCESS, $result);
}

public function testDisallowedSchemaNameFail(): void
{
$input = new ArrayInput(['schema' => 'public']);
$output = new BufferedOutput();

$result = $this->command->run($input, $output);

$this->assertStringContainsString(
"Command is disallowed from being called for the 'public' schema",
$output->fetch()
);
$this->assertEquals(Command::FAILURE, $result);
}
}
16 changes: 15 additions & 1 deletion tests/Command/Doctrine/DoctrineSchemaFixturesLoadCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ protected function setUp(): void
new InputOption('no-interaction'),
]));

$this->command = new DoctrineSchemaFixturesLoadCommand($this->parentCommand, $this->connection);
$this->command = new DoctrineSchemaFixturesLoadCommand($this->parentCommand, $this->connection, ['public']);
$this->command->setApplication($this->application);
}

Expand Down Expand Up @@ -72,4 +72,18 @@ public function testSuccess(): void
$this->assertEquals(Command::SUCCESS, $result);
$this->assertStringContainsString("Load fixtures for 'test_schema'...", $output->fetch());
}

public function testDisallowedSchemaNameFail(): void
{
$input = new ArrayInput(['schema' => 'public']);
$output = new BufferedOutput();

$result = $this->command->run($input, $output);

$this->assertStringContainsString(
"Command is disallowed from being called for the 'public' schema",
$output->fetch()
);
$this->assertEquals(Command::FAILURE, $result);
}
}
Loading