Skip to content

Commit 0a07800

Browse files
committed
fix: introspect of the view in the schema
1 parent ad2a79f commit 0a07800

File tree

7 files changed

+220
-1
lines changed

7 files changed

+220
-1
lines changed

src/SQL/Builder/DropSchemaObjectsSQLBuilder.php

+18
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Doctrine\DBAL\Schema\Schema;
99
use Doctrine\DBAL\Schema\Sequence;
1010
use Doctrine\DBAL\Schema\Table;
11+
use Doctrine\DBAL\Schema\View;
1112

1213
use function array_merge;
1314

@@ -24,6 +25,7 @@ public function buildSQL(Schema $schema): array
2425
$this->buildSequenceStatements($schema->getSequences()),
2526
$this->buildTableStatements($schema->getTables()),
2627
$this->buildNamespaceStatements($schema->getNamespaces()),
28+
$this->buildViewStatements($schema->getViews()),
2729
);
2830
}
2931

@@ -72,4 +74,20 @@ private function buildNamespaceStatements(array $namespaces): array
7274

7375
return $statements;
7476
}
77+
78+
/**
79+
* @param list<View> $views
80+
*
81+
* @return list<string>
82+
*/
83+
private function buildViewStatements(array $views): array
84+
{
85+
$statements = [];
86+
87+
foreach ($views as $view) {
88+
$statements[] = $this->platform->getDropViewSQL($view->getQuotedName($this->platform));
89+
}
90+
91+
return $statements;
92+
}
7593
}

src/Schema/AbstractSchemaManager.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,9 @@ public function introspectSchema(): Schema
801801

802802
$tables = $this->listTables();
803803

804-
return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames);
804+
$views = $this->listViews();
805+
806+
return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames, $views);
805807
}
806808

