diff --git a/lib/Doctrine/DataDict/Oracle.php b/lib/Doctrine/DataDict/Oracle.php index 23cc2f2ab..3feb2a4d0 100644 --- a/lib/Doctrine/DataDict/Oracle.php +++ b/lib/Doctrine/DataDict/Oracle.php @@ -107,15 +107,19 @@ class Doctrine_DataDict_Oracle extends Doctrine_DataDict */ public function getPortableDeclaration(array $field) { - $dbType = strtolower($field['type']); + if ( ! isset($field['data_type'])) { + throw new Doctrine_DataDict_Exception('Native oracle definition must have a data_type key specified'); + } + + $dbType = strtolower($field['data_type']); $type = array(); $length = $unsigned = $fixed = null; - if ( ! empty($field['length'])) { - $length = $field['length']; + if ( ! empty($field['data_length'])) { + $length = $field['data_length']; } - if ( ! isset($field['name'])) { - $field['name'] = ''; + if ( ! isset($field['column_name'])) { + $field['column_name'] = ''; } switch ($dbType) { @@ -125,7 +129,7 @@ class Doctrine_DataDict_Oracle extends Doctrine_DataDict $type[] = 'integer'; if ($length == '1') { $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { + if (preg_match('/^(is|has)/', $field['column_name'])) { $type = array_reverse($type); } } @@ -139,7 +143,7 @@ class Doctrine_DataDict_Oracle extends Doctrine_DataDict $type[] = 'string'; if ($length == '1') { $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { + if (preg_match('/^(is|has)/', $field['column_name'])) { $type = array_reverse($type); } } @@ -156,13 +160,13 @@ class Doctrine_DataDict_Oracle extends Doctrine_DataDict $type[] = 'float'; break; case 'number': - if ( ! empty($field['scale'])) { + if ( ! empty($field['data_scale'])) { $type[] = 'decimal'; } else { $type[] = 'integer'; if ($length == '1') { $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { + if (preg_match('/^(is|has)/', $field['column_name'])) { $type = array_reverse($type); } } @@ -192,4 +196,4 @@ class Doctrine_DataDict_Oracle extends Doctrine_DataDict 'unsigned' => $unsigned, 'fixed' => $fixed); } -} \ No newline at end of file +} diff --git a/lib/Doctrine/Import/Oracle.php b/lib/Doctrine/Import/Oracle.php index d1f846aa3..5dce512bf 100644 --- a/lib/Doctrine/Import/Oracle.php +++ b/lib/Doctrine/Import/Oracle.php @@ -126,6 +126,8 @@ class Doctrine_Import_Oracle extends Doctrine_Import $result = $this->conn->fetchAssoc($sql); + $descr = array(); + foreach($result as $val) { $val = array_change_key_case($val, CASE_LOWER); $decl = $this->conn->dataDict->getPortableDeclaration($val); diff --git a/lib/Doctrine/Import/Schema.php b/lib/Doctrine/Import/Schema.php index bb75bf416..58e4451ed 100644 --- a/lib/Doctrine/Import/Schema.php +++ b/lib/Doctrine/Import/Schema.php @@ -102,7 +102,7 @@ class Doctrine_Import_Schema $array = array(); foreach ((array) $schema AS $s) { - if (is_file($s)) { + if (is_file($s) || is_string($s)) { $array = array_merge($array, $this->parseSchema($s, $format)); } else if (is_dir($s)) { $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($s), @@ -119,7 +119,7 @@ class Doctrine_Import_Schema $this->_buildRelationships($array); - return array('schema' => $array, 'relations' => $this->_relations); + return $array; } /** @@ -144,10 +144,8 @@ class Doctrine_Import_Schema } } - $schema = $this->buildSchema($schema, $format); - - $array = $schema['schema']; - + $array = $this->buildSchema($schema, $format); + foreach ($array as $name => $properties) { if ( ! empty($models) && !in_array($properties['className'], $models)) { continue; diff --git a/lib/Doctrine/Parser.php b/lib/Doctrine/Parser.php index 3f7720bc6..f86a64892 100644 --- a/lib/Doctrine/Parser.php +++ b/lib/Doctrine/Parser.php @@ -131,12 +131,19 @@ abstract class Doctrine_Parser return $contents; } - public function doDump($data, $path) + /** + * doDump + * + * @param string $data + * @param string $path + * @return void + */ + public function doDump($data, $path = null) { - if ($path) { + if ($path !== null) { return file_put_contents($path, $data); } else { return $data; } } -} +} \ No newline at end of file diff --git a/tests/Data/ExportTestCase.php b/tests/Data/ExportTestCase.php new file mode 100644 index 000000000..1692d0fa0 --- /dev/null +++ b/tests/Data/ExportTestCase.php @@ -0,0 +1,35 @@ +. + */ + +/** + * Doctrine_Data_Export_TestCase + * + * @package Doctrine + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + */ +class Doctrine_Data_Export_TestCase extends Doctrine_UnitTestCase +{ +} diff --git a/tests/Data/ImportTestCase.php b/tests/Data/ImportTestCase.php new file mode 100644 index 000000000..1aee17493 --- /dev/null +++ b/tests/Data/ImportTestCase.php @@ -0,0 +1,35 @@ +. + */ + +/** + * Doctrine_Data_Import_TestCase + * + * @package Doctrine + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + */ +class Doctrine_Data_Import_TestCase extends Doctrine_UnitTestCase +{ +} diff --git a/tests/DataDict/OracleTestCase.php b/tests/DataDict/OracleTestCase.php index 28eda8b23..5fafd1f00 100644 --- a/tests/DataDict/OracleTestCase.php +++ b/tests/DataDict/OracleTestCase.php @@ -34,7 +34,7 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { public function testGetPortableDeclarationForUnknownNativeTypeThrowsException() { try { - $this->dataDict->getPortableDeclaration(array('type' => 'some_unknown_type')); + $this->dataDict->getPortableDeclaration(array('data_type' => 'some_unknown_type')); $this->fail(); } catch(Doctrine_DataDict_Exception $e) { $this->pass(); @@ -42,7 +42,7 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { } public function testGetPortableDeclarationSupportsNativeFloatType() { - $type = $this->dataDict->getPortableDeclaration(array('type' => 'float')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'float')); $this->assertEqual($type, array('type' => array('float'), 'length' => null, @@ -51,21 +51,21 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { } public function testGetPortableDeclarationSupportsNativeIntegerTypes() { - $type = $this->dataDict->getPortableDeclaration(array('type' => 'integer')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'integer')); $this->assertEqual($type, array('type' => array('integer'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'pls_integer', 'length' => 1)); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'pls_integer', 'data_length' => 1)); $this->assertEqual($type, array('type' => array('integer', 'boolean'), 'length' => 1, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'binary_integer', 'length' => 1)); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'binary_integer', 'data_length' => 1)); $this->assertEqual($type, array('type' => array('integer', 'boolean'), 'length' => 1, @@ -74,35 +74,35 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { } public function testGetPortableDeclarationSupportsNativeStringTypes() { - $type = $this->dataDict->getPortableDeclaration(array('type' => 'varchar')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'varchar')); $this->assertEqual($type, array('type' => array('string'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'varchar2', 'length' => 1)); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'varchar2', 'data_length' => 1)); $this->assertEqual($type, array('type' => array('string', 'boolean'), 'length' => 1, 'unsigned' => null, 'fixed' => false)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'nvarchar2', 'length' => 1)); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'nvarchar2', 'data_length' => 1)); $this->assertEqual($type, array('type' => array('string', 'boolean'), 'length' => 1, 'unsigned' => null, 'fixed' => false)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'char', 'length' => 1)); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'char', 'data_length' => 1)); $this->assertEqual($type, array('type' => array('string', 'boolean'), 'length' => 1, 'unsigned' => null, 'fixed' => true)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'nchar', 'length' => 1)); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'nchar', 'data_length' => 1)); $this->assertEqual($type, array('type' => array('string', 'boolean'), 'length' => 1, @@ -111,7 +111,7 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { } public function testGetPortableDeclarationSupportsNativeNumberType() { - $type = $this->dataDict->getPortableDeclaration(array('type' => 'number')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'number')); $this->assertEqual($type, array('type' => array('integer'), 'length' => null, @@ -119,7 +119,7 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'number', 'length' => 1)); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'number', 'data_length' => 1)); $this->assertEqual($type, array('type' => array('integer', 'boolean'), 'length' => 1, @@ -129,14 +129,14 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { } public function testGetPortableDeclarationSupportsNativeTimestampType() { - $type = $this->dataDict->getPortableDeclaration(array('type' => 'date')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'date')); $this->assertEqual($type, array('type' => array('timestamp'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'timestamp')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'timestamp')); $this->assertEqual($type, array('type' => array('timestamp'), 'length' => null, @@ -145,21 +145,21 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { } public function testGetPortableDeclarationSupportsNativeClobTypes() { - $type = $this->dataDict->getPortableDeclaration(array('type' => 'clob')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'clob')); $this->assertEqual($type, array('type' => array('clob'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'long')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'long')); $this->assertEqual($type, array('type' => array('string', 'clob'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'nclob')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'nclob')); $this->assertEqual($type, array('type' => array('clob'), 'length' => null, @@ -169,28 +169,28 @@ class Doctrine_DataDict_Oracle_TestCase extends Doctrine_UnitTestCase { } public function testGetPortableDeclarationSupportsNativeBlobTypes() { - $type = $this->dataDict->getPortableDeclaration(array('type' => 'blob')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'blob')); $this->assertEqual($type, array('type' => array('blob'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'long raw')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'long raw')); $this->assertEqual($type, array('type' => array('blob'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'long raw')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'long raw')); $this->assertEqual($type, array('type' => array('blob'), 'length' => null, 'unsigned' => null, 'fixed' => null)); - $type = $this->dataDict->getPortableDeclaration(array('type' => 'raw')); + $type = $this->dataDict->getPortableDeclaration(array('data_type' => 'raw')); $this->assertEqual($type, array('type' => array('blob'), 'length' => null, diff --git a/tests/DoctrineTest/Reporter/Html.php b/tests/DoctrineTest/Reporter/Html.php index 1274fcb76..0f5964b76 100644 --- a/tests/DoctrineTest/Reporter/Html.php +++ b/tests/DoctrineTest/Reporter/Html.php @@ -1,39 +1,83 @@ Doctrine Unit Tests +

-'; + $this->paintSummary(); + $this->paintMessages(); + $this->paintSummary(); + print '
'; + } + + public function paintMessages() + { + print '
'; foreach ($this->_test->getMessages() as $message) { print "

$message

"; } - print ''; - $colour = ($this->_test->getFailCount() > 0 ? 'red' : 'green'); - print '
'; - print $this->_test->getTestCaseCount() . ' test cases.'; + print '
'; + } + + public function paintSummary() + { + $color = ($this->_test->getFailCount() > 0 ? 'red' : 'green'); + print '
'; + print $this->_test->getTestCaseCount() . ' test cases. '; print '' . $this->_test->getPassCount() . ' passes and '; print '' . $this->_test->getFailCount() . ' fails.'; print '
'; } - public function getProgressIndicator(){} + public function getProgressIndicator() {} } diff --git a/tests/Import/SchemaTestCase.php b/tests/Import/SchemaTestCase.php index a47a39bca..4c7abcc47 100644 --- a/tests/Import/SchemaTestCase.php +++ b/tests/Import/SchemaTestCase.php @@ -32,6 +32,9 @@ */ class Doctrine_Import_Schema_TestCase extends Doctrine_UnitTestCase { + public $buildSchema; + public $schema; + public function testYmlImport() { $import = new Doctrine_Import_Schema(); @@ -39,14 +42,65 @@ class Doctrine_Import_Schema_TestCase extends Doctrine_UnitTestCase if ( ! file_exists('classes/User.php')) { $this->fail(); - } else { - unlink('classes/User.php'); } - if ( ! file_exists('classes/Group.php')) { + if ( ! file_exists('classes/Profile.php')) { $this->fail(); + } + } + + public function testBuildSchema() + { + $schema = new Doctrine_Import_Schema(); + $array = $schema->buildSchema('schema.yml', 'yml'); + + $model = $array['User']; + + $this->assertTrue(array_key_exists('connection', $model)); + $this->assertTrue(array_key_exists('className', $model)); + $this->assertTrue(array_key_exists('tableName', $model)); + $this->assertTrue(array_key_exists('columns', $model) && is_array($model['columns'])); + $this->assertTrue(array_key_exists('relations', $model) && is_array($model['relations'])); + $this->assertTrue(array_key_exists('indexes', $model) && is_array($model['indexes'])); + $this->assertTrue(array_key_exists('attributes', $model) && is_array($model['attributes'])); + $this->assertTrue(array_key_exists('templates', $model) && is_array($model['columns'])); + $this->assertTrue(array_key_exists('actAs', $model) && is_array($model['actAs'])); + $this->assertTrue(array_key_exists('options', $model) && is_array($model['options'])); + $this->assertTrue(array_key_exists('package', $model)); + } + + public function testSchemaRelationshipCompletion() + { + $this->buildSchema = new Doctrine_Import_Schema(); + $this->schema = $this->buildSchema->buildSchema('schema.yml', 'yml'); + + foreach ($this->schema as $name => $properties) { + $relations = $this->buildSchema->getRelations($properties); + + foreach ($relations as $alias => $relation) { + if (!$this->_verifyMultiDirectionalRelationship($name, $alias, $relation)) { + $this->fail(); + + return false; + } + } + } + + $this->pass(); + } + + protected function _verifyMultiDirectionalRelationship($class, $relationAlias, $relation) + { + $foreignClass = $relation['class']; + $foreignAlias = isset($relation['foreignAlias']) ? $relation['foreignAlias']:$class; + + $foreignClassRelations = $this->buildSchema->getRelations($this->schema[$foreignClass]); + + // Check to see if the foreign class has the opposite end defined for the class/foreignAlias + if (isset($foreignClassRelations[$foreignAlias])) { + return true; } else { - unlink('classes/Group.php'); + return false; } } } \ No newline at end of file diff --git a/tests/Migration/MysqlTestCase.php b/tests/Migration/MysqlTestCase.php index fcd562094..247be23b6 100644 --- a/tests/Migration/MysqlTestCase.php +++ b/tests/Migration/MysqlTestCase.php @@ -32,15 +32,15 @@ */ class Doctrine_Migration_Mysql_TestCase extends Doctrine_UnitTestCase { - protected $serverExists = false; public function setUp() { parent::setUp(); + try { $dsn = 'mysql://doctrine_tester:d0cTrynR0x!@localhost/doctrine_unit_test'; - $this->conn = $this->manager->openConnection($dsn,'unit_test',true); + $this->conn = $this->manager->openConnection($dsn, 'unit_test', true); $this->conn->connect(); $this->serverExists = true; } catch (Exception $e){ @@ -48,16 +48,14 @@ class Doctrine_Migration_Mysql_TestCase extends Doctrine_UnitTestCase } } - public function testMigration() { - if($this->serverExists){ + if ($this->serverExists){ // Clean up any left over tables from broken test runs. try { - $this->conn->export->dropTable('migration_test'); - $this->conn->export->dropTable('migration_version'); - } catch(Exception $e) { - } + $this->conn->export->dropTable('migration_test'); + $this->conn->export->dropTable('migration_version'); + } catch(Exception $e) { } // New migration for the 'migration_classes' directory $migration = new Doctrine_Migration('mysql_migration_classes'); diff --git a/tests/MigrationTestCase.php b/tests/MigrationTestCase.php index eb9e6cc60..26b6e9704 100644 --- a/tests/MigrationTestCase.php +++ b/tests/MigrationTestCase.php @@ -51,4 +51,4 @@ class Doctrine_Migration_TestCase extends Doctrine_UnitTestCase // Make sure the current version is 0 $this->assertEqual($migration->getCurrentVersion(), 0); } -} +} \ No newline at end of file diff --git a/tests/ParserTestCase.php b/tests/ParserTestCase.php new file mode 100644 index 000000000..8293d9c1c --- /dev/null +++ b/tests/ParserTestCase.php @@ -0,0 +1,99 @@ +. + */ + +/** + * Doctrine_Parser_TestCase + * + * @package Doctrine + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + */ +class Doctrine_Parser_TestCase extends Doctrine_UnitTestCase +{ + public function testGetParserInstance() + { + $instance = Doctrine_Parser::getParser('Yml'); + + if ($instance instanceof Doctrine_Parser_Yml) { + $this->pass(); + } else { + $this->fail(); + } + } + + public function testFacadeLoadAndDump() + { + Doctrine_Parser::dump(array('test' => 'good job', 'test2' => true, array('testing' => false)), 'yml', 'test.yml'); + $array = Doctrine_Parser::load('test.yml', 'yml'); + + $this->assertEqual($array, array('test' => 'good job', 'test2' => true, array('testing' => false))); + } + + public function testParserSupportsEmbeddingPhpSyntax() + { + $parser = Doctrine_Parser::getParser('Yml'); + $yml = "--- +test: good job +test2: true +testing: +w00t: not now +"; + $data = $parser->doLoad($yml); + + $array = $parser->loadData($data); + + $this->assertEqual($array, array('test' => 'good job', 'test2' => true, 'testing' => false, 'w00t' => 'not now')); + } + + public function testParserWritingToDisk() + { + $parser = Doctrine_Parser::getParser('Yml'); + $parser->doDump('test', 'test.yml'); + + $this->assertEqual('test', file_get_contents('test.yml')); + } + + public function testParserReturningLoadedData() + { + $parser = Doctrine_Parser::getParser('Yml'); + $result = $parser->doDump('test'); + + $this->assertEqual('test', $result); + } + + public function testLoadFromString() + { + $yml = "--- +test: good job +test2: true +testing: +w00t: not now +"; + + $array = Doctrine_Parser::load($yml, 'yml'); + + $this->assertEqual($array, array('test' => 'good job', 'test2' => true, 'testing' => false, 'w00t' => 'not now')); + } +} diff --git a/tests/index.php b/tests/index.php new file mode 100755 index 000000000..fd3a33263 --- /dev/null +++ b/tests/index.php @@ -0,0 +1,2 @@ +renameColumn('migration_test','field3','field2'); + { + $this->renameColumn('migration_test','field3','field2'); } -} +} \ No newline at end of file diff --git a/tests/run.php b/tests/run.php index e6391c226..f88e72f06 100644 --- a/tests/run.php +++ b/tests/run.php @@ -263,7 +263,19 @@ $migration->addTestCase(new Doctrine_Migration_Mysql_TestCase()); $test->addTestCase($migration); $test->addTestCase(new Doctrine_Query_ApplyInheritance_TestCase()); -$test->addTestCase(new Doctrine_Import_Schema_TestCase()); -$test->addTestCase(new Doctrine_Export_Schema_TestCase()); -$test->run(); +$parser = new GroupTest('Parser tests', 'parser'); +$parser->addTestCase(new Doctrine_Parser_TestCase()); +$test->addTestCase($parser); + +$schemaFiles = new GroupTest('Schema files', 'schema_files'); +$schemaFiles->addTestCase(new Doctrine_Import_Schema_TestCase()); +$schemaFiles->addTestCase(new Doctrine_Export_Schema_TestCase()); +$test->addTestCase($schemaFiles); + +$data = new GroupTest('Data exporting/importing fixtures', 'data_fixtures'); +$data->addTestCase(new Doctrine_Data_Import_TestCase()); +$data->addTestCase(new Doctrine_Data_Export_TestCase()); +$test->addTestCase($data); + +$test->run(); \ No newline at end of file diff --git a/tests/schema.yml b/tests/schema.yml index 02a946752..375203518 100644 --- a/tests/schema.yml +++ b/tests/schema.yml @@ -1,29 +1,55 @@ --- -User: - tableName: user - className: User - columns: - id: - notnull: true +User: + actAs: [Timestampable] + columns: + id: + type: integer(4) primary: true autoincrement: true - type: integer - length: 4 - name: id - username: - type: string - length: 255 -Group: - tableName: group - className: Group - columns: - id: - notnull: true + username: + type: string(255) + password: + type: string(255) +Profile: + actAs: [Timestampable] + columns: + id: + type: integer(4) primary: true autoincrement: true - type: integer - length: 4 - name: id - name: - type: string - length: 255 \ No newline at end of file + user_id: + type: integer(4) + contact_id: + type: integer(4) + first_name: + type: string(255) + last_name: + type: string(255) + relations: + User: + foreignType: one + Contact: + foreignType: one +Contact: + actAs: [Timestampable] + columns: + id: + type: integer(4) + primary: true + autoincrement: true + name: + type: string(255) +Phonenumber: + actAs: [Timestampable] + columns: + id: + type: integer(4) + primary: true + autoincrement: true + contact_id: + type: integer(4) + phone_number: + type: integer(4) + relations: + Contact: + foreignAlias: Phonenumbers \ No newline at end of file