Spis treści

Baza danych

Wyświetlenie powiązań relacyjnych

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`

Sprawdzenie powiązań relacyjnych

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)){
 ...
}

Sprawdzenie czy rekord można usunąć

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Ń
}

Transakcje

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);
        }
}

Duplikowanie rekordu

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();