Skip to content

Commit

Permalink
Merge pull request #609 from davidgv88/foreignkey_forge
Browse files Browse the repository at this point in the history
Add support for foreign keys to the Forge
  • Loading branch information
lonnieezell authored Oct 12, 2017
2 parents 0364a8a + e50fed0 commit d305d5e
Show file tree
Hide file tree
Showing 9 changed files with 619 additions and 10 deletions.
134 changes: 134 additions & 0 deletions application/Controllers/Checks.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,140 @@ public function index()
{
session()->start();
}

public function forge()
{
echo '<h1>MySQL</h1>';

log_message('debug', 'MYSQL TEST');

$forge_mysql = \Config\Database::forge();

$forge_mysql->getConnection()->query('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;');

$forge_mysql->dropTable('users', true);

$forge_mysql->getConnection()->query('SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;');

$forge_mysql->addField([
'id' => [
'type' => 'INTEGER',
'constraint' => 11
],
'name' => [
'type' => 'VARCHAR',
'constraint' => 50,
]
]);
$forge_mysql->addKey('id', true);
$attributes = array('ENGINE' => 'InnoDB');
$forge_mysql->createTable('users', true, $attributes);

$data_insert = array(
'id' => 1,
'name' => 'User 1',
);
$forge_mysql->getConnection()->table('users')->insert($data_insert);

$drop = $forge_mysql->dropTable('invoices', true);

$forge_mysql->addField([
'id' => [
'type' => 'INTEGER',
'constraint' => 11,
],
'users_id' => [
'type' => 'INTEGER',
'constraint' => 11
],
'other_id' => [
'type' => 'INTEGER',
'constraint' => 11
]
]);
$forge_mysql->addKey('id', true);

$forge_mysql->addForeignKey('users_id','users','id','CASCADE','CASCADE');
$forge_mysql->addForeignKey('other_id','users','id','CASCADE','CASCADE');

$attributes = array('ENGINE' => 'InnoDB');
$res = $forge_mysql->createTable('invoices', true,$attributes);

if(!$res){
var_dump($forge_mysql->getConnection()->mysqli);
}else{
echo '<br><br>OK';

var_dump($forge_mysql->getConnection()->getForeignKeyData('invoices'));
}

$res = $forge_mysql->dropForeignKey('invoices','invoices_other_id_foreign');


echo '<h1>PostgreSQL</h1>';

$forge_pgsql = \Config\Database::forge('pgsql');

$forge_pgsql->dropTable('users',true, true);

$forge_pgsql->addField([
'id' => [
'type' => 'INTEGER',
'constraint' => 11,
'auto_increment' => true,
],
'name' => [
'type' => 'VARCHAR',
'constraint' => 50,
]
]);
$forge_pgsql->addKey('id', true);
$forge_pgsql->createTable('users', true);


$data_insert = array(
'id' => 1,
'name' => 'User 1',
);
$forge_pgsql->getConnection()->table('users')->insert($data_insert);

$forge_pgsql->dropTable('invoices',true);
$forge_pgsql->addField([
'id' => [
'type' => 'INTEGER',
'constraint' => 11,
'auto_increment' => true,
],
'users_id' => [
'type' => 'INTEGER',
'constraint' => 11
],
'other_id' => [
'type' => 'INTEGER',
'constraint' => 11
],
'another_id' => [
'type' => 'INTEGER',
'constraint' => 11
]
]);
$forge_pgsql->addKey('id', true);

$forge_pgsql->addForeignKey('users_id','users','id','CASCADE','CASCADE');
$forge_pgsql->addForeignKey('other_id','users','id');

$res = $forge_pgsql->createTable('invoices', true);

if(!$res){
var_dump($forge_pgsql->getConnection()->mysqli);
}else{
echo '<br><br>OK';
var_dump($forge_pgsql->getConnection()->getForeignKeyData('invoices'));
}

//$res = $forge_pgsql->dropForeignKey('invoices','invoices_other_id_foreign');

}


public function escape()
Expand Down
17 changes: 16 additions & 1 deletion system/Database/BaseConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -1598,7 +1598,7 @@ public function fieldExists($fieldName, $tableName)
*/
public function getFieldData(string $table)
{
$fields = $this->_fieldData($this->protectIdentifiers($table, true, null, false));
$fields = $this->_fieldData($this->protectIdentifiers($table, true, false, false));

return $fields ?? false;
}
Expand All @@ -1618,6 +1618,21 @@ public function getIndexData(string $table)
return $fields ?? false;
}

//--------------------------------------------------------------------

/**
* Returns an object with foreign key data
*
* @param string $table the table name
* @return array
*/
public function getForeignKeyData(string $table)
{
$fields = $this->_foreignKeyData($this->protectIdentifiers($table, true, false, false));

return $fields ?? false;
}

//--------------------------------------------------------------------

/**
Expand Down
114 changes: 108 additions & 6 deletions system/Database/Forge.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ class Forge
* @var array
*/
protected $primaryKeys = [];

/**
* List of foreign keys.
*
* @var type
*/
protected $foreignKeys = [];

