Laraveler


Membuat Aplikasi Laravel 5 MVC Dasar

Aplikasi Laravel mengikuti pola desain Model-View-Controller tradisional , di mana Anda menggunakan:

✓ Controller untuk menangani permintaan pengguna dan mengambil data, dengan memanfaatkan Model
✓ Model untuk berinteraksi dengan database Anda dan mengambil informasi objek Anda
✓ View untuk merender halaman

Permintaan dibuat - misalnya, ketika pengguna memasukkan URL yang terkait dengan aplikasi Anda.
Sebuah rute yang berhubungan dengan URL yang memetakan URL untuk aksi kontroler.
Itu kontroler tindakan memanfaatkan diperlukan Model (s) untuk mengambil informasi dari database, dan kemudian melewati data yang off untuk tampilan.
Dan pandangan itu menampilkan halaman akhir.

Saya suka mengatakan bahwa aplikasi MVC sangat mirip bermain dengan Lego .

Dan membangun satu menggunakan Laravel 5 sangat mudah.

Membangun aplikasi sampel
Demi demonstrasi, saya akan memandu Anda melalui proses pembuatan awal contoh aplikasi Laravel 5 dengan semua komponen MVC - model, tampilan, dan pengontrol.

Jadi, katakanlah Anda ingin membuat aplikasi yang berhubungan dengan mobil ...

Model

Kami akan mulai dengan membuat model, untuk mewakili Mobil.

Laravel hadir dengan antarmuka baris perintah yang fantastis, built-in, CLI Tukang , yang menyediakan Anda dengan banyak perintah yang berguna untuk membantu Anda membangun aplikasi Anda.

Jadi, jalankan baris perintah Anda (dan hubungkan ke mesin virtual Homestead Anda, jika Anda menggunakan Laravel Homestead ), masuk ke direktori utama aplikasi Anda, dan jalankan perintah berikut untuk membuat model Mobil baru:

php artisan make:model Car --migration


Semua model disimpan di appdirektori utama , sehingga perintah tersebut akan menghasilkan app/Car.php file model dengan kode berikut:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Car extends Model
{
    //
}

Karena fungsi model bawaan Laravel, hanya dengan membuat kelas model kosong, Laravel akan berasumsi bahwa model ini dikaitkan dengan tabel database bernama cars.

Dan, sebenarnya, dengan menyediakan --migrationopsi itu ketika membuat model, Laravel juga menghasilkan file migrasi database untuk membuat carstabel basis data itu. File migrasi terletak di [timestamp]_create_cars_table.phpdan berisi kode berikut:

<?php



use Illuminate\Database\Schema\Blueprint;

use Illuminate\Database\Migrations\Migration;



class CreateCarsTable extends Migration

{

    /**

     * Run the migrations.

     *

     * @return void

     */

    public function up()

    {

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

            $table->increments('id');

            $table->timestamps();

        });

    }



    /**

     * Reverse the migrations.

     *

     * @return void

     */

    public function down()

    {

        Schema::drop('cars');

    }

}


(Jika Anda tidak terbiasa dengan konsep migrasi basis data, baca lebih lanjut tentang bagaimana Laravel menggunakan migrasi basis data untuk membantu Anda mengelola basis data Anda langsung dari dalam aplikasi Anda. Luar biasa.)

Yang harus Anda lakukan sekarang adalah menggunakan dokumentasi pembangun Skema Laravel untuk menyelesaikan file migrasi. Jadi Anda dapat menentukan beberapa kolom tambahan untuk, katakanlah, menyimpan pembuatan mobil, model, dan tanggal produksi:

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

    $table->increments('id');

    $table->string('make');

    $table->string('model');

    $table->date('produced_on');

    $table->timestamps();

  });


  Lalu Anda dapat menjalankan migrasi untuk membuat carstabel menggunakan perintah Artisan berikut:

 
php artisan migrate


  Dengan item yang berhubungan dengan basis data yang dialamatkan, kita sekarang dapat melanjutkan untuk membuat pengontrol.

  Catatan: Demi pengujian, pada titik ini, saya hanya secara manual menambahkan entri ke carstabel database.


Controller
Di Laravel, sejenis objek - seperti Mobil, dalam hal ini - disebut sebagai sumber daya .

Karena ini sangat umum untuk membangun aplikasi di sekitar sumber daya, Anda dapat membuat pengontrol sumber daya - pengontrol untuk menangani semua permintaan yang terkait dengan sumber daya - menggunakan perintah Artisan sederhana lain:

