Advertisement
  1. Code
  2. Yii

Pemrograman Dengan Yii2: Perilaku Blameable

Scroll to top
Read Time: 10 min
This post is part of a series called How to Program With Yii2.
How to Program With Yii2: Working With Asset Bundles
How to Program With Yii2: Timestamp Behavior

Indonesian (Bahasa Indonesia) translation by Bagus Dwi (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Jika Anda bertanya, "Apa itu Yii?" lihat tutorial saya sebelumnya: Pengantar Kerangka Yii, yang mengulas manfaat Yii dan menyertakan ikhtisar tentang apa yang baru di Yii 2.0, dirilis pada Oktober 2014.

Dalam seri Programming With Yii2 ini, saya membimbing pembaca untuk menggunakan Framework Yii2 yang baru ditingkatkan untuk PHP. Dalam tutorial ini, saya akan memandu Anda melalui satu lagi perilaku menarik Yii2: membantu mengotomatiskan tugas pengembangan web umum penetapan yang dibuat oleh dan diperbarui oleh user_id di seluruh model di aplikasi web Anda menggunakan pengodean DRY dan Yii2 BlameableBehavior. Kami juga akan membuat log yang mencatat siapa yang memperbarui tabel Status untuk setiap perubahan yang dibuat.

Untuk contoh ini, kami akan terus membayangkan kami sedang membangun kerangka kerja untuk memposting pembaruan status sederhana, mis. mini-Twitter kami sendiri.

Sekadar mengingatkan, saya berpartisipasi dalam rangkaian komentar di bawah ini. Saya terutama tertarik jika Anda memiliki pendekatan yang berbeda, ide tambahan, atau ingin menyarankan topik untuk tutorial selanjutnya.

Apa itu Perilaku?

Perilaku Yii2 pada dasarnya adalah mixin. Wikipedia menggambarkan mixins sebagai "kelas yang berisi kombinasi metode dari kelas lain. Bagaimana kombinasi semacam itu dilakukan tergantung pada bahasa, tetapi tidak dengan pewarisan. "

Yii menggambarkan mereka seperti ini:

Melampirkan perilaku ke komponen "menyuntikkan" metode dan properti perilaku ke dalam komponen, membuat metode dan properti tersebut dapat diakses seolah-olah mereka didefinisikan dalam kelas komponen itu sendiri.

Yii2 menawarkan beberapa perilaku built-in, yang sebagian besar akan kita dokumentasikan, termasuk sluggable (lihat Pemrograman Dengan Yii2: Perilaku yang Dapat Di-Sluggable), dapat disalahkan, dan stempel waktu (mendatang, periksa halaman seri). Perilaku adalah cara mudah untuk menggunakan kembali kode umum di banyak model data Anda tanpa harus mengulang kode di banyak tempat. Menyuntikkan perilaku ke dalam suatu model seringkali dapat dilakukan hanya dengan dua baris kode. Karena jumlah model dalam aplikasi Anda meningkat, perilaku menjadi semakin berguna.

Apa Perilaku Blameable?

Blameable memudahkan kita untuk mengimplementasikan tugas yang sering dibutuhkan dalam menetapkan pengguna saat ini yang sudah login untuk menyisipkan dan memperbarui dalam model ActiveRecord, secara otomatis mengatur properti untuk created_by dan updated_by.

Dalam Pemrograman Dengan Yii2: Otorisasi Dengan Access Control Filter, kami mengimplementasikan perilaku kami yang dapat disalahkan dalam dua bagian. Pertama, kami membuat migrasi untuk menambahkan bidang created_by ke tabel Status kami:

1
<?php
2
3
use yii\db\Schema;
4
use yii\db\Migration;
5
6
class m150128_003709_extend_status_table_for_created_by extends Migration
7
{
8
    public function up()
9
    {
10
      $tableOptions = null;
11
      if ($this->db->driverName === 'mysql') {
12
          $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
13
      }
14
      $this->addColumn('{{%status}}','created_by',Schema::TYPE_INTEGER.' NOT NULL');
15
      $this->addForeignKey('fk_status_created_by', '{{%status}}', 'created_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     
16
    }

Kedua, kami menetapkan bidang created_by ke user_id saat ini dalam tindakan membuat StatusController:

1
public function actionCreate()
2
    {
3
        $model = new Status();
4
5
        if ($model->load(Yii::$app->request->post())) {
6
          $model->created_by = Yii::$app->user->getId();

Menerapkan perilaku Blameable akan melakukan ini secara otomatis untuk kami dan dapat dengan mudah ditambahkan ke semua model ActiveRecord dalam aplikasi web.

Menerapkan Perilaku Blameable di Model Status

Memperluas Tabel Status

Pertama, kita perlu memperpanjang tabel Status dengan migrasi sekali lagi untuk mendukung bidang updated_by.

1
Jeff$ ./yii migrate/create extend_status_table_for_updated_by
2
Yii Migration Tool (based on Yii v2.0.2)
3
4
Create new migration '/Users/Jeff/Sites/hello/migrations/m150209_200619_extend_status_table_for_updated_by.php'? (yes|no) [no]:yes
5
New migration created successfully.

Ini kode migrasi yang akan kita gunakan:

1
<?php
2
3
use yii\db\Schema;
4
use yii\db\Migration;
5
6
class m150209_200619_extend_status_table_for_updated_by extends Migration
7
{
8
    public function up()
9
    {
10
      $tableOptions = null;
11
      if ($this->db->driverName === 'mysql') {
12
          $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
13
      }
14
      $this->addColumn('{{%status}}','updated_by',Schema::TYPE_INTEGER.' NOT NULL');
15
      $this->addForeignKey('fk_status_updated_by', '{{%status}}', 'updated_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     
16
    }
17
18
    public function down()
19
    {
20
      $this->dropForeignKey('fk_status_updated_by','{{%status}}');
21
      $this->dropColumn('{{%status}}','updated_by');
22
    }
23
}

Jika Anda mencoba menjalankan migrasi ini dengan data yang ada di database Anda, Anda akan mendapatkan kesalahan saat mencoba membuat indeks kunci asing, karena updated_by adalah 0 dan tidak ada di tabel pengguna.

1
hello Jeff$ ./yii migrate/up
2
Yii Migration Tool (based on Yii v2.0.2)
3
4
Total 1 new migration to be applied:
5
    m150209_200619_extend_status_table_for_updated_by
6
7
Apply the above migration? (yes|no) [no]:yes
8
*** applying m150209_200619_extend_status_table_for_updated_by
9
    > add column updated_by integer NOT NULL to table {{%status}} ... done (time: 0.042s)
10
    > add foreign key fk_status_updated_by: {{%status}} (updated_by) references {{%user}} (id) ...Exception 'yii\db\IntegrityException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`hello`.`#sql-22f_1d0`, CONSTRAINT `fk_status_updated_by` FOREIGN KEY (`updated_by`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)

11
The SQL being executed was: ALTER TABLE `status` ADD CONSTRAINT `fk_status_updated_by` FOREIGN KEY (`updated_by`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'
12
13
in /Users/Jeff/Sites/hello/vendor/yiisoft/yii2/db/Schema.php:532
14
15
Error Info:
16
Array
17
(
18
    [0] => 23000
19
    [1] => 1452
20
    [2] => Cannot add or update a child row: a foreign key constraint fails (`hello`.`#sql-22f_1d0`, CONSTRAINT `fk_status_updated_by` FOREIGN KEY (`updated_by`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)

21
)

Kita bisa mengatasi ini dengan memperbarui data secara manual dalam migrasi dan kemudian menambahkan kunci asing. Namun, karena ini adalah platform pengujian, paling mudah hanya bermigrasi ke tiga langkah — menjatuhkan tabel Status dan data pengujiannya — lalu bermigrasi lagi:

1
hello Jeff$ ./yii migrate/down 3
2
Yii Migration Tool (based on Yii v2.0.2)
3
4
Total 3 migrations to be reverted:
5
    m150128_233458_extend_status_table_for_slugs
6
  m150128_003709_extend_status_table_for_created_by
7
	m141201_013120_create_status_table
8
9
Revert the above migrations? (yes|no) [no]:yes
10
*** reverting m150128_233458_extend_status_table_for_slugs
11
    > drop column slug from table {{%status}} ... done (time: 0.009s)
12
*** reverted m150128_233458_extend_status_table_for_slugs (time: 0.013s)
13
14
*** reverting m150128_003709_extend_status_table_for_created_by
15
    > drop foreign key fk_status_created_by from table {{%status}} ... done (time: 0.010s)
16
    > drop column created_by from table {{%status}} ... done (time: 0.008s)
17
*** reverted m150128_003709_extend_status_table_for_created_by (time: 0.019s)
18
19
*** reverting m141201_013120_create_status_table
20
    > drop table {{%status}} ... done (time: 0.001s)
21
*** reverted m141201_013120_create_status_table (time: 0.002s)
22
23
Migrated down successfully.
24
25
hello Jeff$ ./yii migrate/up 4
26
Yii Migration Tool (based on Yii v2.0.2)
27
28
Total 4 new migrations to be applied:
29
    m141201_013120_create_status_table
30
	m150128_003709_extend_status_table_for_created_by
31
	m150128_233458_extend_status_table_for_slugs
32
	m150209_200619_extend_status_table_for_updated_by
33
34
Apply the above migrations? (yes|no) [no]:yes
35
*** applying m141201_013120_create_status_table
36
    > create table {{%status}} ... done (time: 0.007s)
37
*** applied m141201_013120_create_status_table (time: 0.010s)
38
39
*** applying m150128_003709_extend_status_table_for_created_by
40
    > add column created_by integer NOT NULL to table {{%status}} ... done (time: 0.007s)
41
    > add foreign key fk_status_created_by: {{%status}} (created_by) references {{%user}} (id) ... done (time: 0.008s)
42
*** applied m150128_003709_extend_status_table_for_created_by (time: 0.016s)
43
44
*** applying m150128_233458_extend_status_table_for_slugs
45
    > add column slug string NOT NULL to table {{%status}} ... done (time: 0.007s)
46
*** applied m150128_233458_extend_status_table_for_slugs (time: 0.008s)
47
48
*** applying m150209_200619_extend_status_table_for_updated_by
49
    > add column updated_by integer NOT NULL to table {{%status}} ... done (time: 0.007s)
50
    > add foreign key fk_status_updated_by: {{%status}} (updated_by) references {{%user}} (id) ... done (time: 0.007s)
51
*** applied m150209_200619_extend_status_table_for_updated_by (time: 0.015s)
52
53
Migrated up successfully.

Menambahkan BlameableBehavior ke Model Status

Selanjutnya, kita akan melampirkan BlameableBehavior ke model Status kami. Dalam model / Status.php kita menambahkan BlameableBehavior setelah Sluggable:

1
class Status extends \yii\db\ActiveRecord
2
{
3
      const PERMISSIONS_PRIVATE = 10;
4
      const PERMISSIONS_PUBLIC = 20;  
5
  
6
      public function behaviors()
7
          {
8
              return [
9
                  [
10
                      'class' => SluggableBehavior::className(),
11
                      'attribute' => 'message',
12
                      'immutable' => true,
13
                      'ensureUnique'=>true,
14
                  ],
15
                  [
16
                      'class' => BlameableBehavior::className(),
17
                      'createdByAttribute' => 'created_by',
18
                      'updatedByAttribute' => 'updated_by',
19
                  ],
20
              ];
21
          }

Kami juga harus menyertakan perilaku Blameable di bagian atas model kami:

1
<?php
2
3
namespace app\models;
4
5
use Yii;
6
use yii\behaviors\SluggableBehavior;
7
use yii\behaviors\BlameableBehavior;

Kemudian, kami menghapus aturan yang diperlukan untuk created_by di aturan model:

1
public function rules()
2
    {
3
        return [
4
            [['message', 'created_at', 'updated_at','created_by'], 'required'],

Seperti ini:

1
public function rules()
2
    {
3
        return [
4
            [['message', 'created_at', 'updated_at'], 'required'],

Ini memungkinkan validasi untuk berhasil dan melanjutkan ke perilaku.

Kami juga dapat mengomentari atau menghapus tugas created_by StatusController dalam aksi pembuatan:

1
public function actionCreate()
2
    {
3
        $model = new Status();
4
5
        if ($model->load(Yii::$app->request->post())) {
6
          //$model->created_by = Yii::$app->user->getId();

Setelah semua perubahan ini selesai, kita dapat menulis posting Status baru:

Our Create Status form awaiting implementation of Blameable BehaviorOur Create Status form awaiting implementation of Blameable BehaviorOur Create Status form awaiting implementation of Blameable Behavior

Dan kita bisa mengintip ke tampilan tabel dengan PHPMyAdmin dan melihat pengaturan created_by dan updated_by:

The Status Table After Blameable Behavior UpdatesThe Status Table After Blameable Behavior UpdatesThe Status Table After Blameable Behavior Updates

Pembaruan Logging ke Tabel Status

Ketika sebuah posting Status dibuat, kita akan selalu tahu siapa yang membuat entri pertama. Tapi, dengan Blameable Behaviors, kita hanya akan tahu siapa yang terakhir memperbarui catatan.

Mari kita berjalan melalui implementasi log sederhana untuk mencatat id dari orang yang membuat setiap pembaruan. Kemudian Anda dapat dengan mudah melihat riwayat updaters atau memperpanjang ini menjadi log revisi penuh.

Membuat Tabel untuk StatusLog

Pertama, kita perlu membuat migrasi untuk StatusLog:

1
hello Jeff$ ./yii migrate/create create_status_log_table
2
Yii Migration Tool (based on Yii v2.0.2)
3
4
Create new migration '/Users/Jeff/Sites/hello/migrations/m150209_204852_create_status_log_table.php'? (yes|no) [no]:yes
5
6
New migration created successfully.

Kemudian, kami mengkodekan migrasi untuk menyertakan bidang relasional untuk tabel Status id dan kolom User updated_by:

1
<?php
2
3
use yii\db\Schema;
4
use yii\db\Migration;
5
6
class m150209_204852_create_status_log_table extends Migration
7
{
8
    public function up()
9
    {
10
          $tableOptions = null;
11
          if ($this->db->driverName === 'mysql') {
12
              $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
13
          }
14
15
          $this->createTable('{{%status_log}}', [
16
            'id' => Schema::TYPE_PK,
17
            'status_id' => Schema::TYPE_INTEGER.' NOT NULL',
18
            'updated_by' => Schema::TYPE_INTEGER.' NOT NULL',
19
            'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
20
          ], $tableOptions);          
21
          $this->addForeignKey('fk_status_log_id', '{{%status_log}}', 'status_id', '{{%status}}', 'id', 'CASCADE', 'CASCADE');     
22
          $this->addForeignKey('fk_status_log_updated_by', '{{%status_log}}', 'updated_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     
23
      }
24
25
26
    public function down()
27
    {
28
      $this->dropForeignKey('fk_status_updated_by','{{%status_log}}');
29
      $this->dropForeignKey('fk_status_id','{{%status_log}}');
30
      $this->dropColumn('{{%status_log}}','updated_by');
31
    }
32
}

Selanjutnya, kami menjalankan migrasi:

1
hello Jeff$ ./yii migrate/up 
2
Yii Migration Tool (based on Yii v2.0.2)
3
4
Total 1 new migration to be applied:
5
    m150209_204852_create_status_log_table
6
7
Apply the above migration? (yes|no) [no]:yes
8
*** applying m150209_204852_create_status_log_table
9
    > create table {{%status_log}} ... done (time: 0.008s)
10
    > add foreign key fk_status_log_id: {{%status_log}} (status_id) references {{%status}} (id) ... done (time: 0.008s)
11
    > add foreign key fk_status_log_updated_by: {{%status_log}} (updated_by) references {{%user}} (id) ... done (time: 0.008s)
12
*** applied m150209_204852_create_status_log_table (time: 0.028s)
13
14
Migrated up successfully.

Cara tercepat untuk membuat model untuk StatusLog (dan file CRUD agar kita dapat dengan mudah menelusuri tabel) adalah dengan generator kode Yii2, Gii. Anda telah melihat saya menggunakannya di tutorial sebelumnya.

Kunjungi http: // localhost:8888/hello/gii dan buat model dengan pengaturan ini:

Gii Code Generator for Status Log ModelGii Code Generator for Status Log ModelGii Code Generator for Status Log Model

Berikut pengaturan CRUD:

Gii Code Generator for Status Log CRUD FilesGii Code Generator for Status Log CRUD FilesGii Code Generator for Status Log CRUD Files

Selanjutnya, kami memperluas acara AfterSave di model Status:

1
public function afterSave($insert,$changedAttributes)
2
        {
3
            parent::afterSave($insert,$changedAttributes);
4
            // when insert false, then record has been updated

5
            if (!$insert) {
6
              // add StatusLog entry

7
              $status_log = new StatusLog;
8
              $status_log->status_id = $this->id;
9
              $status_log->updated_by = $this->updated_by;
10
              $status_log->created_at = time();
11
              $status_log->save();
12
            } 
13
        }

Metode ini memanggil fungsi induk default untuk afterSave tetapi kemudian membuat entri StatusLog baru setiap kali ada pembaruan ke baris Status:

Secara teoritis, kami juga dapat memperluas BlameableBehavior, tetapi karena Anda harus memastikan ada model log untuk setiap model ActiveRecord yang Anda gunakan, tampaknya lebih mudah untuk membangun fungsi ini ke Status.

Jika Anda memperbarui beberapa catatan Status, Anda kemudian dapat menelusuri Log Status menggunakan Gii CRUD. Gambar di bawah ini menunjukkan dua perubahan yang dilakukan oleh Status.id 1.

Status Log CRUD Browser - The Update LogStatus Log CRUD Browser - The Update LogStatus Log CRUD Browser - The Update Log

Jika Anda ingin melangkah lebih jauh, seharusnya relatif mudah untuk memperluas ini ke tabel revisi lengkap dengan teks status sebelumnya dan baru untuk mendukung fungsi rollback.

Apa berikutnya?

Saya harap Anda menikmati belajar tentang Yii2 Behaviors and Blameable. Selanjutnya, kita akan menjelajahi Perilaku Timestamp, yang mengurangi jumlah kode yang perlu Anda tulis dengan setiap model baru untuk operasi umum pembuatan stempel waktu untuk sisipan dan pembaruan.

Tonton tutorial yang akan datang dalam seri Programming With Yii2 saya sambil terus masuk ke dalam berbagai aspek kerangka. Anda juga mungkin ingin melihat saya Membangun Startup Anda Dengan seri PHP yang menggunakan template canggih Yii2 saat saya membangun aplikasi dunia nyata.

Saya menyambut permintaan fitur dan topik. Anda dapat mempostingnya di komentar di bawah atau email saya di situs web Konsultasi Lookahead saya.

Jika Anda ingin tahu kapan tutorial Yii2 berikutnya tiba, ikuti saya @reifman di Twitter atau periksa halaman instruktur saya. Halaman instruktur saya akan mencakup semua artikel dari seri ini segera setelah diterbitkan.

Link Terkait

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.