m140506_102106_rbac_init.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. use yii\base\InvalidConfigException;
  8. use yii\rbac\DbManager;
  9. /**
  10. * Initializes RBAC tables.
  11. *
  12. * @author Alexander Kochetov <creocoder@gmail.com>
  13. * @since 2.0
  14. */
  15. class m140506_102106_rbac_init extends \yii\db\Migration
  16. {
  17. /**
  18. * @throws yii\base\InvalidConfigException
  19. * @return DbManager
  20. */
  21. protected function getAuthManager()
  22. {
  23. $authManager = Yii::$app->getAuthManager();
  24. if (!$authManager instanceof DbManager) {
  25. throw new InvalidConfigException('You should configure "authManager" component to use database before executing this migration.');
  26. }
  27. return $authManager;
  28. }
  29. /**
  30. * @return bool
  31. */
  32. protected function isMSSQL()
  33. {
  34. return $this->db->driverName === 'mssql' || $this->db->driverName === 'sqlsrv' || $this->db->driverName === 'dblib';
  35. }
  36. protected function isOracle()
  37. {
  38. return $this->db->driverName === 'oci';
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. public function up()
  44. {
  45. $authManager = $this->getAuthManager();
  46. $this->db = $authManager->db;
  47. $tableOptions = null;
  48. if ($this->db->driverName === 'mysql') {
  49. // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
  50. $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
  51. }
  52. $this->createTable($authManager->ruleTable, [
  53. 'name' => $this->string(64)->notNull(),
  54. 'data' => $this->binary(),
  55. 'created_at' => $this->integer(),
  56. 'updated_at' => $this->integer(),
  57. 'PRIMARY KEY ([[name]])',
  58. ], $tableOptions);
  59. $this->createTable($authManager->itemTable, [
  60. 'name' => $this->string(64)->notNull(),
  61. 'type' => $this->smallInteger()->notNull(),
  62. 'description' => $this->text(),
  63. 'rule_name' => $this->string(64),
  64. 'data' => $this->binary(),
  65. 'created_at' => $this->integer(),
  66. 'updated_at' => $this->integer(),
  67. 'PRIMARY KEY ([[name]])',
  68. 'FOREIGN KEY ([[rule_name]]) REFERENCES ' . $authManager->ruleTable . ' ([[name]])' .
  69. $this->buildFkClause('ON DELETE SET NULL', 'ON UPDATE CASCADE'),
  70. ], $tableOptions);
  71. $this->createIndex('idx-auth_item-type', $authManager->itemTable, 'type');
  72. $this->createTable($authManager->itemChildTable, [
  73. 'parent' => $this->string(64)->notNull(),
  74. 'child' => $this->string(64)->notNull(),
  75. 'PRIMARY KEY ([[parent]], [[child]])',
  76. 'FOREIGN KEY ([[parent]]) REFERENCES ' . $authManager->itemTable . ' ([[name]])' .
  77. $this->buildFkClause('ON DELETE CASCADE', 'ON UPDATE CASCADE'),
  78. 'FOREIGN KEY ([[child]]) REFERENCES ' . $authManager->itemTable . ' ([[name]])' .
  79. $this->buildFkClause('ON DELETE CASCADE', 'ON UPDATE CASCADE'),
  80. ], $tableOptions);
  81. $this->createTable($authManager->assignmentTable, [
  82. 'item_name' => $this->string(64)->notNull(),
  83. 'user_id' => $this->string(64)->notNull(),
  84. 'created_at' => $this->integer(),
  85. 'PRIMARY KEY ([[item_name]], [[user_id]])',
  86. 'FOREIGN KEY ([[item_name]]) REFERENCES ' . $authManager->itemTable . ' ([[name]])' .
  87. $this->buildFkClause('ON DELETE CASCADE', 'ON UPDATE CASCADE'),
  88. ], $tableOptions);
  89. if ($this->isMSSQL()) {
  90. $this->execute("CREATE TRIGGER dbo.trigger_auth_item_child
  91. ON dbo.{$authManager->itemTable}
  92. INSTEAD OF DELETE, UPDATE
  93. AS
  94. DECLARE @old_name VARCHAR (64) = (SELECT name FROM deleted)
  95. DECLARE @new_name VARCHAR (64) = (SELECT name FROM inserted)
  96. BEGIN
  97. IF COLUMNS_UPDATED() > 0
  98. BEGIN
  99. IF @old_name <> @new_name
  100. BEGIN
  101. ALTER TABLE {$authManager->itemChildTable} NOCHECK CONSTRAINT FK__auth_item__child;
  102. UPDATE {$authManager->itemChildTable} SET child = @new_name WHERE child = @old_name;
  103. END
  104. UPDATE {$authManager->itemTable}
  105. SET name = (SELECT name FROM inserted),
  106. type = (SELECT type FROM inserted),
  107. description = (SELECT description FROM inserted),
  108. rule_name = (SELECT rule_name FROM inserted),
  109. data = (SELECT data FROM inserted),
  110. created_at = (SELECT created_at FROM inserted),
  111. updated_at = (SELECT updated_at FROM inserted)
  112. WHERE name IN (SELECT name FROM deleted)
  113. IF @old_name <> @new_name
  114. BEGIN
  115. ALTER TABLE {$authManager->itemChildTable} CHECK CONSTRAINT FK__auth_item__child;
  116. END
  117. END
  118. ELSE
  119. BEGIN
  120. DELETE FROM dbo.{$authManager->itemChildTable} WHERE parent IN (SELECT name FROM deleted) OR child IN (SELECT name FROM deleted);
  121. DELETE FROM dbo.{$authManager->itemTable} WHERE name IN (SELECT name FROM deleted);
  122. END
  123. END;");
  124. }
  125. }
  126. /**
  127. * {@inheritdoc}
  128. */
  129. public function down()
  130. {
  131. $authManager = $this->getAuthManager();
  132. $this->db = $authManager->db;
  133. if ($this->isMSSQL()) {
  134. $this->execute('DROP TRIGGER dbo.trigger_auth_item_child;');
  135. }
  136. $this->dropTable($authManager->assignmentTable);
  137. $this->dropTable($authManager->itemChildTable);
  138. $this->dropTable($authManager->itemTable);
  139. $this->dropTable($authManager->ruleTable);
  140. }
  141. protected function buildFkClause($delete = '', $update = '')
  142. {
  143. if ($this->isMSSQL()) {
  144. return '';
  145. }
  146. if ($this->isOracle()) {
  147. return ' ' . $delete;
  148. }
  149. return implode(' ', ['', $delete, $update]);
  150. }
  151. }