php artisan make:controller CarController


Itu akan menghasilkan app/Http/Controllers/CarController.phpfile controller dengan kode berikut:

<?php



namespace App\Http\Controllers;



use Illuminate\Http\Request;



use App\Http\Requests;

use App\Http\Controllers\Controller;



class CarController extends Controller

{

    /**

     * Display a listing of the resource.

     *

     * @return Response

     */

    public function index()

    {

        //

    }



    /**

     * Show the form for creating a new resource.

     *

     * @return Response

     */

    public function create()

    {

        //

    }



    /**

     * Store a newly created resource in storage.

     *

     * @return Response

     */

    public function store()

    {

        //

    }



    /**

     * Display the specified resource.

     *

     * @param  int  $id

     * @return Response

     */

    public function show($id)

    {

        //

    }



    /**

     * Show the form for editing the specified resource.

     *

     * @param  int  $id

     * @return Response

     */

    public function edit($id)

    {

        //

    }



    /**

     * Update the specified resource in storage.

     *

     * @param  int  $id

     * @return Response

     */

    public function update($id)

    {

        //

    }



    /**

     * Remove the specified resource from storage.

     *

     * @param  int  $id

     * @return Response

     */

    public function destroy($id)

    {

        //

    }

}



Perhatikan bahwa secara otomatis menghasilkan pengontrol dengan semua tindakan CRUD yang khas.

Sekarang, kita hanya perlu menentukan rute untuk menghubungkan URL dengan semua tindakan pengontrol ini.

Rute
Sekali lagi, karena ini adalah skenario umum, Anda dapat menentukan rute sumber daya tunggal , yang membuat rute untuk semua tindakan pengontrol sumber daya tersebut.

Di file konfigurasi rute - app/Http/routes.php- tambahkan yang berikut untuk menentukan rute sumber daya Mobil:

Route::resource('cars', 'CarController');


Definisi rute tunggal itu akan menentukan semua rute yang terkait dengan sumber daya Mobil kami:



Request Type Path Action Route Name
GET /cars index cars.index
GET /cars/create create cars.create
POST /cars store cars.store
GET /cars/{car} show cars.show
GET /cars/{car}/edit edit cars.edit
PUT/PATCH /cars/{car} update cars.update
DELETE /cars/{car} destroy cars.destroy


Sekarang, demi contoh, mari selesaikan implementasi halaman Show Car.

Controller ini showtindakan
Sesuai tabel sebelumnya, halaman Show Car akan dapat diakses http://app.url/cars/{car}. Dalam hal ini, {car}kehendak, pada kenyataannya, menjadi idobjek mobil dalam database.

Jadi, misalnya, URL untuk melihat mobil dengan iddari 1akan http://app.url/cars/1.

Untuk mengimplementasikan halaman Show Car, dalam aksi pengontrol show, kita perlu:

Gunakan Carmodel untuk mengambil objek Mobil yang ditunjuk dari database.
Muat tampilan untuk halaman Show Car, dan berikan objek Mobil yang diambil dari database.
Pertama, untuk mengakses model Mobil di controller, kita perlu menambahkan usepernyataan baru di atas kelas pengontrol:

.

.

.

use App\Car;



class CarController extends Controller

{

.

.

.

Kemudian, kita dapat menyelesaikan showtindakan dengan kode berikut:

.

.

.

    public function show($id)

    {

      $car = Car::find($id);

      return view('cars.show', array('car' => $car));

    }

.

.

.

Ketika kami mengunjungi URL mobil 1 - http://app.url/cars/1- Laravel membuat 1URL di dapat diakses melalui $idvariabel dalam showfungsi, yang ditunjukkan di atas.

Dan mengambil objek mobil menggunakan Carmodel semudah memanggil Car::finddan melewati itu $id.

Tampilan kemudian dimuat menggunakan viewfungsi dan meneruskan nama tampilan (yang akan kita buat dalam satu menit) dan array dengan data yang akan diberikan ke tampilan.

Terakhir, kita perlu membuat tampilan pertunjukan.

Tampilan dan Melengkapi Halaman
File tampilan LARAVEL semuanya disimpan dalam resources/viewsfolder. Dan mereka dapat diatur menjadi subfolder dalam direktori itu.

Pada langkah sebelumnya, kami meneruskan viewfungsi nama tampilan cars.show. Itu memberitahu Laravel untuk mencari file tampilan yang terletak di subfolder bernama cars(dalam resources/viewsdirektori utama ) bernama show.blade.php.

File tampilan Laravel menggunakan mesin templat Blade , dan karenanya diberi nama .blade.php.

Jadi, untuk menyelesaikan implementasi halaman Show Car ini, kita bisa membuat resources/views/cars/show.blade.phpfile tampilan dengan kode berikut:

<!DOCTYPE html>

<html>

