From 4bbafdd181af7b5be314edca4551f518edf9e5e8 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Tue, 14 Nov 2023 18:14:05 +0300 Subject: [PATCH] Enhancement For Building Relations closes #81 --- samples/createDatabase/UserBookmarksTable.php | 15 ++- .../database/tests/mssql/MSSQLTableTest.php | 10 +- webfiori/database/FK.php | 56 +++++++++ webfiori/database/ForeignKey.php | 2 +- webfiori/database/Table.php | 109 ++++++++++++------ webfiori/database/mssql/MSSQLTable.php | 4 + webfiori/database/mysql/MySQLTable.php | 3 + 7 files changed, 153 insertions(+), 46 deletions(-) create mode 100644 webfiori/database/FK.php diff --git a/samples/createDatabase/UserBookmarksTable.php b/samples/createDatabase/UserBookmarksTable.php index 71c3dc7..0c04b15 100644 --- a/samples/createDatabase/UserBookmarksTable.php +++ b/samples/createDatabase/UserBookmarksTable.php @@ -1,6 +1,6 @@ [ 'type' => 'int', - 'size' => 5 + 'size' => 5, + 'fk' => [ + 'table' => UserInformation::class, + 'name' => 'user_id_fk', + 'col' => 'id', + 'on-update' => FK::CASCADE, + 'on-delete' => FK::RESTRICT + ] ], ]); - - $this->addReference(UserInformationTable::class, [ - 'user-id' => 'id' - ], 'user_id_fk', 'cascade', 'restrict'); } } diff --git a/tests/webfiori/database/tests/mssql/MSSQLTableTest.php b/tests/webfiori/database/tests/mssql/MSSQLTableTest.php index 5240370..a067c2e 100644 --- a/tests/webfiori/database/tests/mssql/MSSQLTableTest.php +++ b/tests/webfiori/database/tests/mssql/MSSQLTableTest.php @@ -227,12 +227,14 @@ public function testFk3() { 'size' => 128 ], 'added-by' => [ - 'type' => 'int' + 'type' => 'int', + 'fk' => [ + 'table' => $t1, + 'col' => 'id', + 'name' => 'added_by_fk' + ] ] ]); - $t2->addReference($t1, [ - 'added-by' => 'id' - ], 'added_by_fk'); $this->assertEquals("if not exists (select * from sysobjects where name='locations' and xtype='U')\n" . "create table [locations] (\n" . " [id] [int] not null,\n" diff --git a/webfiori/database/FK.php b/webfiori/database/FK.php new file mode 100644 index 0000000..c2ddd51 --- /dev/null +++ b/webfiori/database/FK.php @@ -0,0 +1,56 @@ + + *
  • table: It is the table that + * will contain original values. This value can be an object of type + * 'Table', an object of type 'AbstractQuery' or the namespace of a class which is a subclass of + * the class 'AbstractQuery' or the class 'Table'.
  • + *
  • col: The name of the column that will be referenced.
  • + *
  • name: The name of the key.
  • + *
  • on-update [Optional] The 'on update' condition for the key. + * Default value is 'set null'.
  • + *
  • on-delete [Optional] The 'on delete' condition for the key. + * Default value is 'set null'.
  • + * @return Table The method will return the instance at which the method + * is called on. + * + * @throws DatabaseException + */ + public function addReferenceFromArray(string $colName, array $keyProps) : Table { + if (!isset($keyProps['table'])) { + return $this; + } + $table = $this->getRefTable($keyProps['table']); + $keyName = isset($keyProps['name']) ?? ''; + $col = isset($keyProps['col']); + $onUpdate = isset($keyProps['on-update']) ?? FK::SET_NULL; + $onDelete = isset($keyProps['on-delete']) ?? FK::SET_NULL; + + return $this->addReference($table, [$colName => $col], $keyName, $onUpdate, $onDelete); + } /** * Adds a foreign key to the table. * @@ -188,30 +223,32 @@ public function addColumns(array $cols) : Table { * @throws DatabaseException * @since 1.0 */ - public function addReference($refTable, array $cols, string $keyName, string $onUpdate = 'set null', string $onDelete = 'set null') : Table { + public function addReference($refTable, array $cols, string $keyName, string $onUpdate = FK::SET_NULL, string $onDelete = FK::SET_NULL) : Table { + + $this->createFk($this->getRefTable($refTable), $cols, $keyName, $onUpdate, $onDelete); + + return $this; + } + private function getRefTable($refTable) { if (!($refTable instanceof Table)) { if ($refTable instanceof AbstractQuery) { - $refTable = $refTable->getTable(); + return $refTable->getTable(); } else if (class_exists($refTable)) { $q = new $refTable(); if ($q instanceof AbstractQuery) { - $refTable = $q->getTable(); + return $q->getTable(); } else if ($q instanceof Table) { - $refTable = $q; + return $q; } } else { $owner = $this->getOwner(); if ($owner !== null) { - $refTable = $owner->getTable($refTable); + return $owner->getTable($refTable); } } } - - $this->createFk($refTable, $cols, $keyName, $onUpdate, $onDelete); - - return $this; } /** * Returns a column given its index. @@ -378,7 +415,7 @@ public function getEntityMapper() : EntityMapper { * @param string $keyName The name of the foreign key as specified when it * was added to the table. * - * @return ForeignKey|null If a key with the given name exist, the method + * @return FK|null If a key with the given name exist, the method * will return an object that represent it. Other than that, the method will * return null. * @@ -650,7 +687,7 @@ public function removeColByKey(string $colKey) { * * @param string $keyName The name of the foreign key. * - * @return ForeignKey|null If the key was removed, the method will return the + * @return FK|null If the key was removed, the method will return the * removed key as an object. If nothing changed, the method will return null. * * @since 1.0 @@ -744,36 +781,38 @@ public function setWithDbPrefix(bool $withDbPrefix) { public abstract function toSQL(); /** + * + * @param \webfiori\database\Table $refTable + * @param type $cols + * @param type $keyName + * @param type $onUpdate + * @param type $onDelete * @throws DatabaseException */ - private function createFk($refTable, $cols, $keyName, $onUpdate, $onDelete) { - if ($refTable instanceof Table) { - $fk = new ForeignKey(); - $fk->setOwner($this); - $fk->setSource($refTable); - - if ($fk->setKeyName($keyName) === true) { - foreach ($cols as $target => $source) { - if (gettype($target) == 'integer') { - //indexed array. - //It means source and target columns have same name. - $fk->addReference($source, $source); - } else { - //Associative. Probably two columns with different names. - $fk->addReference($target, $source); - } + private function createFk(Table $refTable, $cols, $keyName, $onUpdate, $onDelete) { + $fk = new FK(); + $fk->setOwner($this); + $fk->setSource($refTable); + + if ($fk->setKeyName($keyName) === true) { + foreach ($cols as $target => $source) { + if (gettype($target) == 'integer') { + //indexed array. + //It means source and target columns have same name. + $fk->addReference($source, $source); + } else { + //Associative. Probably two columns with different names. + $fk->addReference($target, $source); } + } - if (count($fk->getSourceCols()) != 0) { - $fk->setOnUpdate($onUpdate); - $fk->setOnDelete($onDelete); - $this->foreignKeys[] = $fk; - } - } else { - throw new DatabaseException('Invalid FK name: \''.$keyName.'\'.'); + if (count($fk->getSourceCols()) != 0) { + $fk->setOnUpdate($onUpdate); + $fk->setOnDelete($onDelete); + $this->foreignKeys[] = $fk; } } else { - throw new DatabaseException('Referenced table is not an instance of the class \'Table\'.'); + throw new DatabaseException('Invalid Foreign Key name: \''.$keyName.'\'.'); } } diff --git a/webfiori/database/mssql/MSSQLTable.php b/webfiori/database/mssql/MSSQLTable.php index ae49fb5..b8c4a5d 100644 --- a/webfiori/database/mssql/MSSQLTable.php +++ b/webfiori/database/mssql/MSSQLTable.php @@ -109,6 +109,10 @@ public function addColumns(array $colsArr) : Table { if ($colObj instanceof MSSQLColumn) { $arrToAdd[$key] = $colObj; + + if (isset($arrOrObj['fk'])) { + $this->addReferenceFromArray($key, $arrOrObj['fk']); + } } } } diff --git a/webfiori/database/mysql/MySQLTable.php b/webfiori/database/mysql/MySQLTable.php index 44daf21..bf7bf84 100644 --- a/webfiori/database/mysql/MySQLTable.php +++ b/webfiori/database/mysql/MySQLTable.php @@ -121,6 +121,9 @@ public function addColumns(array $colsArr) : Table { if ($colObj instanceof MySQLColumn) { $arrToAdd[$key] = $colObj; + if (isset($colsArr['fk'])) { + $this->addReferenceFromArray($key, $arrOrObj['fk']); + } } } }