database-abstraction.txt 13.9 KB
Newer Older
1
++ Modules
zYne's avatar
zYne committed
2 3
++ Export
+++ Introduction
zYne's avatar
zYne committed
4 5 6 7 8
The Export module provides methods for managing database structure. The methods can be grouped based on their responsibility: create, edit (alter or update), list or delete (drop) database elements. The following document lists the available methods, providing examples of their use. 

Every schema altering method in the Export module has an equivalent which returns the sql that is used for the altering operation. For example createTable() executes the query / queries returned by createTableSql().

In this chapter the following tables will be created, altered and finally dropped, in a database named "events_db":
zYne's avatar
zYne committed
9 10 11 12 13
events(id, name, datetime);
people(id, name);
event_participants(event_id, person_id);

+++ Creating a database
14
<code type="php">
zYne's avatar
zYne committed
15 16 17 18 19 20
$conn->export->createDatabase('events_db');
</code>
+++ Creating tables

Now that the database is created, we can proceed with adding some tables. The method createTable() takes three parameters: the table name, an array of field definition and some extra options (optional and RDBMS-specific). Now lets create the events table:

21
<code type="php">
zYne's avatar
zYne committed
22 23 24 25 26 27 28 29
$definition = array (
    'id' => array (
        'type' => 'integer',
        'unsigned' => 1,
        'notnull' => 1,
        'default' => 0,
    ),
    'name' => array (
30
        'type' => 'string',
zYne's avatar
zYne committed
31 32 33 34 35 36 37 38 39 40 41 42
        'length' => 255
    ),
    'datetime' => array (
        'type' => 'timestamp'
    )
);

$conn->export->createTable('events', $definition);
</code>
 
The keys of the definition array are the names of the fields in the table. The values are arrays containing the required key 'type' as well as other keys, depending on the value of 'type'. The values for the 'type' key are the same as the possible Doctrine datatypes. Depending on the datatype, the other options may vary.

zYne's avatar
zYne committed
43
||~ Datatype ||~ length ||~ default ||~ not null ||~ unsigned ||~ autoincrement ||
jackbravo's avatar
jackbravo committed
44
|| string    || x || x || x ||   ||   ||
zYne's avatar
zYne committed
45 46 47 48 49 50 51 52 53
|| boolean   ||   || x || x ||   ||   ||
|| integer   || x || x || x || x || x ||
|| decimal   ||   || x || x ||   ||   ||
|| float     ||   || x || x ||   ||   ||
|| timestamp ||   || x || x ||   ||   ||
|| time      ||   || x || x ||   ||   ||
|| date      ||   || x || x ||   ||   ||
|| clob      || x ||   || x ||   ||   ||
|| blob      || x ||   || x ||   ||   ||
zYne's avatar
zYne committed
54 55 56

Creating the people table:

57
<code type="php">
zYne's avatar
zYne committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71
$options = array(
    'comment' => 'Repository of people',
    'character_set' => 'utf8',
    'collate' => 'utf8_unicode_ci',
    'type'    => 'innodb',
);
$definition = array (
    'id' => array (
        'type' => 'integer',
        'unsigned' => 1,
        'notnull' => 1,
        'default' => 0,
    ),
    'name' => array (
72
        'type' => 'string',
zYne's avatar
zYne committed
73 74 75 76 77 78
        'length' => 255
    )
);
$conn->export->createTable('people', $definition, $options);
</code>

zYne's avatar
zYne committed
79 80


zYne's avatar
zYne committed
81
+++ Creating foreign keys
zYne's avatar
zYne committed
82

zYne's avatar
zYne committed
83 84
Creating the event_participants table with a foreign key:

85
<code type="php">
zYne's avatar
zYne committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
$options = array(
    'foreignKeys' => array('local'   => 'event_id',
                           'foreign' => 'id'
                           'foreignTable' => 'events'
                           'onDelete' => 'CASCADE'),
    'primary' => array('event_id', 'person_id'),
);
$definition = array (
    'event_id' => array (
        'type' => 'integer',
        'unsigned' => 1,
        'notnull' => 1,
        'default' => 0,
    ),
    'person_id' => array (
        'type' => 'integer',
        'unsigned' => 1,
        'notnull' => 1,
        'default' => 0,
    ),
);

$conn->export->createTable('event_participants', $definition, $options);
</code>

Now lets say we want to add foreign key on person_id too. This can be achieved as follows:

113
<code type="php">
zYne's avatar
zYne committed
114 115 116 117 118 119 120
$definition = array('local'   => 'person_id',
                    'foreign' => 'id'
                    'foreignTable' => 'people'
                    'onDelete' => 'CASCADE'))

$conn->export->createForeignKey('event_participants', $definition);
</code>
zYne's avatar
zYne committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

+++ Altering table

Doctrine_Export drivers provide an easy database portable way of altering existing database tables.

NOTE: if you only want to get the generated sql (and not execute it) use Doctrine_Export::alterTableSql() 