  <head>

    <title>Car {{ $car->id }}</title>

  </head>

  <body>

    <h1>Car {{ $car->id }}</h1>

    <ul>

      <li>Make: {{ $car->make }}</li>

      <li>Model: {{ $car->model }}</li>

      <li>Produced on: {{ $car->produced_on }}</li>

    </ul>

  </body>

</html>


Karena kami mengirimkan Carobjek ke tampilan - kembali ke showtindakan pengontrol - dengan tombol array car, kita dapat mengaksesnya dalam tampilan melalui variabel dengan nama yang sama $car,.

Objek diambil melalui model adalah contoh dari kelas model itu.

Dan, seperti yang Anda lihat, nilai Carobjek dapat diakses menggunakan nama yang sama dengan nama carskolom tabel database terkait .

Akhirnya, Anda melihat penggunaan sintaks Blade untuk mencetak informasi. Berikut ini, misalnya, mencetak make mobil:

{{ $car->make }}

Pernyataan itu hanya diterjemahkan ke dalam echopernyataan PHP murni di latar belakang:

<?php echo $car->make; ?>

Tetapi sintaks Blade membuat tampilan tulisan lebih cepat dan lebih menyenangkan, dan membacanya jauh lebih mudah.

Permulaan Aplikasi Web MVC hanya dalam 10 Menit
Dan begitulah!

Begitulah cara cepat, dan mudah, Anda dapat membangun aplikasi web MVC menggunakan Laravel 5.

Dengan kombinasi perintah CLI Artisan dan fungsi built-in yang disediakan, membuat aplikasi Laravel cepat dan menyenangkan.
Read more »

Bagaimana cara Custom Login dengan Memodifikasi Auth Laravel 5.3

Ada banyak kelebihan yang didapatkan ketika membuat sendiri fitur login dari awal. Seperti alur kerja aplikasi yang bebas diatur sedemikian rupa. Namun, ketika menggunakan auth yang sudah disediakan, khususnya fitur login, bukan berarti kita terpaku pada alur yang sudah dibuat Laravel. Dengan menggunakan auth bawaan Laravel, kita juga dimungkinkan membuat fitur login dengan spesifikasi khusus.

Contoh kasus pada tulisan ini dapat diimplementasikan pada Laravel versi 5.3 ke atas.

Jika kita buka controller login yang terletak dalam berkas app/Http/Controllers/Auth/LoginController.php, akan terlihat hanya ada satu method di dalam class tersebut, itupun method constructor. Dalam class controller ini, tidak didefinisikan secara eksplisit fungsi untuk menangani proses login.

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
}

Jika diperhatikan, class controller di atas mengimpor dan menggunakan trait AuthenticatesUsers yang terletak dalam berkas berikut:

vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php

Nah, di dalam trait tersebutlah method yang berhubungan dengan fungsi login didefinisikan. Method yang tersedia lengkap mulai dari menampilkan formulir login, validasi, pengecekan user, sampai dengan respons. Setiap proses dipisah ke dalam method tersendiri. Hal ini memungkinkan pemrogram (programmer) untuk mengubah hal yang dirasa perlu saja.

<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

trait AuthenticatesUsers
{
    use RedirectsUsers, ThrottlesLogins;

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\Http\Response
     */
    public function showLoginForm()
    {
        return view('auth.login');
    }

    /**
     * Handle a login request to the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
     */
    public function login(Request $request)
    {
        $this->validateLogin($request);

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }

