Membuat Web Portofolio Lengkap Dengan Ci4 Bag.2 (Modul Profil)
Setelah sebelumnya kita telah integrasikan antara template SB Admin 2 dengan Codeigniter 4 sekaligus langkah-langkah instalasi Ci4 dengan composer, pada tutorial kali ini kita akan membuat modul profil pada web portofolio ini.
Berikut tampilan modul Profile yang akan kita buat dengan CRUD sebagai berikut :
Sebagai pengantar pada seri membuat web portofolio disini kita membuat beberapa menu diantaranya :
Dashboard : Tampilan awal pada saat login berisi data jumlah profil, portofolio, slider dan user.
Profile : Berisi data profile data lengkap yang nantinya akan ditampilkan di halaman depan web portofolio.
Slider : untuk mengelola tampilan slider yang nantinya akan kita buat.
Seting : berisi menu untuk seting data user admin beserta hak aksesnya.
Log Out : untuk logout dari aplikasi.
Nah pada tutorial ini kita akan membuat modul (Profile) isi dari menu profile untuk tambah data profile, edit dan hapus profile yang biasa kita kenal dengan CRUD.
Untuk halaman index dari profile saya menggunakan data table untuk memudahkan menampilkan data dalam bentuk tabel.
Agar lebih lengkap dan jelas pada akhir tutorial teman-teman bisa langsung download source codenya untuk mengetahui alur dan struktur koding pada codeigniter.
Langkah awal kita buat terlebih dahulu database dengan nama ci4-portofolio, atau disesuaikan dengan nama database teman-teman, kemudian buat sebuah tabel Profile dengan data sebagai berikut :
Id, nama, alamat, email, telp, gambar.
Ubah file seting database .env masukan nama database, user dan passwordnya, disesuaikan dengan localhost database XAMPP di komputer masing-masing.
Controler Profile
Selanjutnya kita buat Controler Profile, dimana controller ini berfungsi sebagai pengatur aksi pada aplikasi atau sebagai pengatur request dari user atau sebagai penghubung antara request user (view) ke model yang nantinya akan dikembalikan ke view dalam bentuk response, berikut soruce code controller Profile :
<?php
namespace App\Controllers;
use \App\Models\ProfileModel;
class Profile extends BaseController
{
protected $profileModel;
public function __construct()
{
$this->profileModel = new ProfileModel();
}
public function index()
{
$data = [
'title' => 'Profile',
'profile' => $this->profileModel->getAllProfile()
];
return view('profile/index', $data);
}
public function tambah()
{
$data = [
'title' => 'Tambah Data Profile',
'validation' => \Config\Services::validation()
];
return view('profile/tambah', $data);
}
public function simpan()
{
if (!$this->validate([
'nama' => [
'rules' => 'required',
'errors' => [
'required' => '{field} harus diisi'
]
],
'alamat' => [
'rules' => 'required',
'errors' => [
'required' => '{field} harus diisi'
]
],
'email' => [
'rules' => 'required|valid_email',
'errors' => [
'required' => '{field} harus diisi',
'valid_email' => 'format {field} salah'
]
],
'telp' => [
'rules' => 'required',
'errors' => [
'required' => '{field} harus diisi'
]
],
'gambar' => [
'rules' => 'max_size[gambar,1024]|is_image[gambar]|mime_in[gambar,image/jpg,image/jpeg,image/png]',
'errors' => [
'max_size' => 'Pilih File / Ukuran gambar terlalu besar',
'is_image' => 'Yang anda pilih bukan gambar',
'mime_in' => 'Yang anda pilih bukan gambar',
]
]
])) {
// jika data tidak valid kembalikan ke halaman tambah pegawai
return redirect()->to('profile/tambah')->withInput();
}
// ambil gambar
$fileSampul = $this->request->getFile('gambar');
// apakah tidak ada gambar yang di upload
if ($fileSampul->getError() == 4) {
$namaSampul = 'default.jpg';
} else {
// generate nama sampul random
$namaSampul = $fileSampul->getRandomName();
// pindahkan file ke folder img
$fileSampul->move('img/profile', $namaSampul);
}
// validasi data sukses
$this->profileModel->save([
'nama' => $this->request->getVar('nama'),
'alamat' => $this->request->getVar('alamat'),
'email' => $this->request->getVar('email'),
'telp' => $this->request->getVar('telp'),
'gambar' => $namaSampul
]);
// menampilkan pesan sukses
session()->setFlashdata('pesan', 'Data berhasil ditambahkan!.');
// kembali ke halaman index Pegawai
return redirect()->to('/profile');
}
public function edit($id)
{
$data = [
'title' => 'Form Edit Data Profil',
'validation' => \Config\Services::validation(),
'profile' => $this->profileModel->getProfileById($id),
];
// jika id data tidak ada di table
if (empty($data['profile'])) {
throw new \CodeIgniter\Exceptions\PageNotFoundException('Data ' . $id . ' tidak ditemukan');
};
return view('profile/edit', $data);
}
public function update($id)
{
if (!$this->validate([
'nama' => [
'rules' => 'required',
'errors' => [
'required' => '{field} harus diisi'
]
],
'alamat' => [
'rules' => 'required',
'errors' => [
'required' => '{field} harus diisi'
]
],
'email' => [
'rules' => 'required|valid_email',
'errors' => [
'required' => '{field} harus diisi',
'valid_email' => 'format {field} salah'
]
],
'telp' => [
'rules' => 'required',
'errors' => [
'required' => '{field} harus diisi'
]
],
'gambar' => [
'rules' => 'max_size[gambar,1024]|is_image[gambar]|mime_in[gambar,image/jpg,image/jpeg,image/png]',
'errors' => [
'max_size' => 'Ukuran gambar terlalu besar',
'is_image' => 'Yang anda pilih bukan gambar',
'mime_in' => 'Yang anda pilih bukan gambar',
]
]
])) {
// jika data tidak valid kembalikan ke halaman tambah pegawai
return redirect()->to('profile/edit/' . $this->request->getVar('id'))->withInput();
}
// ambil gambar
$fileSampul = $this->request->getFile('gambar');
// apakah tidak ada gambar yang di upload
if ($fileSampul->getError() == 4) {
$namaSampul = $this->request->getVar('gambarLama');
} else {
// generate nama sampul random
$namaSampul = $fileSampul->getRandomName();
// pindahkan file ke folder img
$fileSampul->move('img/profile', $namaSampul);
// hapus file lama
if ($this->request->getVar('gambarLama') != 'default.jpg') {
unlink('img/profile/' . $this->request->getVar('gambarLama'));
}
}
// validasi data sukses
$this->profileModel->save([
'id' => $id,
'nama' => $this->request->getVar('nama'),
'alamat' => $this->request->getVar('alamat'),
'email' => $this->request->getVar('email'),
'telp' => $this->request->getVar('telp'),
'gambar' => $namaSampul
]);
// menampilkan pesan sukses
session()->setFlashdata('pesan', 'Data berhasil diedit!.');
// kembali ke halaman index Pegawai
return redirect()->to('/profile');
}
public function delete($id)
{
$profile = $this->profileModel->find($id);
// cek jika gambar default
if ($profile['gambar'] != 'default.jpg') {
// hapus gambar
unlink('img/profile/' . $profile['gambar']);
}
$this->profileModel->delete($id);
// menampilkan pesan data sukses dihapus
session()->setFlashdata('pesan', 'Data berhasil dihapus!..');
// kembali ke halaman index mahasiswa
return redirect()->to('profile');
}
}
Pada Controler Profil dibagi dalam beberapa fungsi yakni, index, tambah, simpan, edit, update, delete.
Profile Model
Profile Model, model berfungsi sebagai penghubung dengan database agar dapat mengelola memperbaharui, dan menginput data, berikut source codenya :
<?php
namespace App\Models;
use CodeIgniter\Model;
class ProfileModel extends Model
{
protected $table = 'profile';
protected $allowedFields = ['nama', 'alamat', 'email', 'telp', 'gambar'];
public function getAllProfile()
{
return $this->db->table('profile')->get()->getResultArray();
}
public function getProfileById($id = false)
{
if ($id == false) {
return $this->findAll();
}
return $this->where(['id' => $id])->first();
}
}
Pada ProfileModel terdapat bebera fungsi yakni getAllProfile untuk menampilkan data profile, dan getProfileById untuk menampilkan profil data tertentu berdasar id.
Migration
Migration adalah skema atau struktur table pada database yang dibuat mengunakan perintah di codeigniter berikut source codenya :
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Profile extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'auto_increment' => true,
],
'nama' => [
'type' => 'VARCHAR',
'constraint' => '250',
],
'alamat' => [
'type' => 'VARCHAR',
'constraint' => '512',
],
'email' => [
'type' => 'VARCHAR',
'constraint' => '256',
],
'telp' => [
'type' => 'VARCHAR',
'constraint' => '256',
],
'gambar' => [
'type' => 'VARCHAR',
'constraint' => '256',
],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('profile', true);
}
public function down()
{
$this->forge->dropTable('profile');
}
}
Migration file adalah skema dari tabel Profile yang berisi kolom nama, alamat, email, telp, gambar beserta nilainya.
View
View merupakan bagian yang menangani presentation logic, disini saya taruh pada folder profile, atau menampilkan tampilan dari aplikasi yang akan dilihat secara langsung oleh user, berikut soruce codenya :
index.php
<?= $this->extend('layout/template'); ?>
<?= $this->section('content'); ?>
<!-- Page Heading -->
<!-- <div class="d-sm-flex align-items-center justify-content-between mb-2">
<h1 class="h3 mb-0 text-gray-800"> <i class="fas fa-fw fa-user-circle"></i> Profile</h1>
</div> -->
<div class="row">
<div class="col-6">
<a href="/profile/tambah" class="btn btn-primary btn-icon-split mb-3">
<span class="icon text-white-50">
<i class="fas fa-plus-circle"></i>
</span>
<span class="text">Tambah Data</span>
</a>
</div>
</div>
<?php if (session()->getFlashdata('pesan')) : ?>
<div class="alert alert-success my-2 text-center" role="alert">
<i class="fas fa-check-circle"></i> <?= session()->getFlashdata('pesan'); ?>
</div>
<?php endif; ?>
<!-- Data Profile -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fas fa-fw fa-user-circle"></i> Data Profile</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Foto</th>
<th>Nama</th>
<th>Alamat</th>
<th>Email</th>
<th>Telp</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($profile as $row) : ?>
<tr>
<td>
<img src="/img/profile/<?= $row['gambar']; ?>" width="100px">
</td>
<td><?= $row['nama']; ?></td>
<td><?= $row['alamat']; ?></td>
<td><?= $row['email']; ?></td>
<td><?= $row['telp']; ?></td>
<td>
<a href="/profile/edit/<?= $row['id']; ?>" class="badge badge-primary">Edit</a>
<form action="/profile/delete/<?= $row['id']; ?>" method="POST" class="d-inline">
<?= csrf_field(); ?>
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="badge badge-danger btn-sm" onclick="return confirm('Apa Anda Yakin hapus data?.');">Delete</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<?= $this->endSection(); ?>
tambah.php
<?= $this->extend('layout/template'); ?>
<?= $this->section('content'); ?>
<!-- Form tambah data -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary"> <i class="fas fa-fw fa-user-circle"></i> Form Tambah Data Profil</h6>
</div>
<div class="card-body">
<form action="/profile/simpan" method="POST" enctype="multipart/form-data">
<?= csrf_field(); ?>
<!-- <div class="form-group">
<label for="nama">Nama</label>
<input type="text" class="form-control" id="nama" name="nama" autofocus value="<?= old('nama'); ?>">
<div class=" invalid-feedback">
<?= $validation->getError('nama'); ?>
</div>
</div> -->
<div class="form-group">
<label for="nama">Nama </label>
<input type="text" class="form-control <?= ($validation->hasError('nama')) ? 'is-invalid' : ''; ?>" id="nama" name="nama" autofocus value="<?= old('nama'); ?>">
<div class="invalid-feedback">
<?= $validation->getError('nama'); ?>
</div>
</div>
<div class="form-group">
<label for="alamat">Alamat </label>
<input type="text" class="form-control <?= ($validation->hasError('alamat')) ? 'is-invalid' : ''; ?>" id="alamat" name="alamat" autofocus value="<?= old('alamat'); ?>">
<div class="invalid-feedback">
<?= $validation->getError('alamat'); ?>
</div>
</div>
<div class="form-group">
<label for="email">Email </label>
<input type="text" class="form-control <?= ($validation->hasError('email')) ? 'is-invalid' : ''; ?>" id="email" name="email" autofocus value="<?= old('email'); ?>">
<div class="invalid-feedback">
<?= $validation->getError('email'); ?>
</div>
</div>
<div class="form-group mb-4">
<label for="telp">Telp </label>
<input type="text" class="form-control <?= ($validation->hasError('telp')) ? 'is-invalid' : ''; ?>" id="telp" name="telp" autofocus value="<?= old('telp'); ?>">
<div class="invalid-feedback">
<?= $validation->getError('telp'); ?>
</div>
</div>
<div class="custom-file mb-3">
<input type="file" class="form-control custom-file-input <?= ($validation->hasError('gambar')) ? 'is-invalid' : ''; ?>" id="gambar" name="gambar" autofocus value="<?= old('gambar'); ?>" id="gambar" name="gambar">
<label class="custom-file-label" for="validatedCustomFile">Pilih Gambar...</label>
<div class="invalid-feedback"> <?= $validation->getError('gambar'); ?></div>
</div>
<button type="submit" class="btn btn-primary"><i class="fas fa-check-circle"></i> Submit</button>
<a href="/profile" class="btn btn-success"><i class="fas fa-undo"></i> Back</a>
</form>
</div>
</div>
<?= $this->endSection(); ?>
edit.php
<?= $this->extend('layout/template'); ?>
<?= $this->section('content'); ?>
<!-- Form tambah data -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary"> <i class="fas fa-fw fa-user-circle"></i> Form Edit Data Profil</h6>
</div>
<div class="card-body">
<form action="/profile/update/<?= $profile['id']; ?>" method="POST" enctype="multipart/form-data">
<?= csrf_field(); ?>
<input type="hidden" name="id" value="<?= $profile['id']; ?>">
<input type="hidden" name="gambarLama" value="<?= $profile['gambar']; ?>">
<!-- <div class="form-group">
<label for="nama">Nama</label>
<input type="text" class="form-control" id="nama" name="nama" autofocus value="<?= old('nama'); ?>">
<div class=" invalid-feedback">
<?= $validation->getError('nama'); ?>
</div>
</div> -->
<div class="form-group">
<label for="nama">Nama </label>
<input type="text" class="form-control <?= ($validation->hasError('nama')) ? 'is-invalid' : ''; ?>" id="nama" name="nama" autofocus value="<?= $profile['nama']; ?>">
<div class="invalid-feedback">
<?= $validation->getError('nama'); ?>
</div>
</div>
<div class="form-group">
<label for="alamat">Alamat </label>
<input type="text" class="form-control <?= ($validation->hasError('alamat')) ? 'is-invalid' : ''; ?>" id="alamat" name="alamat" autofocus value="<?= $profile['alamat']; ?>">
<div class="invalid-feedback">
<?= $validation->getError('alamat'); ?>
</div>
</div>
<div class="form-group">
<label for="email">Email </label>
<input type="text" class="form-control <?= ($validation->hasError('email')) ? 'is-invalid' : ''; ?>" id="email" name="email" autofocus value="<?= $profile['email']; ?>">
<div class="invalid-feedback">
<?= $validation->getError('email'); ?>
</div>
</div>
<div class="form-group mb-4">
<label for="telp">Telp </label>
<input type="text" class="form-control <?= ($validation->hasError('telp')) ? 'is-invalid' : ''; ?>" id="telp" name="telp" autofocus value="<?= $profile['telp']; ?>">
<div class="invalid-feedback">
<?= $validation->getError('telp'); ?>
</div>
</div>
<div class="form-group">
<div class="col-sm-5">
<img class="img-thumbnail" src="/img/profile/<?= $profile['gambar']; ?>" height="20px">
</div>
</div>
<div class="custom-file mb-3">
<div class="col-sm-6">
<input type="file" class="form-control custom-file-input <?= ($validation->hasError('gambar')) ? 'is-invalid' : ''; ?>" id="gambar" name="gambar" autofocus value="<?= old('gambar'); ?>" id="gambar" name="gambar">
<label class="custom-file-label" for="validatedCustomFile">Pilih Gambar...</label>
<div class="invalid-feedback"> <?= $validation->getError('gambar'); ?></div>
</div>
</div>
<button type="submit" class="btn btn-primary"><i class="fas fa-check-circle"></i> Submit</button>
<a href="/profile" class="btn btn-success"><i class="fas fa-undo"></i> Back</a>
</form>
</div>
</div>
<?= $this->endSection(); ?>
Ikuti tutorial menarik lainnya di blog ini :
1. Download Source Code Aplikasi Website Portofolio
2. Tutorial Codeigniter 4 : Konsep Dasar CI4 Yang Penting Untuk Diketahui
3.Tutorial Codeigniter 4 : Membuat Web Portofolio Lengkap Bag.1 (Seting SB Admin 2)
Untuk lebih lengkapnya dan keterbatasan halaman sehinga tidak mungkin semua koding akan ditampilkan, silahkan teman-teman untuk download source code dan database dari tutorial ini dengan klik link berikut :
Download Sorce Code
Apabila tutorial ini bermanfaat, jangan ragu untuk bagikan kepada teman-teman lainya melaui tombol dibawah ini, sekian teman-teman oia pada tutorial selanjutnya pasti lebih seru jangan ketinggalan sering mampir ke blog ini yach 🙂