Skip to content

Commit 19870ca

Browse files
authored
[#42387] Split out schema creation (#7)
* [#42387] Split out schema creation * Always create a new in memory db * Adds indexes * Split out validate function * Remove unused imports * Rename create and drop schema
1 parent 80a02f0 commit 19870ca

File tree

5 files changed

+151
-77
lines changed

5 files changed

+151
-77
lines changed

src/NestedSetSchemaInterface.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace PNX\NestedSet;
4+
5+
/**
6+
* Provides Nested Set schema operations.
7+
*/
8+
interface NestedSetSchemaInterface {
9+
10+
/**
11+
* Creates the nested set table.
12+
*/
13+
public function create();
14+
15+
/**
16+
* Drops the nested set table.
17+
*/
18+
public function drop();
19+
20+
}

src/Storage/BaseDbalStorage.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace PNX\NestedSet\Storage;
4+
5+
use Doctrine\DBAL\Connection;
6+
7+
/**
8+
* Abstract base class for DBAL storage classes.
9+
*/
10+
abstract class BaseDbalStorage {
11+
12+
/**
13+
* The regex for validating table names.
14+
*/
15+
const VALID_TABLE_REGEX = '/^[a-zA-Z]\w{1,64}$/';
16+
17+
/**
18+
* The database connection.
19+
*
20+
* @var \Doctrine\DBAL\Connection
21+
*/
22+
protected $connection;
23+
24+
/**
25+
* The table name to use for storing the nested set.
26+
*
27+
* @var string
28+
*/
29+
protected $tableName;
30+
31+
/**
32+
* DbalTree constructor.
33+
*
34+
* @param \Doctrine\DBAL\Connection $connection
35+
* The database connection.
36+
* @param string $tableName
37+
* (optional) The table name to use.
38+
*/
39+
public function __construct(Connection $connection, $tableName = 'tree') {
40+
$this->connection = $connection;
41+
if (!$this->validTableName($tableName)) {
42+
throw new \InvalidArgumentException("Table name must match the regex " . self::VALID_TABLE_REGEX);
43+
}
44+
$this->tableName = $tableName;
45+
}
46+
47+
/**
48+
* Checks if the table name is valid.
49+
*
50+
* Table names must:
51+
* - start with a letter
52+
* - only contain letters, numbers, and underscores
53+
* - be maximum 64 characters.
54+
*
55+
* @param string $tableName
56+
* The table name.
57+
*
58+
* @return bool
59+
* TRUE if the table name is valid.
60+
*/
61+
protected function validTableName($tableName) {
62+
return (bool) preg_match(self::VALID_TABLE_REGEX, $tableName);
63+
}
64+
65+
}

src/Storage/DbalNestedSet.php

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,14 @@
22

33
namespace PNX\NestedSet\Storage;
44

5-
use Doctrine\DBAL\Connection;
65
use Exception;
7-
use PNX\NestedSet\Node;
86
use PNX\NestedSet\NestedSetInterface;
7+
use PNX\NestedSet\Node;
98

109
/**
1110
* Provides a DBAL implementation of a Tree.
1211
*/
13-
class DbalNestedSet implements NestedSetInterface {
14-
15-
/**
16-
* The regex for validating table names.
17-
*/
18-
const VALID_TABLE_REGEX = '/^[a-zA-Z]\w{1,64}$/';
19-
20-
/**
21-
* The database connection.
22-
*
23-
* @var \Doctrine\DBAL\Connection
24-
*/
25-
protected $connection;
26-
27-
/**
28-
* The table name to use for storing the nested set.
29-
*
30-
* @var string
31-
*/
32-
protected $tableName;
33-
34-
/**
35-
* DbalTree constructor.
36-
*
37-
* @param \Doctrine\DBAL\Connection $connection
38-
* The database connection.
39-
* @param string $tableName
40-
* (optional) The table name to use.
41-
*/
42-
public function __construct(Connection $connection, $tableName = 'tree') {
43-
$this->connection = $connection;
44-
if (!preg_match(self::VALID_TABLE_REGEX, $tableName)) {
45-
throw new \InvalidArgumentException("Table name must match the regex " . self::VALID_TABLE_REGEX);
46-
}
47-
$this->tableName = $tableName;
48-
}
12+
class DbalNestedSet extends BaseDbalStorage implements NestedSetInterface {
4913

5014
/**
5115
* {@inheritdoc}
@@ -169,10 +133,10 @@ public function findDescendants(Node $node, $depth = 0) {
169133
$query->select('child.id', 'child.revision_id', 'child.left_pos', 'child.right_pos', 'child.depth')
170134
->from($this->tableName, 'child')
171135
->from($this->tableName, 'parent')
172-
->where('child.left_pos > parent.left_pos')
173-
->andWhere('child.right_pos < parent.right_pos')
174136
->andWhere('parent.id = :id')
175137
->andWhere('parent.revision_id = :revision_id')
138+
->andwhere('child.left_pos > parent.left_pos')
139+
->andWhere('child.right_pos < parent.right_pos')
176140
->setParameter(':id', $node->getId())
177141
->setParameter(':revision_id', $node->getRevisionId());
178142
if ($depth > 0) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace PNX\NestedSet\Storage;
4+
5+
use Doctrine\DBAL\Schema\Schema;
6+
use PNX\NestedSet\NestedSetSchemaInterface;
7+
8+
/**
9+
* Provides DBAL Nested set schema operations.
10+
*/
11+
class DbalNestedSetSchema extends BaseDbalStorage implements NestedSetSchemaInterface {
12+
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
public function create() {
17+
$schema = new Schema();
18+
$tree = $schema->createTable($this->tableName);
19+
$tree->addColumn("id", "integer", ["unsigned" => TRUE]);
20+
$tree->addColumn("revision_id", "integer", ["unsigned" => TRUE]);
21+
$tree->addColumn("left_pos", "integer", ["unsigned" => TRUE]);
22+
$tree->addColumn("right_pos", "integer", ["unsigned" => TRUE]);
23+
$tree->addColumn("depth", "integer", ["unsigned" => TRUE]);
24+
25+
$tree->setPrimaryKey(['id', 'revision_id']);
26+
$tree->addIndex(['id', 'revision_id', 'left_pos', 'right_pos', 'depth']);
27+
$tree->addIndex(['left_pos', 'right_pos']);
28+
$tree->addIndex(['right_pos']);
29+
30+
foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) {
31+
$this->connection->exec($sql);
32+
}
33+
}
34+
35+
/**
36+
* {@inheritdoc}
37+
*/
38+
public function drop() {
39+
$schema = new Schema();
40+
$schema->dropTable($this->tableName);
41+
foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) {
42+
$this->connection->exec($sql);
43+
}
44+
}
45+
46+
}

tests/Functional/DbalNestedSetTest.php

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
use Console_Table;
66
use Doctrine\DBAL\Configuration;
77
use Doctrine\DBAL\DriverManager;
8-
use Doctrine\DBAL\Schema\Schema;
98
use PNX\NestedSet\Node;
109
use PNX\NestedSet\Storage\DbalNestedSet;
10+
use PNX\NestedSet\Storage\DbalNestedSetSchema;
1111

1212
/**
1313
* Tests the Dbal Tree implementation.
@@ -37,18 +37,25 @@ class DbalNestedSetTest extends \PHPUnit_Framework_TestCase {
3737
*/
3838
protected $tableName = 'nested_set';
3939

40+
/**
41+
* The nested set schema.
42+
*
43+
* @var \PNX\NestedSet\Storage\DbalNestedSetSchema
44+
*/
45+
protected $schema;
46+
4047
/**
4148
* {@inheritdoc}
4249
*/
4350
protected function setUp() {
44-
if ($this->connection === NULL) {
45-
$this->connection = DriverManager::getConnection([
46-
'url' => 'sqlite:///:memory:',
47-
], new Configuration());
48-
$this->createTable();
49-
$this->loadTestData();
50-
$this->nestedSet = new DbalNestedSet($this->connection, $this->tableName);
51-
}
51+
$this->connection = DriverManager::getConnection([
52+
'url' => 'sqlite:///:memory:',
53+
], new Configuration());
54+
55+
$this->schema = new DbalNestedSetSchema($this->connection, $this->tableName);
56+
$this->schema->create();
57+
$this->loadTestData();
58+
$this->nestedSet = new DbalNestedSet($this->connection, $this->tableName);
5259
}
5360

5461
/**
@@ -423,34 +430,6 @@ public function testValidateTableInvalidFirstChars() {
423430
$this->nestedSet = new DbalNestedSet($this->connection, "1abc");
424431
}
425432

426-
/**
427-
* Drops the table.
428-
*/
429-
protected function dropTable() {
430-
$schema = new Schema();
431-
$schema->dropTable("tree");
432-
foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) {
433-
$this->connection->exec($sql);
434-
}
435-
}
436-
437-
/**
438-
* Creates the table.
439-
*/
440-
protected function createTable() {
441-
$schema = new Schema();
442-
$tree = $schema->createTable($this->tableName);
443-
$tree->addColumn("id", "integer", ["unsigned" => TRUE]);
444-
$tree->addColumn("revision_id", "integer", ["unsigned" => TRUE]);
445-
$tree->addColumn("left_pos", "integer", ["unsigned" => TRUE]);
446-
$tree->addColumn("right_pos", "integer", ["unsigned" => TRUE]);
447-
$tree->addColumn("depth", "integer", ["unsigned" => TRUE]);
448-
449-
foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) {
450-
$this->connection->exec($sql);
451-
}
452-
}
453-
454433
/**
455434
* Loads the test data.
456435
*/

0 commit comments

Comments
 (0)