    /**
     * Validate the user login request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return void
     */
    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => 'required|string',
            'password' => 'required|string',
        ]);
    }

    /**
     * Attempt to log the user into the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    protected function attemptLogin(Request $request)
    {
        return $this->guard()->attempt(
            $this->credentials($request), $request->has('remember')
        );
    }

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }

    /**
     * Send the response after the user was authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendLoginResponse(Request $request)
    {
        $request->session()->regenerate();

        $this->clearLoginAttempts($request);

        return $this->authenticated($request, $this->guard()->user())
                ?: redirect()->intended($this->redirectPath());
    }

    /**
     * The user has been authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */
    protected function authenticated(Request $request, $user)
    {
        //
    }

    /**
     * Get the failed login response instance.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    protected function sendFailedLoginResponse(Request $request)
    {
        $errors = [$this->username() => trans('auth.failed')];

        if ($request->expectsJson()) {
            return response()->json($errors, 422);
        }

        return redirect()->back()
            ->withInput($request->only($this->username(), 'remember'))
            ->withErrors($errors);
    }

    /**
     * Get the login username to be used by the controller.
     *
     * @return string
     */
    public function username()
    {
        return 'email';
    }

    /**
     * Log the user out of the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function logout(Request $request)
    {
        $this->guard()->logout();

        $request->session()->invalidate();

        return redirect('/');
    }

    /**
     * Get the guard to be used during authentication.
     *
     * @return \Illuminate\Contracts\Auth\StatefulGuard
     */
    protected function guard()
    {
        return Auth::guard();
    }
}

***

Sebagai contoh permulaan, kita punya kasus untuk mengubah path lokasi view login yang secara bawaan merujuk ke “auth.login”, kemudian diubah menjadi “user.login”.

Untuk memodifikasi path tersebut, tentunya tidak dianjurkan mengubah langsung pada trait. Alih-alih melakukan perubahan pada trait AuthenticatesUsers, kita dapat menimpanya method tersebut sesuai dengan konsep trait di PHP.

Dalam trait, method untuk menampilkan form login bernama showLoginForm(). Untuk menimpa atau mengabaikan method ini dalam trait, kita hanya perlu menambahkan nama method yang sama ke dalam class LoginController.

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\Http\Response
     */
    public function showLoginForm()
    {
        return view('user.login');
    }
}

Voila! Path formulir login sudah diubah sesuai dengan contoh kasus pertama. Tentunya, kita juga dapat menambahkan variabel pada view layaknya controller yang sering kita buat sebelumnya.

***

Contoh kedua misalnya, kita akan menambahkan validasi di formulir login yang sebelumnya hanya mengecek email dan password, maka di custom login yang kita buat juga akan melakukan pengecekan kode unik.

Dalam trait, method untuk memvalidasi input dari pengguna bernama validateLogin(). Salin method ini ke dalam LoginController, dan tambahkan validasi kode unique sesuai dengan spesifikasi contoh kasus.

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
     */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\Http\Response
     */
    public function showLoginForm()
    {
        return view('user.login');
    }

    /**
     * Validate the user login request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return void
     */
    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => 'required|string',
            'password' => 'required|string',
            'code' => 'required|exists|users,code',
        ]);
    }
}

***

Nah, sampai di sini, kita sudah berhasil memodifikasi dua hal, yaitu path formulir login dan validasi input tambahan.

Sekarang, masuk ke contoh lainnya, yang mana selain input email dan password, sistem juga harus mengecek status user apakah sudah aktif atau belum. Di dalam pangkalan data, kalian menyimpan data “A” sebagai penanda status user sudah aktif.

Facade Auth di Laravel sudah menyediakan data kombinasi selain email dan password. Sebagai contoh, untuk mengecek credential user, kalian bisa menuliskan skrip seperti di bawah.

$loggedIn = \Auth::attempt([
    'email' => $request->email,
    'password' => $request->password,
    'status' => 'A',
], $remember);

Setiap kali ingin menambahkan kombinasi pengecekan, kalian cukup mendefinisikannya pada argumen pertama method attempt() dalam facade Auth.

Di trait AuthenticateUsers, penulisan skripnya sedikit berbeda walau pada dasarnya menggunakan package yang sama. Sebelum memodifikasinya, terlebih dahulu kita lihat isi method attemptLogin() yang sudah ada.

/**
 * Attempt to log the user into the application.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return bool
 */
protected function attemptLogin(Request $request)
{
    return $this->guard()->attempt(
        $this->credentials($request), $request->filled('remember')
    );
}

Method attemptLogin() juga terikat dependensi dengan method lain yang bernama credentials(). Method ini berfungsi untuk mengambil request apa saja yang dimasukkan oleh pengguna. Secara bawaan, hanya email dan password yang diizinkan untuk digunakan.