<code type="php">
$dbh  = new PDO('dsn','username','pw');
$conn = Doctrine_Manager::getInstance()
        ->openConnection($dbh);

$a    = array('add' => array('name' => array('type' => 'string', 'length' => 255)));


$conn->export->alterTableSql('mytable', $a);

// On mysql this method returns: 
// ALTER TABLE mytable ADD COLUMN name VARCHAR(255)
</code>

Doctrine_Export::alterTable() takes two parameters:

: string //$name// : name of the table that is intended to be changed. 

: array //$changes// : associative array that contains the details of each type of change that is intended to be performed.
147 148 149

An optional third parameter (default: false) is accepted in alterTable and alterTableSql; it is named //$check// and it identifies if the DBMS driver can perform the requested table alterations if the value is true or actually perform them otherwise.

zYne's avatar
zYne committed
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
The types of changes that are currently supported are defined as follows:

* //name//
New name for the table.

* //add//

Associative array with the names of fields to be added as indexes of the array. The value of each entry of the array should be set to another associative array with the properties of the fields to be added. The properties of the fields should be the same as defined by the Doctrine parser.

* //remove//

Associative array with the names of fields to be removed as indexes of the array. Currently the values assigned to each entry are ignored. An empty array should be used for future compatibility.

* //rename//

Associative array with the names of fields to be renamed as indexes of the array. The value of each entry of the array should be set to another associative array with the entry named name with the new field name and the entry named Declaration that is expected to contain the portion of the field declaration already in DBMS specific SQL code as it is used in the CREATE TABLE statement.

* //change//

Associative array with the names of the fields to be changed as indexes of the array. Keep in mind that if it is intended to change either the name of a field and any other properties, the change array entries should have the new names of the fields as array indexes.

The value of each entry of the array should be set to another associative array with the properties of the fields to that are meant to be changed as array entries. These entries should be assigned to the new values of the respective properties. The properties of the fields should be the same as defined by the Doctrine parser.

<code type="php">
$a = array('name' => 'userlist',
           'add' => array(
                    'quota' => array(
                        'type' => 'integer',
                        'unsigned' => 1
                        )
                    ),
            'remove' => array(
                    'file_limit' => array(),
                    'time_limit' => array()
                    ),
            'change' => array(
                    'name' => array(
                        'length' => '20',
                        'definition' => array(
189
                            'type' => 'string',
zYne's avatar
zYne committed
190 191 192 193 194 195 196 197
                            'length' => 20
                            )
                        )
                    ),
            'rename' => array(
                    'sex' => array(
                        'name' => 'gender',
                        'definition' => array(
198
                            'type' => 'string',
zYne's avatar
zYne committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
                            'length' => 1,
                            'default' => 'M'
                            )
                        )
                    )
            
            );

$dbh  = new PDO('dsn','username','pw');
$conn = Doctrine_Manager::getInstance()->openConnection($dbh);

$conn->export->alterTable('mytable', $a);
</code>
+++ Creating indices
To create an index, the method createIndex() is used, which has similar signature as createConstraint(), so it takes table name, index name and a definition array. The definition array has one key fields with a value which is another associative array containing fields that will be a part of the index. The fields are defined as arrays with possible keys: 


sorting, with values ascending and descending 

length, integer value 

Not all RDBMS will support index sorting or length, in these cases the drivers will ignore them. In the test events database, we can assume that our application will show events occuring in a specific timeframe, so the selects will use the datetime field in WHERE conditions. It will help if there is an index on this field.


223
<code type="php">
zYne's avatar
zYne committed
224 225 226 227 228 229 230 231 232 233
$definition = array(
    'fields' => array(
        'datetime' => array()
    )
);
$conn->export->createIndex('events', 'event_timestamp', $definition);
</code>
+++ Deleting database elements
For every create*() method as shown above, there is a corresponding drop*() method to delete a database, a table, field, index or constraint. The drop*() methods do not check if the item to be deleted exists, so it's developer's responsibility to check for exceptions.

234
<code type="php">
zYne's avatar
zYne committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
// drop a sequence
try {
    $conn->export->dropSequence('nonexisting');
} catch(Doctrine_Exception $e) {

}
// another sequence
$result = $conn->export->dropSequence('people');

// drop a constraint
$conn->export->dropConstraint('events', 'PRIMARY', true);
// note: the third parameter gives a hint
//       that this is a primary key constraint
$conn->export->dropConstraint('event_participants', 'unique_participant');

// drop an index
$conn->export->dropIndex('events', 'event_timestamp');

// drop a table
$conn->export->dropTable('events');

// drop the database already!
$conn->export->dropDatabase('events_db');
</code>

 
 


 
 

++ Import
+++ Introduction

To see what's in the database, you can use the list*() family of functions in the Import module.

* listDatabases()

* listFunctions()

* listSequences(): takes optional database name as a parameter. If not supplied, the currently selected database is assumed.

