Skip to content

Commit

Permalink
Merge pull request #83 from WebFiori/dev
Browse files Browse the repository at this point in the history
Enhancement For Building Relations
  • Loading branch information
usernane authored Nov 14, 2023
2 parents 839c360 + 26b63c1 commit 90171f2
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 50 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
74 changes: 74 additions & 0 deletions webfiori/database/FK.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?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 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';
/**
* Creates new foreign key.
*
* @param string $name The name of the key. It must be a string, and it's not empty.
* Also, it must not contain any spaces or any characters other than A-Z, a-z and
* underscore. The default value is 'key_name'.
*
* @param Table $ownerTable The table that will contain the key.
*
* @param Table $sourceTable The name of the table that contains the
* original values.
*
* @param array $cols An associative array that contains the names of key
* columns. The indices must be columns in the owner table and the values are
* columns in the source table.
*
* @throws DatabaseException If one of the tables of the foreign key is not set.
*/
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
110 changes: 75 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 = $keyProps['name'] ?? '';
$col = $keyProps['col'] ?? '';
$onUpdate = $keyProps['on-update'] ?? FK::SET_NULL;
$onDelete = $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,33 @@ 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;
return $refTable;
}
/**
* Returns a column given its index.
Expand Down Expand Up @@ -378,7 +416,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 +688,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 +782,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
16 changes: 14 additions & 2 deletions webfiori/database/mssql/MSSQLTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public function addColumn(string $key, Column $colObj) : bool {
*/
public function addColumns(array $colsArr) : Table {
$arrToAdd = [];

$fksArr = [];

foreach ($colsArr as $key => $arrOrObj) {
if ($arrOrObj instanceof MSSQLColumn) {
$arrToAdd[$key] = $arrOrObj;
Expand All @@ -109,12 +110,23 @@ public function addColumns(array $colsArr) : Table {

if ($colObj instanceof MSSQLColumn) {
$arrToAdd[$key] = $colObj;

if (isset($arrOrObj['fk'])) {
$fksArr[$key] = $arrOrObj['fk'];

}
}
}
}
}

return parent::addColumns($arrToAdd);
parent::addColumns($arrToAdd);

foreach ($fksArr as $col => $fkArr) {
$this->addReferenceFromArray($col, $fkArr);
}

return $this;
}
/**
* Returns a string which can be used to add table comment as extended
Expand Down
14 changes: 12 additions & 2 deletions webfiori/database/mysql/MySQLTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public function addColumn(string $key, Column $colObj) : bool {
*/
public function addColumns(array $colsArr) : Table {
$arrToAdd = [];

$fksArr = [];

foreach ($colsArr as $key => $arrOrObj) {
if ($arrOrObj instanceof MySQLColumn) {
$arrToAdd[$key] = $arrOrObj;
Expand All @@ -121,12 +122,21 @@ public function addColumns(array $colsArr) : Table {

if ($colObj instanceof MySQLColumn) {
$arrToAdd[$key] = $colObj;
if (isset($colsArr['fk'])) {
$fksArr[$key] = $arrOrObj['fk'];
}
}
}
}
}

return parent::addColumns($arrToAdd);
parent::addColumns($arrToAdd);

foreach ($fksArr as $col => $fkArr) {
$this->addReferenceFromArray($col, $fkArr);
}

return $this;
}
/**
* Returns the character set that is used by the table.
Expand Down

0 comments on commit 90171f2

Please sign in to comment.