/**
 * Get the needed authorization credentials from the request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
protected function credentials(Request $request)
{
    return $request->only($this->username(), 'password');
}

Untuk memodifikasinya, hal pertama yang dilakukan adalah menambahkan izin untuk request yang bernama “status” (dengan asumsi nama kolom di pangkalan data juga “status”).

/**
 * Get the needed authorization credentials from the request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
protected function credentials(Request $request)
{
    return $request->only($this->username(), 'password', 'status');
}

Langkah selanjutnya, definisikan status harus bernilai “A”. Karena pengecekan status ini bukan berasal dari masukan data user, maka kita dapat menambahkan nilai pada object $request dengan method merge().

/**
 * Attempt to log the user into the application.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return bool
 */
protected function attemptLogin(Request $request)
{
    $request->merge(['status' => 'A']);

    return $this->guard()->attempt(
        $this->credentials($request), $request->filled('remember')
    );
}

Sebagai alternatif penggunaan method merge(), kalian juga dapat menggunakan method add() seperti yang dicontohkan oleh Laravel Daily.

$request->request->add(['status' => 'A']);

Terakhir, jangan lupa untuk menyalin kedua method tersebut beserta isinya ke dalam class LoginController. Dan, seharusnya aplikasi yang kita bangun sudah berfungsi sesuai dengan spesifikasi contoh-contoh kasus di atas.

***

Tentunya, tidak dapat semua contoh kasus saya jabarkan di tulisan sini. Dalam dunia pemrograman sesungguhnya, ada ratusan atau bahkan ribuan kombinasi contoh kasus yang terjadi, tergantung dengan spesifikasi dari pemilik aplikasi.

Pengenalan custom login di tulisan ini memberikan gambaran bagi kalian yang ingin memanfaatkan fitur auth di Laravel, namun tanpa harus membuatnya dari awal.

Terakhir, sebagai informasi, tak hanya fitur login yang menggunakan trait seperti di atas. Fitur seperti register dan password juga mempunyai konsep yang sama. Yang perlu kalian perhatikan adalah nama trait yang digunakan, serta memahami sedikit demi sedikit fungsi dalam trait tersebut.

Read more »

Memisah File Log Aplikasi Laravel 5.1

Apa Itu Log Aplikasi?

Log aplikasi adalah segala catatan terkait dengan aplikasi kita. Catatan ini biasanya dituliskan oleh developer (atau otomatis ditulis oleh framework yang dipakai) untuk membantu proses debugging atau bug fixing di kemudian hari.

Laravel secara default menyimpan log aplikasi di file storage/logs/laravel.log. Setiap error atau exception yang terjadi saat aplikasi berjalan akan disimpan di file tersebut.

Jika kita ingin menambah log secara manual, kita bisa memanggil beberapa fungsi yang sudah disediakan:

Log::emergency($log);
Log::alert($log);
Log::critical($log);
Log::error($log);
Log::warning($log);
Log::notice($log);
Log::info($log);
Log::debug($log);

Urutan fungsi-fungsi di atas juga menyatakan level seberapa penting log tersebut, dimulai dari emergency yang paling penting dan diakhiri dengan debug yang tidak terlalu penting. Dokumentasi tentang Log bisa dibaca lebih lengkap di website Laravel.

Yang menjadi masalah adalah, apapun fungsi yang kita panggil, semua log akan ditulis ke dalam satu file yang sama, yaitu laravel.log. Jadi log untuk debugging aplikasi bercampur dengan log terkait error aplikasi. Hal ini sedikit menyusahkan ketika ternyata aplikasi kita masih banyak errornya, sehingga log debugging kita dengan cepat ‘tenggelam’ ditimpa log error yang mengalir tiada henti :D.

Tantangan

Bagaimana caranya memisah file log untuk masing-masing level? Jadi Log::error() akan ditulis ke error.log, Log::info() ditulis ke info.log, dan Log::debug() ditulis ke debug.log.

(Pencarian) Solusi

Pencarian solusi dari tantangan ini sedikit berliku. Sumber pertama tetap website laravel.com. Di bagian konfigurasi logging dijelaskan bahwa di belakang layar Laravel menggunakan library Monolog. Jika kita ingin memodifikasi perilaku Log bawaan Laravel, kita bisa membuka file app/bootstrap/app.php dan menambahkan kode berikut di akhir baris tepat sebelum return $app:

$app->configureMonologUsing(function($monolog) {
    $monolog->pushHandler(...);
});

Pertanyaan selanjutnya, apa yang harus ditambahkan di pushHandler? Apa itu pushHandler?

Pencarian berlanjut ke sebuah diskusi di laravel.io dengan penemuan potongan kode berikut:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$view_log = new Logger('View Logs');
$view_log->pushHandler(new StreamHandler('path/to/log.log', Logger::INFO));