* listTableConstraints(): takes a table name

* listTableFields(): takes a table name

* listTableIndexes(): takes a table name

* listTables(): takes an optional database name

* listTableTriggers(): takes a table name

* listTableViews(): takes a table name

* listUsers()

* listViews(): takes an optional database name


+++ Listing databases
296
<code type="php">
zYne's avatar
zYne committed
297 298 299 300 301
$dbs = $conn->import->listDatabases();
print_r($dbs);
</code>
+++ Listing sequences

302
<code type="php">
303
$seqs = $conn->import->listSequences('events_db');
zYne's avatar
zYne committed
304 305 306 307 308
print_r($seqs);
</code>

+++ Listing constraints

309
<code type="php">
310
$cons = $conn->import->listTableConstraints('event_participants');
zYne's avatar
zYne committed
311 312 313 314
</code>

+++ Listing table fields

315
<code type="php">
316
$fields = $conn->import->listTableFields('events');
zYne's avatar
zYne committed
317 318 319 320 321 322 323 324 325 326 327 328 329
print_r($fields);
/*
prints:
Array
(
    [0] => id
    [1] => name
    [2] => datetime
)
*/
</code>

+++ Listing table indices
330
<code type="php">
331
$idx = $conn->import->listTableIndexes('events');
zYne's avatar
zYne committed
332 333 334 335 336 337 338 339 340 341 342 343
print_r($idx);
/*
prints:
Array
(
    [0] => event_timestamp
)
*/
</code>

+++ Listing tables

344
<code type="php">
345
$tables = $conn->import->listTables();
zYne's avatar
zYne committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359
print_r($tables);
/*
prints:
Array
(
    [0] => event_participants
    [1] => events
    [2] => people
)
*/
</code>

+++ Listing views

360
<code type="php">
zYne's avatar
zYne committed
361 362 363
// currently there is no method to create a view,
// so let's do it "manually"
$sql = "CREATE VIEW names_only AS SELECT name FROM people";
364
$conn->exec($sql);
zYne's avatar
zYne committed
365
$sql = "CREATE VIEW last_ten_events AS SELECT * FROM events ORDER BY id DESC LIMIT 0,10";
366
$conn->exec($sql);
zYne's avatar
zYne committed
367
// list views
368
$views = $conn->import->listViews();
zYne's avatar
zYne committed
369 370 371 372 373 374 375 376 377 378 379
print_r($views);
/*
prints:
Array
(
    [0] => last_ten_events
    [1] => names_only
)
*/
</code>

zYne's avatar
zYne committed
380 381 382 383 384
++ DataDict
+++ Introduction
Doctrine uses DataDict module internally to convert native RDBMS types to Doctrine types and the reverse. DataDict module uses two methods for the conversions:
1. getPortableDeclaration(), which is used for converting native RDBMS type declaration to portable Doctrine declaration
2. getNativeDeclaration(), which is used for converting portable Doctrine declaration to driver specific type declaration
zYne's avatar
zYne committed
385 386


zYne's avatar
zYne committed
387 388 389 390
+++ Getting portable declaration
<code type="php">
$dbh  = new PDO('mysql:host=localhost;dbname=test', 'username', 'pw');
$conn = Doctrine_Manager::getInstance()->openConnection($dbh);
zYne's avatar
zYne committed
391

zYne's avatar
zYne committed
392
$decl = $conn->dataDict->getPortableDeclaration('VARCHAR(255)');
zYne's avatar
zYne committed
393

zYne's avatar
zYne committed
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
print_r($decl);
/*
array('type' => 'string',
      'length' => 255,
      'fixed'  => false,
      'unsigned' => false
      );
*/
</code>
+++ Getting native declaration
<code type="php">
$dbh  = new PDO('mysql:host=localhost;dbname=test', 'username', 'pw');
$conn = Doctrine_Manager::getInstance()->openConnection($dbh);

$portableDecl = array('type' => 'string',
                             'length' => 20,
                             'fixed' => true);
$nativeDecl = $conn->dataDict->getNativeDeclaration($portableDecl);

print $nativeDecl; // CHAR(20)
</code>
zYne's avatar
zYne committed
415

416
++ Drivers
zYne's avatar
zYne committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
+++ Mysql
++++ Setting table type

<code type="php">
$dbh  = new PDO('dsn','username','pw');
$conn = Doctrine_Manager::getInstance()->openConnection($dbh);

$fields = array('id' => array(
                    'type' => 'integer',
                    'autoincrement' => true),
                'name' => array(
                    'type' => 'string',
                    'fixed' => true,
                    'length' => 8)
                );
// the following option is mysql specific and
// skipped by other drivers
$options = array('type' => 'MYISAM');

$conn->export->createTable('mytable', $fields);

// on mysql this executes query:
// CREATE TABLE mytable (id INT AUTO_INCREMENT PRIMARY KEY,
//        name CHAR(8));
</code>