807809
/**
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Exception;
6+
7+
use Doctrine\DBAL\Schema\SchemaException;
8+
use LogicException;
9+
10+
use function sprintf;
11+
12+
/** @psalm-immutable */
13+
final class ViewAlreadyExists extends LogicException implements SchemaException
14+
{
15+
public static function new(string $viewName): self
16+
{
17+
return new self(sprintf('The view "%s" already exists.', $viewName));
18+
}
19+
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Exception;
6+
7+
use Doctrine\DBAL\Schema\SchemaException;
8+
use LogicException;
9+
10+
use function sprintf;
11+
12+
/** @psalm-immutable */
13+
final class ViewDoesNotExist extends LogicException implements SchemaException
14+
{
15+
public static function new(string $viewName): self
16+
{
17+
return new self(sprintf('There exists no view with the name "%s".', $viewName));
18+
}
19+
}

src/Schema/Schema.php

+74
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use Doctrine\DBAL\Schema\Exception\SequenceDoesNotExist;
1212
use Doctrine\DBAL\Schema\Exception\TableAlreadyExists;
1313
use Doctrine\DBAL\Schema\Exception\TableDoesNotExist;
14+
use Doctrine\DBAL\Schema\Exception\ViewAlreadyExists;
15+
use Doctrine\DBAL\Schema\Exception\ViewDoesNotExist;
1416
use Doctrine\DBAL\SQL\Builder\CreateSchemaObjectsSQLBuilder;
1517
use Doctrine\DBAL\SQL\Builder\DropSchemaObjectsSQLBuilder;
1618

@@ -57,18 +59,23 @@ class Schema extends AbstractAsset
5759
/** @var array<string, Sequence> */
5860
protected array $_sequences = [];
5961

62+
/** @var array<string, View> */
63+
protected array $_views = [];
64+
6065
protected SchemaConfig $_schemaConfig;
6166

6267
/**
6368
* @param array<Table> $tables
6469
* @param array<Sequence> $sequences
6570
* @param array<string> $namespaces
71+
* @param array<View> $views
6672
*/
6773
public function __construct(
6874
array $tables = [],
6975
array $sequences = [],
7076
?SchemaConfig $schemaConfig = null,
7177
array $namespaces = [],
78+
array $views = [],
7279
) {
7380
$schemaConfig ??= new SchemaConfig();
7481

@@ -91,6 +98,10 @@ public function __construct(
9198
foreach ($sequences as $sequence) {
9299
$this->_addSequence($sequence);
93100
}
101+
102+
foreach ($views as $view) {
103+
$this->_addView($view);
104+
}
94105
}
95106

96107
protected function _addTable(Table $table): void
@@ -134,6 +145,26 @@ protected function _addSequence(Sequence $sequence): void
134145
$this->_sequences[$seqName] = $sequence;
135146
}
136147

148+
protected function _addView(View $view): void
149+
{
150+
$namespaceName = $view->getNamespaceName();
151+
$viewName = $this->normalizeName($view);
152+
153+
if (isset($this->_views[$viewName])) {
154+
throw ViewAlreadyExists::new($viewName);
155+
}
156+
157+
if (
158+
$namespaceName !== null
159+
&& ! $view->isInDefaultNamespace($this->getName())
160+
&& ! $this->hasNamespace($namespaceName)
161+
) {
162+
$this->createNamespace($namespaceName);
163+
}
164+
165+
$this->_views[$viewName] = $view;
166+
}
167+
137168
/**
138169
* Returns the namespaces of this schema.
139170
*
@@ -249,6 +280,29 @@ public function getSequences(): array
249280
return array_values($this->_sequences);
250281
}
251282

283+
public function hasView(string $name): bool
284+
{
285+
$name = $this->getFullQualifiedAssetName($name);
286+
287+
return isset($this->_views[$name]);
288+
}
289+
290+
public function getView(string $name): View
291+
{
292+
$name = $this->getFullQualifiedAssetName($name);
293+
if (! $this->hasView($name)) {
294+
throw ViewDoesNotExist::new($name);
295+
}
296+
297+
return $this->_views[$name];
298+
}
299+
300+
/** @return list<View> */
301+
public function getViews(): array
302+
{
303+
return array_values($this->_views);
304+
}
305+
252306
/**
253307
* Creates a new namespace.
254308
*
@@ -332,6 +386,26 @@ public function dropSequence(string $name): self
332386
return $this;
333387
}
334388

389+
/**
390+
* Creates a new view.
391+
*/
392+
public function createView(string $name, string $sql): View
393+
{
394+
$view = new View($name, $sql);
395+
$this->_addView($view);
396+
397+
return $view;
398+
}
399+
400+
/** @return $this */
401+
public function dropView(string $name): self
402+
{
403+
$name = $this->getFullQualifiedAssetName($name);
404+
unset($this->_views[$name]);
405+
406+
return $this;
407+
}
408+
335409
/**
336410
* Returns an array of necessary SQL queries to create the schema on the given platform.
337411
*

tests/Functional/Schema/SchemaManagerFunctionalTestCase.php

+19
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,25 @@ public function testCreateAndListViews(): void
692692
self::assertStringContainsString('view_test_table', $filtered[0]->getSql());
693693
}
694694

695+
public function testIntrospectSchemaWithView(): void
696+
{
697+
$this->createTestTable('view_test_table');
698+
699+
$name = 'doctrine_test_view';
700+
$sql = 'SELECT * FROM view_test_table';
701+
702+
$view = new View($name, $sql);
703+
704+
$this->schemaManager->createView($view);
705+
706+
$schema = $this->schemaManager->introspectSchema();
707+
708+
$filtered = array_values($this->filterElementsByName($schema->getViews(), $name));
709+
self::assertCount(1, $filtered);
710+
711+
self::assertStringContainsString('view_test_table', $filtered[0]->getSql());
712+
}
713+
695714
public function testAutoincrementDetection(): void
696715
{
697716
if (! $this->connection->getDatabasePlatform()->supportsIdentityColumns()) {

tests/Schema/SchemaTest.php

+68
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Doctrine\DBAL\Schema\SchemaException;
1010
use Doctrine\DBAL\Schema\Sequence;
1111
use Doctrine\DBAL\Schema\Table;
12+
use Doctrine\DBAL\Schema\View;
1213
use Doctrine\DBAL\Types\Types;
1314
use PHPUnit\Framework\TestCase;
1415

@@ -169,6 +170,73 @@ public function testAddSequenceTwiceThrowsException(): void
169170
new Schema([], [$sequence, $sequence]);
170171
}
171172

173+
public function testAddViews(): void
174+
{
175+
$view = new View('a_view', 'SELECT 1');
176+
177+
$schema = new Schema([], [], null, [], [$view]);
178+
179+
self::assertTrue($schema->hasView('a_view'));
180+
self::assertSame('a_view', $schema->getView('a_view')->getName());
181+
182+
self::assertEquals([$view], $schema->getViews());
183+
}
184+
185+
public function testViewAccessCaseInsensitive(): void
186+
{
187+
$view = new View('a_View', 'SELECT 1');
188+
189+
$schema = new Schema([], [], null, [], [$view]);
190+
self::assertTrue($schema->hasView('a_view'));
191+
self::assertTrue($schema->hasView('a_View'));
192+
self::assertTrue($schema->hasView('A_VIEW'));
193+
194+
self::assertEquals($view, $schema->getView('a_view'));
195+
self::assertEquals($view, $schema->getView('a_View'));
196+
self::assertEquals($view, $schema->getView('A_VIEW'));
197+
}
198+
199+
public function testGetUnknownViewThrowsException(): void
200+
{
201+
$this->expectException(SchemaException::class);
202+
203+
$schema = new Schema();
204+
$schema->getView('unknown');
205+
}
206+
207+
public function testCreateView(): void
208+
{
209+
$schema = new Schema();
210+
$view = $schema->createView('a_view', 'SELECT 1');
211+
212+
self::assertEquals('a_view', $view->getName());
213+
self::assertEquals('SELECT 1', $view->getSql());
214+
215+
self::assertTrue($schema->hasView('a_view'));
216+
self::assertSame('a_view', $schema->getView('a_view')->getName());
217+
218+
self::assertEquals([$view], $schema->getViews());
219+
}
220+
221+
public function testDropView(): void
222+
{
223+
$view = new View('a_View', 'SELECT 1');
224+
225+
$schema = new Schema([], [], null, [], [$view]);
226+
227+
$schema->dropView('a_view');
228+
self::assertFalse($schema->hasView('a_view'));
229+
}
230+
231+
public function testAddViewTwiceThrowsException(): void
232+
{
233+
$this->expectException(SchemaException::class);
234+
235+
$view = new View('a_View', 'SELECT 1');
236+
237+
new Schema([], [], null, [], [$view, $view]);
238+
}
239+
172240
public function testConfigMaxIdentifierLength(): void
173241
{
174242
$schemaConfig = new SchemaConfig();

0 commit comments

Comments
 (0)