$view_log->addInfo("User $user clicked");

Ada sedikit pencerahan, tapi solusi belum terbayang, maka pencarian terus dilanjutkan. Tujuan berikutnya adalah sebuah diskusi di laracasts.com. Disini ada potongan kode yang mirip dengan kode sebelumnya:

$bubble = false;

// Stream Handlers
$infoStreamHandler = new StreamHandler( storage_path("/logs/laravel_info.log"), Monolog::INFO, $bubble);
$warningStreamHandler = new StreamHandler( storage_path("/logs/laravel_warning.log"), Monolog::WARNING, $bubble);
$errorStreamHandler = new StreamHandler( storage_path("/logs/laravel_error.log"), Monolog::ERROR, $bubble);

// Get monolog instance and push handlers
$monolog = $log->getMonolog();
$monolog->pushHandler($infoStreamHandler);
$monolog->pushHandler($warningStreamHandler);
$monolog->pushHandler($errorStreamHandler);

Akhirnya pencarian dilanjutkan ke halaman github Monolog dan membaca source code.

Sampai disini mulai muncul beberapa temuan penting:

  • Laravel menggunakan Monolog
  • Monolog punya fungsi pushHandler
  • Ada 3 parameter penting di pushHandler:
    • Handler itu sendiri
    • Level log yang ingin di handle
    • $bubble, apakah log ini akan diteruskan ke atas (ke level yang lebih rendah).

Handler

Handler ini mengatur aksi apa yang akan dilakukan terkait log yang terjadi. Yang paling lumrah adalah menulikan ke file. Tapi bisa juga log ini dikirim via email, diteruskan ke syslog, atau dikirim ke layanan manajamen log seperti loggly. Daftar lengkap handler yang didukung oleh Monolog bisa dilihat disini.

Level Log

Seperti sudah disebutkan sebelumnya, ada delapan level log yang tersedia dan sudah baku digunakan. Parameter level log ini memungkinkan kita untuk mendaftarkan handler yang berbeda untuk setiap level. Misalnya untuk log error dikirim ke email, tapi kalau debug dan warning cukup ditulis ke file saja.

Bubble

Parameter $bubble mengindikasikan apakah setelah sebuah log diproses oleh handler tertentu akan diteruskan ke handler lainnya (jika memang ada).

Untuk lebih jelasnya, silakan praktekkan kode berikut ini:

...
$bubble = false; // silakan diganti true atau false, dan lihat hasilnya
$monolog->pushHandler(new \Monolog\Handler\StreamHandler($app->storagePath() . "/logs/error1.log", \Monolog\Logger::ERROR, $bubble));
$monolog->pushHandler(new \Monolog\Handler\StreamHandler($app->storagePath() . "/logs/error2.log", \Monolog\Logger::ERROR, $bubble));
...

Lalu panggil kode berikut dari manapun:

\Log::error('error');    

Jika $bubble=true maka error log akan tercatat di kedua file, sedangkan jika $bubble=false error log hanya akan tercatat di file error2.log (handler yang terakhir didaftarkan).

Solusi

Dari hasil pencarian di atas, akhirnya ketemu solusi seperti berikut ini:

$app->configureMonologUsing(function ($monolog) use ($app) {
    $bubble = false;

    $monolog->pushHandler(new \Monolog\Handler\StreamHandler($app->storagePath() . "/logs/debug.log", Logger::DEBUG,
        $bubble));
    $monolog->pushHandler(new \Monolog\Handler\StreamHandler($app->storagePath() . "/logs/info.log", Logger::INFO,
        $bubble));            
    $monolog->pushHandler(new \Monolog\Handler\StreamHandler($app->storagePath() . "/logs/notice.log", Logger::NOTICE,
        $bubble));

}); 

Atau dengan sedikit ilmu ‘opreker’, kita tahu bahwa Monolog sudah memiliki fungsi getLevels() sehingga kode diatas bisa dipercantik menjadi seperti ini:

$app->configureMonologUsing(function ($monolog) use ($app) {
    $bubble = false;

    foreach ($monolog->getLevels() as $name => $level) {
        $name = strtolower($name);
        $monolog->pushHandler(new \Monolog\Handler\StreamHandler($app->storagePath() . "/logs/{$name}.log", $level,
            $bubble));
    }
}); 

Kembali mengingatkan, kode diatas ditambahkan ke file app/bootstrap/app.php, di akhir baris tepat sebelum return $app.

Read more »


© adimancv.com