Anda di halaman 1dari 113

rahmadhany.triastanto@gmail.

com

Daftar Isi

Daftar Isi .............................................................................................................. 1

Daftar Gambar .................................................................................................... 6

Petunjuk Membaca ............................................................................................ 9

Tentang Penulis .................................................................................................. 9

Sumber kode ........................................................................................................ 9

Lisensi .................................................................................................................... 9

Pendahuluan ...................................................................................................... 10

a. Framework ........................................................................................... 10

b. Mengapa framework? ...................................................................... 10

c. Laravel ................................................................................................... 11

a. Desain sistem ...................................................................................... 13

I. Hari ke-1: Membangun CRUD ............................................................... 14

a. Environment configuration ........................................................... 14

b. Persiapan Laravel .............................................................................. 16

1. Pindah ke folder Code .................................................................. 16

2. Instalasi Laravel via Composer ................................................ 16

3. Periksa folder instalasi .............................................................. 17

4. Konfigurasi database & file permission ............................... 18

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 1


rahmadhany.triastanto@gmail.com

5. Instalasi additional packages .................................................. 19

6. Memulai aplikasi Pustarel.........................................................20

7. Akses Pustarel via browser........................................................ 22

c. Pemasangan Autentikasi ................................................................. 22

1. Authentication Scaffold .............................................................. 23

2. Migrasi table users & password_resets ................................ 24

3. Membuat user Admin .................................................................. 25

4. Login ke dalam Pustarel ............................................................. 26

5. Registrasi user tambahan .......................................................... 26

d. Migrasi database ............................................................................... 27

1. Membuat file migration ............................................................ 27

2. Menulis kode migration ............................................................. 27

3. Mengeksekusi migration ...........................................................29

e. Mengode CRUD Questions ............................................................... 30

1. Menyiapkan model Question ................................................... 30

2. Menyiapkan test data untuk Question .................................. 31

3. Mengode view index Question ................................................. 33

4. Menampilkan flash data di index Question ........................ 37

5. Mengode controller index Question ....................................... 37

6. Mengode view create Question .............................................. 40

7. Mengode controller create Question .....................................43

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 2


rahmadhany.triastanto@gmail.com

8. Validasi form data di store Question .....................................43

9. Mengode controller store Question ........................................45

10. Konfigurasi route untuk index, create, & store Question


46

11. Mengode view edit Question ................................................... 50

12. Mengode controller edit Question .......................................... 52

13. Validasi form data update Question ...................................... 53

14. Mengode controller update Question .................................... 53

15. Mengode controller delete Question .....................................55

16. Konfigurasi route untuk edit, update, & delete Question


55

17. Mengode search Question .......................................................... 57

II. Hari ke-2: CRUD Tingkat Lanjut .................................................... 60

a. Eloquent dengan contoh ................................................................. 60

1. Menerima model .......................................................................... 60

2. Menambah constraint ................................................................ 60

3. Satu atau lebih record dengan Collection ............................ 61

4. Satu record dalam bentuk model ............................................ 61

b. Menyempurnakan CRUD Question ................................................62

1. Menggunakan Named Route daripada url helper ..............62

2. Menggunakan Route Model Binding .......................................63

3. Menggunakan Route Resource ................................................. 64

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 3


rahmadhany.triastanto@gmail.com

4. Reusable form dengan Laravel Collective ............................ 65

5. Menggunakan Query Scope ....................................................... 68

6. Menggunakan metode Mass Assignment ............................. 70

7. Mengode ekspor menjadi Excel ................................................ 71

8. Mengode ekspor menjadi PDF ................................................... 72

c. Membuat CRUD Examination ......................................................... 74

1. Mengode model, controller, dan form request


Examination .............................................................................................. 75

2. Mengode route & view Examination ...................................... 78

3. Memasang Middleware auth ................................................... 83

d. Menyempurnakan CRUD Examination ....................................... 83

1. Mendefinisikan one-to-many relationship........................ 83

2. Mendefinisikan many-to-many relationship .................... 86

3. Mengode pemasangan Question ke Examination ............. 90

e. Konfigurasi Role Based Access Control ...................................... 99

1. Mengganti laratrust menjadi laravel-permission .......... 99

2. Instalasi laravel-permission ................................................. 100

3. Menambahkan hasRole Trait ................................................... 102

4. Membuat seed untuk mengisi Role & Permission ...........103

5. Menugaskan Role kepada User............................................... 106

6. Memasang middleware di route .......................................... 108

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 4


rahmadhany.triastanto@gmail.com

7. Mencoba 403 Forbidden ........................................................... 109

8. Menyesuaikan view sesuai Role & Permission ................. 110

III. Hari ke-3: Segera terbit! ............................................................... 112

IV. Penutup: Segera Terbit! ................................................................. 112

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 5


rahmadhany.triastanto@gmail.com

Daftar Gambar

Gambar 1 Hirarki Framework ...................................................................... 10

Gambar 2 Taylor Otwell ................................................................................. 11

Gambar 3 Logo Laravel ................................................................................... 11

Gambar 4 Tren PHP Framework di Dunia ................................................ 12

Gambar 5 Tren PHP Framework di Indonesia ........................................ 12

Gambar 6 Use Case Diagram Pustarel ...................................................... 13

Gambar 7 Desain database aplikasi Pustarel ......................................... 14

Gambar 8 Aplikasi Pustarel berhasil dimulai ....................................... 22

Gambar 9 Route yang telah diregistrasi authentication scaffold . 23

Gambar 10 Controller & view yang dibuat oleh authentication


scaffold ................................................................................................................ 23

Gambar 11 Tabel users & password_resets berhasil dimigrasi ....... 24

Gambar 12 User Admin Pustarel berhasil di-insert. ........................... 25

Gambar 13 Tampilan ketika sudah login ke Pustarel .......................... 26

Gambar 14 Tabel-tabel untuk pustarel berhasil di-create .............. 30

Gambar 15 Test data berhasil dibuat untuk table questions ........... 33

Gambar 16 Daftar route yang telah diregsitrasi ................................. 48

Gambar 17 Tampilan view index Question ............................................. 48

Gambar 18 Tampilan view create Question beserta validasi ......... 49

Gambar 19 Berhasil menyimpan record di table questions ............ 50

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 6


rahmadhany.triastanto@gmail.com

Gambar 20 Tampilan ketika berhasil mengubah Question ............. 56

Gambar 21 Tampilan ketika berhasil menghapus Question ............. 57

Gambar 22 Mencari keyword ‘quia’ pada halaman ke-2 ....................59

Gambar 23 Hasil Ekspor menjadi Excel .................................................... 72

Gambar 24 Hasil Ekspor menjadi PDF ....................................................... 74

Gambar 25 Error karena kolom updated_by diisi dengan null ........82

Gambar 26 One-to-many relationship antara users dan


examinations ................................................................................................... 84

Gambar 27 Many-to-many relationship antara questions dan


examinations .................................................................................................... 87

Gambar 28 View examinations.index dengan link questions


yang berelasi ..................................................................................................... 97

Gambar 29 View examinations.questions ............................................. 98

Gambar 30 Melakukan attach() pada many-to-many relationship


............................................................................................................................... 98

Gambar 31 Melakukan detach() pada many-to-many relationship


............................................................................................................................... 99

Gambar 32 Validasi composite key pada pivot table


examination_question............................................................................. 99
Gambar 33 Desain tabel untuk package laravel-permission ......... 102

Gambar 34 Permissions untuk Pustarel .................................................105

Gambar 35 Roles untuk Pustarel ...............................................................105

Gambar 36 Pivot table antara permissions & roles .......................... 106

Gambar 37 Student tidak memiliki role untuk dapat mengakses

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 7


rahmadhany.triastanto@gmail.com

halaman questions ........................................................................................ 110

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 8


rahmadhany.triastanto@gmail.com

Petunjuk Membaca

Akan segera diisi.

Tentang Penulis

Akan segera diisi.

Sumber kode

Akan segera diisi.

Lisensi

Copy (PDF, EPUB, MOBI) buku ini diberikan kepada pemilik akun
situs leanpub.com melalui mekanisme penjualan yang dilakukan
pada situs leanpub.com. Adapun copy buku ini yang diperoleh tidak
melalui cara yang telah disebutkan maka dianggap telah
melakukan pembajakan.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 9


rahmadhany.triastanto@gmail.com

Pendahuluan

a. Framework

Gambar 1 Hirarki Framework

Software Framework adalah abstraksi yang menyediakan fungsi


generik sehingga dapat dipilih & dimodifikasi untuk membangun
software sehingga terhubung ke banyak API (Web Framework,
Application Framework, etc.).

Web Framework adalah Software Framework yang dirancang


untuk pengembangan & aplikasi web (Angular, Ruby on Rails, Yii,
Zend, Laravel).

PHP Framework adalah Web Framework yang dikhususkan dalam


platform PHP (Zend, Symfony, Laravel, SlimPHP, CodeIgniter).

b. Mengapa framework?

• Memudahkan untuk bekerja dengan kompleksitas.


• Menulis kode program yang bersih dan dapat digunakan
kembali sehingga memudahkan proyek.
• Memaksa tim mengimplementasi kode dengan cara yang
yang konsisten, lebih sedikit bug, dan aplikasi yang lebih

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 10


rahmadhany.triastanto@gmail.com

fleksibel.
• Menguji dan debugging kode dengan lebih mudah.

c. Laravel

Taylor Otwell menciptakan Laravel sebagai upaya untuk


menyediakan alternatif yang lebih canggih dari CodeIgniter.
Laravel adalah PHP Framework yang paling populer di seluruh
dunia, dengan komunitas pengembang yang sangat besar.

Gambar 2 Taylor Otwell Gambar 3 Logo Laravel

Laravel terdiri dari berbagai packages seperti the lightweight


Blade templating engine, unit testing, ORM, a packaging system,
RESTful controllers dll. yang sangat membantu mempercepat
proses development.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 11


rahmadhany.triastanto@gmail.com

.
Gambar 4 Tren PHP Framework di Dunia

Gambar 5 Tren PHP Framework di Indonesia

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 12


rahmadhany.triastanto@gmail.com

a. Desain sistem

Pustarel adalah aplikasi berbasis web untuk menyelenggarakan


ujian online dimana student dapat mengikuti ujian yang telah
disiapkan oleh lecturer yang terdiri dari beberapa soal,
dilaksanakan pada jadwal & durasi yang telah ditentukan, sampai
dengan hasil ujian yang dikirimkan melalui email.

Use case diagram dari aplikasi Pustarel dapat digambarkan


sebagai berikut:

Gambar 6 Use Case Diagram Pustarel

Kemudian desain database dari aplikasi Pustarel ini adalah


sebagai berikut:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 13


rahmadhany.triastanto@gmail.com

Gambar 7 Desain database aplikasi Pustarel

I. Hari ke-1: Membangun CRUD

a. Environment configuration

Dalam pengembangan Pustarel, Laravel menggunakan perintah


artisan yang diakses melalui command line php dari
Powershell/CMD untuk Windows atau bash untuk MacOS & Linux
yang selanjutnya disebut terminal.

Selain itu, untuk menggunakan Laravel versi 5.7 beberapa aplikasi


yang harus di-install & dikonfigurasi agar dapat berjalan:

1. PHP >= 7.1.3 dengan instalasi extension: OpenSSL, PDO,

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 14


rahmadhany.triastanto@gmail.com

Mbstring, Tokenizer, XML, Ctype, dan JSON.


• Pastikan command php dapat diakses melalui terminal.
Untuk Windows, atur konfigurasi Environment melalui:
System Properties → Environment Variables... → System
Variables → PATH → Isi path menuju php.exe. Jika berhasil,
cek versi php melalui perintah ini di terminal:

refreshenv
php -version

Maka akan muncul tampilan seperti berikut:

PHP 7.2.9-1+ubuntu18.04.1+deb.sury.org+1 (cli) (built: Aug 19 2018 07:16:54)


( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.9-1+ubuntu18.04.1+deb.sury.org+1, Copyright (c)
1999-2018, by Zend Technologies
with blackfire v1.22.0~linux-x64-non_zts72, https://blackfire.io, by
Blackfire

• Pastikan extension yang disebutkan diatas sudah


terpasang dengan perintah:

php -m

2. Composer (https://getcomposer.org/).
• Pastikan Composer dapat diakses melalui terminal dengan
mengecek pada terminal:

composer --version

Maka akan muncul tampilan seperti berikut:

Composer version 1.7.3 2018-11-01 10:05:06

3. MySQL Community Edition 5.7 atau mariaDB 10.1.

Adapun untuk poin 1 & 3 dapat diganti dengan menggunakan:

⚫ Homestead (https://laravel.com/docs/5.7/homestead).
⚫ XAMPP 7.2.* for Windows.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 15


rahmadhany.triastanto@gmail.com

Untuk mendukung proses development disarankan agar dapat


menggunakan aplikasi berikut:

1. Text Editor seperti Visual Studio Code, Sublime 3, Atom,


Notepad++.
2. Database Manager (DBeaver 5.20, MySQL Workbench 6.3,
HeidiSQL 9.5).

b. Persiapan Laravel

1. Pindah ke folder Code


Buka terminal kemudian arahkan ke folder proyek yang diinginkan
(proyek ini disimpan di folder Code):
# MacOS & Linux (isi sesuai nama user)
$ cd /home/triastanto/Code/
#
# Windows (sesuaikan partisi dan direktori)
cd D:\Code\

2. Instalasi Laravel via Composer


Lakukan instalasi Laravel versi 5.7 dengan nama proyek pustarel:
composer create-project --prefer-dist laravel/laravel pustarel

Maka akan mucul tampilan seperti berikut dan dibuatnya folder


baru bernama pustarel:
Installing laravel/laravel (v5.7.0)
- Installing laravel/laravel (v5.7.0): Downloading (100%)
Created project in pustarel
> @php -r "file_exists('.env') || copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 72 installs, 0 updates, 0 removals
...
Writing lock file
Generating optimized autoload files

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 16


rahmadhany.triastanto@gmail.com

> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
...
Package manifest generated successfully.
> @php artisan key:generate
Application key set successfully.

3. Periksa folder instalasi


Pindah ke dalam folder pustarel yang berhasil dibuat oleh
composer pada terminal:
# Windows
D:\Code>cd pustarel
D:\Code\Pustarel>dir

# Pada MacOS atau Linux


$ cd pustarel
$ ls

Berikut adalah isi dari folder pustarel setelah berhasil meng-


install laravel:
drwxrwxrwx 1 vagrant vagrant 4096 Oct 9 17:10 .
drwxr-xr-x 4 root root 4096 Oct 16 13:44 ..
drwxrwxrwx 1 vagrant vagrant 0 Oct 9 17:08 app
-rwxrwxrwx 1 vagrant vagrant 1686 Oct 9 17:08 artisan
drwxrwxrwx 1 vagrant vagrant 0 Oct 9 17:08 bootstrap
-rwxrwxrwx 1 vagrant vagrant 1527 Oct 9 17:08 composer.json
-rwxrwxrwx 1 vagrant vagrant 148843 Oct 9 17:10 composer.lock
drwxrwxrwx 1 vagrant vagrant 4096 Oct 9 17:08 config
drwxrwxrwx 1 vagrant vagrant 0 Oct 9 17:08 database
-rwxrwxrwx 1 vagrant vagrant 213 Oct 9 17:08 .editorconfig
-rwxrwxrwx 1 vagrant vagrant 706 Oct 9 17:10 .env
-rwxrwxrwx 1 vagrant vagrant 655 Oct 9 17:08 .env.example
-rwxrwxrwx 1 vagrant vagrant 111 Oct 9 17:08 .gitattributes
-rwxrwxrwx 1 vagrant vagrant 177 Oct 9 17:08 .gitignore
-rwxrwxrwx 1 vagrant vagrant 1022 Oct 9 17:08 package.json
-rwxrwxrwx 1 vagrant vagrant 1134 Oct 9 17:08 phpunit.xml
drwxrwxrwx 1 vagrant vagrant 4096 Oct 9 17:08 public
-rwxrwxrwx 1 vagrant vagrant 3924 Oct 9 17:08 readme.md
drwxrwxrwx 1 vagrant vagrant 0 Oct 9 17:08 resources
drwxrwxrwx 1 vagrant vagrant 0 Oct 9 17:08 routes
-rwxrwxrwx 1 vagrant vagrant 563 Oct 9 17:08 server.php
drwxrwxrwx 1 vagrant vagrant 0 Oct 9 17:08 storage
drwxrwxrwx 1 vagrant vagrant 0 Oct 9 17:08 tests

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 17


rahmadhany.triastanto@gmail.com

drwxrwxrwx 1 vagrant vagrant 4096 Oct 9 17:10 vendor


-rwxrwxrwx 1 vagrant vagrant 537 Oct 9 17:08 webpack.mix.js
vagrant@homestead:~/Code/pustarel$

4. Konfigurasi database & file permission


Setelah database server (MySQL/MariaDB) sudah running serta
database & hak akses telah disiapkan, maka isi konfigurasi koneksi
database pada pustarel dengan menyunting file .env.
APP_NAME=Pustarel
...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=pustarel
DB_USERNAME=homestead
DB_PASSWORD=secret
...

Karena Laravel secara default menggunakan utf8mb4 sebagai


default character set, khusus untuk database MySQL < 5.7.7 atau
MariaDB < 10.2.2, akan mengalami error:
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max
key length is 767 bytes (SQL: alter table users add unique users_email_unique(email))
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max
key length is 767 bytes

Oleh karena itu, perlu dikonfigurasi default string length pada file
AppServiceProvider.php di folder app/Providers:
use Illuminate\Support\Facades\Schema;
...
public function boot()
{
Schema::defaultStringLength(191);
}
...

Kemudian jika menggunakan Homestead atau MacOS lakukan


konfigurasi permission pada terminal.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 18


rahmadhany.triastanto@gmail.com

sudo chmod -R 777 storage


sudo chmod -R 777 bootstrap/cache

5. Instalasi additional packages


Di dalam Pustarel, ada beberapa open source php packages yang
digunakan antara lain:

1. Laravel Collective HTML 5.7


(https://github.com/LaravelCollective/html)
2. DOMPDF Wrapper for Laravel 5 0.8
(https://github.com/barryvdh/laravel-dompdf)
3. Laravel Excel 3.1
(https://github.com/maatwebsite/Laravel-Excel)
4. Laratrust 5.0 (pada bab selanjutnya akan diganti)
(https://github.com/santigarcor/laratrust)

Untuk melakukan instalasi packages tersebut dilakukan melalui


terminal:
composer require laravelcollective/html "santigarcor/laratrust:5.0.*" barryvdh/laravel-
dompdf maatwebsite/excel

Jika berhasil di-install maka akan muncul pesan sebagai berikut:


Using version ^0.8.3 for barryvdh/laravel-dompdf
Using version ^3.1 for maatwebsite/excel
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 11 installs, 0 updates, 0 removals
- Installing sabberworm/php-css-parser (8.1.0): Loading from cache
- Installing phenx/php-svg-lib (v0.3.2): Loading from cache
- Installing phenx/php-font-lib (0.5.1): Loading from cache
- Installing dompdf/dompdf (v0.8.2): Loading from cache
- Installing barryvdh/laravel-dompdf (v0.8.3): Loading from cache
- Installing laravelcollective/html (v5.7.1): Downloading (100%)
- Installing markbaker/complex (1.4.7): Loading from cache
- Installing phpoffice/phpspreadsheet (1.5.0): Loading from cache
- Installing maatwebsite/excel (3.1.3): Loading from cache
- Installing kkszymanowski/traitor (0.2.5): Loading from cache

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 19


rahmadhany.triastanto@gmail.com

- Installing santigarcor/laratrust (5.0.9): Loading from cache


phpoffice/phpspreadsheet suggests installing mpdf/mpdf (Option for rendering PDF with
PDF Writer)
phpoffice/phpspreadsheet suggests installing tecnickcom/tcpdf (Option for rendering PDF
with PDF Writer)
phpoffice/phpspreadsheet suggests installing jpgraph/jpgraph (Option for rendering
charts, or including charts with PDF
or HTML Writers)
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: barryvdh/laravel-dompdf
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: laravelcollective/html
Discovered Package: maatwebsite/excel
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: santigarcor/laratrust

6. Memulai aplikasi Pustarel


Sebelum memulai aplikasi baru Laravel, perlu dilakukan
pembuatan application key yang digunakan untuk mengenkripsi
user sessions dan data terenkripsi lainnya. Ketikkan perintah pada
terminal:
php artisan key:generate

Setiap kali file .env mengalami perubahan maka perlu dilakukan


rekonfigurasi config dan cache pada Laravel yang dilakukan pada
terminal:
php artisan config:cache

Ada beberapa cara untuk memulai/menjalankan aplikasi Pustarel


yaitu:

1. Melalui php built-in web server via artisan dengan


mengetikkan perintah pada terminal:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 20


rahmadhany.triastanto@gmail.com

php artisan serve

maka akan muncul


Laravel development server started: <http://127.0.0.1:8000>

Kemudian kita dapat mengkases development server melalui


http://127.0.0.1:8000 atau http://localhost:8000 dan untuk
menghentikannya tekan Ctrl+C pada terminal.

2. Melalui homestead (buku ini menggunakan cara ini).


3. Untuk Windows dapat melalui XAMPP 7.2.* dengan konfigurasi
VirtualHost. Langkah-langkahnya meliputi:
• Buka Notepad sebagai Administrator (Run as Administrator)
dan buka file C:\Windows\System32\drivers\etc\hosts.

Tambahkan baris berikut:


...
127.0.0.1 pustarel.test

• Buka file xampp\apache\conf\httpd.conf dan tambahkan baris


berikut (sesuaikan xampp dengan folder xampp Anda):
<Directory "D:/Code/pustarel">
Options Indexes FollowSymLinks Includes ExecCGI
AllowOverride All
Require all granted
</Directory>

• Buka file xampp\apache\conf\extra\httpd-vhosts.conf dan


tambahkan baris berikut (sesuaikan xampp dengan folder
xampp Anda):
<VirtualHost *:80>
DocumentRoot D:/Code/pustarel/public
ServerName pustarel.test
</VirtualHost>

4. Untuk Linux dapat melalui instalasi Apache, PHP & MySQL via
package manager (apt/yum/rpm/dll.) dengan konfigurasi
VirtualHost.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 21


rahmadhany.triastanto@gmail.com

7. Akses Pustarel via browser


Setelah berhasil coba akses via browser dan akan muncul tampilan
seperti ini:

Gambar 8 Aplikasi Pustarel berhasil dimulai

c. Pemasangan Autentikasi

Laravel secara default memiliki pre-built authentication scaffold


yang menangani registrasi user baru, autentikasi dan reset
password serta view yang siap dipakai untuk masing-masing

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 22


rahmadhany.triastanto@gmail.com

controller tersebut.

1. Authentication Scaffold
Untuk membuat authentication scaffold tersebut pada pustarel
ketik:
php artisan make:auth

maka akan muncul:


Authentication scaffolding generated successfully.

Secara otomatis akan dibuat controller pada folder


app/Http/Controllers/Auth, view pada folder resources/views/auth
dan registrasi route pada web.php.
...

Auth::routes();

...

Gambar 9 Route yang telah diregistrasi authentication scaffold

Gambar 10 Controller & view yang dibuat oleh authentication scaffold

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 23


rahmadhany.triastanto@gmail.com

2. Migrasi table users & password_resets


Laravel secara default menyiapkan file yang berfungsi seperti
dump SQL (melalui mekanisme migration) yang berisi DDL untuk
tabel users & password_resets yang akan digunakan oleh
authentication scaffold yang telah dibuat pada langkah
sebelumnya. Untuk mengeksekusi migrasi tersebut, ketik:
php artisan migrate

Jika berhasil akan muncul:


Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table

Gambar 11 Tabel users & password_resets berhasil dimigrasi

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 24


rahmadhany.triastanto@gmail.com

3. Membuat user Admin


Untuk dapat masuk ke dalam Pustarel kita harus menyiapkan user
& password yang tersimpan di dalam table users. Untuk membuat
record tersebut kita dapat menggunakan tinker dengan mengetik:
php artisan tinker

maka akan muncul:


Psy Shell v0.9.8 (PHP 7.2.9-1+ubuntu18.04.1+deb.sury.org+1 — cli) by Justin Hileman

Kemudian ketikkan baris ganjil perintah berikut pada console


tinker (baris genap adalah output):
>>> $admin = new \App\User();
=> App\User {#2903}
>>> $admin->name = 'Admin Pustarel';
=> "Admin Pustarel"
>>> $admin->email = 'admin@pustarel.test';
=> "admin@pustarel.test"
>>> $admin->password = Hash::make('rahasia');
=> "$2y$10$QiXo4uWlgOUYv/0pix65yuutbWi/MmHDrLDjzkn5xqFyoVCIQYK1q"
>>> $admin->save();
=> true
>>> exit

Gambar 12 User Admin Pustarel berhasil di-insert.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 25


rahmadhany.triastanto@gmail.com

4. Login ke dalam Pustarel


Setelah behasil menambah record user Admin Pustarel, silahkan
klik link LOGIN pada halaman awal Pustarel (pojok kanan atas) dan
masukkan username dan password yang bersesuaian pada langkah
sebelumnya. Jika telah berhasil login maka muncul tampilan:

Gambar 13 Tampilan ketika sudah login ke Pustarel

5. Registrasi user tambahan


Kemudian klik logout dan daftarkan user lainnya melalui tombol
REGISTER pada halaman awal (http://pustarel.test) di pojok kanan
atas untuk melakukan proses registrasi user tambahan. User yang

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 26


rahmadhany.triastanto@gmail.com

dibuat adalah student dan lecturer Dengan email


student@pustarel.test dan lecturer@pustarel.test.

d. Migrasi database

Pada subbab sebelumnya telah dilakukan proses migration untuk


tabel users dan password_resets yang dibuat oleh authentication
scaffold. Pada bab ini akan dibahas mengenai pembuatan
migrations untuk tabel tabel yang akan digunakan oleh Pustarel.

Migration sendiri berfungsi seperti version control khusus untuk


database agar kita secara mudah dapat bekerja sama dengan tim.
Di dalam migration terdapat schema builder yang dapat membuat
skema database langsung dari Laravel terlepas apapun jenis
databasenya. Dengan migration, proses penambahan kolom atau
constraint di tengah proses development dapat terdokumentasi
dengan baik.

1. Membuat file migration


Untuk memulai migration, kita buat file migration pada terminal:
php artisan make:migration create_pustarel_tables

Jika berhasil akan muncul pesan seperti di bawah ini:


Created Migration: 2018_11_19_234139_create_pustarel_tables

Maka file akan dibuat pada folder database/migrations sesuai nama


tersebut.

2. Menulis kode migration


Untuk membuat database pustarel sesuai desain buka file:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 27


rahmadhany.triastanto@gmail.com

2018_11_19_234139_create_pustarel_tables

Ketik kode untuk function up() & function down():


...
public function up()
{
// Membuat tabel questions
Schema::create('questions', function (Blueprint $table) {
$table->increments('id');
$table->string('text', 191);
$table->string('a', 191);
$table->string('b', 191);
$table->string('c', 191);
$table->string('d', 191);
$table->string('e', 191);
$table->char('answer', 1);
$table->timestamps();
});

// Membuat tabel examinations


Schema::create('examinations', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 191);
$table->unsignedInteger('updated_by');
$table->datetime('start');
$table->unsignedInteger('duration');
$table->timestamps();
});

// Membuat tabel examination_question


Schema::create('examination_question', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('examination_id');
$table->unsignedInteger('question_id');
$table->timestamps();
});

// Membuat tabel payloads


Schema::create('payloads', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('examination_question_id');
$table->unsignedInteger('answered_by');
$table->char('choice', 1);
$table->string('attachment', 100);
$table->timestamps();
});

// Membuat tabel examination_result

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 28


rahmadhany.triastanto@gmail.com

Schema::create('examination_result', function (Blueprint $table) {


$table->increments('id');
$table->unsignedInteger('payload_id');
$table->unsignedInteger('result');
$table->timestamps();
});
}

public function down()


{
// Menghapus seluruh tabel
Schema::drop('questions');
Schema::drop('examinations');
Schema::drop('examination_question');
Schema::drop('payloads');
Schema::drop('examination_result');
}
...

3. Mengeksekusi migration
Untuk menerapkan migration yang sudah dibuat ke dalam
database ketik perintah berikut di terminal:
php artisan migrate

maka akan muncul pesan seperti berikut:


Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrating: 2018_11_19_234139_create_pustarel_tables
Migrated: 2018_11_19_234139_create_pustarel_tables

Buka database manager dan lihat table sudah dibuat oleh Laravel
sesuai kode yang ditulis.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 29


rahmadhany.triastanto@gmail.com

Gambar 14 Tabel-tabel untuk pustarel berhasil di-create

e. Mengode CRUD Questions


1. Menyiapkan model Question
Di dalam konsep MVC PHP, setiap table direpresentasikan oleh
model yang digunakan untuk melakukan DDL (Data Definition
Language) dan DML (Data Manipulation Language) pada database.

Untuk membuat model ketik perintah ini dari terminal:


php artisan make:model Question

Jika berhasil akan muncul pesan sebagai berikut:


Model created successfully.

Laravel akan membuat file Question.php di folder app dengan isi


sebagai berikut:
<?php

namespace App;

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 30


rahmadhany.triastanto@gmail.com

use Illuminate\Database\Eloquent\Model;

class Question extends Model


{
//
}

Perlu diperhatikan bahwa dalam membuat model dan tidak


melakukan konfigurasi tambahan, ada beberapa aturan yang harus
diikuti di dalam Laravel antara lain:

1. Diutamakan menggunakan bahasa inggris dalam melakukan


penamaan model, table, class, trait, dsb. karena akan
mempercepat konfigurasi contoh: Laravel secara otomatis akan
melakukan konversi plural noun menjadi singular noun pada
instance dari sebuah model.
2. Penamaan file model & class name menggunakan aturan
singular noun dengan mixed case dimana pada setiap huruf
awal kata dikapitalisasi. Contoh: Question, ExaminationResult.
3. Penamaan table menggunakan aturan plural noun dengan
lower case atau singular noun dengan snake case untuk table
many-to-many. Contoh: questions, examination_result.
4. Tabel memiliki field id (AUTO INCREMENT UNSIGNED INTEGER)
sebagai primary key.
5. Penamaan foreign key dilakukan dengan gabungan antara
singular noun antara nama table dan karakter _id. Contoh:
examination_id, question_id.

2. Menyiapkan test data untuk Question


Laravel menyediakan metode untuk mengisi test data melalui
seeding yang tersimpan dalam sebuah class misalnya

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 31


rahmadhany.triastanto@gmail.com

QuestionsTableSeeder di dalam folder database/seeds. Biasanya


seeder ini dipasangkan dengan PHP Library Faker dimana kita dapat
menyesuaikan jenis keacakan data yang diinginkan dalam sebuah
test data.

Untuk membuat test data untuk table questions, buat terlebih


dahulu Factory class yang bernama QuestionFactory.php di folder
database/factories.

<?php

use Faker\Generator as Faker;

$factory->define(App\Question::class, function (Faker $faker) {


return [
'text' => str_replace( ".", "?", $faker->sentence(10, true) ),
'a' => $faker->sentence(3, true),
'b' => $faker->sentence(3, true),
'c' => $faker->sentence(3, true),
'd' => $faker->sentence(3, true),
'e' => $faker->sentence(3, true),
'answer' => $faker->randomElement(['a','b','c','d','e']),
];
});

Kemudian buat file class seeder yang bernama


QuestionsTableSeeder.php

php artisan make:seeder QuestionsTableSeeder

Maka akan terbuat file QuestionsTableSeeder.php di folder


database/seeds dan muncul pesan berhasil seperti berikut:
Seeder created successfully.

Isi function run() di dalam QuestionsTableSeeder.php:


...
public function run()
{
factory(App\Question::class, 50)->create();
}
...

Isi function run() di dalam file DatabaseSeeder.php:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 32


rahmadhany.triastanto@gmail.com

...
public function run()
{
$this->call(QuestionsTableSeeder::class);
}
...

Terkahir, jalankan perintah seeder pada terminal:


php artisan db:seed

dan akan muncul pesan berhasil seperti:


Seeding: QuestionsTableSeeder
Database seeding completed successfully.

Gambar 15 Test data berhasil dibuat untuk table questions

3. Mengode view index Question


Di dalam konsep MVC PHP, view berisi kode HTML yang memisahkan
application logic dari presentation logic dimana Laravel
menggunakan Blade sebagai template engine sebagai language
untuk presentation logic. Dengan Blade, sintaks PHP masih dapat
digunakan di dalam view. Blade dalam prosesnya akan di-compile

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 33


rahmadhany.triastanto@gmail.com

menjadi kode php dan disimpan di dalam cache dan hampir tidak
menambahkan beban pada aplikasi. File blade disimpan di folder
resources/views dengan penamaan misalnya untuk file
app.blade.php yang disimpan di resources/views/layouts akan
diberi nama view layouts.app.

Sebelum membuat view index Question, tambahkan stylesheet


fontawesome di app.blade.php di folder resources/views/layouts
agar dapat menampilkan icon di Pustarel. Kode diletakkan setelah
baris:
<link href="{{ asset('css/app.css') }}" rel="stylesheet">

Dengan kode:
...
<link rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-
B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU"
crossorigin="anonymous">
...

Untuk membuat view index Question yang menampilkan test data


yang telah kita buat pada langkah sebelumnya, buat file
index.blade.php di folder resources/views/questions.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Question</div>
<div class="card-body">
@include('layouts._flash')
<div class="mb-3">
<div class="d-inline p-2 float-lg-left">
<div class="btn-group mb-3" role="group">
<a href="{{ url('questions/create') }}" class="btn btn-
primary">Add</a>
<a href="{{ url('questions/export/excel') }}" class="btn
btn-success">Excel</a>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 34


rahmadhany.triastanto@gmail.com

<a href="{{ url('questions/export/pdf') }}" class="btn


btn-success">PDF</a>
</div>
</div>
<div class="d-inline p-2 float-lg-right">
<div class="btn-group mb-3" role="group">
<input class="form-control mr-sm-2"
type="search"
placeholder="Search"
aria-label="Search">
<button class="btn btn-success"
type="submit">
Search
</button>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Text &amp; Choices</th>
<th scope="col">Answer</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach ($paginated as $question)
<tr>
<th scope="row">{{ $question->id }}</th>
<td>
{{ $question->text }}
<ol type="a">
<li>{{ $question->a }}</li>
<li>{{ $question->b }}</li>
<li>{{ $question->c }}</li>
<li>{{ $question->d }}</li>
<li>{{ $question->e }}</li>
</ol>
</td>
<td>{{ $question->answer }}</td>
<td>
<button class="btn btn-sm btn-light">
<i class="fa fa-edit"></i>
</button>
<button class="btn btn-sm btn-light">
<i class="fa fa-trash-alt"></i>
</button>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 35


rahmadhany.triastanto@gmail.com

</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="mx-auto">
{{ $paginated->links() }}
</div>
</div>
</div>
</div>
</div>
@endsection

Penjelasan kode:

• Kode @extends(‘layouts.app’) adalah sintaks blade yang


digunakan untuk menjadikan layouts.app.blade.php adalah
parent dari view ini.
• Kode @section(‘content’) adalah sintaks blade yang digunakan
untuk mengisi blok template bernama content yang telah
didefinisikan pada layouts.app.blade.php.
• Kode @include('layouts._flash') adalah sintaks blade untuk
meng-include blade template _flash.blade.php di folder
resources/views/layouts.

• Kode {{ url('questions/create') }} digunakan untuk membuat


url, misal: pustarel.test/questions/create
• Kode foreach($paginated as $question) endforeach adalah sintaks
blade untuk melakukan perulangan pada collection $paginated
dan ditampilkan dalam bentuk tabel.
• Kode {{ $paginated->links() }} digunakan untuk menampilkan
pagination yang telah dibuat pada controller.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 36


rahmadhany.triastanto@gmail.com

4. Menampilkan flash data di index Question


Untuk menampilkan pesan ketika berhasil melakukan create
record, digunakan flash data untuk menyimpan data hanya untuk
request selanjutnya dan kemudian secara otomatis dihapus.

untuk menampilkan pesan melalui flash data, pada view index


Question terdapat blade template yang di-include yaitu
layouts._flash. Buat file tersebut dengan nama _flash.blade.php di
folder resources/views/layouts:
@if (session()->has('flash_notification.message'))
<div class="alert alert-{{ session()->get('flash_notification.level') }} alert-
dismissible fade show"
role="alert">
{{ session()->get('flash_notification.message') }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
@endif

Penjelasan kode:

• Kode session()->has('flash_notification.message') melakukan


pengecekan apakah ada flash data yang disimpan. Jika ya, maka
tampilkan flash message.
• Kode session()->get(‘flash_notification.messsage’) digunakan
untuk menampilkan data flash data.

5. Mengode controller index Question


Di dalam konsep MVC PHP, controller berisi kode PHP yang
berkaitan dengan proses mengambil data dari model dan
mengirimkannya ke view.

Untuk membuat controller Question, ketik perintah ini di terminal:


php artisan make:controller QuestionController –-resource

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 37


rahmadhany.triastanto@gmail.com

maka akan terbuat file QuestionController.php di folder


app/Http/Controllers dan muncul pesan berhasil:
Controller created successfully.

Adapun hasil dari pembuatan controller tersebut berisi:


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Question;

class QuestionController extends Controller


{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}

/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}

/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}

/**

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 38


rahmadhany.triastanto@gmail.com

* Display the specified resource.


*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}

/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}

Untuk menampilkan seluruh test data dari table questions yang

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 39


rahmadhany.triastanto@gmail.com

sudah di-generate, tambahkan kode berikut pada function index():


...
public function index()
{
$paginated = Question::paginate();

return view('questions.index', compact('paginated'));


}
...

Penjelasan kode:

• Kode $paginated = Question::paginate(); melakukan query SQL


SELECT * FROM questions LIMIT 1, 15 dan menyimpannya dalam
variable $paginated.
• Kode return view('questions.index', compact('paginated'));

mengirimkan isi $paginated dalam variable internal blade


yaitu paginated melalui view questions.index.blade.php.

6. Mengode view create Question


View create Question adalah view yang digunakan untuk
menampilkan form untuk menambahkan record pada tabel
questions di dalam Pustarel. View ini memanfaatkan sintaks blade
foreach dengan menggabungkan fungsi php range.

Selain itu, dalam pembuatan HTML form, Laravel mewajibkan


untuk menyertakan hidden CSRF token field agar terhindar dari
serangan CSRF. Validasi ini secara default dilakukan oleh CSRF
protection middleware.

Untuk membuat view untuk create Question, buat file


create.blade.php di folder resources/views/questions dengan kode:
@extends('layouts.app')
@section('content')
<div class="container">

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 40


rahmadhany.triastanto@gmail.com

<div class="row justify-content-center">


<div class="col-md-8">
<div class="card">
<div class="card-header">Add Question</div>
<div class="card-body">
<form id="createQuestion" method="post" action="{{ url('questions')
}}">
@csrf
<div class="form-group">
<label for="text">Text</label>
<input type="text"
name="text"
id="text"
class="form-control @if ( $errors->has('text') ) is-
invalid @endif"
placeholder="Enter question text"
value="{{ old('text') }}">
<div class="invalid-feedback"> {{ $errors->first('text') }}
</div>
</div>
<label>Choices of answer</label>
@foreach (range('a','e') as $alphabet)
<div class="form-group">
<input type="text"
name="{{ $alphabet }}"
id="{{ $alphabet }}"
class="form-control @if ( $errors->has($alphabet) ) is-
invalid @endif"
placeholder="Enter choice for {{ $alphabet }}"
value="{{ old($alphabet) }}">
<div class="invalid-feedback"> {{ $errors->first($alphabet)
}} </div>
</div>
@endforeach
<div class="form-group">
<label for="e">Answer</label>
<div>
@foreach (range('a','e') as $alphabet)
<div class="form-check form-check-inline">
<input class="form-check-input @if ( $errors-
>has('answer') ) is-invalid @endif"
type="radio"
name="answer"
id="inlineRadio{{ $alphabet }}"
value="{{ $alphabet }}"
@if( $alphabet == old('answer') ) checked
@endif>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 41


rahmadhany.triastanto@gmail.com

<label class="form-check-label" for="inlineRadio{{


$alphabet }}">
{{ $alphabet }}
</label>
</div>
@endforeach
</div>
</div>
<div class="btn-group mb-3" role="group">
<input class="btn btn-primary" type="submit"
value="Submit">
<input class="btn btn-success" type="button"
value="Reset" onclick="document.getElementById('createQuestion').reset();">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection

Penjelasan kode:

• Kode {{ url('questions') }} digunakan untuk menampilkan url


untuk melakukan peyimpanan, misal: pustarel.test/questions.
• Kode @csrf adalah sintaks blade untuk menampilkan hidden
CSRF token field.
• Kode @if ( $errors->has('text') ) is-invalid @endif digunakan
untuk mengecek apakah ada pesan error ketika data tidak valid.
• Kode {{ $errors->first('text') }} digunakan untuk
menampilkan pesan error ketika data tidak valid.
• Kode {{ old('text') }} terdapat helper function old() yang
digunakan untuk menampilkan input data pada request
sebelumnya yang bermanfaat pada proses validasi.
• Kode @foreach (range(‘a’,’e’) as $alphabet) @endforeach adalah
sintaks blade untuk melakukan looping dengan mengurutkan
abjad a sampai e menggunakan fungsi native php range.
Sehingga kita dapat melakukan perulangan pembuatan input &

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 42


rahmadhany.triastanto@gmail.com

radio button dari a sampai dengan e.


• Kode {{ $alphabet }} digunakan untuk melakukan echo pada
blade.

7. Mengode controller create Question


Untuk menampilkan view create Question, tambahkan kode di file
QuestionController.php pada function create():
...
public function create()
{
return view('questions.create');
}
...

Penjelasan kode:

• Kode return view(‘questions.create’) menggunakan laravel


helpers view untuk mengembalikan view dengan
create.blade.php di folder resources/views/questions.

8. Validasi form data di store Question


Setiap data yang dikirimkan melalui form akan disimpan dalam
variabel $request yang merupakan instance dari
Illuminate\Http\Request dimana pada instance ini dapat dilakukan
proses validasi. Laravel menyediakan berbagai metode validasi
yang umum dibutuhkan seperti min, max, mimetypes, unique, required,
dan sebagainya.

Sebelum melakukan pengkodean di controller store Question, kita


buat terlebih dahulu form request di terminal:
php artisan make:request StoreQuestionRequest

Maka akan dibuat file di folder app/Http/Requests yang bernama

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 43


rahmadhany.triastanto@gmail.com

StoreQuestionRequest.php dan muncul pesan berikut jika berhasil:


Request created successfully.

Adapun isi file dari StoreQuestionRequest.php adalah sebagai


berikut:
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreQuestionRequest extends FormRequest


{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return false;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}

Untuk melakukan validasi form data dengan aturan bahwa semua


field harus diisi dan maksimal karakter 255, ubah kode pada file di
atas menjadi:
...
public function authorize()
{
return false;
return true;

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 44


rahmadhany.triastanto@gmail.com

}
...
public function rules()
{
return [

];
return [
'text' => 'required|min:5|max:255',
'a' => 'required|max:255',
'b' => 'required|max:255',
'c' => 'required|max:255',
'd' => 'required|max:255',
'e' => 'required|max:255',
'answer' => 'required|max:255',
];
}
...

9. Mengode controller store Question


Proses peyimpanan (insert & update) pada model yang
direpresentasikan oleh Eloquent dapat dilakukan melalui 2 (dua)
metode yaitu mass assigment dan save(). Proses penyimpanan
melalui metode save() mengharuskan pengesetan atribute secara
eksplisit sedangkan metode mass assignment cukup dengan
mengirimkan array dalam bentuk pair key value. Metode save()
lebih aman karena menghindari adanya unexpected HTTP request
sedangkan metode mass assigment memiliki metode
whilelist/blacklist agar dapat menentukan secara eksplisit
attribute mana saja yang dapat/tidak dapat di-mass assignment.

Untuk pembuatan record baru tabel questions, pada controller ini


akan menggunakan metode save() yang dikode dalam function
store():

use App\Question;
Use App\Http\Requests\StoreQuestionRequest;
...

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 45


rahmadhany.triastanto@gmail.com

public function store(StoreQuestionRequest $request)


{
$question = New Question;
$question->text = $request->input('text');
$question->a = $request->input('a');
$question->b = $request->input('b');
$question->c = $request->input('c');
$question->d = $request->input('d');
$question->e = $request->input('e');
$question->answer = $request->input('answer');
$question->save();

return redirect()
->route('questions.index')
->with('flash_notification', [
'level' => 'success',
'message' => 'Berhasil menyimpan Question! (ID: ' . $question->id . ')'
]);
}
...

Penjelasan kode:

• 9 baris kode yang diawali oleh $question = New Question; dan


diakhiri oleh $question->save(); melakukan proses penerimaan
data dari $request yang disimpan dalam model instance
Question yaitu $question dan menyimpannya melalui function
save().

• Kode dibawahnya yaitu redirect() dan seterusnya digunakan


untuk kembali ke named route questions.index dengan
menyertakan flash data flash_notification yang akan
ditampilkan.

10. Konfigurasi route untuk index, create, & store Question


Semua route di dalam laravel didefinisikan di dalam folder routes
yang di-load secara otomatis. File web.php mendefinisikan route
untuk web interface yang di-assign web middleware group yang

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 46


rahmadhany.triastanto@gmail.com

menyediakan fitur seperti session state dan CSRF protection.


Sedangkan file api.php adalah route yang bersifat stateless dan di-
assign api middleware group.

Setelah proses pengkodean mekanisme index, create, & store


Question dilakukan, kita akan mengkonfigurasi route-nya pada file
web.php:

...
Route::get('questions', 'QuestionController@index')->name('questions.index');
Route::get('questions/create', 'QuestionController@create')->name('questions.create');
Route::post('questions', 'QuestionController@store')->name('questions.store');

Penjelasan kode:

• Kode Route::get() mendefinisikan route untuk method GET dan


Route::post() mendefinisikan route untuk method POST.
• Didalam Facade tersebut, parameter yang diisi yaitu url yang
dituju serta controller yang digunakan.
• Kemudian masing-masing route diberi nama menggunakan
function name() sehingga route seperti ini dinamakan named
route. Contoh: untuk named route questions.create akan
memiliki url questions/create dengan metode GET.

Untuk memastikan pembuatan route telah berhasil, ketikkan kode


ini di terminal:
php artisan route:list

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 47


rahmadhany.triastanto@gmail.com

Maka muncul daftar route yang didaftarkan di dalam web.php:

Gambar 16 Daftar route yang telah diregsitrasi

Gambar 17 Tampilan view index Question

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 48


rahmadhany.triastanto@gmail.com

Gambar 18 Tampilan view create Question beserta validasi

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 49


rahmadhany.triastanto@gmail.com

Gambar 19 Berhasil menyimpan record di table questions

11. Mengode view edit Question


View edit Question adalah form yang menampilkan halaman
seperti create Question tetapi sudah diisi data yang ingin diubah.
Buat view dengan nama edit.blade.php di folder
resources/views/questions dengan kode:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Edit Question (ID: {{ $question->id }})</div>
<div class="card-body">

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 50


rahmadhany.triastanto@gmail.com

<form id="editQuestion" method="post"


action="{{ route('questions.update', ['id' => $question->id ])
}}">
@method('PUT')
@csrf
<div class="form-group">
<label for="text">Text</label>
<input type="text"
name="text"
id="text"
class="form-control @if ( $errors->has('text') ) is-
invalid @endif"
placeholder="Enter question text"
value="{{ $question->text }}">
<div class="invalid-feedback"> {{ $errors->first('text') }}
</div>
</div>
<label>Choices of answer</label>
@foreach (range('a','e') as $alphabet)
<div class="form-group">
<input type="text"
name="{{ $alphabet }}"
id="{{ $alphabet }}"
class="form-control @if ( $errors->has($alphabet) ) is-
invalid @endif"
placeholder="Enter choice for {{ $alphabet }}"
value="{{ $question->$alphabet }}">
<div class="invalid-feedback"> {{ $errors->first($alphabet)
}} </div>
</div>
@endforeach
<div class="form-group">
<label for="e">Answer</label>
<div>
@foreach (range('a','e') as $alphabet)
<div class="form-check form-check-inline">
<input class="form-check-input @if ( $errors-
>has('answer') ) is-invalid @endif"
type="radio"
name="answer"
id="inlineRadio{{ $alphabet }}"
value="{{ $alphabet }}"
@if( $alphabet == $question->answer ) checked
@endif>
<label class="form-check-label" for="inlineRadio{{
$alphabet }}">
{{ $alphabet }}
</label>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 51


rahmadhany.triastanto@gmail.com

</div>
@endforeach
</div>
</div>
<div class="btn-group mb-3" role="group">
<input class="btn btn-primary" type="submit" value="Edit">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection

Penjelasan kode:

• Kode @method('PUT') menambahkan hidden field untuk


melakukan spoofing action PUT. Hal ini dikarenakan HTML form
tidak mendukung PUT, PATCH, atau DELETE actions.
• Berbeda dengan url(), kode route('questions.update', ['id' =>
$question->id ]) menggunakan named route untuk
menampilkan url berdasarkan route yang telah diregistrasi di
web.php.

12. Mengode controller edit Question


Untuk menampilkan view edit Question, tambahkan kode di file
QuestionController.php pada function edit():
...
public function edit($id)
{
$question = Question::find($id);

return view('questions.edit', compact('question'));


}
...

Penjelasan kode:

• Kode return view(‘questions.edit’) mengembalikan view

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 52


rahmadhany.triastanto@gmail.com

edit.blade.php di folder resources/views/questions.

13. Validasi form data update Question


Sama seperti controller store Question, validasi dilakukan pada
controller update Question. Oleh karena itu, buat form request
pada terminal:
php artisan make:request UpdateQuestionRequest

Dan tambahkan kode validasi pada UpdateQuestionRequest.php di


folder app/Http/Requests:
...
public function authorize()
{
return false;
return true;
}
...
public function rules()
{
return [
];
return [
'text' => 'required|min:5|max:255',
'a' => 'required|max:255',
'b' => 'required|max:255',
'c' => 'required|max:255',
'd' => 'required|max:255',
'e' => 'required|max:255',
'answer' => 'required|max:255',
];
}

...

14. Mengode controller update Question


Setelah membuat view edit Question, tambahkan kode untuk
controller update Question yang mirip dengan controller store
Question:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 53


rahmadhany.triastanto@gmail.com

use App\Http\Requests\UpdateQuestionRequest;
...
public function update(UpdateQuestionRequest $request, $id)
{
$question = Question::find($id);

$question->text = $request->input('text');
$question->a = $request->input('a');
$question->b = $request->input('b');
$question->c = $request->input('c');
$question->d = $request->input('d');
$question->e = $request->input('e');
$question->answer = $request->input('answer');
$question->save();

return redirect()
->route('questions.index')
->with('flash_notification', [
'level' => 'success',
'message' => 'Berhasil mengubah Question! (ID: ' . $question->id . ')'
]);
}
...

Sebelum menulis kode untuk delete Question, lakukan perubahan


pada view questions.index yaitu:
...
<button class="btn btn-sm btn-light">
<i class="fa fa-edit"></i>
</button>
<button class="btn btn-sm btn-light">
<i class="fa fa-trash-alt"></i>
</button>
<a href="{{ route('questions.edit', ['id' => $question->id]) }}"
class="btn btn-sm btn-light">
<i class="fa fa-edit"></i>
</a>
<form action="{{ route('questions.destroy', ['id' => $question->id]) }}"
method="POST">
@method('DELETE')
{{ csrf_field() }}
<button type="submit" value="x"
class="btn btn-sm btn-light">
<i class="fa fa-trash-alt"></i>
</button>
</form>
...

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 54


rahmadhany.triastanto@gmail.com

Penjelasan kode:

• route('questions.edit', ['id' => $question->id]) menampilkan


url dengan tambahan parameter id.
• Kode @mothod(‘DELETE’) digunakan untuk form method spoofing
DELETE.
• Kode {{ csrf_field() }} sama dengan sintaks blade @csrf.

15. Mengode controller delete Question


Untuk melakukan delete Question, tambahkan kode pada function
destroy() di QuestionController.php:
...
public function destroy($id)
{
$question = Question::find($id);

$question->delete();

return redirect()
->route('questions.index')
->with('flash_notification', [
'level' => 'warning',
'message' => 'Berhasil menghapus Question! (ID: ' . $question->id . ')'
]);
}
...

16. Konfigurasi route untuk edit, update, & delete Question


Setelah proses pengkodean mekanisme edit, update, & delete
Question dilakukan, kita akan mengkonfigurasi route-nya pada file
web.php:

...
Route::get('questions/{id}/edit', 'QuestionController@edit')->name('questions.edit');
Route::put('questions/{id}', 'QuestionController@update')->name('questions.update');
Route::delete('questions/{id}', 'QuestionController@destroy')
->name('questions.destroy');

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 55


rahmadhany.triastanto@gmail.com

Gambar 20 Tampilan ketika berhasil mengubah Question

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 56


rahmadhany.triastanto@gmail.com

Gambar 21 Tampilan ketika berhasil menghapus Question

17. Mengode search Question


Untuk melakukan search, ubah kode di view questions.index pada
bagian tombol search agar menjadi form dengan method GET.
<div class="btn-group mb-3" role="group">
<input class="form-control mr-sm-2"
type="search"
placeholder="Search"
aria-label="Search">
<button class="btn btn-success"
type="submit">
Search
</button>
</div>
<form action="{{ route('questions.index') }}" method="GET">
<div class="btn-group mb-3" role="group">
<input class="form-control mr-sm-2"
type="search"

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 57


rahmadhany.triastanto@gmail.com

placeholder="Search"
name="keyword"
value="{{ $keyword }}">
<button class="btn btn-success" type="submit">
Search
</button>
</div>
</form>

Penjelasan kode:

• Pada form dengan method GET tidak diperlukan CSRF field.


• Kode $keyword digunakan untuk menampilkan keyword/search
query yang digunakan apabila dilakukan pencarian.

Kemudian ubah controller index Question agar dapat melakukan


pencarian dengan query:
...
public function index()
{
$paginated = Question::paginate();
return view('questions.index', compact('paginated'));
}
...
...
public function index(Request $request)
{
$keyword = $request->input('keyword');

if(is_null($keyword)) {
$paginated = Question::paginate();
} else {
$paginated = Question::where('text', 'like', '%' . $keyword .'%')
->orWhere('a', 'like', '%' . $keyword .'%')
->orWhere('b', 'like', '%' . $keyword .'%')
->orWhere('c', 'like', '%' . $keyword .'%')
->orWhere('d', 'like', '%' . $keyword .'%')
->orWhere('e', 'like', '%' . $keyword .'%')
->paginate();

$paginated->appends($request->only('keyword'));
}

return view('questions.index', compact('paginated', 'keyword' ));


}
...

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 58


rahmadhany.triastanto@gmail.com

Penjelasan kode:

• Kode Question::where()->OrWhere()->paginate() jika keyword


adalah ‘abc’ maka query yang ekuivalen
‘SELECT * FROM questions WHERE `text` LIKE ‘%abc%’ OR `a` LIKE

‘%abc%’ OR `b` LIKE ‘%abc%’ OR `c` LIKE ‘%abc%’ OR `d` LIKE

‘%abc%’ OR `e` LIKE ‘%abc%’ LIMIT 0, 15’.

Dimana ini adalah query untuk mencari berdasarkan keyword


dan melakukan paginasi.
• Kode $paginated->appends($request->only('keyword')); akan
menambahkan ‘?keyword=abc’ pada setiap url di link paginasi.

Gambar 22 Mencari keyword ‘quia’ pada halaman ke-2

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 59


rahmadhany.triastanto@gmail.com

II. Hari ke-2: CRUD Tingkat Lanjut

a. Eloquent dengan contoh


1. Menerima model
Setelah membuat & mengkonfigurasi model dengan tabel pada
database pada pembahasan sebelumnya, Eloquent dapat
melakukan query layaknya seperti di database.
$questions = Question::all();

foreach ($questions as $question) {


echo $question->name;
}

Pada kode diatas, method all() mengembalikan seluruh isi tabel


questions dalam bentuk instance dari Collection. SQL query yang
ekuivalen dari method ini adalah SELECT * FROM questions.

2. Menambah constraint
Selain method all(), Eloquent dapat menambahkan constraint ke
dalam query-nya dan menggunakan method get() untuk menerima
hasilnya.
$question = Question::where('answer', 'a')
->orderBy('text', 'desc')
->get();

Pada kode diatas, model Question melakukan query untuk mencari


record dimana kolom answer adalah ‘a’, dengan pengurutan hasil
query berdasarkan kolom text secara descending, dan ambil

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 60


rahmadhany.triastanto@gmail.com

sepuluh record pertama dari hasil yang didapatkan. SQL query yang
ekuivalen adalah SELECT * FROM questions WHERE answer = 'a' ORDER
BY text DESC.

3. Satu atau lebih record dengan Collection


Untuk method seperti all() dan get() dimana menerima satu atau
lebih record yang direpresentasikan dengan instance dari
Illuminate\Database\Eloquent\Collection. Dimana pada Collection
class ini menyediakan berbagai macam method yang yang sangat
membantu untuk mengelola result tersebut.
$questions = $questions->reject(function ($question) {
return $question->answer == 'a';
});

Pada kode diatas, digunakan method reject() untuk


mengembalikan instance Collection baru yang berisi record yang
tidak memiliki answer ‘a’.

4. Satu record dalam bentuk model


Selain menerima result dalam bentuk Collection, Eloquent dapat
menerima result satu record (yaitu instance dari model)
menggunakan method find() atau first().
$question = App\Question::find(1);

$question = App\Question::where('answer', ‘a’)->first();

Dalam kode diatas, method find() akan mengembalikan satu record


berdasarkan pencarian kolom primary key sedangkan method
first() akan mengembalikan satu record berdasarkan constraint
sebelumnya.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 61


rahmadhany.triastanto@gmail.com

b. Menyempurnakan CRUD Question


1. Menggunakan Named Route daripada url helper
Named routes digunakan untuk membuat URL atau redirect untuk
route yang spesifik. Misalnya pada route:
Route::get('questions/{id}/edit', 'QuestionController@edit')->name('questions.edit');

Didapatkan URL http://pustarel.test/questions/1/edit dengan


hanya mengakses named route questions.edit dengan cara:
route('questions.edit', ['id' => 1]);

Dengan menggunakan named route, apabila definisi URL dari route


mengalami perubahan, tidak diperlukan perubahan untuk
penggunaan named route tersebut. Sehingga Laravel dapat
membuat URL tanpa harus terikat dengan definisi aktual pada
registrasi route. Bayangkan apabila menggunakan helper url() dan
terjadi perubahan definisi aktual URL, maka semua URL yang dituju
menggunakan helper url() harus diubah satu per satu.

Untuk menggunakan named route, tambahkan kode untuk named


route pada action ekspor ke Excel dan ekspor ke PDF:
...
Route::get('questions/export/excel', 'QuestionController@excel');
Route::get('questions/export/pdf', 'QuestionController@pdf');
Route::get('questions/export/excel', 'QuestionController@excel')
->name('questions.export.excel');
Route::get('questions/export/pdf', 'QuestionController@pdf')
->name('questions.export.pdf');
...

Kemudian ubah kode pada view questions.index agar menggunakan


named route:
...
<a href="{{ url('questions/create') }}" class="btn btn-primary">Add</a>
<a href="{{ url('questions/export/excel') }}" class="btn btn-success">Excel</a>
<a href="{{ url('questions/export/pdf') }}" class="btn btn-success">PDF</a>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 62


rahmadhany.triastanto@gmail.com

<a href="{{ route('questions.create') }}" class="btn btn-primary">Add</a>


<a href="{{ route('questions.export.excel') }}" class="btn btn-success">Excel</a>
<a href="{{ route('questions.export.pdf') }}" class="btn btn-success">PDF</a>
...

2. Menggunakan Route Model Binding


Perhatikan proses injection ID dari sebuah model ke dalam route
atau controller action biasanya dilakukan seperti ini pada web.php:
Route::put('questions/{id}', 'QuestionController@edit);

Dan definisi function edit() di controller:


...
public function edit($id)
{
$examination = Examination::find($id);
...

Pada definisi route diatas, function edit() perlu melakukan query


terhadap model yang merepresentasikan ID tersebut agar dapat
melakukan penyimpanan atau perubahan data. Dengan
menggunakan Route Model Binding, proses ini dapat dieliminasi
karena Laravel secara otomatis akan melakukan injeksi instance
dari model secara langsung ke dalam route. Sehingga kode
registrasi route di atas dapat diubah menjadi:
Route::put('questions/{question}', 'QuestionController@edit);

Dan definisi function edit() di controller dapat diubah menjadi:


...
public function edit(Question $question)
{
$question = Question::find($id);
...

Untuk menggunakan Route Model Binding, ubah kode pada function


show(), edit(), update(), destroy():

...
public function show($id)

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 63


rahmadhany.triastanto@gmail.com

{
public function show(Question $question)
{
...
public function edit($id)
{
$question = Question::find($id);
public function edit(Question $question)
{
...
public function update($id, Question $question)
{
$question = Question::find($id);
public function update(UpdateQuestionRequest $request, Question $question)
{
...
public function destroy($id)
{
$question = Question::find($id);
public function destroy(Question $question)
{
...

3. Menggunakan Route Resource


Sebelumnya, telah didefinisikan route yang digunakan CRUD
Question satu per satu untuk masing-masing action. Selain itu,
Laravel menyediakan resource routing untuk mempersingkat
registrasi route. Resource routing meng-assign CRUD route ke
dalam sebuah controller dalam satu baris kode. Berikut adalah
action yang di-handle oleh resource routing:

Verb URI Action Route Name

GET /questions index questions.index

GET /questions/create create questions.create

POST /questions store questions.store

GET /questions/{photo} show questions.show

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 64


rahmadhany.triastanto@gmail.com

GET /questions/{photo} edit questions.edit


/edit

PUT/PATCH /questions/{photo} update questions.update

DELETE /questions/{photo} destroy questions.destroy

Untuk menggunakan resource routing, ganti baris yang telah


dibuat pada route file web.php, dengan mengubah kode:
...
Route::get('questions', 'QuestionController@index')->name('questions.index');
Route::get('questions/create', 'QuestionController@create')->name('questions.create');
Route::post('questions', 'QuestionController@store')->name('questions.store');

Route::get('questions/{id}/edit', 'QuestionController@edit')->name('questions.edit');
Route::put('questions/{id}', 'QuestionController@update')->name('questions.update');
Route::delete('questions/{id}', 'QuestionController@destroy')-
>name('questions.destroy');

Route::resource('questions', 'PhotoController')->except(['show']);

Dengan menggunakan kode ini, route didefinisikan secara partial


route resource dimana semua resource route dibuat kecuali untuk
show. Sehingga route yang jumlahnya enam baris menjadi hanya
satu baris.

4. Reusable form dengan Laravel Collective


Untuk menyederhanakan dan mempercepat pembuatan HTML Form
element, package Laravel Collective menyediakan sintaks yang
lebih terstruktur dan mudah dibaca. Untuk menggunakan package
ini, install menggunakan composer (tetapi pada buku ini telah
dilakukan pada tahap sebelumnya) pada terminal:
composer require laravelcollective/html

Pada CRUD Question, ada dua view yaitu questions.create dan


questions.edit yang hampir sama isi elemen form-nya. Dengan

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 65


rahmadhany.triastanto@gmail.com

menggunakan Laravel Collective dan fitur Form model binding,


kedua form tersebut dapat diringkas dengan membuat elemen
tersebut menjadi reusable pada view questions.create dan view
questions.edit.

Untuk membuat form reusable, Buat blade baru yaitu


_form.blade.php di folder resources/views/questions:
@if (isset($question))
{!! Form::model($question, [
'route' => [ 'questions.update', 'id' => $question->id ],
'method' => 'put',
'id' => 'question-form'
]) !!}
@else
{!! Form::open([ 'route' => 'questions.store',
'method' => 'POST',
'id' => 'question-form'
]) !!}
@endif

<div class="form-group">
{!! Form::label('text', 'Text') !!}
{!! Form::text('text', null, [
'class' => 'form-control' . ($errors->has('text')?' is-invalid':''),
'id' => 'text',
'placeholder' => 'Enter question text'
]) !!}
<div class="invalid-feedback"> {{ $errors->first('text') }} </div>
</div>

{!! Form::label(null, 'Choices of answer') !!}


@foreach (range('a','e') as $alphabet)
<div class="form-group">
{!! Form::text( $alphabet, null, [
'class' => 'form-control' . ($errors->has($alphabet)?' is-invalid':''),
'id' => $alphabet,
'placeholder' => "Enter choice for " . $alphabet
] ) !!}
<div class="invalid-feedback"> {{ $errors->first($alphabet) }} </div>
</div>
@endforeach

<div class="form-group">
{!! Form::label(null, 'Answer') !!}

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 66


rahmadhany.triastanto@gmail.com

<div>
@foreach (range('a','e') as $alphabet)
<div class="form-check form-check-inline">
{!! Form::radio('answer', $alphabet,
($alphabet == old('answer')? true:false), [
'class' => 'form-check-input' . ($errors->has('answer')?' is-
invalid':''),
'id' => 'inlineRadio' . $alphabet
]) !!}
<label class="form-check-label" for="inlineRadio{{ $alphabet }}">
{{ $alphabet }}
</label>
</div>
@endforeach
</div>
</div>

<div class="btn-group mb-3" role="group">


@if (isset($question))
<input class="btn btn-primary" type="submit" value="Edit">
@else
<input class="btn btn-primary" type="submit" value="Submit">
<input class="btn btn-success" type="button" value="Reset"
onclick="document.getElementById('question-form').reset();">
@endif
</div>
{{ Form::close() }}

Penjelasan kode:

• Kode Form::model() digunakan untuk membuka html form dan


mempopulasi elemen di dalam form berdasarkan model yang
telah di-passing. Fitur ini dinamakan Form Model Binding.
Kode ini secara otomatis menambahkan hidden token field CSRF.
• Kode Form::open() digunakan untuk membuka html form tanpa
model yang di-passing. Kode ini secara otomatis menambahkan
hidden token field CSRF.
• Kode Form::label(), Form::text(), dan Form::radio() masing-
masing digunakan untuk membuat element html label, input
text, dan input radio.

Kemudian ubah view questions.create agar menggunakan form

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 67


rahmadhany.triastanto@gmail.com

yang telah dibuat di atas:


@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Add Question</div>
<div class="card-body">
@include('questions._form')
</div>
</div>
</div>
</div>
@endsection

Dan ubah kode untuk questions.edit:


@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Edit Question (ID: {{ $question->id }})</div>
<div class="card-body">
@include('questions._form')
</div>
</div>
</div>
</div>
@endsection

5. Menggunakan Query Scope


Query scope adalah fitur untuk menambah constraint pada sebuah
model. Dengan query scope, constraint menjadi reusable di dalam
aplikasi. Ada dua macan query scope yaitu global scope dan local
scope dimana global scope menerapkan constraint yang selalu
dijalakan pada semua query yang dilakukan di dalam model
sedangkan local scope didefinisikan sebagai common set of
constraint yang bersifat reusable.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 68


rahmadhany.triastanto@gmail.com

Untuk menerapkan local scope, definisikan scope pada model


Question:
...
public function scopeSearchKeywordLike($query, $k)
{
$query->where('text', 'like', '%' . $k .'%')
->orWhere('a', 'like', '%' . $k .'%')
->orWhere('b', 'like', '%' . $k .'%')
->orWhere('c', 'like', '%' . $k .'%')
->orWhere('d', 'like', '%' . $k .'%')
->orWhere('e', 'like', '%' . $k .'%');
}
...

Penjelasan kode:

• Untuk mendefiniskan scope, buat public function dengan


konvensi nama yang diawali scope. Contoh:

public function scopeSearchKeywordLike($query, $k)

secara otomatis, Laravel akan meresolusi scope agar dapat


diakses melalui:

Question::searchKeywordLike($k)

Kemudian, Pada CRUD Question khususnya controller index


Question, ubah kode pada function index() agar dapat menerapkan
local scope searchKeywordLike():
...
public function index(Request $request)
{
...
$paginated = Question::where('text', 'like', '%' . $keyword .'%')
->orWhere('a', 'like', '%' . $keyword .'%')
->orWhere('b', 'like', '%' . $keyword .'%')
->orWhere('c', 'like', '%' . $keyword .'%')
->orWhere('d', 'like', '%' . $keyword .'%')
->orWhere('e', 'like', '%' . $keyword .'%')
->paginate();
$paginated = Question::searchKeywordLike($keyword)
->paginate();
...

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 69


rahmadhany.triastanto@gmail.com

}
...

6. Menggunakan metode Mass Assignment


Selain metode penyimpanan save() yang secara eksplit mengisi
atribut/kolom model satu per satu, Laravel menyediakan metode
Mass Assigment untuk melakukan create atau update hanya dalam
satu baris kode dengan mengirimkan key value pair HTTP request.
Dengan menggunakan metode ini, proses penyimpanan record
pada tabel harus mendefinisikan atribut $fillable atau $guarded
karena secara default, Eloquent memproteksi semua kolom.

Untuk menggunakan metode mass assignment pada model


Question, tambahkan atribute fillable:
class Question extends Model
{
protected $fillable = ['text', 'a', 'b', 'c', 'd', 'e', 'answer'];
...
}

Kemudian ganti kode QuestionController.php pada function store():


...
$question = New Question;
$question->text = $request->input('text');
$question->a = $request->input('a');
$question->b = $request->input('b');
$question->c = $request->input('c');
$question->d = $request->input('d');
$question->e = $request->input('e');
$question->answer = $request->input('answer');
$question->save();
$question = Question::create($request->all());
...

Dan ganti kode QuestionController.php pada function update():


...
$question->text = $request->input('text');
$question->a = $request->input('a');
$question->b = $request->input('b');

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 70


rahmadhany.triastanto@gmail.com

$question->c = $request->input('c');
$question->d = $request->input('d');
$question->e = $request->input('e');
$question->answer = $request->input('answer');
$question->save();
$question->update($request->all());

...

7. Mengode ekspor menjadi Excel


Package Laravel Excel adalah library yang dibuat berdasarkan
package PHPSpreadsheet dengan tujuan untuk mempermudah
proses ekspor maupun import file excel.

Untuk menambah fitur Ekspor menjadi Excel, buat class Export


pada terminal:
php artisan make:export QuestionsExport --model=Question

dan akan terbuat file QuestionsExport.php di app/Exports:


<?php

namespace App\Exports;

use App\Question;
use Maatwebsite\Excel\Concerns\FromCollection;

class QuestionsExport implements FromCollection


{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return Question::all();
}
}

Kemudian tambahkan pada QuestionController.php fungsi excel():


use App\Exports\QuestionsExport;
use Maatwebsite\Excel\Facades\Excel;
...

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 71


rahmadhany.triastanto@gmail.com

public function excel()


{
return Excel::download(new QuestionsExport,
'questions-' . date('YmdHis') . '.xlsx');
}
...

Terakhir tambahkan route pada file web.php:


...
Route::get('questions/export/excel', 'QuestionController@excel');

Setelah berhasil maka hasil ekspor menjadi Excel adalah sebagai


berikut:

Gambar 23 Hasil Ekspor menjadi Excel

8. Mengode ekspor menjadi PDF


Package DOMPDF Wrapper for Laravel adalah library yang dibuat
berdasarkan package DOMPDF dengan tujuan untuk melakukan
eksport PDF untuk HTML layout yang memenuhi aturan CSS 2.1.
Untuk menambah fitur Ekspor menjadi PDF, tambahkan fungsi pdf()

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 72


rahmadhany.triastanto@gmail.com

pada QuestionController.php:
use PDF;
...
public function pdf()
{
$data = Question::all();
$pdf = PDF::loadView('questions._pdf', compact('data'));
return $pdf->download('questions-' . date('YmdHis') . '.pdf');
}
...

Buat view questions._pdf untuk mengatur tampilan pdf yang akan


dibuat:
<h1>Questions</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>Text</th>
<th>a</th>
<th>b</th>
<th>c</th>
<th>d</th>
<th>e</th>
<th>Answer</th>
</tr>
</thead>
<tbody>
@foreach($data as $question)
<tr>
<th>{{ $question->id }}</th>
<th>{{ $question->text }}</th>
<th>{{ $question->a }}</th>
<th>{{ $question->b }}</th>
<th>{{ $question->c }}</th>
<th>{{ $question->d }}</th>
<th>{{ $question->e }}</th>
<th>{{ $question->answer }}</th>
</tr>
@endforeach
</tbody>
</table>

Terakhir tambahkan route pada web.php:


...
Route::get('questions/export/pdf', 'QuestionController@pdf');

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 73


rahmadhany.triastanto@gmail.com

Ini adalah hasil ekspor ke PDF:

Gambar 24 Hasil Ekspor menjadi PDF

c. Membuat CRUD Examination

Untuk membuat CRUD Examination, langkah yang ditempuh sama


seperti pembahasan sebelumnya, dimulai dari pembuatan model,
controller, form request, view, dan konfigurasi route. Pembuatan
CRUD akan memanfaatkan Laravel Collective HTML, metode Mass
Assigment, route resource, dan Query Scope.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 74


rahmadhany.triastanto@gmail.com

1. Mengode model, controller, dan form request


Examination
Buat controller, model, dan form request untuk Examination:
php artisan make:controller ExaminationController --resource
php artisan make:model Examination
php artisan make:request StoreExaminationRequest
php artisan make:request UpdateExaminationRequest

Ubah kode pada model Examination:


class Examination extends Model
{
protected $fillable = ['name', 'updated_by', 'start', 'duration'];

public function scopeSearchKeywordLike($query, $k)


{
$query->where('name', 'like', '%' . $k . '%')
->orWhere('start', 'like', '%' . $k . '%')
->orWhere('duration', 'like', '%' . $k . '%');
}
}

Ubah kode pada controller Examination menjadi seperti di bawah:


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Examination;
use App\Http\Requests\StoreExaminationRequest;
use App\Http\Requests\UpdateExaminationRequest;
use Illuminate\Support\Facades\Auth;

class ExaminationController extends Controller


{
public function index(Request $request)
{
$keyword = $request->input('keyword');

if(is_null($keyword))
$paginated = Examination::paginate();
else {
$paginated = Examination::searchKeywordLike($keyword)
->paginate();

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 75


rahmadhany.triastanto@gmail.com

$paginated->appends($request->only('keyword'));
}

return view('examinations.index', compact('paginated', 'keyword' ));


}

public function create()


{
return view('examinations.create');
}

public function store(StoreExaminationRequest $request)


{
$examination = Examination::create($request->all()
+ ['updated_by' => Auth::id()]);

return redirect()
->route('examinations.index')
->with('flash_notification', [
'level' => 'success',
'message' => 'Berhasil menyimpan Examination! (ID: '
. $examination->id . ')'
]);
}

public function show(Examination $examination)


{
//
}

public function edit(Examination $examination)


{
return view('examinations.edit', compact('examination'));
}

public function update(UpdateExaminationRequest $request, Examination $examination)


{
$examination->update($request->all()
+ ['updated_by' => Auth::id()]);

return redirect()
->route('examinations.index')
->with('flash_notification', [
'level' => 'success',
'message' => 'Berhasil mengubah Examination! (ID: '
. $examination->id . ')'
]);

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 76


rahmadhany.triastanto@gmail.com

public function destroy(Examination $examination)


{
$examination->delete();

return redirect()
->route('examinations.index')
->with('flash_notification', [
'level' => 'warning',
'message' => 'Berhasil menghapus Examination! (ID: '
. $examination->id . ')'
]);
}
}

Penjelasan kode:

• Kode Auth::id() pada function store() dan function update()


digunakan untuk mengembalikan id dari user yang telah login
ke dalam Pustarel.

Tambahkan kode berikut pada StoreExaminationRequest.php:


<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreExaminationRequest extends FormRequest


{
public function authorize()
{
return false;
return true;
}

public function rules()


{
return [
];
return [
'name' => 'required',
'start' => 'required|date',
'duration' => 'required|numeric'
];

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 77


rahmadhany.triastanto@gmail.com

}
}

Tambahkan kode berikut pada UpdateExaminationRequest.php:


<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UpdateExaminationRequest extends FormRequest


{
public function authorize()
{
return false;
return true;
}

public function rules()


{
return [
];
return [
'name' => 'required',
'start' => 'required|date',
'duration' => 'required|numeric'
];
}
}

2. Mengode route & view Examination


Buat dan ketik kode berikut untuk view examinations.index:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Examination</div>
<div class="card-body">
@include('layouts._flash')
<div class="mb-3">
<div class="d-inline p-2 float-lg-left">
<div class="btn-group mb-3" role="group">
<a href="{{ route('examinations.create') }}"

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 78


rahmadhany.triastanto@gmail.com

class="btn btn-primary">Add</a>
</div>
</div>
<div class="d-inline p-2 float-lg-right">
<form action="{{ route('examinations.index') }}"
method="GET">
<div class="btn-group mb-3" role="group">
<input class="form-control mr-sm-2"
type="search"
placeholder="Search"
name="keyword"
value="{{ $keyword }}">
<button class="btn btn-success" type="submit">
Search
</button>
</div>
</form>
</div>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Start</th>
<th scope="col">Duration</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach ($paginated as $question)
<tr>
<th scope="row">{{ $question->id }}</th>
<td> {{ $question->name }} </td>
<td>{{ $question->start }}</td>
<td>{{ $question->duration }}</td>
<td>
<a href="{{ route('examinations.edit', ['id' =>
$question->id]) }}"
class="btn btn-sm btn-light">
<i class="fa fa-edit"></i>
</a>
<form action="{{ route('examinations.destroy', ['id'
=> $question->id]) }}"
method="POST">
@method('DELETE')
{{ csrf_field() }}
<button type="submit" value="x"

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 79


rahmadhany.triastanto@gmail.com

class="btn btn-sm btn-light">


<i class="fa fa-trash-alt"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="mx-auto">
{{ $paginated->links() }}
</div>
</div>
</div>
</div>
</div>
@endsection

Buat dan ketik kode berikut untuk view examinations.create:


@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Add Examination</div>
<div class="card-body">
@include('examinations._form')
</div>
</div>
</div>
</div>
@endsection

Buat dan ketik kode berikut untuk view examinations.edit:


@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Edit Examination (ID: {{ $examination->id
}})</div>
<div class="card-body">
@include('examinations._form')
</div>
</div>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 80


rahmadhany.triastanto@gmail.com

</div>
</div>
@endsection

Buat dan ketik kode berikut untuk view examinations._form:


@if (isset($examination))
{!! Form::model($examination, [
'route' => [ 'examinations.update', 'id' => $examination->id ],
'method' => 'put',
'id' => 'examination-form'
])
!!}
@else
{!! Form::open([
'route' => 'examinations.store',
'method' => 'POST',
'id' => 'examination-form'
]) !!}
@endif

<div class="form-group">
{!! Form::label('name', 'Text') !!}
{!! Form::text('name', null, [
'class' => 'form-control' . ($errors->has('name')?' is-invalid':''),
'id' => 'name',
'placeholder' => 'Enter examination name'
]) !!}
<div class="invalid-feedback"> {{ $errors->first('name') }} </div>
</div>

<div class="form-group">
{!! Form::label('start', 'Start') !!}
{!! Form::text('start', null, [
'class' => 'form-control' . ($errors->has('start')?' is-invalid':''),
'id' => 'start',
'placeholder' => 'Enter examination start (Y-m-d H:i:s)'
]) !!}
<div class="invalid-feedback">{{ $errors->first('start') }}</div>
</div>

<div class="form-group">
{!! Form::label('duration', 'Duration') !!}
{!! Form::text('duration', null, [
'class' => 'form-control' . ($errors->has('duration')?' is-invalid':''),
'id' => 'name',
'placeholder' => 'Enter examination duration (number only)'
]) !!}
<div class="invalid-feedback">{{ $errors->first('duration') }}</div>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 81


rahmadhany.triastanto@gmail.com

</div>

<div class="btn-group mb-3" role="group">


@if (isset($examination))
<input class="btn btn-primary" type="submit" value="Edit">
@else
<input class="btn btn-primary" type="submit" value="Submit">
<input class="btn btn-success" type="button" value="Reset"
onclick="document.getElementById('examination-form').reset();">
@endif
</div>
{{ Form::close() }}

Tambahkan kode berikut ke dalam file web.php:


...
Route::resource('examinations', 'ExaminationController')->except(['show']);

Apabila kita coba untuk melakukan create Examination tanpa


melakukan login maka akan muncul error seperti ini:

Gambar 25 Error karena kolom updated_by diisi dengan null

Oleh karena itu, kita perlu mekanisme proteksi halaman bahwa


yang boleh melakukan create examination harus login.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 82


rahmadhany.triastanto@gmail.com

3. Memasang Middleware auth


Middleware adalah mekanisme penyaringan HTTP request sebelum
& sesudah memasuki aplikasi. Misalnya, Laravel menyediakan
middleware yang berfungsi untuk memverifikasi bahwa user
teregistrasi sudah melakukan login. Jika user belum login, maka
middleware akan me-redirect user tersebut ke halaman login dan
sebaliknya apabila user telah login, maka middleware akan
mengizikan request untuk melalui proses selanjutnya di dalam
aplikasi.

Tentunya, middleware dapat dibuat untuk menangani kegitan


lainya selain autentikasi. CORS middleware, logging middleware,
CSRF middleware, throttle middleware adalah pre-built
middleware dimana seluruh middleware tersebut disimpan di
folder app/Http/Middlware.

Sehingga untuk memastikan hanya user yang telah login yang


dapat melakukan CRUD Examination, tambahkan middleware auth:
Route::get('/home', 'HomeController@index')->name('home');
...
Route::get('/home', 'HomeController@index')
->name('home')
->middleware('auth');
...

d. Menyempurnakan CRUD Examination


1. Mendefinisikan one-to-many relationship
One-to-many relationship digunakan untuk mendefinisikan

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 83


rahmadhany.triastanto@gmail.com

hubungan dua table dimana satu record pada sebuah model dapat
memiliki satu atau lebih record pada model lainnya. Pada desain
Pustarel, satu record users dapat memiliki satu atau lebih record
examinations.

Gambar 26 One-to-many relationship antara users dan examinations

Di dalam Pustarel, untuk mendefinisikan one-to-many


relationship yang disebutkan di atas, perlu dilakukan definisi
function pada model User dan Examination.

Tambahkan kode ini untuk model User:


...
class User extends Authenticatable
{
...
public function examinations()
{
return $this->hasMany('App\Examination', 'updated_by');
}
}
...

Tambahkan kode ini untuk model Examination:


...
class Examination extends Model
{
...

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 84


rahmadhany.triastanto@gmail.com

public function user()


{
return $this->belongsTo('App\User', 'updated_by');
}
}

Pada model User, untuk mendefinisikan hubungan satu record


users memiliki banyak record examinations dilakukan dengan cara
deklarasi function examinations() dimana didalamnya
menggunakan function hasMany() dengan parameter pertama
adalah nama model yang direlasikan yaitu ‘App\Examination’ dan
parameter kedua adalah foreign key di table examinations, yaitu
updated_by.

Pada Model Examination, untuk mendefinisikan inversi dari


hubungan di atas, dilakukan dengan cara deklarasi function user()
dimana di dalamnya menggunakan function belongsTo() dengan
parameter pertama adalah nama model yang direlasikan yaitu
‘App\User’ dan parameter kedua adalah foreign yang terdapat di
tabel examinations, yaitu updated_by.

Ketik perintah baris bercetak tebal pada tinker:


>>> $e = User::find(3);
=> App\User {#2983
id: 3,
name: "Lecturer",
email: "lecturer@pustarel.test",
email_verified_at: null,
created_at: "2018-11-20 00:46:44",
updated_at: "2018-11-20 00:46:44",
}
>>> $e->examinations;
=> Illuminate\Database\Eloquent\Collection {#3133
all: [
App\Examination {#3132
id: 1,
name: "Vero aliquid alias labore.",
updated_by: 3,

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 85


rahmadhany.triastanto@gmail.com

start: "1984-01-11 00:00:00",


duration: 100,
created_at: "2018-12-01 22:43:21",
updated_at: "2018-12-01 22:43:21",
},
App\Examination {#3131
id: 2,
name: "Molestiae non autem autem aliquam perferendis fuga.",
updated_by: 3,
start: "1986-10-28 00:00:00",
duration: 91,
created_at: "2018-12-01 22:43:21",
updated_at: "2018-12-01 22:43:21",
},
...

Pada contoh kode tinker yang ditulis di atas, ditunjukkan record


examinations mana saja yang dibuat oleh users dengan primary
key 3 dengan perintah $e = User::find(3) dan $e->examinations;.

2. Mendefinisikan many-to-many relationship


Many-to-many relationship digunakan untuk mendefinisikan
hubungan dua table dimana banyak record pada sebuah model
dapat memiliki satu atau lebih record pada model lainnya dan
begitu pula sebaliknya. Pada Pustarel, hubungan ini
direpresentasikan antara tabel examinations dan questions. dimana
satu record examinations dapat terdiri dari satu atau lebih record
questions dan sebaliknya satu record questions dapat berada di satu

atau lebih record examinations.

Untuk mendefinisikan hubungan ini, dibutuhkan pivot tabel yang


menyimpan pasangan foreign key masing-masing tabel yang
berelasi. Eloquent memiliki konvensi penamaan ketiga tabel ini,
misalnya questions, examinations, dan examination_question dimana
penamaan pivot table diturunkan dari hasil penggabungan nama

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 86


rahmadhany.triastanto@gmail.com

kedua tabel yang yang berelasi dalam bentuk singular noun


dipisahkan dengan karakter _.

Gambar 27 Many-to-many relationship antara questions dan examinations

Tambahkan kode ini pada model Examination:


...
class Examination extends Model
{
...
public function questions()
{
return $this->belongsToMany('App\Question')
->withTimestamps();
}
}

Tambahkan kode ini pada model Question:


...
class Question extends Model
{
...
public function examinations()
{
return $this->belongsToMany('App\Examination')
->withTimestamps();
}
}

Pada model Examination, untuk mendefinisikan hubungan satu

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 87


rahmadhany.triastanto@gmail.com

record examinations memiliki banyak record questions dilakukan


dengan cara deklarasi function questions() dimana didalamnya
menggunakan function belongsToMany() dengan parameter pertama
adalah nama model yang direlasikan yaitu ‘App\Question’.

Pada Model Question, untuk mendefinisikan inversi dari hubungan


di atas, dilakukan dengan cara deklarasi function examinations()
dimana di dalamnya menggunakan function belongsToMany()
dengan parameter pertama adalah nama model yang direlasikan
yaitu ‘App\Examination’.

Ketik perintah baris bercetak tebal pada tinker:


>>> $e = Examination::find(1);
[!] Aliasing 'Examination' to 'App\Examination' for this Tinker session.
=> App\Examination {#2972
id: 1,
name: "Vero aliquid alias labore.",
updated_by: 3,
start: "1984-01-11 00:00:00",
duration: 100,
created_at: "2018-12-01 22:43:21",
updated_at: "2018-12-01 22:43:21",
}
>>> $e->questions;
=> Illuminate\Database\Eloquent\Collection {#2976
all: [
App\Question {#2990
id: 1,
text: "Sed rerum nostrum qui sit nostrum quam unde aliquam officiis?",
a: "Deleniti impedit non.",
b: "Mollitia omnis nihil.",
c: "Aut nihil in.",
d: "Voluptatem vitae nobis sed.",
e: "Exercitationem vero excepturi.",
answer: "e",
created_at: "2018-12-01 22:43:21",
updated_at: "2018-12-01 22:43:21",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2989
examination_id: 1,
question_id: 1,
created_at: "2019-01-01 00:00:00",
updated_at: "2019-01-01 00:00:00",

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 88


rahmadhany.triastanto@gmail.com

},
},
App\Question {#2991
id: 2,
text: "Cumque id voluptatem consequatur quasi qui aliquid ratione magni
?",
a: "Tempora nulla explicabo consequuntur.",
b: "Reprehenderit laboriosam magnam.",
c: "Facilis animi itaque totam.",
d: "Rerum quia et.",
e: "Velit dicta dignissimos animi.",
answer: "b",
created_at: "2018-12-01 22:43:21",
updated_at: "2018-12-01 22:43:21",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2988
examination_id: 1,
question_id: 2,
created_at: "2019-01-01 00:00:00",
updated_at: "2019-01-01 00:00:00",
},
},
...

Pada contoh kode tinker yang ditulis di atas, ditunjukkan record


questions mana saja yang digunakan dalam examinations dengan
primary key 1 (dapat diartikan juga dalam satu ujian banyak soal).
Untuk mencari record tersebut digunakan kode $e =

Examination::find(1) dan untuk mencari record yang berelasi pada


tabel questions digunakan kode $e->questions.

Untuk menunjukkan record examinations mana saja yang


menggunakan questions dengan primary key 1 digunakan kode
$q->examinations setelah mencari record pada table questions pada
kode $q = Question::find(1).

Ketik kode bercetak tebal berikut pada tinker:


>>> $q = Question::find(1);
[!] Aliasing 'Question' to 'App\Question' for this Tinker session.
=> App\Question {#2977
id: 1,
text: "Sed rerum nostrum qui sit nostrum quam unde aliquam officiis?",
a: "Deleniti impedit non.",

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 89


rahmadhany.triastanto@gmail.com

b: "Mollitia omnis nihil.",


c: "Aut nihil in.",
d: "Voluptatem vitae nobis sed.",
e: "Exercitationem vero excepturi.",
answer: "e",
created_at: "2018-12-01 22:43:21",
updated_at: "2018-12-01 22:43:21",
}
>>> $q->examinations;
=> Illuminate\Database\Eloquent\Collection {#2998
all: [
App\Examination {#2974
id: 1,
name: "Vero aliquid alias labore.",
updated_by: 3,
start: "1984-01-11 00:00:00",
duration: 100,
created_at: "2018-12-01 22:43:21",
updated_at: "2018-12-01 22:43:21",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2986
question_id: 1,
examination_id: 1,
created_at: "2019-01-01 00:00:00",
updated_at: "2019-01-01 00:00:00",
},
},
],
}
>>>

Apabila diperhatikan, untuk mengakses record yang berelasi pada


jenis relationship ini, tidak diperlukan akses secara eksplisit
mengakses pivot table examination_question tetapi cukup dari
model yang berelasi saja misalnya $e->questions dan
$q->examinations.

3. Mengode pemasangan Question ke Examination


Setelah mendefinisikan one-to-many relationship pada model
Examination dan model Question, dapat dibuat halaman untuk
memasangkan antara record examinations dan record questions yang

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 90


rahmadhany.triastanto@gmail.com

disimpan dalam pivot table examination_question.

Tambahkan kode berikut pada ExaminationController.php untuk


melakukan attach() dan detach() pada pivot tabel
examination_question.

...
public function attachQuestion(AttachExaminationQuestionRequest $request,
Examination $examination)
{
$question = Question::find($request->input('question_id'));
$examination->questions()->attach($question);

return redirect()
->route('examinations.questions.index', ['id' => $examination->id])
->with('flash_notification', [
'level' => 'success',
'message' => sprintf('Berhasil memasang Question (ID:%u) '
. 'pada Examination (ID:%u)', $question->id, $examination->id)
]);
}

public function detachQuestion(DetachExaminationQuestionRequest $request,


Examination $examination)
{
$question = Question::find($request->input('question_id'));
$examination->questions()->detach($question);

return redirect()
->route('examinations.questions.index', ['id' => $examination->id])
->with('flash_notification', [
'level' => 'warning',
'message' => sprintf('Berhasil melepas Question (ID:%u) '
. 'dari Examination (ID:%u)', $question->id, $examination->id)
]);
}
...

Penjelasan kode:

• Kode attach() digunakan untuk memasang record questions


pada record examinations. Sehingga membuat record pada pivot
table examination_question dengan id yang berelasi.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 91


rahmadhany.triastanto@gmail.com

• Kode detach() digunakan untuk melepas record questions ari


record examinations. Sehingga akan menghapus record pada
pivot table examination_question dengan id yang berelasi.

Untuk melakukan validasi, buat dua form request pada terminal:


php artisan make:request AttachExaminationQuestionRequest
php artisan make:request DetachExaminationQuestionRequest

Ubah kode untuk AttachExaminationQuestionRequest.php:


...
use Illuminate\Validation\Rule;
...
public function authorize()
{
return false;
}
public function authorize()
{
return true;
}

...
public function rules()
{
return [];
}
public function rules()
{
// $this->examination == $this->route('examination')
return [
'question_id' => [
'required',
Rule::unique('examination_question')->where(function ($query){
$query->where('examination_id', $this->route('examination')->id);
})
],
];
}
...

Ubah kode untuk DetachExaminationQuestionRequest.php:


...
use Illuminate\Validation\Rule;
...
public function authorize()

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 92


rahmadhany.triastanto@gmail.com

{
return false;
}
public function authorize()
{
return true;
}
...
public function rules()
{
return [];
}
public function rules()
{
// $this->examination == $this->route('examination')
return [
'question_id' => [
'required',
Rule::exists('examination_question')->where(function ($query){
$query->where('examination_id', $this->route('examination')->id);
})
]
];
}
...

Penjelasan kode:

• Kode Rule::unique() adalah validation rule yang ditambahkan


additional where clause dimana akan memastikan tidak boleh
ada duplikasi record composite (gabungan) question_id dan
examination_id yang belum disimpan di pivot table
examination_question sebelum dilakukan attach(). Jika
ditemukan duplikasi record tersebut, maka akan muncul error.
• Kode Rule::exists() adalah validation rule yang ditambahkan
additional where clause dimana akan memastikan harus ada
record composite (gabungan) question_id dan examination_id
yang sudah disimpan di pivot table examination_question
sebelum dilakukan detach(). Jika tidak ditemukan record
tersebut, maka akan muncul error.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 93


rahmadhany.triastanto@gmail.com

Buat view examinations.questions dengan kode:


@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Question of Examination (ID:{{ $examination->id
}})</div>
<div class="card-body">
@include('layouts._flash')
<div class="mb-3">
<div class="list-group">
<a href="#" class="list-group-item list-group-item-action
flex-column align-items-start">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{ $examination->name }}</h5>
<small class="text-muted">{{ $examination->duration
}} minutes</small>
</div>
<small class="text-muted">Start at: {{ $examination-
>start }}</small>
</a>
</div>
{!! Form::open([
'route' => ['examinations.questions.attach', 'id' =>
$examination->id ],
'method' => 'POST',
]) !!}
{!! Form::hidden('examination_id', $examination->id ) !!}
<div class="p-2">
{!! Form::select(
'question_id',
$questions,
null,
[
'placeholder' => 'Select Question',
'class' => 'form-control' . ($errors-
>has('question_id')?' is-invalid':''),
]
) !!}
<div class="invalid-feedback">{{ $errors }}</div>
</div>
<div class="p-2">
{!! Form::submit('Attach', [ 'class' => 'btn btn-primary
btn-block' ]) !!}
</div>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 94


rahmadhany.triastanto@gmail.com

{!! Form::close() !!}


</div>
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Text &amp; Choices</th>
<th scope="col">Answer</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach ($examination->questions as $question)
<tr>
<th scope="row">{{ $question->id }}</th>
<td>
{{ $question->text }}
<ol type="a">
<li>{{ $question->a }}</li>
<li>{{ $question->b }}</li>
<li>{{ $question->c }}</li>
<li>{{ $question->d }}</li>
<li>{{ $question->e }}</li>
</ol>
</td>
<td>{{ $question->answer }}</td>
<td>
{!! Form::model($examination, [
'route' => [ 'examinations.questions.detach',
'id' => $examination->id ],
'method' => 'delete',
])
!!}
{!! Form::hidden('question_id', $question->id ) !!}
{!! Form::button(
'<i class="fa fa-trash-alt"></i>',
[
'class' => 'btn btn-sm btn-light',
'type' => 'submit'
])
!!}
{!! Form::close() !!}
</td>
</tr>
@endforeach
</tbody>
</table>
</div>

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 95


rahmadhany.triastanto@gmail.com

</div>
</div>
</div>
</div>
@endsection

Ubah kode pada view examinations.index menjadi:


...
<form action="{{ route('examinations.destroy', ['id' => $examination->id]) }}"
method="POST">
@method('DELETE')
{{ csrf_field() }}
<button type="submit" value="x"
class="btn btn-sm btn-light">
<i class="fa fa-trash-alt"></i>
</button>
</form>
{!! Form::open([
'route' => ['examinations.destroy', $examination->id],
'method' => 'delete'
]) !!}
{!! Form::button(
'<i class="fa fa-trash-alt"></i>',
[
'class' => 'btn btn-sm btn-light',
'type' => 'submit'
]
) !!}
{!! Form::close() !!}
<a href="{{ route('examinations.questions.index', ['id' => $examination->id]) }}"
class="btn btn-sm btn-light">
<i class="fas fa-question"></i>
</a>
...

Tambahkan kode pada route web.php:


...
Route::post('examinations/{examination}/questions',
'ExaminationController@attachQuestion')
->name('examinations.questions.attach');
Route::delete('examinations/{examination}/questions',
'ExaminationController@detachQuestion')
->name('examinations.questions.detach');

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 96


rahmadhany.triastanto@gmail.com

Gambar 28 View examinations.index dengan link questions yang berelasi

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 97


rahmadhany.triastanto@gmail.com

Gambar 29 View examinations.questions

Gambar 30 Melakukan attach() pada many-to-many relationship

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 98


rahmadhany.triastanto@gmail.com

Gambar 31 Melakukan detach() pada many-to-many relationship

Gambar 32 Validasi composite key pada pivot table examination_question

e. Konfigurasi Role Based Access Control


1. Mengganti laratrust menjadi laravel-permission
Terkadang di dalam proyek aplikasi web, diperlukan proses
perbaruan maupun penggantian package yang digunakan.
Composer sebagai php dependency manager, dapat melakukan

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 99


rahmadhany.triastanto@gmail.com

kegiatan tersebut dengan sangat mudah. Kali ini, package


santigarcor/laratrust yang sudah di-install pada tahap
sebelumnya akan diganti dengan package spatie/laravel-

permission.

Untuk melakukan penghapusan package yang sudah di-install


sebelumnya melalui composer khususnya package laratrust, ketik
perintah ini di terminal:
composer remove santigarcor/laratrust

Maka akan muncul tampilan seperti berikut:


Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 0 installs, 0 updates, 2 removals
- Removing santigarcor/laratrust (5.0.9)
- Removing kkszymanowski/traitor (0.2.5)
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: barryvdh/laravel-dompdf
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: laravelcollective/html
Discovered Package: maatwebsite/excel
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.

Composer secara otomatis akan menghapus package yang terdiri


package dependant beserta file-filenya di folder vendor.

2. Instalasi laravel-permission
Selain menyediakan layanan autentikasi (Authentication) secara
out of the box, Laravel juga menyediakan cara sederhana untuk
mengotorisasi (Authorization) tindakan pengguna terhadap
resource yang dilayani. Seperti halnya autentikasi, pendekatan

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 100


rahmadhany.triastanto@gmail.com

Laravel untuk otorisasi dilakukan dengan dua cara melalui Gates


dan Policy. Mekanisme ini bertujuan untuk mendefinisikan ability
(alias permission) dan proses pengecekannya di application logic
maupun blade template.

Adapun, package laravel-permission menyempurnakan mekanisme


tersebut dengan mengasosiasikan User model dengan roles dan
permissions. Roles dan permissions yang telah dikonfigurasi,
secara otomatis teregistrasi pada class Illuminate\Auth\Access\Gate.

Untuk melakukan instalasi laravel-permission ketik perintah pada


terminal:
composer require spatie/laravel-permission

Setelah berhasil di-install, lakukan konfigurasi publikasi


konfigurasi terkait file migrasi tabel yang diperlukan:

php artisan vendor:publish ⏎

--provider="Spatie\Permission\PermissionServiceProvider" ⏎
--tag="migrations"

Setelah berhasil dipublikasi dan dibuat file migrasi, jalankan


migrasi table:
php artisan migrate

Kemudian lakukan publikasi terkait package ini:


php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --
tag="config"

maka akan terbuat file permission.php di folder config sebagai


konfigurasi package laravel-permission. Dan berikut adalah
struktur table yang dibuat oleh package ini:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 101


rahmadhany.triastanto@gmail.com

Gambar 33 Desain tabel untuk package laravel-permission

Berikut adalah tabel yang dibuat oleh laravel-permission:

permissions: Meyimpan permission untuk Pustarel.

roles: Menyimpan role untuk Pustarel.

role_has_permission: Pivot table yang menyimpan informasi antara


permission table dan role table.

model_has_roles: Pivot table yang menyimpan informasi antara role


table dan user table (atau model lainnya yang dipilih).

model_has_permissions: Pivot table yang menyimpan informasi


antara user table dan permission table (atau model lainnya yang
dipilih).

3. Menambahkan hasRole Trait


Untuk menggunakan laravel-permission dengan model User,
tambahkan HasRole trait:
...
use Spatie\Permission\Traits\HasRoles;

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 102


rahmadhany.triastanto@gmail.com

class User extends Authenticatable


{
...
use HasRoles;
...

Kode ini berfungsi untuk mengijinkan model User berasosiasi


dengan permissions dan roles. Setiap role diasosikan dengan
beberapa permissions dimana keduanya direpresentasikan oleh
model.

4. Membuat seed untuk mengisi Role & Permission


Untuk membuat role dan permission untuk Pustarel, ubah kode
pada RolesAndPermissionsSeeder.php:
<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RolesAndPermissionsSeeder extends Seeder


{
public function run()
{
// Reset cached roles and permissions
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

Permission::create(['name' => 'browse questions']);


Permission::create(['name' => 'create questions']);
Permission::create(['name' => 'edit questions']);
Permission::create(['name' => 'delete questions']);

Permission::create(['name' => 'browse examinations']);


Permission::create(['name' => 'create examinations']);
Permission::create(['name' => 'edit examinations']);
Permission::create(['name' => 'delete examinations']);

Permission::create(['name' => 'take examinations']);

Permission::create(['name' => 'browse results']);

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 103


rahmadhany.triastanto@gmail.com

$role = Role::create(['name' => 'lecturer'])


->givePermissionTo([
'browse questions',
'create questions',
'edit questions',
'delete questions',
]);

$role->givePermissionTo([
'browse examinations',
'create examinations',
'edit examinations',
'delete examinations',
]);

$role->givePermissionTo('browse results');

$role = Role::create(['name' => 'student'])


->givePermissionTo('take examinations', 'browse results');
}
}

Ubah juga kode di dalam file DatabaseSeeder.php dengan kode:


...
public function run()
{
// $this->call(QuestionsTableSeeder::class);
$this->call(RolesAndPermissionsSeeder::class);
}
...

Untuk menjalankan seeder, ketik perintah di terminal:


php artisan db:seed

Maka seeder akan mengisi table permissions dan roles sesuai yang
disebutkan di atas.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 104


rahmadhany.triastanto@gmail.com

Gambar 34 Permissions untuk Pustarel

Gambar 35 Roles untuk Pustarel

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 105


rahmadhany.triastanto@gmail.com

Gambar 36 Pivot table antara permissions & roles

5. Menugaskan Role kepada User


Agar user lecturer & student yang sudah diregistrasi pada bagian
sebelumnya memiliki roles & permissions yang sesuai, perlu
dilakukan penugasan roles lecturer dan student via tinker (ketik
baris dengan font bold):
>>> $lecturer = User::where('name', 'Lecturer')->first();
[!] Aliasing 'User' to 'App\User' for this Tinker session.
=> App\User {#2969
id: 3,
name: "Lecturer",
email: "lecturer@pustarel.test",
email_verified_at: null,
created_at: "2018-11-20 00:46:44",
updated_at: "2018-11-20 00:46:44",
}
>>> $lecturer->assignRole('lecturer');
=> App\User {#2969
id: 3,
name: "Lecturer",
email: "lecturer@pustarel.test",
email_verified_at: null,
created_at: "2018-11-20 00:46:44",

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 106


rahmadhany.triastanto@gmail.com

updated_at: "2018-11-20 00:46:44",


roles: Illuminate\Database\Eloquent\Collection {#2997
all: [
Spatie\Permission\Models\Role {#2996
id: 1,
name: "lecturer",
guard_name: "web",
created_at: "2018-11-30 14:06:32",
updated_at: "2018-11-30 14:06:32",
pivot: Illuminate\Database\Eloquent\Relations\MorphPivot {#2998
model_id: 3,
role_id: 1,
model_type: "App\User",
},
},
],
},
}
>>> $student = User::where('name', 'Student')->first();
[!] Aliasing 'User' to 'App\User' for this Tinker session.
=> App\User {#2969
id: 2,
name: "Student",
email: "student@pustarel.test",
email_verified_at: null,
created_at: "2018-11-20 00:46:21",
updated_at: "2018-11-20 00:46:21",
}
>>> $student->assignRole('student');
=> App\User {#2969
id: 2,
name: "Student",
email: "student@pustarel.test",
email_verified_at: null,
created_at: "2018-11-20 00:46:21",
updated_at: "2018-11-20 00:46:21",
roles: Illuminate\Database\Eloquent\Collection {#2997
all: [
Spatie\Permission\Models\Role {#2996
id: 2,
name: "student",
guard_name: "web",
created_at: "2018-11-30 14:06:32",
updated_at: "2018-11-30 14:06:32",
pivot: Illuminate\Database\Eloquent\Relations\MorphPivot {#2998
model_id: 2,
role_id: 2,
model_type: "App\User",

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 107


rahmadhany.triastanto@gmail.com

},
},
],
},
}

6. Memasang middleware di route


Package laravel-permission menyediakan Rolemiddleware,
PermissionMiddleware, RoleOrOermissionMiddleware untuk
menyaring HTTP Request berdasarkan role, permission maupun
role or permission.

Untuk melakukan registrasi middleware diatas, tambahkan


definisi name dan class pada variable $routeMiddleware. Tambahkan
kode ini pada file Kernel.php di folder app/Http:
protected $routeMiddleware = [
...
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
'role_or_permission' =>
\Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
];

Setelah melakukan registrasi, middleware perlu dipasang agar


dapat melakukan penyaringan HTTP request. Ada 3 (tiga) cara untuk
memasang middleware yaitu global middleware, route
middleware, dan controller middleware. Global middleware
melakukan penyaringan pada semua HTTP request, Route
middleware melakukan penyaringan berdasarkan registrasi route,
dan controller middleware melakukan penyaringan berdasarkan
controller.

Kali ini akan menggunakan route middle untuk menyaring


berdasarkan auth middleware role middleware, dan permission
middleware. Ubah route pada web.php menjadi:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 108


rahmadhany.triastanto@gmail.com

...
Route::resource('questions', 'QuestionController')->except(['show']);
Route::get('questions/export/excel', 'QuestionController@excel');
Route::get('questions/export/pdf', 'QuestionController@pdf');
Route::resource('examinations', 'ExaminationController')->except(['show']);
Route::post('examinations/{examination}/questions',
'ExaminationController@attachQuestion')
->name('examinations.questions.attach');
Route::delete('examinations/{examination}/questions',
'ExaminationController@detachQuestion')
->name('examinations.questions.detach');

Route::group(['middleware' => ['auth', 'role:lecturer']], function(){


Route::resource('questions', 'QuestionController')->except(['show']);
Route::get('questions/export/excel', 'QuestionController@excel');
Route::get('questions/export/pdf', 'QuestionController@pdf');
Route::resource('examinations', 'ExaminationController')->except(['show']);
Route::post('examinations/{examination}/questions',
'ExaminationController@attachQuestion')
->name('examinations.questions.attach');
Route::delete('examinations/{examination}/questions',
'ExaminationController@detachQuestion')
->name('examinations.questions.detach');

});

Penjelasan kode:

• Kode Route::group() menambahkan route attribute di dalam


sebuah grup seperti middleware dan namespaces.
• Group route ini menggunakan middleware auth dan
role:lecturer.

7. Mencoba 403 Forbidden


Setelah konfigurasi role dan permission sudah dilakukan, coba
untuk login sebagai student dan buka route question.index (misal:
http://pustarel.test/questions) dan akan muncul halaman 403
forbidden bahwa student tidak memiliki role untuk mengakses
halaman ini.

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 109


rahmadhany.triastanto@gmail.com

Gambar 37 Student tidak memiliki role untuk dapat mengakses halaman questions

8. Menyesuaikan view sesuai Role & Permission


Selain membatasi akses secara route/url, halaman Question &
Examination seharusnya tidak boleh tampil pada halaman home
student tetapi tampil pada halaman home lecturer. Selain itu,
hanya role student yang boleh melakukan take examination bukan
role lecturer. Namun, untuk permissions browse results bisa diakses
oleh lecturer maupun student.

Untuk menyesuaikan view halaman home, ubah kode view


layouts.app:

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 110


rahmadhany.triastanto@gmail.com

...
<ul class="navbar-nav mr-auto">

</ul>

<ul class="navbar-nav mr-auto">


@auth

@role('lecturer')
<li class="nav-item">
<a class="nav-link" href="{{ route('questions.index') }}">{{ __('Question')
}}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('examinations.index') }}">{{
__('Examination') }}</a>
</li>
@endrole

@role('student')
<li class="nav-item">
<a class="nav-link" href="">{{ __('Take Examination') }}</a>
</li>
@endrole

@can('browse results')
<li class="nav-item">
<a class="nav-link" href="">{{ __('Browse Results') }}</a>
</li>
@endcan

@endauth
</ul>
...

Penjelasan kode:

• Kode @auth @endauth memeriksa apakah user sudah login ke


dalam Pustarel.
• Kode @role(‘lecturer’) @endrole memeriksa apakah user yang
sudah login memiliki role lecturer.
• Kode @role(‘student’) @endrole memeriksa apakah user yang
sudah login memiliki role student.
• Kode @can(‘browse results’) @endcan memeriksa apakah user

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 111


rahmadhany.triastanto@gmail.com

yang sudah login memiliki permission browse results.

III. Hari ke-3: Segera terbit!

IV. Penutup: Segera Terbit!

3 HARI JADI APLIKASI DENGAN LARAVEL 5.7 112

Anda mungkin juga menyukai