Skip to content

Commit

Permalink
Enhancement For Building Relations
Browse files Browse the repository at this point in the history
closes #81
  • Loading branch information
usernane committed Nov 14, 2023
1 parent fc6b2a5 commit 4bbafdd
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 46 deletions.
15 changes: 9 additions & 6 deletions samples/createDatabase/UserBookmarksTable.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php


use webfiori\database\FK;
use webfiori\database\mysql\MySQLTable;

class UserBookmarksTable extends MySQLTable {
Expand All @@ -27,12 +27,15 @@ public function __construct() {
],
'user_id' => [
'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');
}
}
10 changes: 6 additions & 4 deletions tests/webfiori/database/tests/mssql/MSSQLTableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
56 changes: 56 additions & 0 deletions webfiori/database/FK.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
/**
* This file is licensed under MIT License.
*
* Copyright (c) 2023 Ibrahim BinAlshikh
*
* For more information on the license, please visit:
* https://github.com/WebFiori/.github/blob/main/LICENSE
*
*/
namespace webfiori\database;

/**
* A class that represents a foreign key.
*
* A foreign key must have an owner table and a source table. The
* source table will contain original values and the owner is simply the table
* that own the key.
*
* @author Ibrahim
*/
class FK extends webfiori\database\ForeignKey {
/**
* An action that can be performed on update or delete.
*
* @var string
*/
const SET_NULL = 'set null';
/**
* An action that can be performed on update or delete.
*
* @var string
*/
const SET_DEFAULT = 'set default';
/**
* An action that can be performed on update or delete.
*
* @var string
*/
const NO_ACTION = 'no action';
/**
* An action that can be performed on update or delete.
*
* @var string
*/
const CASCADE = 'cascade';
/**
* An action that can be performed on update or delete.
*
* @var string
*/
const RESTRICT = 'restrict';
public function __construct(string $name = 'key_name', Table $ownerTable = null, Table $sourceTable = null, array $cols = []) {
parent::__construct($name, $ownerTable, $sourceTable, $cols);
}
}
2 changes: 1 addition & 1 deletion webfiori/database/ForeignKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*
* @author Ibrahim
*
* @version 1.0
* @deprecated Use the class FK.
*/
class ForeignKey {
/**
Expand Down
109 changes: 74 additions & 35 deletions webfiori/database/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,41 @@ public function addColumns(array $cols) : Table {

return $this;
}
/**
* Adds a single-column foreign key to the table.
*
* @param string $colName The name of the column that will reference the other table.
*
* @param array $keyProps An array that will hold key properties. The array should
* have following indices:
* <ul>
* <li><b>table</b>: 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'.</li>
* <li><b>col</b>: The name of the column that will be referenced.</li>
* <li><b>name</b>: The name of the key.</li>
* <li><b>on-update</b> [Optional] The 'on update' condition for the key.
* Default value is 'set null'.</li>
* <li><b>on-delete</b> [Optional] The 'on delete' condition for the key.
* Default value is 'set null'.</li>
* @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.
*
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.'\'.');
}
}

Expand Down
4 changes: 4 additions & 0 deletions webfiori/database/mssql/MSSQLTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']);
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions webfiori/database/mysql/MySQLTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']);
}
}
}
}
Expand Down

0 comments on commit 4bbafdd

Please sign in to comment.