/**
* Character set used.
Expand Down Expand Up @@ -330,7 +337,63 @@ public function addField($field)
}

//--------------------------------------------------------------------

/**
* Add Foreign Key
*
* @param array $field
*
* @return \CodeIgniter\Database\Forge
*/
public function addForeignKey($fieldName= '',$tableName = '', $tableField = '', $onUpdate = false, $onDelete = false)
{

if( ! isset($this->fields[$fieldName]))
{
throw new \RuntimeException('Field "'.$fieldName.'" not exist');
}

$this->foreignKeys[$fieldName] = [
'table' => $tableName,
'field' => $tableField,
'onDelete' => $onDelete,
'onUpdate' => $onUpdate
];


return $this;
}

//--------------------------------------------------------------------

/**
* Foreign Key Drop
*
* @param string $table Table name
* @param string $foreign_name Foreign name
*
* @return bool
*/
public function dropForeignKey($table, $foreign_name)
{

$sql = sprintf($this->dropConstraintStr,$this->db->escapeIdentifiers($this->db->DBPrefix.$table),$this->db->escapeIdentifiers($this->db->DBPrefix.$foreign_name));

if ($sql === false)
{
if ($this->db->DBDebug)
{
throw new DatabaseException('This feature is not available for the database you are using.');
}

return false;
}

return $this->db->query($sql);
}

//--------------------------------------------------------------------

/**
* Create Table
*
Expand Down Expand Up @@ -425,8 +488,10 @@ protected function _createTable($table, $if_not_exists, $attributes)
$columns[$i] = ($columns[$i]['_literal'] !== false) ? "\n\t" . $columns[$i]['_literal'] : "\n\t" . $this->_processColumn($columns[$i]);
}

$columns = implode(',', $columns)
. $this->_processPrimaryKeys($table);
$columns = implode(',', $columns);

$columns .= $this->_processPrimaryKeys($table);
$columns .= $this->_processForeignKeys($table);

// Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL)
if ($this->createTableKeys === true)
Expand Down Expand Up @@ -472,11 +537,12 @@ protected function _createTableAttributes($attributes)
*
* @param string $table_name Table name
* @param bool $if_exists Whether to add an IF EXISTS condition
* @param bool $cascade Whether to add an CASCADE condition
*
* @return mixed
* @throws \CodeIgniter\Database\Exceptions\DatabaseException
*/
public function dropTable($table_name, $if_exists = false)
public function dropTable($table_name, $if_exists = false, $cascade = false)
{
if ($table_name === '')
{
Expand All @@ -488,13 +554,14 @@ public function dropTable($table_name, $if_exists = false)
return false;
}


// If the prefix is already starting the table name, remove it...
if (! empty($this->db->DBPrefix) && strpos($table_name, $this->db->DBPrefix) === 0)
{
$table_name = substr($table_name, strlen($this->db->DBPrefix));
}

if (($query = $this->_dropTable($this->db->DBPrefix . $table_name, $if_exists)) === true)
if (($query = $this->_dropTable($this->db->DBPrefix . $table_name, $if_exists, $cascade)) === true)
{
return true;
}
Expand Down Expand Up @@ -523,10 +590,11 @@ public function dropTable($table_name, $if_exists = false)
*
* @param string $table Table name
* @param bool $if_exists Whether to add an IF EXISTS condition
* @param bool $cascade Whether to add an CASCADE condition
*
* @return string
*/
protected function _dropTable($table, $if_exists)
protected function _dropTable($table, $if_exists, $cascade)
{
$sql = 'DROP TABLE';

Expand All @@ -545,7 +613,9 @@ protected function _dropTable($table, $if_exists)
}
}

return $sql . ' ' . $this->db->escapeIdentifiers($table);
$sql = $sql . ' ' . $this->db->escapeIdentifiers($table);

return $sql;
}

//--------------------------------------------------------------------
Expand Down Expand Up @@ -1076,6 +1146,38 @@ protected function _processIndexes($table)
}

//--------------------------------------------------------------------
/**
* Process foreign keys
*
* @param string $table Table name
*
* @return string
*/
protected function _processForeignKeys($table) {
$sql = '';

$allowActions = array('CASCADE','SET NULL','NO ACTION','RESTRICT','SET DEFAULT');

if (count($this->foreignKeys) > 0){
foreach ($this->foreignKeys as $field => $fkey) {
$name_index = $table.'_'.$field.'_foreign';

$sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers($name_index)
. ' FOREIGN KEY(' . $this->db->escapeIdentifiers($field) . ') REFERENCES '.$this->db->escapeIdentifiers($this->db->DBPrefix.$fkey['table']).' ('.$this->db->escapeIdentifiers($fkey['field']).')';

if($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions)){
$sql .= " ON DELETE ".$fkey['onDelete'];
}

if($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions)){
$sql .= " ON UPDATE ".$fkey['onDelete'];
}

}
}

return $sql;
}
//--------------------------------------------------------------------

/**
Expand Down
Loading

0 comments on commit d305d5e

Please sign in to comment.