Memulai Pembuatan Aplikasi Web dengan Yii2 (END): Penanganan Upload File

Muhammad Arslan 17 Oktober 2016

Memulai Pembuatan Aplikasi Web dengan Yii2  (END): Penanganan Upload File

Kadangkala kita membutuhkan bagaimana suatu gambar dapat diunggah agar dapat tampil di slideshow atau menjadi gambar sampul dari suatu halaman profil. Yii2 memiliki penanganan upload file yang cukup mudah, semisal untuk mengunggah suatu gambar dengan ekstensi tertentu seperti PNG, JPG, ataupun SVG. Di tutorial ini kita akan mencoba bagaimana mengunggah sebuah gambar dan akan muncul di sebuah slideshow yang dihasilkan oleh widget bawaan Yii2.

Persiapan Coding

Karena kita masih akan menggunakan source code dari tutorial sebelumnya yang membahas pembuatan CRUD sendiri di Yii2, maka kita akan menambahkan tabel bernama team_galleries yang akan digunakan untuk menyimpan berbagai gambar dan informasinya yang terkait dengan suatu tim sepakbola. Berikut adalah sql untuk membuat tabel team_galleries plus dengan pembuatan foreign key-nya.
CREATE TABLE IF NOT EXISTS `team_galleries` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(200) NOT NULL,
  `description` text NOT NULL,
  `filepath` text NOT NULL,
  `team_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_teams_team_galleries` (`team_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=19 ;

ALTER TABLE team_galleries ADD CONSTRAINT fk_teams_teams_galleries FOREIGN KEY (team_id) REFERENCES teams (id) ON DELETE CASCADE ON UPDATE CASCADE;

Bilamana Anda belum memiliki tabel - tabel sebelumnya, dapat melihat tutorial "Memulai Pembuatan Aplikasi Web dengan Yii2: CRUD Dasar ke MySQL".

Membuat Model untuk Tabel Galeri Tim

Untuk mediasi ke MySQL, kita membutuhkan sebuah model yang bernama TeamGalleries. Silahkan buat kode berikut dan simpan di dalam sebuah file dengan nama TeamGalleries.php di folder models:
<?php

namespace app\models;

use yii\db\ActiveRecord;

class TeamGalleries extends ActiveRecord { public $teamsCount;

public static function tableName()
{
    return 'team_galleries';
}

public function getTeam(){
    return $this-&gt;hasOne(Teams::className(), ['id' =&gt; 'team_id']);
}

}

Sekarang perbaiki juga model Teams agar dapat mengambil galeri dengan menambahkan method getGallery():

<?php

namespace app\models;

use yii\db\ActiveRecord;

class Teams extends ActiveRecord
{
    public $teamsCount;

    public static function tableName()
    {
        return 'teams';
    }

    public function getLeague(){
        return $this->hasOne(Leagues::className(), ['id' => 'league_id']);
    }

    public function getGallery(){
        return $this->hasMany(TeamGalleries::className(), ['team_id' => 'id']);
    }
}

Membuat Daftar Galeri untuk Tim Sepak Bola

Karena kita tidak akan membuat controller baru, kita akan gunakan lagi HelloCrudController. Silahkan buat action baru dengan nama actionGallery dan tambahkan penggunaan class TeamGalleries seperti pada kode berikut dibawah ini:
<?php

namespace app\controllers;

use Yii; use yii\filters\AccessControl; use yii\web\Controller; use yii\helpers\Url; use yii\web\UploadedFile;

use app\models\Teams; use app\models\Leagues; use app\models\TeamsForm; use app\models\TeamGalleries;

class HelloCrudController extends Controller {

public function actions()
{
    return [
        'error' =&gt; [
            'class' =&gt; 'yii\web\ErrorAction',
        ],
    ];
}

public function behaviors()
{
    return [
        'access' =&gt; [
            'class' =&gt; AccessControl::className(),
            'only' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
            'rules' =&gt; [
                [
                    'actions' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
                    'allow' =&gt; true,
                    'roles' =&gt; ['@'],
                ],
            ],
        ],
    ];
}


......................................................................



public function actionGallery($id)
{
    $team = Teams::findOne(['id' =&gt; $id]);
    $galleries = TeamGalleries::find()-&gt;where(['team_id' =&gt; $id])-&gt;orderBy('id')-&gt;all();
    return $this-&gt;render('gallery', ['team'=&gt;$team, 'galleries'=&gt;$galleries]);
}

}

Sekarang buat views untuk halaman daftar galeri saat melihat galeri dari suatu tim. Buat kode berikut di dalam file gallery.php dan taruh di folder views/hello-crud:

<?php

use yii\widgets\Breadcrumbs;
use yii\helpers\Url;
use yii\helpers\Html;

$this->title = "Hello CRUD";

?>


<div class="row">
    <div class="col-md-12">
        <h1><?php echo $team['name'] ?> Gallery</h1>
        <hr/>

        <?php

        echo Breadcrumbs::widget([
            'itemTemplate' => "<li>{link}</li>\n", // template for all links
            'links' => [
                ['label' => 'Team List', 'url' => ['hello-crud/index']],
                ['label' => $team['name'], 'url' => ['hello-crud/detail', 'id'=>$team['id']]],
                'Gallery',
            ],
        ]);

        ?>
    </div>
</div>

<div>   
    <div class="col-md-2">
        <div class="list-group">
          <a href="<?php echo Url::to(['hello-crud/add-photo', 'id'=>$team['id']]); ?>" class="list-group-item"><i class="glyphicon glyphicon-eye-open"></i> Add New</a>
        </div>
    </div>
    <div class="col-md-10">
        <table class="table table-striped">
            <thead>
              <tr>
                <th>Name</th>
                <th>Description</th>
                <th>File Path</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
                <?php if (count($galleries) > 0) { ?>
                    <?php foreach ($galleries as $item): ?>
                        <tr>
                            <td><?= Html::encode("{$item['name']}") ?></td>
                            <td><?= Html::encode("{$item['description']}") ?></td>
                            <td><?= Html::encode("{$item['filepath']}") ?></td>
                            <td style="width:15%;text-align:center;">
                                <a class="btn btn-success btn-sm" href="<?php echo Url::to(['hello-crud/edit-photo', 'id'=>$team['id'], 'gal_id'=>$item['id']]); ?>"><i class="glyphicon glyphicon-pencil"></i></a> 
                                <a class="btn btn-danger btn-sm" href="<?php echo Url::to(['hello-crud/delete-photo', 'id'=>$team['id'], 'gal_id'=>$item['id']]); ?>"><i class="glyphicon glyphicon-trash"></i></a> 
                            </td>
                          </tr>
                    <?php endforeach; ?>
                <?php } else { ?>
                <tr>
                    <td style="text-align:center;font-size:15px;padding:25px;" colspan="5">No data found...</td>
                </tr>
                <?php } ?>

            </tbody>
        </table>
    </div>
</div>

Untuk membuka halaman galeri suatu tim silahkan tambahkan link View Gallery di file views/hello-crud/detail.php:

..........................................................

<div>   
    <div class="col-md-2">
        <div class="list-group">
          <a href="<?php echo Url::to(['hello-crud/gallery', 'id'=>$team['id']]); ?>" class="list-group-item"><i class="glyphicon glyphicon-eye-open"></i> View Gallery</a>
          <a href="<?php echo Url::to(['hello-crud/edit', 'id'=>$team['id']]); ?>" class="list-group-item"><i class="glyphicon glyphicon-pencil"></i> Edit Team</a>
          <a href="<?php echo Url::to(['hello-crud/delete', 'id'=>$team['id']]); ?>" class="list-group-item"><i class="glyphicon glyphicon-trash"></i> Delete Team</a>
        </div>
    </div>
    <div class="col-md-10">

..........................................................

Pastikan Anda sudah memiliki data tim sepakbola. Maka Anda akan melihat halaman kosong seperti ini terlebih dahulu:

Selection_018

Bila nanti tutorial ini sudah diselesaikan, maka akan muncul tampilan seperti berikut:

Selection_019

Membuat Form untuk Tambah Galeri Tim

Karena kita akan membuat fitur tambah galeri untuk suatu tim, kita membutuhkan Model untuk memvalidasi form tambah galeri. Silahkan buat sebuah file yang bernama TeamGalleriesForm.php dan taruh di folder models. Kemudian buat kode berikut:
<?php

namespace app\models;

use yii\base\Model;

class TeamGalleriesForm extends Model { public $name; public $description; public $photo; public $team_id;

public function rules()
{
    return [
        ['name', 'required','message' =&gt; 'Nama gambar gak boleh kosong'],
        ['name', 'string','max'=&gt;'50'],

        ['description', 'string'],

        ['photo', 'file', 'extensions' =&gt; ['png', 'jpg', 'gif'], 'maxSize' =&gt; 1024*1024],
    ];
}

}

Pada kode diatas, nama file tidak boleh kosong dan maksimal 50 karakter, sedangkan deskripsi boleh diisi atau tidak. Enaknya lagi, kita dapat menentukan ekstensi file apa saja yang dapat diunggah oleh pengguna, dalam hal ini kita hanya memperbolehkan .png, .jpg, .gif dengan maksimal ukuran 1024 * 1024. Model form ini akan digunakan di proses validasi tambah galeri untuk suatu tim.

Membuat Tambah Galeri Tim

Masih di HelloCrudController, silahkan tambahkan model TeamGalleriesForm di bagian class import dan tambahkan juga actionAddPhoto untuk memfasilitasi proses penambahan galeri:
<?php

namespace app\controllers;

use Yii; use yii\filters\AccessControl; use yii\web\Controller; use yii\helpers\Url; use yii\web\UploadedFile;

use app\models\Teams; use app\models\Leagues; use app\models\TeamsForm; use app\models\TeamGalleries; use app\models\TeamGalleriesForm;

class HelloCrudController extends Controller {

public function actions()
{
    return [
        'error' =&gt; [
            'class' =&gt; 'yii\web\ErrorAction',
        ],
    ];
}

public function behaviors()
{
    return [
        'access' =&gt; [
            'class' =&gt; AccessControl::className(),
            'only' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
            'rules' =&gt; [
                [
                    'actions' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
                    'allow' =&gt; true,
                    'roles' =&gt; ['@'],
                ],
            ],
        ],
    ];
}


......................................................................


public function actionAddPhoto($id)
{
    $forms = new TeamGalleriesForm();

    if ($forms-&gt;load(Yii::$app-&gt;request-&gt;post()) &amp;&amp; $forms-&gt;validate())
    {
        $request = Yii::$app-&gt;request;
        $forms-&gt;photo = UploadedFile::getInstance($forms, 'photo');

        $team = new TeamGalleries();
        $team-&gt;name = $request-&gt;post('TeamGalleriesForm')['name'];
        $team-&gt;description = $request-&gt;post('TeamGalleriesForm')['description'];
        $team-&gt;team_id = $id;
        $team-&gt;save();

        $filepath = 'upload/'.$forms-&gt;photo-&gt;baseName.'_'.sha1($team-&gt;id).'.'.$forms-&gt;photo-&gt;extension;
        $forms-&gt;photo-&gt;saveAs($filepath);
        $team-&gt;filepath = $filepath;
        $team-&gt;save();

        return $this-&gt;redirect(Url::to(['hello-crud/gallery', 'id'=&gt;$id]));
    }
    else 
    {
        $team = Teams::findOne(['id' =&gt; $id]);
        return $this-&gt;render('add_photo', ['team'=&gt;$team, 'forms'=&gt;$forms]);
    }
}

}

Pada actionAddPhoto kita load terlebih dahulu model TeamGalleriesForm, kemudian kita lakukan validasi terhadap post data yang datang. Apabila lolos validasi maka gambar akan disimpan di folder upload dan informasinya akan disimpan oleh model TeamGalleries. Bila tidak lolos validasi dan request adalah GET, maka akan ditampilkan lagi halaman tambah galeri.

Berikut adalah kode untuk views tambah galeri. Buat kode berikut di dalam file views/hello-crud/add_photo.php:

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\widgets\Breadcrumbs;
use yii\helpers\Url;

$this->title = "Hello CRUD";

?>

<div class="row">
    <div class="col-md-12">
        <h1><?php echo $team['name'] ?> Gallery</h1>
        <hr/>

        <?php

        echo Breadcrumbs::widget([
            'itemTemplate' => "<li>{link}</li>\n", // template for all links
            'links' => [
                ['label' => 'Team List', 'url' => ['hello-crud/index']],
                ['label' => $team['name'], 'url' => ['hello-crud/detail', 'id'=>$team['id']]],
                ['label' => 'Gallery', 'url' => ['hello-crud/gallery', 'id'=>$team['id']] ],
                'Add New',
            ],
        ]);

        ?>
    </div>
</div>

<div>   
    <div class="col-md-12">
        <?php $form = ActiveForm::begin([
                'id' => 'teams-form',
                'options' => ['class' => 'form-horizontal', 'enctype' => 'multipart/form-data']
            ])
        ?>

        <div class="form-group">
            <div class="col-lg-8">
            <?= $form->field($forms, 'photo')->fileInput(); ?>
            </div>
        </div>

        <div class="form-group">
            <div class="col-lg-8">
            <?= $form->field($forms, 'name')->hint('Diisi dengan nama yang terdiri dari angka, huruf kecil atau huruf besar'); ?>
            </div>
        </div>

        <div class="form-group">
            <div class="col-lg-8">
            <?= $form->field($forms, 'description')->TextArea(); ?>
            </div>
        </div>

        <div class="form-group">
            <div class="col-lg-8">
                <?= Html::submitButton('Simpan', ['class' => 'btn btn-primary']) ?>
            </div>
        </div>

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

Berikut adalah beberapa tampilan dari kode - kode diatas:

Selection_020 Selection_022 Selection_021

Membuat Edit Galeri Tim

Sekarang kita akan membuat proses dimana kita dapat mengubah nama dan deskripsi foto yang diunggah. Silahkan tambahkan actionEditPhoto() di dalam controllers/HelloCrudController.php:
<?php

namespace app\controllers;

use Yii; use yii\filters\AccessControl; use yii\web\Controller; use yii\helpers\Url; use yii\web\UploadedFile;

use app\models\Teams; use app\models\Leagues; use app\models\TeamsForm; use app\models\TeamGalleries; use app\models\TeamGalleriesForm;

class HelloCrudController extends Controller {

public function actions()
{
    return [
        'error' =&gt; [
            'class' =&gt; 'yii\web\ErrorAction',
        ],
    ];
}

public function behaviors()
{
    return [
        'access' =&gt; [
            'class' =&gt; AccessControl::className(),
            'only' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
            'rules' =&gt; [
                [
                    'actions' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
                    'allow' =&gt; true,
                    'roles' =&gt; ['@'],
                ],
            ],
        ],
    ];
}


......................................................................


public function actionEditPhoto($id, $gal_id)
{

    $forms = new TeamGalleriesForm();

    if ($forms-&gt;load(Yii::$app-&gt;request-&gt;post()) &amp;&amp; $forms-&gt;validate())
    {
        $request = Yii::$app-&gt;request;

        $photo = TeamGalleries::findOne(['id'=&gt;$gal_id]);
        $photo-&gt;name = $request-&gt;post('TeamGalleriesForm')['name'];
        $photo-&gt;description = $request-&gt;post('TeamGalleriesForm')['description'];
        $photo-&gt;save();

        return $this-&gt;redirect(Url::to(['hello-crud/gallery', 'id'=&gt;$id]));
    }
    else 
    {
        $team = Teams::findOne(['id' =&gt; $id]);
        $photo = TeamGalleries::findOne(['id'=&gt;$gal_id]);
        return $this-&gt;render('edit_photo', ['team'=&gt;$team, 'forms'=&gt;$forms, 'photo'=&gt;$photo]);
    }
}

}

Prosesnya hampir sama dengan tambah foto. Hanya saja kita ambil terlebih dahulu foto yang akan kita edit melalui model TeamGalleries. Kemudian kita ubah nama dan deskripsinya sesuai dengan data yang kita kirimkan melalui form edit foto. Bila berhasil halaman akan diarahkan ke halaman daftar galeri, bila validasi gagal atau request adalah GET maka kita tampilkan form edit foto.

Sedangkan kode dibawah ini adalah kode untuk views edit foto. Silahkan buat kode berikut di dalam file views/hello-crud/edit_photo.php:

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\widgets\Breadcrumbs;
use yii\helpers\Url;

$this->title = "Hello CRUD";

?>

<div class="row">
    <div class="col-md-12">
        <h1>Edit Photo</h1>
        <hr/>

        <?php

        echo Breadcrumbs::widget([
            'itemTemplate' => "<li>{link}</li>\n", // template for all links
            'links' => [
                ['label' => 'Team List', 'url' => ['hello-crud/index']],
                ['label' => $team['name'], 'url' => ['hello-crud/detail', 'id'=>$team['id']]],
                ['label' => 'Gallery', 'url' => ['hello-crud/gallery', 'id'=>$team['id']] ],
                'Edit ',
            ],
        ]);

        ?>
    </div>
</div>

<div>   
    <div class="col-md-12">
        <?php $form = ActiveForm::begin([
                'id' => 'teams-form',
                'options' => ['class' => 'form-horizontal', 'enctype' => 'multipart/form-data']
            ])
        ?>

        <div class="form-group">
            <div class="col-lg-8">
            <?= $form->field($forms, 'name')->textInput(['value'=>$photo['name']])->hint('Diisi dengan nama yang terdiri dari angka, huruf kecil atau huruf besar'); ?>
            </div>
        </div>

        <div class="form-group">
            <div class="col-lg-8">
            <?= $form->field($forms, 'description')->TextArea(['value'=>$photo['description']]); ?>
            </div>
        </div>

        <div class="form-group">
            <div class="col-lg-8">
                <?= Html::submitButton('Simpan', ['class' => 'btn btn-primary']) ?>
            </div>
        </div>

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

Berikut adalah beberapa tampilan dari kode - kode diatas:

Selection_024 Selection_025 Selection_026

Membuat Hapus Galeri Tim Sepak Bola

Untuk proses penghapusan salah satu foto dari galeri, cukup mudah. Kita cari dulu foto mana yang akan dihapus dengan menggunakan findOne() kemudian foto yang terpilih kita hapus dengan method delete(), lalu kita arahkan kembali ke halaman daftar galeri. Silahkan tambahkan actionDeletePhoto() di dalam controller controllers/HelloCrudController.php:
<?php

namespace app\controllers;

use Yii; use yii\filters\AccessControl; use yii\web\Controller; use yii\helpers\Url; use yii\web\UploadedFile;

use app\models\Teams; use app\models\Leagues; use app\models\TeamsForm; use app\models\TeamGalleries; use app\models\TeamGalleriesForm;

class HelloCrudController extends Controller {

public function actions()
{
    return [
        'error' =&gt; [
            'class' =&gt; 'yii\web\ErrorAction',
        ],
    ];
}

public function behaviors()
{
    return [
        'access' =&gt; [
            'class' =&gt; AccessControl::className(),
            'only' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
            'rules' =&gt; [
                [
                    'actions' =&gt; ['index', 'detail', 'add', 'edit', 'delete', 'delete-all', 'gallery', 'add-photo', 'edit-photo', 'delete-photo'],
                    'allow' =&gt; true,
                    'roles' =&gt; ['@'],
                ],
            ],
        ],
    ];
}


......................................................................


public function actionDeletePhoto($id, $gal_id)
{
    $photo = TeamGalleries::findOne(['id'=&gt;$gal_id]);
    unlink($photo-&gt;filepath);
    $photo-&gt;delete();

    return $this-&gt;redirect(Url::to(['hello-crud/gallery', 'id'=&gt;$id]));        
}

}

Menampilkan Galeri di Halaman Detail Tim Sepak Bola

Karena kita sudah membuat CRUD untuk galeri tim sepak bola, sekarang kita tampilkan galerinya tersebut dengan carousel di halaman detail tim sepakbola. Silahkan ubah views/hello-crud/detail.php menjadi kode seperti berikut:
<?php

use yii\widgets\Breadcrumbs; use yii\helpers\Url; use yii\bootstrap\Carousel;

$this->title = "Hello CRUD";

?>

<div class="row"> <div class="col-md-12"> <h1><?php echo $team['name'] ?></h1> <hr/>

    &lt;?php

    echo Breadcrumbs::widget([
        'itemTemplate' =&gt; "&lt;li&gt;{link}&lt;/li&gt;\n", // template for all links
        'links' =&gt; [
            ['label' =&gt; 'Team List', 'url' =&gt; ['hello-crud/index']],
            $team['name'],
        ],
    ]);

    ?&gt;
&lt;/div&gt;

</div>

<div>
<div class="col-md-2"> <div class="list-group"> <a href="<?php echo Url::to(['hello-crud/gallery', 'id'=>$team['id']]); ?>" class="list-group-item"><i class="glyphicon glyphicon-eye-open"></i> View Gallery</a> <a href="<?php echo Url::to(['hello-crud/edit', 'id'=>$team['id']]); ?>" class="list-group-item"><i class="glyphicon glyphicon-pencil"></i> Edit Team</a> <a href="<?php echo Url::to(['hello-crud/delete', 'id'=>$team['id']]); ?>" class="list-group-item"><i class="glyphicon glyphicon-trash"></i> Delete Team</a> </div> </div> <div class="col-md-10"> <div class="col-md-4"> <?php

        $items = [];

        foreach ($team-&gt;gallery as $item){
            $items[] = [
                    'content' =&gt; '&lt;img style="width:300px;" src="'.$item-&gt;filepath.'"/&gt;',
                    'caption' =&gt; '&lt;h4&gt;'.$item-&gt;name.'&lt;/h4&gt;&lt;p&gt;'.$item-&gt;description.'&lt;/p&gt;',
                ];
        }

        echo Carousel::widget([
            'items' =&gt; $items,
        ]);

        ?&gt;
    &lt;/div&gt;

    &lt;div class="col-md-8"&gt;
        &lt;p&gt;&lt;b&gt;League&lt;/b&gt;: &lt;?php echo $team-&gt;league['name'] ?&gt;&lt;/p&gt;
        &lt;p&gt;&lt;b&gt;Country&lt;/b&gt;: &lt;?php echo $team-&gt;country ?&gt;&lt;/p&gt;
        &lt;p&gt;&lt;?php echo $team['description'] ?&gt;&lt;/p&gt;

    &lt;/div&gt;      

</div>

Dan berikut adalah contoh screenshot setelah halaman detail tim sepakbolah memiliki sejumlah foto:

Selection_027 Selection_028

Penutup

Setelah mempelajari bagian akhir dari seri tutorial ini, diharapkan Anda sudah dapat membuat aplikasi web sendiri menggunakan Yii2. Di tutorial berikutnya, Anda akan mempelajari teknik - teknik lainnya yang dapat dilakukan di Yii2. Semoga bermanfaat, terima kasih telah mengikuti seri tutorial ini :D.

(codepolitan/yiiframework)