use information_schema; SELECT `REFERENCED_TABLE_NAME`,`TABLE_NAME`,`DELETE_RULE` FROM `REFERENTIAL_CONSTRAINTS` WHERE `CONSTRAINT_SCHEMA`='nazwa_bazy_danych' ORDER BY `REFERENCED_TABLE_NAME`
Jak sprawdzić czy rekord z danej tabeli o identyfikatorze id jest używany w innych tabelach powiązanych relacyjne.
Mechanizm przydatny w celu ukrycia np. przycisku usuń jeżeli rekord i tak nie będzie mógł być usunięty.
Utworzyłem w common\models klasę o nazwie Pomocnik
<?php namespace common\models; class Pomocnik { public function checkRelation($table_name, $id) { preg_match("/dbname=([^;]*)/", \Yii::$app->db->dsn, $matches); $dbname = $matches[1]; $sql = " SELECT TABLE_NAME, COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = '{$table_name}' AND REFERENCED_COLUMN_NAME = 'id' AND CONSTRAINT_SCHEMA = '{$dbname}'; "; $connection = \Yii::$app->db; $model = $connection->createCommand($sql); $lista = $model->queryAll(); foreach ($lista as $element) { $tabela = $element['TABLE_NAME']; $col = $element['COLUMN_NAME']; $sql1 = "SELECT count(*) as `liczba` FROM {$tabela} WHERE `{$col}` = {$id} "; $model1 = $connection->createCommand($sql1); $tab = $model1->queryOne(); if ($tab['liczba'] > 0) { return false; } } return true; } }
CheckRelation zwraca wartość true jeśli rekord o identyfikatorze id = $model→id nie występuje w tabelach powiązanych z tabelą users
W widoku
if(Pomocnik::checkRelation('users',$model->id)){ ... }
Funkcja sprawdzająca czy istnieją tabele relacyjne używające id usuwanego rekordu i czy reguła klucza obcego jest ustawiona na RESTRICT. Jeśli jest taki przypadek zwraca false w przeciwnym przypadku true.
Przydatne do wyświetlania lub nie przycisku DELETE.
public function checkDelete($table_name, $id) { preg_match("/dbname=([^;]*)/", \Yii::$app->db->dsn, $matches); $dbname = $matches[1]; $sql = " SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = '{$table_name}' AND REFERENCED_COLUMN_NAME = 'id' AND CONSTRAINT_SCHEMA = '{$dbname}'; "; $connection = \Yii::$app->db; $model = $connection->createCommand($sql); $lista = $model->queryAll(); foreach ($lista as $element) { $tabela = $element['TABLE_NAME']; $tabela_ref = $element['REFERENCED_TABLE_NAME']; $col = $element['COLUMN_NAME']; $sql1 = "SELECT count(*) as `liczba` FROM {$tabela} WHERE `{$col}` = {$id} "; $model1 = $connection->createCommand($sql1); $tab = $model1->queryOne(); if ($tab['liczba'] > 0) { $sql2 = " SELECT count(*) as `liczba` FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE TABLE_NAME = '{$tabela}' AND REFERENCED_TABLE_NAME = '{$tabela_ref}' AND DELETE_RULE = 'RESTRICT' AND CONSTRAINT_SCHEMA = '{$dbname}'; "; $model2 = $connection->createCommand($sql2); $tab2 = $model2->queryOne(); if ($tab2['liczba'] > 0) { return false; } } } return true; }
W widoku
if(Pomocnik::checkDelete('users',$model->id)){ przycisk USUŃ }
Podczas zapisywania danych w kilku modelach jednocześnie zależy nam aby zostały zapisane dane we wszystkich modelach albo wcale. Służą do tego transakcje.
W kontrolerze:
use yii\db\Transaction; ... public function actionZapisz(){ ... $transaction = \Yii::$app->db->beginTransaction( Transaction::SERIALIZABLE ); try { ... $model1->save(); ... $model2->save(); $transaction->commit(); } catch (Exception $e) { $transaction->rollBack(); throw new BadRequestHttpException($e->getMessage(), 0, $e); } }
Jak zduplikować rekord zmieniając wartości wybranych atrybutów.
W akcji kontrolera: Tworzymy model istniejącego rekordu
$model = $this->findModel($id);
Modyfikujemy wybrane atrybuty
$model->id = null; // !!! Ważne jeśli id jest PRIMARY i autoincrement $model->data_zakonczenia = null; $model->rozpoczecie = date('Y-m-d'); $model->zakonczony = 0; $model->widoczny = 0;
Ustawiamy parametr informujący, że należy stworzyć nowy rekord
$model->isNewRecord = true;
Zapisujemy model do rekordu
$model->save();