Pada tulisan ini saya akan membuat series mengenai pemrograman dengan Yii Framework. Series ini akan disusun untuk membuat sebuah program sederhana yang memanfaatkan fitur-fitur umum yang sangat mungkin digunakan di banyak kasus. Tulisan ini akan menggunakan Basic Template Yii2 (yang menurut saya penggunaannya sedikit lebih sulit daripada advance template Yii2).

Secara garis besar (dan mungkin akan bertambah sesuai keperluan yang mungkin terjadi) outline dari seri tulisan ini akan terdiri dari hal berikut.

  1. Prainstalasi
  2. Instalasi YiiFramework 2.0
  3. Login
  4. Login dengan Database pada Yii2
  5. Bekerja dengan Gii
  6. Module pada Yii2
  7. Layout dasar dan Manipulasinya pada Yii2
  8. Costum Asset dan Asset Bundle pada Yii2
  9. Alias pada Yii2
  10. Bekerja dengan Form
  11. Timestamp, Blameable, dan Sluggable Behavior pada Yii2
  12. Menggunakan Rich Text Input CkEditor dan Alternatifnya pada Yii2
  13. Gridview dan Listview
  14. SEO Friendly Url dengan slug
  15. Scenario pada Model Yii2
  16. Retrieve data pada Yii2
  17. Relasi Database pada Yii2
  18. Menggunakan Bootstrap4
  19. Widget Kartik dan Kartik Gridview
  20. Select2 dengan Kartik Ekstension
  21. Dependent Dropdown pada Yii2
  22. Bekerja dengan Modals
  23. Membuat Costum Template untuk Gii
  24. Mengupload File
  25. Mengupload File dengan Kartik Widget
  26. Gridview atau Datatables?
  27. Session dan Cookie pada Yii2
  28. Menggunakan AdminLTE pada Yii2
  29. Membuat Themes pada Yii2
  30. Menggunakan GoogleMaps API pada Yii2
  31. Menggunakan Socket.io pada Yii2
  32. Handling Error
  33. Bekerja dengan AuthClient
  34. Menggunakan Amazon S3 pada Yii2
  35. Mengirim Email dengan Swiftmailer pada Yii2
  36. Middleware pada Yii2
  37. Mengenal RBAC pada Yii2
  38. Implementasi RBAC pada Yii2
  39. Notifikasi Real Time dengan Socket.io pada Yii2

Anda dapat mengunduh dan memantau progress dari series ini lewat repositori Github belajararief-yii2series. Silahkan bintangi (star) untuk dapat lebih mudah memantau perkembangan repositori.

Requirement

Untuk memudahkan anda dalam memahami petunjuk ini, maka beberapa hal yang perlu diperhatikan diantaranya:

  1. Sistem Operasi yang saya gunakan adalah Windows 10 64bit dengan terminal menggunakan powershell terminal (beberapa command seperti cd dapat berbeda dengan command prompt biasa), namun saya akan berusaha sebisa mungkin mencontohkan perintah pada sistem operasi lain jika memunkinkan.
  2. Stack yang digunakan adalah Wamp Server (Apache 2.2, MySQL, PHP 7).
  3. Yii yang digunakan adalah Yii 2.0 dengan catatan jquery yang digunakan bukan jquery3. Beberapa perintah jquery akan berbeda pada jquery3, dan beberapa extensions yang saya gunakan sepertinya belum mendukung jquery3

Skenario Dependent Dropdown

Kali ini kita akan membuat sebuah skenario baru. Kita akan membuat penghitung jumlah pembaca artikel. Penghitung ini nanti juga akan menyimpan data kapan suatu artikel dibaca/ditekan. Selanjutnya dari informasi tersebut kita akan membuat grafik pembaca artikel. Grafik dapat dilihat dengan terlebih dahulu memilih pengguna dan artikel yang dibuat oleh pengguna tersebut dengan menggunakan dependent dropdown.

Menginstall Kartik Dep Drop (Dependent Dropdown)

Kita akan menggunakan widget DepDrop dari kartik untuk dapat menerapkan dependent dropdown dengan lebih mudah. Untuk menginstall kartik/DepDrop jalankan perintah di bawah ini.

composer require kartik-v/yii2-widget-depdrop "dev-master"

Membuat Tabel Menghitung Artikel

Selanjutnya kita akan membuat tabel blog_counter sebagai tempat menampung penghitungan artikel yang telah dibaca. Jalankan perintah di bawah ini pada terminal untuk membuat migration-file dengan nama create_blog_counter_table.

yii migrate/create create_blog_counter_table

Selanjutnya modifikasi file tersebut menjadi seperti di bawah ini.

<?php

use yii\db\Migration;

/**
 * Handles the creation of table `{{%blog_counter}}`.
 */
