yii2
164 строки · 6.9 Кб
1<?php
2/**
3* @link https://www.yiiframework.com/
4* @copyright Copyright (c) 2008 Yii Software LLC
5* @license https://www.yiiframework.com/license/
6*/
7
8use yii\base\InvalidConfigException;
9use yii\db\Migration;
10use yii\db\Query;
11use yii\rbac\DbManager;
12
13/**
14* Fix MSSQL trigger.
15*
16* @see https://github.com/yiisoft/yii2/pull/17966
17*
18* @author Aurelien Chretien <chretien.aurelien@gmail.com>
19* @since 2.0.35
20*/
21class m200409_110543_rbac_update_mssql_trigger extends Migration
22{
23/**
24* @throws yii\base\InvalidConfigException
25* @return DbManager
26*/
27protected function getAuthManager()
28{
29$authManager = Yii::$app->getAuthManager();
30if (!$authManager instanceof DbManager) {
31throw new InvalidConfigException('You should configure "authManager" component to use database before executing this migration.');
32}
33
34return $authManager;
35}
36
37protected function findForeignKeyName($table, $column, $referenceTable, $referenceColumn)
38{
39return (new Query())
40->select(['OBJECT_NAME(fkc.constraint_object_id)'])
41->from(['fkc' => 'sys.foreign_key_columns'])
42->innerJoin(['c' => 'sys.columns'], 'fkc.parent_object_id = c.object_id AND fkc.parent_column_id = c.column_id')
43->innerJoin(['r' => 'sys.columns'], 'fkc.referenced_object_id = r.object_id AND fkc.referenced_column_id = r.column_id')
44->andWhere('fkc.parent_object_id=OBJECT_ID(:fkc_parent_object_id)',[':fkc_parent_object_id' => $this->db->schema->getRawTableName($table)])
45->andWhere('fkc.referenced_object_id=OBJECT_ID(:fkc_referenced_object_id)',[':fkc_referenced_object_id' => $this->db->schema->getRawTableName($referenceTable)])
46->andWhere(['c.name' => $column])
47->andWhere(['r.name' => $referenceColumn])
48->scalar($this->db);
49}
50
51/**
52* @return bool
53*/
54protected function isMSSQL()
55{
56return $this->db->driverName === 'mssql' || $this->db->driverName === 'sqlsrv' || $this->db->driverName === 'dblib';
57}
58
59/**
60* {@inheritdoc}
61*/
62public function up()
63{
64if ($this->isMSSQL()) {
65$authManager = $this->getAuthManager();
66$this->db = $authManager->db;
67$schema = $this->db->getSchema()->defaultSchema;
68$triggerSuffix = $this->db->schema->getRawTableName($authManager->itemChildTable);
69
70$this->execute("IF (OBJECT_ID(N'{$schema}.trigger_{$triggerSuffix}') IS NOT NULL) DROP TRIGGER {$schema}.trigger_{$triggerSuffix};");
71$this->execute("IF (OBJECT_ID(N'{$schema}.trigger_auth_item_child') IS NOT NULL) DROP TRIGGER {$schema}.trigger_auth_item_child;");
72
73$this->execute("CREATE TRIGGER {$schema}.trigger_delete_{$triggerSuffix}
74ON {$schema}.{$authManager->itemTable}
75INSTEAD OF DELETE
76AS
77BEGIN
78DELETE FROM {$schema}.{$authManager->itemChildTable} WHERE parent IN (SELECT name FROM deleted) OR child IN (SELECT name FROM deleted);
79DELETE FROM {$schema}.{$authManager->itemTable} WHERE name IN (SELECT name FROM deleted);
80END;"
81);
82
83$foreignKey = $this->findForeignKeyName($authManager->itemChildTable, 'child', $authManager->itemTable, 'name');
84$this->execute("CREATE TRIGGER {$schema}.trigger_update_{$triggerSuffix}
85ON {$schema}.{$authManager->itemTable}
86INSTEAD OF UPDATE
87AS
88DECLARE @old_name NVARCHAR(64) = (SELECT name FROM deleted)
89DECLARE @new_name NVARCHAR(64) = (SELECT name FROM inserted)
90BEGIN
91IF @old_name <> @new_name
92BEGIN
93ALTER TABLE {$authManager->itemChildTable} NOCHECK CONSTRAINT {$foreignKey};
94UPDATE {$authManager->itemChildTable} SET child = @new_name WHERE child = @old_name;
95END
96UPDATE {$authManager->itemTable}
97SET name = (SELECT name FROM inserted),
98type = (SELECT type FROM inserted),
99description = (SELECT description FROM inserted),
100rule_name = (SELECT rule_name FROM inserted),
101data = (SELECT data FROM inserted),
102created_at = (SELECT created_at FROM inserted),
103updated_at = (SELECT updated_at FROM inserted)
104WHERE name IN (SELECT name FROM deleted)
105IF @old_name <> @new_name
106BEGIN
107ALTER TABLE {$authManager->itemChildTable} CHECK CONSTRAINT {$foreignKey};
108END
109END;"
110);
111}
112}
113
114/**
115* {@inheritdoc}
116*/
117public function down()
118{
119if ($this->isMSSQL()) {
120$authManager = $this->getAuthManager();
121$this->db = $authManager->db;
122$schema = $this->db->getSchema()->defaultSchema;
123$triggerSuffix = $this->db->schema->getRawTableName($authManager->itemChildTable);
124
125$this->execute("DROP TRIGGER {$schema}.trigger_update_{$triggerSuffix};");
126$this->execute("DROP TRIGGER {$schema}.trigger_delete_{$triggerSuffix};");
127
128$this->execute("CREATE TRIGGER {$schema}.trigger_auth_item_child
129ON {$schema}.{$authManager->itemTable}
130INSTEAD OF DELETE, UPDATE
131AS
132DECLARE @old_name VARCHAR (64) = (SELECT name FROM deleted)
133DECLARE @new_name VARCHAR (64) = (SELECT name FROM inserted)
134BEGIN
135IF COLUMNS_UPDATED() > 0
136BEGIN
137IF @old_name <> @new_name
138BEGIN
139ALTER TABLE {$authManager->itemChildTable} NOCHECK CONSTRAINT FK__auth_item__child;
140UPDATE {$authManager->itemChildTable} SET child = @new_name WHERE child = @old_name;
141END
142UPDATE {$authManager->itemTable}
143SET name = (SELECT name FROM inserted),
144type = (SELECT type FROM inserted),
145description = (SELECT description FROM inserted),
146rule_name = (SELECT rule_name FROM inserted),
147data = (SELECT data FROM inserted),
148created_at = (SELECT created_at FROM inserted),
149updated_at = (SELECT updated_at FROM inserted)
150WHERE name IN (SELECT name FROM deleted)
151IF @old_name <> @new_name
152BEGIN
153ALTER TABLE {$authManager->itemChildTable} CHECK CONSTRAINT FK__auth_item__child;
154END
155END
156ELSE
157BEGIN
158DELETE FROM {$schema}.{$authManager->itemChildTable} WHERE parent IN (SELECT name FROM deleted) OR child IN (SELECT name FROM deleted);
159DELETE FROM {$schema}.{$authManager->itemTable} WHERE name IN (SELECT name FROM deleted);
160END
161END;");
162}
163}
164}
165