Skip to content

Commit

Permalink
Changed work with foreign key and new unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeysviridenko committed Jul 4, 2017
1 parent e2f24cd commit 27ff006
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 1 deletion.
17 changes: 17 additions & 0 deletions phalcon/db/adapter/pdo/mysql.zep
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use Phalcon\Db\Index;
use Phalcon\Db\Reference;
use Phalcon\Db\IndexInterface;
use Phalcon\Db\Adapter\Pdo as PdoAdapter;
use Phalcon\Application\Exception;
use Phalcon\Db\ReferenceInterface;

/**
* Phalcon\Db\Adapter\Pdo\Mysql
Expand Down Expand Up @@ -382,4 +384,19 @@ class Mysql extends PdoAdapter

return referenceObjects;
}

/**
* Adds a foreign key to a table
*/
public function addForeignKey(string! tableName, string! schemaName, <ReferenceInterface> reference) -> boolean
{
var foreignKeyCheck;

let foreignKeyCheck = this->{"prepare"}(this->_dialect->getForeignKeyChecks());
if !foreignKeyCheck->execute() {
throw new Exception("DATABASE PARAMETER 'FOREIGN_KEY_CHECKS' HAS TO BE 1");
}

return this->{"execute"}(this->_dialect->addForeignKey(tableName, schemaName, reference));
}
}
18 changes: 17 additions & 1 deletion phalcon/db/dialect/mysql.zep
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,11 @@ class Mysql extends Dialect
{
var sql, onDelete, onUpdate;

let sql = "ALTER TABLE " . this->prepareTable(tableName, schemaName) . " ADD FOREIGN KEY `" . reference->getName() . "`(" . this->getColumnList(reference->getColumns()) . ") REFERENCES " . this->prepareTable(reference->getReferencedTable(), reference->getReferencedSchema()) . "(" . this->getColumnList(reference->getReferencedColumns()) . ")";
let sql = "ALTER TABLE " . this->prepareTable(tableName, schemaName) . " ADD";
if reference->getName() {
let sql .= " CONSTRAINT `" . $reference->getName() . "`";
}
let sql = " FOREIGN KEY (" . this->getColumnList(reference->getColumns()) . ") REFERENCES " . this->prepareTable(reference->getReferencedTable(), reference->getReferencedSchema()) . "(" . this->getColumnList(reference->getReferencedColumns()) . ")";

let onDelete = reference->getOnDelete();
if !empty onDelete {
Expand Down Expand Up @@ -719,4 +723,16 @@ class Mysql extends Dialect

return "";
}

/**
* Generates SQL to check DB parameter FOREIGN_KEY_CHECKS.
*/
public function getForeignKeyChecks() -> string
{
var sql;

let sql = "SELECT @@foreign_key_checks";

return sql;
}
}
21 changes: 21 additions & 0 deletions tests/_data/schemas/mysql/phalcon_test.sql
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,27 @@ ALTER TABLE `stock`
ALTER TABLE `stock`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;

--
-- Table for testing foreign key
--
DROP TABLE IF EXISTS `foreign_key_parent`;
CREATE TABLE `foreign_key_parent` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL,
`refer_int` INT(10) NOT NULL,
PRIMARY KEY (`id`),
KEY (`refer_int`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `foreign_key_child`;
CREATE TABLE `foreign_key_child` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL,
`child_int` INT(10) NOT NULL,
PRIMARY KEY (`id`),
KEY (`child_int`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
Expand Down
38 changes: 38 additions & 0 deletions tests/_support/Helper/Dialect/MysqlTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,44 @@ protected function getAddForeignKey()
];
}

protected function addForeignKey($foreignKeyName = '', $onUpdate = '', $onDelete = '')
{
$sql = 'ALTER TABLE `foreign_key_child` ADD';
if ($foreignKeyName) {
$sql .= ' CONSTRAINT `' . $foreignKeyName . '`';
}
$sql .= ' FOREIGN KEY (`child_int`) REFERENCES `foreign_key_parent`(`refer_int`)';

if ($onDelete) {
$sql .= ' ON DELETE ' . $onDelete;
}
if ($onUpdate) {
$sql .= ' ON UPDATE ' . $onUpdate;
}

return $sql;
}

protected function getForeignKey($foreignKeyName)
{
$sql = "SELECT
COUNT(`CONSTRAINT_NAME`)
FROM information_schema.REFERENTIAL_CONSTRAINTS
WHERE TABLE_NAME = 'foreign_key_child' AND
`UPDATE_RULE` = 'CASCADE' AND
`DELETE_RULE` = 'RESTRICT' AND
`CONSTRAINT_NAME` = '$foreignKeyName'";

return $sql;
}

protected function dropForeignKey($foreignKeyName)
{
$sql = "ALTER TABLE `foreign_key_child` DROP FOREIGN KEY $foreignKeyName";

return $sql;
}

protected function getDropForeignKey()
{
return [
Expand Down
77 changes: 77 additions & 0 deletions tests/unit/Db/Adapter/Pdo/MysqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Phalcon\Db\Reference;
use Phalcon\Test\Module\UnitTest;
use Phalcon\Db\Adapter\Pdo\Mysql;
use Helper\Dialect\MysqlTrait;

/**
* \Phalcon\Test\Unit\Db\Adapter\Pdo\MysqlTest
Expand All @@ -26,6 +27,8 @@
*/
class MysqlTest extends UnitTest
{
use MysqlTrait;

/**
* @var Mysql
*/
Expand Down Expand Up @@ -65,6 +68,8 @@ function () {
'artists',
'childs',
'customers',
'foreign_key_child',
'foreign_key_parent',
'issue12071_body',
'issue12071_head',
'issue_11036',
Expand Down Expand Up @@ -156,4 +161,76 @@ function ($identifier, $expected) {
]
);
}

/**
* Tests Mysql::addForeignKey
*
* @test
* @issue 556
* @author Sergii Svyrydenko <sergey.v.sviridenko@gmail.com>
* @since 2017-07-03
*/
public function shouldAddForeignKey()
{
$this->specify(
"Foreign key hasn't created",
function ($sql, $expected) {
expect($this->connection->execute($sql))->equals($expected);
},
[
'examples' => [
[$this->addForeignKey('test_name_key', 'CASCADE', 'RESTRICT'), true],
[$this->addForeignKey('', 'CASCADE', 'RESTRICT'), true]
]
]
);
}

/**
* Tests Mysql::getForeignKey
*
* @test
* @issue 556
* @author Sergii Svyrydenko <sergey.v.sviridenko@gmail.com>
* @since 2017-07-03
*/
public function shouldCheckAddedForeignKey()
{
$this->specify(
"Foreign key isn't created",
function ($sql, $expected) {
expect($this->connection->execute($sql, ['MYSQL_ATTR_USE_BUFFERED_QUERY']))->equals($expected);
},
[
'examples' => [
[$this->getForeignKey('test_name_key'), true],
[$this->getForeignKey('foreign_key_child_ibfk_1'), true]
]
]
);
}

/**
* Tests Mysql::dropAddForeignKey
*
* @test
* @issue 556
* @author Sergii Svyrydenko <sergey.v.sviridenko@gmail.com>
* @since 2017-07-03
*/
public function shouldDropForeignKey()
{
$this->specify(
"Foreign key can't be created",
function ($sql, $expected) {
expect($this->connection->execute($sql))->equals($expected);
},
[
'examples' => [
[$this->dropForeignKey('test_name_key'), true],
[$this->dropForeignKey('foreign_key_child_ibfk_1'), true]
]
]
);
}
}

0 comments on commit 27ff006

Please sign in to comment.