class m200220_060724_create_blog_counter_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function safeUp()
    {
        $tableOptions = null;
        if ($this->db->driverName === 'mysql') {
            $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
        }

        $this->createTable('{{%blog_counter}}', [
            'id' => $this->primaryKey(),
            'blog_id' => $this->integer(),
            'created_at' => $this->integer(),
            'updated_at' => $this->integer(),
        ], $tableOptions);
        

        // creates index for column `blog_id`
        $this->createIndex(
            'idx-blogcounter-blog_id',
            'blog_counter',
            'blog_id'
        );

        // add foreign key for table `user`
        $this->addForeignKey(
            'fk-bloccounter-blog_id',
            'blog_counter',
            'blog_id',
            'blog',
            'id',
            'CASCADE'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function safeDown()
    {
        $this->dropTable('{{%blog_counter}}');
    }
}

Kemudian buat model BlogCounter dengan Gii dan jangan lupa tambahkan timeStampBehavior pada model tersebut.

Menambahkan Penghitungan pada saat Artikel di Klik

Untuk menambahkan perhitungan terlebih dahulu kita menambahkan method addBlogCounter pada model \app\models\Blog.php kita. Method yang kita buat seperti di bawah ini.

    public function addBlogCounter()
    {
        $blogCounter = new BlogCounter();
        $blogCounter->blog_id = $this->id;
        return $blogCounter->save();
    }

Kemudian buka \app\controllers\BlogController.php dan pada actionView kita tambahkan baris berikut.

    public function actionView($slug)
    {
        $model = $this->findModel($slug);
        $model->addBlogCounter();
        
        return $this->render('view', [
            'model' => $this->findModel($slug),
        ]);
    }

Menampilkan Statistik Artikel dengan Dependent Dropdown

Terakhir kita akan membuat halaman untuk melihat statistik artikel seperti pada manajemen dashboard. Pertama kita buat terlebih dahulu model untuk menampilkan data grafik. Buat model \app\modules\administrator\models\StatistikSearch.php seperti di bawah ini.

<?php

namespace app\modules\administrator\models;

use app\models\Blog;
use app\models\BlogCounter;
use yii\base\Model;
use yii\helpers\Json;

/**
 * BlogSearch represents the model behind the search form of `app\models\Blog`.
 */
class StatistikSearch extends Model
{
    public $user_id;
    public $title;
    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [['user_id'], 'integer'],
            [['title'], 'string'],
        ];
    }

    public function getBlogCountByMonthJson()
    {
        return Json::encode($this->getBlogCountByMonth());
    }

    public function getBlogCountByMonth()
    {
        $blogCountByMonth = BlogCounter::find()
        ->select(['MONTH(FROM_UNIXTIME(created_at)) month', 'count(id) AS count'])
        ->where(['blog_id' => $this->getBlog()->id ])
        ->groupBy('MONTH(FROM_UNIXTIME(created_at))')->asArray()->all();

        return $blogCountByMonth;
    }

    public function getBlog()
    {
        return Blog::findOne(['created_by' => $this->user_id, 'slug' => $this->title]);
    }
}

Model tersebut dalam Yii disebut ModelForm yang akan menampilkan data perhitungan yang dihitung berdasarkan bulan pada artikel tertentu. Selanjutnya buat controllers \app\modules\administrator\controllers\StatistikController.php pada seperti di bawah ini. 

<?php

namespace app\modules\administrator\controllers;

use Yii;
use app\models\Blog;
use app\modules\administrator\models\StatistikSearch;
use yii\filters\AccessControl;
use yii\web\Controller;

/**
 * StatistikController implements the CRUD actions for Blog model.
 */
