Skip to content

Commit

Permalink
#15426: Added ability to create and drop database views
Browse files Browse the repository at this point in the history
  • Loading branch information
vladis84 authored and samdark committed Jan 19, 2018
1 parent 1bc17a3 commit 8d50844
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 1 deletion.
2 changes: 1 addition & 1 deletion framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Yii Framework 2 Change Log

2.0.14 under development
------------------------

- Enh #15426: Added abilitiy to create and drop database views (igravity, vladis84)
- Enh #10186: Use native `hash_equals` in `yii\base\Security::compareString()` if available, throw exception if non-strings are compared (aotd1, samdark)
- Bug #15122: Fixed `yii\db\Command::getRawSql()` to properly replace expressions (hiscaler, samdark)
- Enh #15496: CSRF token is now regenerated on changing identity (samdark, rhertogh)
Expand Down
30 changes: 30 additions & 0 deletions framework/db/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,36 @@ public function dropCommentFromTable($table)
return $this->setSql($sql);
}

/**
* Creates a SQL View.
*
* @param string $viewName the name of the view to be created.
* @param string|Query $subquery the select statement which defines the view.
* This can be either a string or a [[Query]] object.
* @return $this the command object itself.
* @since 2.0.14
*/
public function createView($viewName, $subquery)
{
$sql = $this->db->getQueryBuilder()->createView($viewName, $subquery);

return $this->setSql($sql)->requireTableSchemaRefresh($viewName);
}

/**
* Drops a SQL View.
*
* @param string $viewName the name of the view to be dropped.
* @return $this the command object itself.
* @since 2.0.14
*/
public function dropView($viewName)
{
$sql = $this->db->getQueryBuilder()->dropView($viewName);

return $this->setSql($sql)->requireTableSchemaRefresh($viewName);
}

/**
* Executes the SQL statement.
* This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs.
Expand Down
37 changes: 37 additions & 0 deletions framework/db/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,43 @@ public function dropCommentFromTable($table)
return 'COMMENT ON TABLE ' . $this->db->quoteTableName($table) . ' IS NULL';
}

/**
* Creates a SQL View.
*
* @param string $viewName the name of the view to be created.
* @param string|Query $subQuery the select statement which defines the view.
* This can be either a string or a [[Query]] object.
* @return string the `CREATE VIEW` SQL statement.
* @since 2.0.14
*/
public function createView($viewName, $subQuery)
{
if ($subQuery instanceof Query) {
list($rawQuery, $params) = $this->build($subQuery);
array_walk(
$params,
function(&$param) {
$param = $this->db->quoteValue($param);
}
);
$subQuery = strtr($rawQuery, $params);
}

return 'CREATE VIEW ' . $this->db->quoteTableName($viewName) . ' AS ' . $subQuery;
}

/**
* Drops a SQL View.
*
* @param string $viewName the name of the view to be dropped.
* @return string the `DROP VIEW` SQL statement.
* @since 2.0.14
*/
public function dropView($viewName)
{
return 'DROP VIEW ' . $this->db->quoteTableName($viewName);
}

/**
* Converts an abstract column type into a physical column type.
*
Expand Down
35 changes: 35 additions & 0 deletions tests/framework/db/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1182,4 +1182,39 @@ public function testRetryHandler()
$this->assertTrue($hitHandler);
$this->assertTrue($hitCatch);
}

public function testCreateView()
{
$db = $this->getConnection();
$subquery = (new \yii\db\Query())
->select('bar')
->from('testCreateViewTable')
->where(['>', 'bar', '5']);
if ($db->getSchema()->getTableSchema('testCreateViewTable')) {
$db->createCommand()->dropTable('testCreateViewTable')->execute();
}
if ($db->getSchema()->getTableSchema('testCreateView') !== null) {
$db->createCommand()->dropView('testCreateView')->execute();
}
$db->createCommand()->createTable('testCreateViewTable', [
'id' => Schema::TYPE_PK,
'bar' => Schema::TYPE_INTEGER,
])->execute();
$db->createCommand()->insert('testCreateViewTable', ['bar' => 1])->execute();
$db->createCommand()->insert('testCreateViewTable', ['bar' => 6])->execute();
$db->createCommand()->createView('testCreateView', $subquery)->execute();
$records = $db->createCommand('SELECT [[bar]] FROM {{testCreateView}};')->queryAll();

$this->assertEquals([['bar' => 6]], $records);
}

public function testDropView()
{
$db = $this->getConnection();
$viewName = 'animal_view'; // since it already exists in the fixtures
$this->assertNotNull($db->getSchema()->getTableSchema($viewName));
$db->createCommand()->dropView($viewName)->execute();

$this->assertNull($db->getSchema()->getTableSchema($viewName));
}
}

0 comments on commit 8d50844

Please sign in to comment.