class StatistikController extends Controller
{
    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'actions' => ['index',  'title'],
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
        ];
    }

    /**
     * Lists all Blog models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new StatistikSearch();
        $dataJson = '[{"month":"", "count":""}]';
        if($searchModel->load(Yii::$app->request->queryParams)){
            $dataJson = $searchModel->getBlogCountByMonthJson();
            // return var_dump($dataJson);
        }

        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataJson' => $dataJson,
        ]);
    }

    public function actionTitle() {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $out = [];
        if (isset($_POST['depdrop_parents'])) {
            $parents = $_POST['depdrop_parents'];
            if ($parents != null) {
                $user_id = $parents[0];
                $out = self::getTitleList($user_id); 
                // the getSubCatList function will query the database based on the
                // user_id and return an array like below:
                // [
                //    ['id'=>'<sub-cat-id-1>', 'name'=>'<sub-cat-name1>'],
                //    ['id'=>'<sub-user_id_2>', 'name'=>'<sub-cat-name2>']
                // ]
                return ['output'=>$out, 'selected'=>''];
            }
        }
        return ['output'=>'', 'selected'=>''];
    }

    private function getTitleList($user_id)
    {
        $blog = Blog::find()->select(['slug as id', 'title as name'])->where(['created_by' => $user_id])->asArray()->all();
        return $blog ?? ['id' => '', 'name' => ''];
    }

}

Selanjutnya kita buat view pada \app\modules\administrator\views\Statistik dengan nama index.php dan _serach.php dengan isi seperti di bawah ini.

<?php
# index.php
use app\assets\ChartJsAsset;
use yii\helpers\Html;
use yii\grid\GridView;

/* @var $this yii\web\View */
/* @var $searchModel app\modules\administrator\models\BlogSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Blogs';
$this->params['breadcrumbs'][] = $this->title;


// Register ChartJsAsset
ChartJsAsset::register($this);
?>
<div class="blog-index">

    <h1><?= Html::encode($this->title) ?></h1>
    <?php echo $this->render('_search', ['model' => $searchModel]); ?>

    

    <div class="col-md-12">

        <canvas id="blogCountByMonthChart"></canvas>

    </div>


</div>
<?php
// then register our Js
$this->registerJs(<<<JS
    // we create function for generate count per month first
    function generateDataCount(month, blogCount){
        var result = blogCount.find(o => o.month == month);
        if(result == null) return 0;
        return result.count;
    }

    var blogCount = $dataJson; // blogCount json
    var ctx = document.getElementById('blogCountByMonthChart').getContext('2d'); //ctx, you can replace it with jQuery if you have one

    // Then we generate data with some simple looping
    var i = 0;
    data = [];
    while(i < 12)
    {
        data[i] = generateDataCount(i+1, blogCount);
        i++;
    }

    // and then generate to chartJs
    var chart = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
            datasets: [{
                label: "Blog Count By Month",
                backgroundColor: 'rgb(255, 99, 132)',
                borderColor: 'rgb(255, 99, 132)',
                data: data,
            }]
        },
        options: {}
    });
JS
);
?>
<?php
# _search.php
use app\models\User;
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use kartik\depdrop\DepDrop;
use kartik\select2\Select2;
use yii\helpers\ArrayHelper;
use yii\helpers\Url;

/* @var $this yii\web\View */
/* @var $model app\modules\administrator\models\BlogSearch */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="blog-search">

    <?php $form = ActiveForm::begin([
        'action' => ['index'],
        'method' => 'get',
    ]); ?>

    <?= $form->field($model, 'user_id')->widget(Select2::class, [
        'data' => ArrayHelper::map(User::find()->asArray()->all(), 'id', 'username'),
        'options' => ['placeholder' => 'Select User ...'],
        'pluginOptions' => ['allowClear' => true]
    ]) ?>

    <?= $form->field($model, 'title')->widget(DepDrop::classname(), [
        'type' => DepDrop::TYPE_SELECT2,
        // 'data' => [2 => 'Tablets'],
        'options' => ['id' => 'statistiksearch-title', 'placeholder' => 'Title ...'],
        'select2Options' => ['pluginOptions' => ['allowClear' => true]],
        'pluginOptions' => [
            'depends' => ['statistiksearch-user_id'],
            'url' => Url::to(['/administrator/statistik/title']),
            // 'params' => ['input-type-1', 'input-type-2']
        ]
    ]) ?>

    <div class="form-group">
        <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
        <?= Html::resetButton('Reset', ['class' => 'btn btn-secondary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

Terakhir kita akan mengubah menu pada \app\views\layout\main.php untuk menambahkan menu statistik.

    echo Nav::widget([
        'options' => ['class' => 'navbar-nav ml-auto'],
        'items' => [
            ['label' => 'Home', 'url' => ['/site/index']],
            ['label' => 'About', 'url' => ['/site/about']],
            ['label' => 'Contact', 'url' => ['/site/contact']],
            ['label' => 'Blog', 'url' => ['/administrator/blog'], 'visible' => !Yii::$app->user->isGuest, 'items' => [
                ['label' => 'Manajemen', 'url' => ['/administrator/blog']],
                ['label' => 'Statistik', 'url' => ['/administrator/statistik']],
            ]],
            ['label' => 'Register', 'url' => ['/site/signup'], 'visible' => Yii::$app->user->isGuest],
            Yii::$app->user->isGuest ? (
                ['label' => 'Login', 'url' => ['/site/login']]
            ) : (
                '<li>'
                . Html::beginForm(['/site/logout'], 'post')
                . Html::submitButton(
                    'Logout (' . Yii::$app->user->identity->username . ')',
                    ['class' => 'btn  btn-outline-success my-2 my-sm-0'] // logout  btn-link
                )
                . Html::endForm()
                . '</li>'
            )
        ],
    ]);

Demikian tulisan ini, semoga bermanfaat dan Happy Coding!