Cron Job Laravel Windows, Otomatisasi Script Menggunakan Task Scheduler

tutorial laravel

Cron Job Laravel Windows – Pada kali ini kita akan membahas bagaimana cara membuat sebuah cron atau sebuah task scheduling menggunakan laravel di operating system berbasis windows. Sebetulnya hal ini tidak lumrah, karena biasanya aplikasi berbasis laravel akan di host pada os berbasis linux dan untuk otomatisasi task-nya menggunakan scheduler system bawaan linux (konfigurasi-nya menggunakan perintah crontab -e), namun sebagai bahan referensi kali ini kita akan membuat Cron Job Laravel pada OS Windows.

Baca juga cara membuat aplikasi web, web service & aplikasi android :  https://soft-gain.com/2019/10/17/laravel-aplikasi-inventory-barang-berbasis-web/

Goals – Membuat Cron Job Dengan Laravel Pada OS Windows

Pada artikel ini kita akan mencoba membuat dan memahami bagaimana cara men-otomatisasi sebuah task menggunakan laravel pada os windows. Kita akan mempelajari langkah demi langkah pembuatan task dengan laravel (untuk detail-nya bisa dilihat di-dokumentasi resminya : https://laravel.com/docs/7.x/scheduling#scheduling-queued-jobs), dan memanfaatkan fitur task scheduler pada windows sebagai agent untuk menjalankan otomatisasi script.

Materi

Pertama-tama masukan perintah berikut ini untuk membuat sebuah command baru :

php artisan make:command belajarMembuatCron

Maka secara otomatis akan ter-generate sebuah file baru belajarMembuatCron.php didalam folder Console/Commands, buka file tersebut dan isi seperti ini :

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class belajarMembuatCron extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sg:belajar-membuat-cron';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Hanya ingin belajar membuat cron';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        echo 'Cron kita sudah jalan!';
        \Log::info('Cron kita sudah jalan!');
    }
}

Perlu diperhatikan, pada $signature adalah nama command yang akan kita gunakan saat hendak menjalankan perintah, pada $description kita isikan deskripsi task ini dijalankan untuk tujuan apa (penting juga untuk mengisi deskripsi saat kita bekerja secara tim, supaya teman kita tidak bingung command ini berfungsi untuk apa), pada function handle kita isikan script yang hendak di eksekusi saat command ini dijalankan (pada contoh ini kita hanya akan menampilkan pesan saja pada layar command line dan men-print string pada file laravel.log -> dengan perintah \Log::info(), pada case yang lebih serius bagian ini bisa diisikan script yang lebih complex).

Berikutnya ubah file kernel.php menjadi seperti ini :

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // $schedule->command('inspire')
        //          ->hourly();
        $schedule->command('sg:belajar-membuat-cron')->everyMinute();
    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}

Kita akan menambahkan command yang baru saja kita buat pada fungsi schedule, dibagian ini :

$schedule->command('sg:belajar-membuat-cron')->everyMinute(); 

Dimana didalam method command kita mendeklarasikan perintah yang sudah kita buat dalam $signature sebelumnya lalu kita memanggil fungsi ->everyMinute(); yang artinya kita hendak menjalankan perintah ini setiap menit.

Setelah itu coba jalankan perintah yang baru saja kita buat seperti gambag dibawah ini :

tutorial laravel artisan command
Contoh Artisan Command

Jika pada file laravel.log juga ter-print seperti gambar dibawah ini, berarti untuk proses pembuatan perintah menggunakan laravel telah berhasil kita lakukan :

tutorial laravel artisan command
Hasil print \Log::info()

Berikutnya, kita akan mencoba menjalankan perintah diatas secara otomatis dengan memanfaatkan task scheduler pada windows. Pertama-tama kita perlu membuat sebuah batch file yang akan berisi script untuk men-eksekusi perintah php yang sudah kita buat sebelumnya.

Buka notepad biasa dan masukan code dibawah ini :

cd D:\xampp\htdocs\belajar-laravel
D:
php artisan schedule:run

Harap disesuaikan dengan dimana root project Anda disimpan (disini saya menyimpannya didalam d:/xampp/htdocs/belajar-laravel), lalu save file tersebut dengan ekstensi .bat (contoh : laravel-belajar-cron.bat). Untuk men-test file batch yang kita buat sudah benar atau belum tinggal di double click saja batch file yang barusan kita buat dan kita cek file laravel.log kita, jika sudah ter-print pesan sukses artinya kita telah berhasil dalam proses pembuatan batch file.

Selanjutnya kita akan men-kofigurasi task scheduler untuk dapat men-eksekusi batch file yang sudah kita buat sebelumnya, pertama buka task scheduler lalu pada bagian action, pilih create basic task :

Cron Job Laravel Windows
Create Basic Task

Isikan nama dan deskripsi untuk task yang akan kita buat lalu klik next :

Cron Job Laravel Windows
Pilih daily trigger

Pada Bagian diatas, pilih Daily dulu saja lalu klik next :

Cron Job Laravel Windows
Konfigurasi daily task

Pada bagian ini langsung klik next dulu saja :

Cron Job Laravel Windows
Pilih metode action

Pada bagian ini pilih start program karena kita akan menggunakan batch file yang sudah kita buat sebelumnya lalu klik next :

laravel cron task scheduler
Browse batch file

Pada bagian diatas pilih batch file (saya menaruh batch file yang sudah kita buat pada folder project agar mudah ditemukan, pada praktek-nya batch file bisa di taruh dimana saja dengan catatan tidak didalam folder yang membutuhkan permission khusus saat hendak di eksekusi) lalu klik next lalu finish :

Jika berhasil maka task yang baru saja kita buat akan muncul dalam Task scheduler Library :

laravel cron task scheduler
Berhasil dibuat

Silahkan double klik task yang sudah kita buat karena kita akan melakukan sedikit perubahan, dibagian tab general silahkan di check pada bagian Run With Highest Privileges :

laravel cron task scheduler
Run With Highest Privileges

Berikutnya buka pada bagian tab trigger lalu klik edit pada bagian task yang baru kita buat, silahkan disesuaikan dengan gambar dibawah untuk men-eksekusi task setiap satu menit :

laravel cron task scheduler
Run every one minutes

Untuk bagian diatas bisa disesuaikan sesuai kebutuhan mau dijalankan dengan interval seperti apa task yang sudah kita buat, klik ok.

Terakhir kita buka lagi menu Task scheduler Library, klik kanan task yang sudah kita buat lalu pilih run. Jika berhasil maka task yang sudah kita buat sebelumnya akan di-eksekusi setiap satu menit, seperti contoh dibawah ini :

laravel cron task scheduler
Berjalan dengan interval satu menit

Bisa dilihat diatas, pada file laravel.log kita telah berhasil menjalankan cron laravel dengan memanfaatkan task scheduler pada windows dengan interval per satu menit.

Penutup

Kita telah berhasil memanfaatkan task scheduler pada windows untuk menjalankan cron pada laravel, namun lagi ini bukanlah suatu hal yang akan sering kita jumpai, karena lumrahnya laravel itu sendiri di host pada os linux dan kita tinggal men-konfigurasi menggunakan perintah crontab -e untuk menjalankan cron laravel yang sudah kita buat. Mostly sama saja, hanya peran task scheduler yang digantikan oleh system automatic task bawaan linux. Kiranya demikian saja semoga dapat bermanfaat bagi rekan-rekan yang sedang mencari alternatif penggunaan cron laravel pada os windows, terima kasih.

Cara Membuat Android Navigation Drawer, Side Navigasi Menu

Cara Membuat Aplikasi Android

Membuat Android Navigation Drawer – Kali ini kita akan mencoba membuat navigation drawer pada aplikasi berbasis android. Navigation drawer adalah sebuah menu yang biasanya ditempatkan pada sisi kiri layar aplikasi (side menu navigation), hampir setiap aplikasi memiliki komponen ini sebagai navigasi pada tampilan antar muka nya, maka dari itu saya mencoba untuk menjabarkan bagaimana cara membuat android navigation drawer secara sederhana.

Goals – Mampu Membuat Android Navigation Drawer

Tujuan dari pembahasan ini adalah mampu dan pahamnya kita dalam pembuatan navigation browser pada android, kita akan membahasnya langkah demi langkah guna memudahkan kita untuk memahami bagaimana cara kerja dari navigation browser ini. Dan berikut ini adalah contoh hasil dari navigation browser yang kita buat :

Membuat Android Navigation Drawer
Navigation Browser

Materi Pembahasan

Untuk dapat menggunakan navigation drawer, kita akan memanfaatkan widget DrawerLayout sebagai layout utama, cara menggunakannya mudah tinggal kita tambahkan saja widget ini pada layout utama yang kita miliki (dalam case ini, acticity_main.xml adalah layout yang saya gunakan sebagai layout utama). Ubah activity_main menjadi seperti ini :

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/container_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <include
                android:id="@+id/toolbar"
                layout="@layout/toolbar" />

        </LinearLayout>

        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="220dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#ffffff"
        android:choiceMode="singleChoice"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="1dp" />

</android.support.v4.widget.DrawerLayout>

Lalu berikutnya kita akan memanfaatkan Toolbar sebagai wadah untuk menempatkan elemen navigasi atau menu, buatlah sebuah layout dengan nama toolbar.xml, isi dari toolbar.xml seperti :

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Dikarenakan menu navigasi yang akan kita buat ditaruh pada komponen listView, maka kita juga perlu membuat layout untuk menampung masing-masing item pada menu navigasi. Buatlah layout list_view_item_row.xml dan isikan code berikut ini :

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/activatedBackgroundIndicator"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:padding="10dp">

    <ImageView
        android:id="@+id/imageViewIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:paddingRight="10dp" />

    <TextView
        android:id="@+id/textViewName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/imageViewIcon"
        android:paddingRight="10dp"
        android:text="Item Name"
        android:textColor="@android:color/black"
        android:textAppearance="?android:attr/textAppearanceListItemSmall" />

</RelativeLayout>

Lalu untuk masing-masing nama menu akan kita taruh dalam file values/strings.xml, tambahkan code berikut ini :

<string-array name="navigation_drawer_items_array">
        <item>Barang</item>
        <item>Transaksi</item>
        <item>User</item>
</string-array>

Kita juga akan membuat model untuk men-definisikan masing-masing item pada list navigasi, buatlah sebuah class dengan nama SideMenu dan isikan code berikut ini :

package com.soft_gain.myinventory.Model;

public class SideMenu {
    public int icon;
    public String name;

    public SideMenu(int icon, String name) {
        this.icon = icon;
        this.name = name;
    }
}

Dikarenakan kita menggunakan model, kita juga membutuhkan adapter yang membantu kita mengelola data dari model dan men-presentasikan-nya pada listview. Buatlah sebuah class baru dengan nama SideMenuAdapter, lalu isikan code berikut ini :

package com.soft_gain.myinventory;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.soft_gain.myinventory.Model.SideMenu;

public class SideMenuAdapter extends ArrayAdapter<SideMenu> {
    Context mContext;
    int layoutResourceId;
    SideMenu data[] = null;

    public SideMenuAdapter(Context mContext, int layoutResourceId, SideMenu[] data) {
        super(mContext, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.mContext = mContext;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View listItem = convertView;

        LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
        listItem = inflater.inflate(layoutResourceId, parent, false);

        ImageView imageViewIcon = (ImageView) listItem.findViewById(R.id.imageViewIcon);
        TextView textViewName = (TextView) listItem.findViewById(R.id.textViewName);

        SideMenu folder = data[position];


        imageViewIcon.setImageResource(folder.icon);
        textViewName.setText(folder.name);

        return listItem;
    }
}

Berikutnya kita akan melakukan sedikit modifikasi pada MainActivity.java, pertama-tama deklarasi-kan attribute berikut pada class MainActivity :

private String[] mNavigationDrawerItemTitles;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
Toolbar toolbar;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
android.support.v7.app.ActionBarDrawerToggle mDrawerToggle;

Berikutnya lakukan modifikasi pada bagian onCreate :

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTitle = mDrawerTitle = getTitle();
        mNavigationDrawerItemTitles= getResources().getStringArray(R.array.navigation_drawer_items_array);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        setupToolbar();

        DataModel[] drawerItem = new DataModel[3];

        drawerItem[0] = new DataModel(R.drawable.connect, "Barang");
        drawerItem[1] = new DataModel(R.drawable.fixtures, "Transaksi");
        drawerItem[2] = new DataModel(R.drawable.table, "User");
        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        getSupportActionBar().setHomeButtonEnabled(true);

        DrawerItemCustomAdapter adapter = new DrawerItemCustomAdapter(this, R.layout.list_view_item_row, drawerItem);
        mDrawerList.setAdapter(adapter);
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerLayout.setDrawerListener(mDrawerToggle);
        setupDrawerToggle();
}

Lalu tambahkan juga metode-metode berikut ini pada class MainActivity :

    private class DrawerItemClickListener implements ListView.OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }

    }

    private void selectItem(int position) {

        switch (position) {
            case 0:
                Toast.makeText(getApplicationContext() ,"Barang  diclick",Toast.LENGTH_SHORT).show();
                break;
            case 1:
                Toast.makeText(getApplicationContext() ,"Transaksi diclick",Toast.LENGTH_SHORT).show();
                break;
            case 2:
                Toast.makeText(getApplicationContext() ,"User diclick",Toast.LENGTH_SHORT).show();
                break;

            default:
                break;
        }
    }    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getSupportActionBar().setTitle(mTitle);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }

    void setupToolbar(){
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }

    void setupDrawerToggle(){
        mDrawerToggle = new android.support.v7.app.ActionBarDrawerToggle(this,mDrawerLayout,toolbar,R.string.app_name, R.string.app_name);
        mDrawerToggle.syncState();
    }

Bagian yang menurut saya paling penting adalah pada metode selectItem, dimana didalamnya terdapat switch statement yang kita gunakan untuk men-execute event berdasarkan menu navigasi mana yang user pilih, untuk contoh diatas kita hanya akan menampilkan informasi berupa popup menggunakan Toast, ke depannya bisa di-kombinasi-kan dengan pemanggilan sebuah activity baru atau pun fragment yang mengantarkan user pada tampilan interface yang berbeda (contoh menggunakan fragment bisa dilihat disini : https://soft-gain.com/2020/06/23/contoh-sederhana-recyclerview-cardview-dengan-implementasi-retrofit/).

Penutup

Demikianlah contoh pembuatan navigation browser pada aplikasi berbasis android, menurut saya konsep pembuatan navigasi seperti ini cukup penting untuk dapat dikuasai dan dipahami mengingat pentingnya komponen ini untuk pengembangan sebuah asplikasi, seperti biasa silahkan ambil source utuhnya pada repo saya (https://github.com/ImmanuelJL/myinventory.git), terima kasih.

Contoh Sederhana Recyclerview CardView, Dengan Implementasi Retrofit

Cara Membuat Aplikasi Android

Contoh Sederhana Recyclerview Retrofit – Untuk tutorial android kali ini, kita akan mencoba mengimplementasikan contoh sederhana menampilkan data dengan recyclerview dan menggunakan retrofit sebagai REST client HTTP. Setelah sebelumnya kita telah berhasil membuat fungsi untuk login dan logout user (https://soft-gain.com/2020/06/19/cara-membuat-aplikasi-android-rest-api-menggunakan-retrofit/), sekarang kita akan coba menampilkan data pada Recyclerview dengan memanfaatkan retrofit sebagai REST client HTTP. Tanpa berlama-lama lagi langsung saja kita masuk pada pembahasan Contoh Sederhana Recyclerview CardView.

Recyclerview sendiri sebenarnya adalah sebuah dependencies yang digunakan untuk menampilkan data dalam bentuk list, biasanya dikombinasikan dengan cardview sebagai pembungkus atau frame layout masing-masing data. Dikarenakan kita akan menggunakan dua
dependencies ini, silahkan tambahkan dua library ini pada file build.gradle :

implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'

Berikutnya kita akan membuat model, untuk pembuatan model saya menggunakan website ini (http://www.jsonschema2pojo.org/) yang membantu saya memudahkan untuk men-convert hasil json string saya ke dalam java class, caranya sangat mudah tinggal paste-kan saja string json kita kedalam text area sebelah kiri lalu tekan preview, kurang lebih seperti ini :

Contoh Sederhana Recyclerview CardView
Masukan json string
Contoh Sederhana Recyclerview CardView
Hasil dalam bentuk class

Kita tinggal copy paste saja hasil preview diatas ke dalam class java kita, atau bisa jika klik tombol zip untuk download java class kita dalam dalam bentuk file.

Berikutnya buatlah 4 buah model seperti gambar dibawah ini (yang mana hasil java class dari website jsonschema2pojo akan kita taruh dalam model ini) :

Contoh Sederhana Recyclerview CardView
Model Barang

Pertama didalam model barang kita memiliki fungsi getSuccess yang yang akan kita gunakan untuk mengambil object success dari json response yang kita terima :

package com.soft_gain.myinventory.Model.Barang;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Barang {
    @SerializedName("success")
    @Expose
    private Success success;

    public Success getSuccess() {
        return success;
    }

    public void setSuccess(Success success) {
        this.success = success;
    }
}

Lalu didalam model success, kita memiliki fungsi getData yang kita gunakan untuk mengambil object data dalam bentuk list :

package com.soft_gain.myinventory.Model.Barang;

import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Success {
    @SerializedName("data")
    @Expose
    private List<Datum> data = null;

    public List<Datum> getData() {
        return data;
    }

    public void setData(List<Datum> data) {
        this.data = data;
    }
}

Lalu didalam model datum atau model data, kita men-serialisasi-kan satu persatu attribute kedalam object java :

package com.soft_gain.myinventory.Model.Barang;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Datum {
    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("nama_barang")
    @Expose
    private String namaBarang;
    @SerializedName("jumlah_barang")
    @Expose
    private Integer jumlahBarang;
    @SerializedName("keterangan")
    @Expose
    private Object keterangan;
    @SerializedName("created_at")
    @Expose
    private String createdAt;
    @SerializedName("updated_at")
    @Expose
    private String updatedAt;
    @SerializedName("updated_by")
    @Expose
    private Integer updatedBy;
    @SerializedName("get_updated_by")
    @Expose
    private GetUpdatedBy getUpdatedBy;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getNamaBarang() {
        return namaBarang;
    }

    public void setNamaBarang(String namaBarang) {
        this.namaBarang = namaBarang;
    }

    public Integer getJumlahBarang() {
        return jumlahBarang;
    }

    public void setJumlahBarang(Integer jumlahBarang) {
        this.jumlahBarang = jumlahBarang;
    }

    public Object getKeterangan() {
        return keterangan;
    }

    public void setKeterangan(Object keterangan) {
        this.keterangan = keterangan;
    }

    public String getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(String createdAt) {
        this.createdAt = createdAt;
    }

    public String getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(String updatedAt) {
        this.updatedAt = updatedAt;
    }

    public Integer getUpdatedBy() {
        return updatedBy;
    }

    public void setUpdatedBy(Integer updatedBy) {
        this.updatedBy = updatedBy;
    }

    public GetUpdatedBy getGetUpdatedBy() {
        return getUpdatedBy;
    }

    public void setGetUpdatedBy(GetUpdatedBy getUpdatedBy) {
        this.getUpdatedBy = getUpdatedBy;
    }
}

Untuk model getUpdatedBy sementara ini tidak dipakai jadi kita skip saja. Berikutnya buka file Interface.java dan tambahkan code berikut ini sebagai end point api kita :

@POST("barang")
Call<Barang> postBarang(@Header("Authorization") String Authorization);

Perlu diperhatikan diatas, dimana kita memanggil model barang.java pada end point postBarang (dibagian ini : Call<Barang>), end point postBarang ini lah yang akan kita panggil pada bagian antar muka nantinya. Berikutnya kita akan menambahkan file BarangAdapter yang akan kita gunakan untuk data binding dengan RecyclerView :

package com.soft_gain.myinventory.Barang;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.soft_gain.myinventory.Barang.BarangFragmentList;
import com.soft_gain.myinventory.Model.Barang.Datum;
import com.soft_gain.myinventory.R;

import java.util.List;

public class BarangAdapter extends RecyclerView.Adapter<BarangAdapter.CustomViewHolder>{
    private List<Datum> dataList;
    private Context context;

    public BarangAdapter(List<Datum> dataList){
        this.dataList = dataList;
    }

    public BarangAdapter(BarangFragmentList connectFragment, List<Datum> dataList) {}

    class CustomViewHolder extends RecyclerView.ViewHolder {
        public final View mView;
        TextView txtTitle;

        CustomViewHolder(View itemView) {
            super(itemView);
            mView = itemView;

            txtTitle = mView.findViewById(R.id.title);
        }
    }

    @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater.inflate(R.layout.adapter, parent, false);
        return new CustomViewHolder(view);
    }

    @Override
    public void onBindViewHolder(CustomViewHolder holder, int position) {
        holder.txtTitle.setText(dataList.get(position).getNamaBarang());
    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }
}

Perlu diperhatikan pada BarangAdapter diatas, dimana kita memanggil model Datum atau model data sebagai list yang mana model inilah yang akan kita inisiasi-kan kedalam recyclerview nantinya. Lalu berikutnya kita akan membuat fragment sebagai implementasi antar muka yang akan kita gunakan untuk menampilkan list data pada user. Tambahkan file BarangFragmentList.java dan isinya kurang lebih seperti ini :

package com.soft_gain.myinventory.Barang;

import android.app.ProgressDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.soft_gain.myinventory.Api.Client;
import com.soft_gain.myinventory.Api.Interface;
import com.soft_gain.myinventory.Barang.BarangAdapter;
import com.soft_gain.myinventory.Model.Barang.Barang;
import com.soft_gain.myinventory.R;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class BarangFragmentList extends Fragment {
    ProgressDialog progressDoalog;
    SharedPreferences myPrefs;

    public BarangFragmentList() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View rootView = inflater.inflate(R.layout.fragment_barang_list, container, false);
        RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        progressDoalog = new ProgressDialog(getActivity());
        progressDoalog.setMessage("Loading....");
        progressDoalog.show();

        myPrefs = getActivity().getSharedPreferences("sg_shared_pref", getActivity().MODE_PRIVATE);
        String token = myPrefs.getString("token", "");

        Interface service = Client.getClient().create(Interface.class);
        Call<Barang> call = service.postBarang("Bearer "+token);
        call.enqueue(new Callback<Barang>() {
            @Override
            public void onResponse(Call<Barang> call, Response<Barang> response) {
                /*Log.v("log softgain : ", String.valueOf(response.body().getSuccess().getData().get(0).getNamaBarang()));*/
                progressDoalog.dismiss();
                RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
                recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
                BarangAdapter mAdapter = new BarangAdapter(response.body().getSuccess().getData());
                recyclerView.setAdapter(mAdapter);
                recyclerView.setItemAnimator(new DefaultItemAnimator());
            }

            @Override
            public void onFailure(Call<Barang> call, Throwable t) {
                /*Log.v("log softgain : ", String.valueOf(t));*/
                progressDoalog.dismiss();
                Toast.makeText(getActivity(), "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
            }
        });

        return rootView;
    }
}

Perhatikan pada fragment diatas, dimana kita memanggil end point postBarang yang sudah kita buat sebelumnya, perlu diperhatikan juga dimana model yang kita jadikan acuan untuk inisiasi data adalah model barang (model ini harus disesuaikan dengan model yang kita deklarasikan pada end point di interface). Barulah pada bagian onResponse, kita men-inisiasi-kan getData (pada bagian ini : BarangAdapter mAdapter = new BarangAdapter(response.body().getSuccess().getData())) kedalam barangAdapter (yang mana sudah kita sesuaikan dalam BarangAdapter.java yang juga didalamnya kita inisiasi-kan model Datum atau model data), sehingga attribute yang ada dalam model datum atau model data dapat kita inisiasi-kan kedalam recyclerview. Lalu berikutnya tambahkan class BarangFragmentList pada MainActivity.java dibagian method selectItem (disini kita menggunakan side navigation menu yang akan kita bahas pada artikel berbeda). Berikutnya tambahkan layout fragment_barang_list.xml, di file ini kita akan menggunakan RecyclerView :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"  />

</RelativeLayout>

Terakhir kita akan tambahkan layout adapter.xml, yang mana pada file inilah kita akan menggunakan CardView :

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view_friend"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardUseCompatPadding="true" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/title"
            style="@style/TextAppearance.AppCompat.Medium"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:paddingTop="20dp"
            android:lines="2"
            android:text="title" />

    </RelativeLayout>

</android.support.v7.widget.CardView>

Berikut ini adalah contoh hasil dari apa yang sudah kita buat diatas :

Contoh Sederhana Recyclerview CardView
Contoh Recyclerview CardView

Demikian contoh sederhana dari implementasi recyclerview dan cardview menggunakan retrofit sebagai REST client HTTP, untuk full source-nya bisa diambil di repo saya (https://github.com/ImmanuelJL/myinventory.git), terima kasih.

Tutorial Splash Screen Android, Layar Pembuka Aplikasi Android

Cara Membuat Aplikasi Android

Pada kali ini kita akan membahas tentang bagaimana membuat splash screen pada aplikasi android, artikel ini adalah kelanjutan dari (https://soft-gain.com/2020/06/19/cara-membuat-aplikasi-android-rest-api-menggunakan-retrofit/). Splash screen itu sendiri adalah sebuah tampilan atau interface yang menjadi layar pembuka saat kita pertama kali menjalankan aplikasi android, biasanya pada layar disertakan nama aplikasi, logo dan warna dominan yang menjadi ciri khas dari aplikasi tersebut. Tanpa berbasa-basi lagi, langsung saja kita masuk pada pembahasan tutorial splash screen android.

Pertama, kita akan membuat sebuah layout baru dengan nama activity_splash.xml, layout ini lah yang akan menjadi tampilan antar muka yang di lihat oleh user. Isinya kurang lebih seperti ini :

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimaryDark"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="My Inventory"
        android:textColor="#fff"
        android:textSize="40sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Pada interface di atas, kita hanya akan menampilkan nama dari aplikasi ini saja, silahkan dikembangkan sesuai kebutuhan apakah hendak menggunakan gambar dan lain sebagainya.

Berikutnya kita akan membuat satu activiy baru yaitu SplashActivity.java, dalam activity ini kita hanya memanggil layout activity_splash lalu kita memberikan jeda kira-kira 3 detik dan langsung membuka activity baru yaitu MainActivity.java. Isi dari SplashActivity seperti ini :

package com.soft_gain.myinventory;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_splash);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent home = new Intent(SplashActivity.this, MainActivity.class);
                startActivity(home);
                finish();
            }
        },3000);
    }
}

Terakhir kita akan merubah sedikit file AndroidManifest.xmlm di dalamnya kita akan melakukan sedikit konfigurasi untuk menentukan SplashActivity lah yang akan kita jalankan terlebih dahulu saat aplikasi dijalankan. Tambahkan baris kode ini pada tag aplication :

<activity android:name=".SplashActivity" android:theme="@style/Theme.AppCompat.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
</activity>

Selanjutnya kita tinggal coba menjalankan aplikasi pada emulator atau pada perangkat hp kita secara langsung. Seperti ini lah kurang lebih hasil dari splash screen yang sudah kita buat :

Tutorial Splash Screen Android
Splash Screen

Demikian lah tutorial membuat splash screen pada aplikasi android, menurut saya hal ini relatif mudah dan silahkan dimodifikasi atau di sesuaikan tampilan dari halaman splash-nya dengan aplikasi android yang sedang anda kembangkan.

Menurut saya secara pribadi, splash screen ini adalah salah satu elemen penting untuk menunjukan value atau nilai dari brand yang sedang coba kita kembangkan, karena splash screen ini menentukan first impression user saat pertama kali membuka aplikasi yang kita buat, saya sendiri suka menghabiskan banyak waktu hanya untuk geser-geser logo ganti warna sampai saya merasa telah menentukan formula yang tepat untuk tampilan dari splash screen saya (splash screen pada tutorial kali ini sederhana karena hanya contoh saja). Pepatah berkata jangan melihat buku dari cover-nya, tapi kenyataannya banyak orang yang menilai sesuatu dari penampilannya terlebih dahulu, barulah tertarik untuk melihat isinya. Untuk full source nya bisa di ambil di sini (https://github.com/ImmanuelJL/myinventory.git), terima kasih.

Menyembunyikan Id Pada Url, Tutorial Laravel Obfuscation

tutorial laravel

Menyembunyikan Id Pada Url – Pada kesempatan kali ini kita akan mempraktekan cara pembuatan obfuscation (Menyembunyikan Id Pada Url) menggunakan laravel, artikel ini adalah kelanjutan dari artikel (https://soft-gain.com/2019/10/17/laravel-aplikasi-inventory-barang-berbasis-web/). Sebelum memulai pembahasan kita akan sedikit membahas tentang apa itu obfuscation, obfuscation sendiri adalah bagian dari cryptography, kata obfuscation sendiri berarti bingung atau dikaburkan, yang mana sesuai dengan tujuan peng-obfuscation itu sendiri adalah untuk membuat informasi internal dari aplikasi kita sulit dimengerti. Tutorial laravel obfuscation id ini sendiri dibuat dengan menggunakan
library hasids/hashids (https://hashids.org/).

Sesuai dengan tujuannya untuk meng-kaburkan informasi (informasi yang kita maksud disini adalah id atau primary key table pada database), obfuscation ini dibuat untuk tujuan keamanan data, dimana biasanya kita akan melihat sebuah request yang dikirimkan oleh client pada server dengan integer biasa (https://website.id/product/edit/17), dengan penggunaan library ini maka id dari primary key kita akan dibuat acak menjadi seperti (https://website/product/edit/XclMn), tentu dengan peng-acakan primary key seperti ini user tidak bisa dengan mudah menebak data ini memiliki id berapa, ada berapa banyak kira-kira data yang ada pada table ini, dan juga tidak bisa membuka sembarang data karena user tidak mengetahui string acak seperti apa yang harus dia masukan pada url address bar.

Baiklah langsung saja kita masuk pada pembahasannya, pertama silahkan install librarynya menggunakan perintah ini :

composer require hashids/hashids

Selanjutnya kita akan memanfaatkan file .env untuk menyimpan secret key kita, secret key ini sangat penting karena kita harus memiliki key ini jika hendak mengembalikan id yang sudah diacak menjadi seperti semula. Tambahkan potongan code dibawah ini :

MY_SECRET_SALT_KEY=softgain1234!@#$

Selanjutnya kita akan melakukan sedikit modifikasi pada bagian model, kali ini module yang akan kita jadikan contoh adalah module sg_barang, jadi silahkan buka model sg_barang.php dan tambahkan potongan code dibawah ini :

public function getIdAttribute(){
        $hashids = new \Hashids\Hashids( env('MY_SECRET_SALT_KEY','MySecretSalt') );

        return $hashids->encode($this->attributes['id']);
}

Pada potongan code diatas, bisa dilihat kalau kita memanfaatkan fitur laravel untuk meng-overwrite value dari database (fungsi getIdAttribute) dalam case ini yang kita overwrite adalah value id, didalamnya kita memanggil library hashids yang sudah di install sebelumnya lalu dengan perintah return $hashids->encode($this->attributes[‘id’]); maka id yang akan ditampilkan pada sisi front end adalah id yang sudah di acak stringnya. Kurang lebih seperti inilah contoh url yang sudah dilakukan pengacakan pada attribute id :

Menyembunyikan Id Pada Url
Hasil Obfuscation Id

Selanjutnya kita buka sg_barang controller dan tambahkan potongan source ini :

public function __construct(){
        $this->Hashids = new \Hashids\Hashids( env('MY_SECRET_SALT_KEY','MySecretSalt') );
}

Diatas adalah potongan saat kita memanggil library hashids.

$id = $this->Hashids->decode($id)[0];

Dan diatas adalah contoh saat kita mengembalikan id yang sudah diacak ke bentuk semula.

Dan karena kita juga sudah membuat aplikasi ini berbasis web service (https://soft-gain.com/2020/06/13/tutorial-laravel-membuat-aplikasi-web-service/), jangan lupa juga untuk memodifikasi pada sg_barang controller untuk bagian api controller-nya (sebetulnya, lebih efisien pengembangan dibuat berdasarkan pattern repository, sehingga ketika terjadi perubahan source kita tidak perlu melakukan modifikasi pada dua source seperti ini, namun mempertimbangkan tutorial ini untuk pemula seperti saya, akhirnya saya putuskan untuk membuatnya masing-masing agar lebih mudah dipahami).

Demikianlah pembuatan obfuscation id dengan menggunakan framework laravel, seperti biasa silahkan ambil full source-nya pada repo saya (https://github.com/ImmanuelJL/myinventory.git) gunakan cabang aplikasi-stok-barang, saya sendiri baru belakangan ini mengenal teknik peng-acakan id seperti ini, karena adanya permintaan yang tidak menginginkan mudahnya akses informasi antar sesama pengguna, pengalaman memanglah guru yang paling berharga, terima kasih.

Tutorial Laravel Import Excel ke Database

tutorial laravel

Tutorial Laravel Import Excel – Pada artikel kali ini kita akan membahas tentang import excel ke database menggunakan laravel. Setelah sebelumnya kita mencoba meng-export data dengan laravel (https://soft-gain.com/2020/06/10/tutorial-export-excel-laravel-aplikasi-inventory-part-6/), kali ini kita akan mencoba kebalikannya, yaitu import data dari excel ke database.

Pertama tambahkan baris ini pada file route kita :

Route::post('/barang/import', 'sg_barang@import');

Selanjutnya tambahkan fungsi import pada controller sg_barang :

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\sg_barang as model;
use Excel;
use Auth;

class sg_barang extends Controller
{
    public function index(){
    	$barangs = model::with('getUpdatedBy')->get();

    	return view('barang.table',compact('barangs'));
    }

    public function create(){
    	return view('barang.form');
    }

    public function store(Request $request){
    	model::create($request->all());

    	return redirect('barang');
    }

    public function show(){
    	//
    }

    public function edit($id){
    	$editForm = true;
    	$barangs = model::find($id);

    	return view('barang.form',compact('barangs','editForm'));
    }

    public function update(Request $request, $id){
    	$data = $request->except('_method', '_token');
    	model::where('id',$id)->update($data);

    	return redirect('barang');
    }

    public function destroy($id){
    	model::destroy($id);

    	return redirect('barang');
    }

    public function import(Request $request){ // <--- FUNGSI INI
        Excel::load($request->file('import')->getRealPath(), function ($reader){
            foreach ($reader->toArray() as $key => $row) {
                $data['nama_barang'] = (isset($row['nama_barang']) && $row['nama_barang']!='') ? $row['nama_barang'] : null;
                $data['jumlah_barang'] = (isset($row['jumlah_barang']) && $row['jumlah_barang']!='') ? $row['jumlah_barang'] : null;
                $data['keterangan'] = (isset($row['keterangan']) && $row['keterangan']!='') ? $row['keterangan'] : null;
                $data['updated_by'] = Auth::user()->id;
                model::create($data);
            }
        });

        return redirect('barang');
    }
}

Berikut ini adalah sedikit penjelasan pada fungsi import, pertama request yang dikirim dari client akan di handle oleh fungsi load, lalu dengan memanfaatkan anonymous kita simpan data yang sudah kita terima dari client ke dalam bentuk array dalam variabel $reader. Lalu kita akan melakukan looping pada variabel reader dan kita akan mengambil perbaris data berdasarkan nama pada header kolomnya, perlu diperhatikan penamaan pada kolom header akan diubah menjadi huruf kecil dan karakter spasi akan diganti dengan karakter underscore (contoh : Nama Barang = nama_barang). Lalu hasil looping tadi akan kita simpan pada database dan kita response kita kembalikan pada client.

Lalu tambahkan potongan source code ini pada file sg_barang/table.blade.php :

<a class="btn btn-success toggle-import-form" href="javascript:;">
                            Import from Excel
                        </a>
                        {!! Form::model('', ['url' => url('/barang/import'), 'method' => 'post', 'enctype'=>'multipart/form-data', 'id'=>'import-form']) !!}
                            {{ csrf_field() }}
                            </br>
                            <div class="form-group col-xs-12 col-lg-6">
                                <a class="btn btn-primary" href="{{ url('csv-template/import-template.csv') }}" download>
                                    Download Import Template
                                </a>
                            </div>
                            <div class="form-group col-xs-12 col-lg-12">
                                {{ Form::file('import', ['class' => 'form-control', 'required']) }}
                            </div>
                            <div class="form-group col-xs-12 col-lg-12">
                                <button type="submit" class="btn btn-primary">Submit</button>
                            </div>
{!! Form::close() !!}

Di file ini juga kita akan menambahkan sedikit animasi untuk menampilkan form import (ini di buat hanya untuk mempercantik tampilan saja, tidak ada pengaruhnya dengan fungsi import itu sendiri). Kita akan menambahkan potongan source ini pada bagian paling bawah dari file :

@push('scripts')
    <script type="text/javascript">
        $(document).ready(function() {
            $('#import-form').hide();

            $('.toggle-import-form').click(function(){
                $('#import-form').slideToggle();
            });
        });
    </script>
@endpush

Lalu pada file layouts/app.blade.php kita tambahkan potongan source code ini di bagian paling akhir setelah semua tag javascript di deklarasikan :

@stack('scripts')

Penggunaan dari @push dan @stack ini sendiri adalah untuk menempatkan beberapa blok konten dari script yang kita deklarasikan di dalam @push ke dalam bagian dimana @stack kita deklarasikan. Sebagai contoh pada file table.blade.php kita bisa menggunakan beberapa perintah jquery tanpa harus mendeklarasikan jquery pada file tersebut, hal itu bisa kita lakukan karena kita menaruh perintah jquery itu di dalam @push lalu @stack pada file app.blade.php kita tempatkan persis dibawah setelah library jquery kita deklarasikan.

Terakhir kita juga akan menambahkan sebuah folder baru dengan nama csv-template, yang di dalamnya akan kita taruh file csv yang akan kita gunakan sebagai template untuk import data (root-project/public/csv-template/import-template.csv). Dan seperti ini lah kurang lebih tampilan form untuk import excel yang sudah di buat :

Tutorial Laravel Import Excel
Import Excel

Untuk full source-nya seperti biasa bisa di ambil dari repo saya (https://github.com/ImmanuelJL/belajar-laravel), silahkan di ambil dari cabang aplikasi-stok-barang. Terima kasih.

Cara Membuat Aplikasi Android, REST API menggunakan Retrofit

Cara Membuat Aplikasi Android

Cara Membuat Aplikasi Android – Melanjutkan artikel sebelumnya dimana kita sudah membuat web service atau api menggunakan framework laravel (https://soft-gain.com/2020/06/13/tutorial-laravel-membuat-aplikasi-web-service/), maka kali ini kita akan mencoba membahas cara membuat aplikasi berbasis android dengan maksud meng-implementasikan web service yang sudah dibuat sebelumnya. Sebelum masuk pada pembahasan, jika ingin membaca mengenai dasar pembuatan aplikasi berbasis android bisa di temukan pada artikel ini (https://soft-gain.com/2020/06/15/cara-membuat-aplikasi-android-hello-world-android-studio/).

Tujuan – Mampu Membuat Aplikasi Android Yang Terintegrasi Dengan Web Service

Artikel ini dibuat dengan harapan kita mampu membuat aplikasi berbasis android dan meng-integrasi-kan nya dengan sebuah web service, pembahasan pada tutorial ini akan dibagi menjadi beberapa artikel yang meliputi dasar-dasar dari pemrograman aplikasi android yang bersifat umum seperti membuat list data, membuat form berserta dengan metode olah datanya (CRUD), pengetahuan dasar tentang activity, fragment, manifest, gradle dan lain-lain.

Materi Pembahasan

Untuk membuat aplikasi kita dapat menggunakan web service yang sudah dibuat sebelumnya, kita perlu meng-install library bernama retrofit (https://square.github.io/retrofit/), retrofit sendiri adalah sebuah REST client HTTP untuk java atau android yang digunakan untuk membuat HTTP request dan memproses HTTP response dari web service sehingga dapat di gunakan pada aplikasi berbasis android. Untuk meng-install library ini pada aplikasi kita, buka file build.gradle dan tambahkan code di bawah ini pada bagian dependencies :

implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
implementation 'com.squareup.retrofit2:retrofit:2.0.2'

Setelah ditambahkan jangan lupa untuk menekan tombol sync now dan pastikan anda terhubung dengan internet.

Selain retrofit, kita juga meng-install gson, gson sendiri adalah library buatan Google yang di gunakan untuk meng-konvert json menjadi java object atau pun sebaliknya.

Selanjutnya kita akan menambahkan package baru dengan nama Api, di dalamnya kita akan membuat dua file, client.java dan interface.java. Kurang lebih seperti ini tampilan dari struktur direktori nya :

Cara Membuat Aplikasi Android

Class client.java berisi koneksi antara client dengan server, di dalam file ini juga kita akan mendeklarasikan end point api kita, kita akan men-deklarasikannya dalam atribut BASE_URL, silahkan diganti dan di sesuaikan dengan end point api masing-masing (dalam case saya end point yang saya pakai adalah http://192.168.43.12:8080/belajar-laravel/public/api/, dimana 192.168.43.12 adalah ip local pc saya), isi dari client.java seperti ini :

package com.soft_gain.myinventory.Api;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class Client {
    public static final String BASE_URL = "http://end-point-api-anda/";
    private static Retrofit retrofit = null;
    public static Retrofit getClient() {
        if (retrofit==null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

Class interface.java sendiri berisi metode yang akan di gunakan untuk melakukan pertukaran data antara client dan server, isi dari interface.java kurang lebih seperti ini :

package com.soft_gain.myinventory.Api;

import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.HTTP;
import retrofit2.http.POST;
import retrofit2.http.PUT;

import com.soft_gain.myinventory.Model.Auth.Login;

public interface Interface {
    @FormUrlEncoded
    @POST("login")
    Call<Login> postLogin(@Field("email") String email,
                           @Field("password") String password);
}

Berikutnya kita akan membuat model, pertama buatlah package baru dengan nama Model, lalu buat lagi package baru di dalam Model dengan nama Auth, lalu di dalam package Auth tambahkan dua file Login.java dan Token.java, kurang lebih seperti ini strukturnya :

Cara Membuat Aplikasi Android

Isi dari Login.java seperti ini :

package com.soft_gain.myinventory.Model.Auth;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Login {
    @SerializedName("success")
    @Expose
    private Token success;

    public Token getSuccess() {
        return success;
    }
}

Dan Token.java seperti ini :

package com.soft_gain.myinventory.Model.Auth;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Token {
    @SerializedName("token")
    @Expose
    private String token;

    public String getToken() {
        return token;
    }
}

Berikutnya kita akan menambahkan LoginActivity.java, class ini berfungsi untuk menghandle otentikasi user yang akan kita implementasikan pada aplikasi kita, isinya kurang lebih seperti ini :

package com.soft_gain.myinventory;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.soft_gain.myinventory.Model.Auth.Login;
import com.soft_gain.myinventory.Api.Client;
import com.soft_gain.myinventory.Api.Interface;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class LoginActivity extends Activity {
    Button b1,b2;
    EditText ed1,ed2;
    Interface mApiInterface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        b1 = (Button)findViewById(R.id.button);
        b2 = (Button)findViewById(R.id.button2);
        ed1 = (EditText)findViewById(R.id.editText);
        ed2 = (EditText)findViewById(R.id.editText2);

        mApiInterface = Client.getClient().create(Interface.class);

        b1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Call<Login> postLoginExe = mApiInterface.postLogin(ed1.getText().toString(), ed2.getText().toString());
                postLoginExe.enqueue(new Callback<Login>() {
                    @Override
                    public void onResponse(Call<Login> call, Response<Login> response) {
                        if(response.isSuccessful()){
                            /*Log.v("log softgain : ", String.valueOf(response.body().getSuccess().getToken()));*/
                            Toast.makeText(getApplicationContext(),
                                    "Login berhasil",Toast.LENGTH_SHORT).show();

                            SharedPreferences sgSharedPref = getApplicationContext().getSharedPreferences("sg_shared_pref", getApplicationContext().MODE_PRIVATE);
                            SharedPreferences.Editor editor = sgSharedPref.edit();
                            String token = String.valueOf(response.body().getSuccess().getToken());
                            editor.putString("token", token);
                            editor.apply();

                            startActivity(new Intent(LoginActivity.this, MainActivity.class));
                        }else{
                            Toast.makeText(getApplicationContext() ,"Login gagal",Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(Call<Login> call, Throwable t) {
                        /*Log.v("log softgain : ", String.valueOf(t));*/
                        Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_LONG).show();
                    }
                });
            }
        });

        b2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

Perhatikan di atas, kita menambahkan sebuah on click event pada button login atau yang saya deklarasikan sebagai b1, yang mana didalamnya kita memanggil api interface yang sudah kita buat sebelumnya. Kita akan mencoba meng-handle response yang kita terima melalui method onResponse, di dalam onResponse kita memiliki if statement response.isSuccessful() yang kita gunakan untuk do event berikutnya bila proses otentikasi user berhasil. Perlu di perhatikan jika proses otentikasi user berhasil maka kita akan menyimpan token yang kita peroleh dari response server ke dalam shared preferences, penyimpanan informasi token ke shared preferences ada pada bagian ini :

SharedPreferences sgSharedPref = getApplicationContext().getSharedPreferences("sg_shared_pref", getApplicationContext().MODE_PRIVATE);
                            SharedPreferences.Editor editor = sgSharedPref.edit();
                            String token = String.valueOf(response.body().getSuccess().getToken());
                            editor.putString("token", token);
                            editor.apply();

Untuk detail mengenai shared preferences akan di bahas pada artikel yang berbeda.

Lalu kita juga akan membuka activity baru yaitu MainActivity, proses untuk membuka activity baru ada pada bagian ini :

startActivity(new Intent(LoginActivity.this, MainActivity.class));

Berikutnya kita tambahkan layout baru yaitu activity_login.xml, ini adalah tampilan yang akan di lihat oleh user sebagai halaman login, isi nya kurang lebih seperti ini :

<?xml version = "1.0" encoding = "utf-8"?>
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:tools = "http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height = "match_parent" tools:context = ".LoginActivity">

<TextView android:text = "Login" android:layout_width="wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/textview"
android:textSize = "35dp"
android:layout_alignParentTop = "true"
android:layout_centerHorizontal = "true" />

<TextView android:text = "@string/app_name" android:layout_width="wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/textview2"
android:textSize = "35dp"
android:layout_below="@+id/textview"
android:layout_centerHorizontal = "true" />

<EditText
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/editText"
android:hint = "Email"
android:focusable = "true"
android:textColorHighlight = "#ff7eff15"
android:textColorHint = "#ff2937"
android:layout_alignParentLeft = "true"
android:layout_alignParentStart = "true"
android:layout_alignParentRight = "true"
android:layout_alignParentEnd = "true"
android:layout_centerInParent="true" />

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:ems="10"
android:id="@+id/editText2"
android:layout_below="@+id/editText"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/editText"
android:layout_alignEnd="@+id/editText"
android:textColorHint="#ff2937"
android:hint="Password" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="login"
android:id="@+id/button"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@+id/textview"
android:layout_toStartOf="@+id/textview"
style="@style/Widget.AppCompat.Button.Colored"/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:id="@+id/button2"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/textview"
android:layout_toEndOf="@+id/textview"
style="@style/Widget.AppCompat.Button.Colored"/>

</RelativeLayout>

Selanjutnya kita juga akan melakukan sedikit modifikasi pada MainActivity.java, kurang lebih jadi seperti ini :

package com.soft_gain.myinventory;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
SharedPreferences sharedPrefs = getSharedPreferences("sg_shared_pref", MODE_PRIVATE);
SharedPreferences.Editor ed;
if(!sharedPrefs.contains("token")){
startActivity(new Intent(MainActivity.this, LoginActivity.class));
}

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@SuppressLint("ResourceType")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.top_menu, menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_logout) {
logout();
return true;
}
return super.onOptionsItemSelected(item);
}

private void logout() {
SharedPreferences sgSharedPref = getApplicationContext().getSharedPreferences("sg_shared_pref", getApplicationContext().MODE_PRIVATE);
sgSharedPref.edit().clear().commit();

startActivity(new Intent(MainActivity.this, LoginActivity.class));
}
}

Perhatikan di atas, dimana kita menambahkan method baru yaitu logout, yang berisikan penghapusan shared preferences berisi informasi token dan pemindahan user kembali ke activity LoginActivity, on click event dari method logout ini sendiri kita trigger melalui interface pada top menu yang di presentasikan melalui top_menu.xml (detail pembuatannya akan dibahas pada artikel yang berbeda). Pada bagian onCreate juga kita menambahkan if statement (pengecekan token pada shared preferences) untuk memastikan hanya user yang memiliki token saja yang bisa mengakses MainActivity.

Penutup

Demikian lah pembahasan kali ini, untuk full source nya bisa di ambil di repo saya (https://github.com/ImmanuelJL/myinventory.git), terima kasih.

Update :

Part 2 : https://soft-gain.com/2020/06/23/contoh-sederhana-recyclerview-cardview-dengan-implementasi-retrofit/

Part 3 : https://soft-gain.com/2020/06/28/aplikasi-crud-android-database-mysql-menggunakan-retrofit-dan-laravel/

Cara Membuat Aplikasi Android, Hello World Android Studio

Cara Membuat Aplikasi Android

Pada kesempatan kali ini saya hendak mencoba membagikan pengalaman saya membuat aplikasi android hello world menggunakan android studio, android studio bisa di download secara gratis di sini (https://developer.android.com/studio). Sebenarnya untuk membuat aplikasi berbasis android tidak lah harus menggunakan android studio, hanya saja android studio di rekomendasikan karena mendapat support penuh dari Google selaku pengembang dari OS berbasis android. Seperti awal dari semua pembuatan aplikasi, kita akan memulainya dengan membuat aplikasi hello world. Tanpa perlu berbasa-basi lagi langsung saja kita masuk pada pembahasan, pembuatan aplikasi android hello world menggunakan android studio.

Kita buka android studio nya, lalu pilih sesuai gambar di bawah ini untuk membuat project baru :

Hello World Android Studio

Di halaman berikutnya, kita di minta untuk mengisikan nama aplikasi, domain company dan dimana aplikasi project ingin kita tempatkan. Seperti gambar di bawah ini :

Hello World Android Studio

Selanjutnya kita akan memilih pada perangkat apa dan minimum versi OS berapa aplikasi yang hendak kita buat bisa berjalan. Seperti gambar ini :

Hello World Android Studio

Lalu berikutnya kita akan di tampilkan beberapa activity default yang bisa kita jadikan dasar pengembangan aplikasi kita, untuk saat ini kita pilih saja empty activity, seperti gambar di bawah ini :

Cara Membuat Aplikasi Android

Berikutnya kita akan di minta mengisikan nama pada activity dan layout utama pada aplikasi kita, seperti gambar di bawah ini :

Cara Membuat Aplikasi Android

Lalu tinggal klik finish, jika sudah selesai seperti ini lah tampilan dari source project yang baru kita buat :

Cara Membuat Aplikasi Android

Jika kita lihat gambar di atas, di sebelah kiri kita memiliki struktur folder yang akan kita gunakan jika mengembangkan aplikasi menggunakan android studio. Pertama kita memiliki folder manifest, di dalamnya terdapat file AndroidManifest.xml, file ini berisi komponen dasar dari aplikasi kita, seperti activity, services dan user permission, jangan lupa juga jika kita hendak menambahkan activity baru untuk di deklarasikan di dalam file ini.

Berikutnya ada folder java, di dalamnya berisi file-file ber-ekstensikan .java, folder ini berisi class-class yang di tulis dengan bahasa pemrograman java, biasanya file ini berisi activity, fragment, model, class helper kita dalam membuat aplikasi dan lain-lain, intinya di folder inilah kita akan menaruh semua source code kita nantinya.

Berikutnya ada folder res, folder res sendiri di bagi lagi menjadi 4 bagian yaitu drawable, layout, mipmap, dan values. Folder drawable sendiri berisikan asset berupa gambar yang hendak kita gunakan pada aplikasi, folder layout merupakan tempat di mana kita manruh source untuk membuat interface atau tampilan yang akan di lihat oleh user, folder mipmap biasanya di gunakan untuk menyimpan file atau icon launcher pada aplikasi, folder values berisikan file-file untuk menampung interface value yang bisa kita gunakan secara global pada aplikasi.

Terakhir ada gradle, yang berisikan informasi versi OS, SDK dan library apa saja yang kita gunakan dalam aplikasi, file ini jugalah yang menjadi build tool untuk menjalankan aplikasi kita pada andriod studio.

Terakhir kita akan coba jalankan aplikasi, untuk menjalankan aplikasi ada dua pilihan yaitu menggunakan emulator atau menggunakan perangkat asli, saya sendiri belum pernah menggunakan emulator karena membutuhkan ram dalam jumlah yang cukup besar, dan juga dengan pertimbangan testing aplikasi pada perangkat asli memiliki tingkat keakuratan QC yang lebih baik.

Saya sendiri menggunakan hp xiaomi redmi 3s untuk proses debug dan test aplikasi, pada hp xiaomi silahkan masuk ke setting -> about phone lalu ketuk miui version sampai keluar pop up “you are now a developer”. Berikutnya buka setting -> additional setting -> developer options enable kan usb debugging pada pengaturan ini. Selanjutnya sambung kan hp dengan PC menggunakan kabel usb, lalu klik run pada andriod studio, maka akan di munculkan beberapa pilihan debugging tools yang ter-install pada pc kita :

Cara Membuat Aplikasi Android

Jika sudah tampil maka tinggal klik ok saja dan tunggu proses installasi pada hp, perlu menjadi catatan mungkin terdapat perbedaan cara menghubungkan perangkat hp dengan andriod studio untuk dapat terbaca sebagai debugging tools. Demikianlah pembahasan pada kali ini, terima kasih.

Tutorial Laravel, Membuat Aplikasi Web Service

tutorial laravel

Tutorial laravel kali ini adalah kelanjutan dari tutorial sebelumnya yang mana kita sudah mencoba untuk menggunakan passport sebagai otentikasi user (https://soft-gain.com/2020/06/12/tutorial-laravel-rest-api-menggunakan-otentikasi-passport/), dimana kali ini kita akan mencoba membuat web service untuk aplikasi inventory yang sedang kita coba kembangkan. Langsung saja kita masuk ke dalam pembahasan pada artikel tutorial laravel, membuat aplikasi web service.

Pertama-tama kita akan membuat controller baru khusus untuk web service yang akan kita buat ini, controller yang akan kita buat adalah sg_transaksi, sg_barang dan sg_user, controller ini akan kita taruh di dalam folder baru bernama Api. Dan untuk testing tools nya kita akan gunakan postman, kalau belum ada silahkan di install terlebih dahulu postman-nya. Lalu silahkan ketik perintah berikut ini untuk meng-generate controller :

php artisan make:controller Api/sg_transaksi
php artisan make:controller Api/sg_barang
php artisan make:controller Api/sg_user

Isi dari sg_transaksi controller kurang lebih seperti ini :

<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\sg_transaksi as model;
use App\sg_barang;
use Auth;

class sg_transaksi extends Controller
{
    public function index(){
    	$data = model::with('getNamaBarang','getCreatedBy','getUpdatedBy')->orderBy('id','desc')->get();
    	$success['data'] =  $data;
        
        return response()->json(['success' => $success], 200);
    }

    public function store(Request $request){
    	$validatedData = $request->validate([
	        'id_barang' => 'required|max:255',
	        'jenis_transaksi' => 'required',
	        'jumlah_barang' => 'required',
	    ]);

	    $request['created_by'] = Auth::user()->id;

    	model::create($request->all());

    	$this->trx = new \App\Http\Controllers\sg_transaksi;
    	$this->trx->updateSgBarang($request);

    	return response()->json(['success' => true], 200);
    }

    public function edit($id){
    	$data = model::find($id);
    	$success['data'] =  $data;
        
        return response()->json(['success' => $success], 200);
    }

    public function update(Request $request, $id){
    	$validatedData = $request->validate([
	        'id_barang' => 'required|max:255',
	        'jenis_transaksi' => 'required',
	        'jumlah_barang' => 'required',
	    ]);

	    $request['updated_by'] = Auth::user()->id;

	    $this->trx = new \App\Http\Controllers\sg_transaksi;
    	$this->trx->updateSgBarang($request, $id);

    	$data = $request->except('_method', '_token');
    	model::where('id',$id)->update($data);

    	return response()->json(['success' => true], 200);
    }

    public function delete($id){
    	$value = model::where('id',$id);
    	$sg_barang = sg_barang::where('id',$value->value('id_barang'));

        if( $value->first()->jenis_transaksi == 'Masuk' ){
            $sg_barang->update(["jumlah_barang"=>(int) $sg_barang->value('jumlah_barang') - (int) $value->first()->jumlah_barang]);
        }elseif( $value->first()->jenis_transaksi == 'Keluar' ){
            $sg_barang->update(["jumlah_barang"=>(int) $sg_barang->value('jumlah_barang') + (int) $value->first()->jumlah_barang]);
        }
    	model::destroy($id);
        
        return response()->json(['success' => true], 200);
    }
}

Untuk sg_barang controller seperti ini :

<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\sg_barang as model;
use Auth;

class sg_barang extends Controller
{
    public function index(){
    	$data = model::with('getUpdatedBy')->get();
    	$success['data'] =  $data;
        
        return response()->json(['success' => $success], 200);
    }

    public function store(Request $request){
    	$validatedData = $request->validate([
	        'nama_barang' => 'required|max:255',
	        'jumlah_barang' => 'required',
	    ]);

	    $request['updated_by'] = Auth::user()->id;

    	model::create($request->all());

    	return response()->json(['success' => true], 200);
    }

    public function edit($id){
    	$data = model::find($id);
    	$success['data'] =  $data;
        
        return response()->json(['success' => $success], 200);
    }

    public function update(Request $request, $id){
    	$validatedData = $request->validate([
	        'nama_barang' => 'required|max:255',
	        'jumlah_barang' => 'required',
	    ]);

	    $request['updated_by'] = Auth::user()->id;

    	$data = $request->except('_method', '_token');
    	model::where('id',$id)->update($data);

    	return response()->json(['success' => true], 200);
    }

    public function delete($id){
    	model::destroy($id);
        
        return response()->json(['success' => true], 200);
    }
}

Untuk sg_user controller seperti ini :

<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use App\User as model;
use Auth;

class sg_user extends Controller
{
    public function index(){
    	$data = model::all();
    	$success['data'] =  $data;
        
        return response()->json(['success' => $success], 200);
    }

    public function store(Request $request){
    	$validatedData = $request->validate([
	        'name' => 'required|max:255',
	        'email' => 'email',
		    'password' => 'required|confirmed|min:6',
		    'role' => 'required',
	    ]);

    	model::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
            'role' => $request->role,
        ]);

    	return response()->json(['success' => true], 200);
    }

    public function edit($id){
    	$data = model::find($id);
    	$success['data'] =  $data;
        
        return response()->json(['success' => $success], 200);
    }

    public function update(Request $request, $id){

    	if(isset($request->password) && isset($request->password_confirmation) && $request->password !== '' && $request->password_confirmation !== ''){
    		$validatedData = $request->validate([
		        'name' => 'required|max:255',
		        'email' => 'email',
			    'password' => 'required|confirmed|min:6',
			    'role' => 'required',
		    ]);
    	}else{
    		$validatedData = $request->validate([
		        'name' => 'required|max:255',
		        'email' => 'email',
			    'role' => 'required',
		    ]);
    	}

    	$data = $request->except('_method', '_token', 'password_confirmation');

    	if(isset($request->password) && isset($request->password_confirmation) && $request->password !== '' && $request->password_confirmation !== ''){
    		model::where('id',$id)->update([
	            'name' => $request->name,
	            'email' => $request->email,
	            'password' => Hash::make($request->password),
	            'role' => $request->role,
	        ]);
    	}else{
    		model::where('id',$id)->update([
	            'name' => $request->name,
	            'email' => $request->email,
	            'role' => $request->role,
	        ]);
    	}

    	return response()->json(['success' => true], 200);
    }

    public function delete($id){
    	model::destroy($id);
        
        return response()->json(['success' => true], 200);
    }
}

Terakhir kita akan tambah kan route nya pada api.php, kurang lebih jadi seperti ini :

<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::post('login', 'Api\AuthController@login');

Route::group(['middleware' => 'auth:api'], function(){
    Route::post('barang', 'Api\sg_barang@index');
    Route::put('barang/store', 'Api\sg_barang@store');
    Route::post('barang/edit/{id}', 'Api\sg_barang@edit');
    Route::post('barang/update/{id}', 'Api\sg_barang@update');
    Route::delete('barang/delete/{id}', 'Api\sg_barang@delete');

    Route::post('transaksi', 'Api\sg_transaksi@index');
    Route::put('transaksi/store', 'Api\sg_transaksi@store');
    Route::post('transaksi/edit/{id}', 'Api\sg_transaksi@edit');
    Route::post('transaksi/update/{id}', 'Api\sg_transaksi@update');
    Route::delete('transaksi/delete/{id}', 'Api\sg_transaksi@delete');

    Route::group(['prefix' => '', 'middleware' => ['role']], function() {
	    Route::post('user', 'Api\sg_user@index');
	    Route::put('user/store', 'Api\sg_user@store');
	    Route::post('user/edit/{id}', 'Api\sg_user@edit');
	    Route::post('user/update/{id}', 'Api\sg_user@update');
	    Route::delete('user/delete/{id}', 'Api\sg_user@delete');
	});
});

Kita akan mencoba membahas beberapa perbedaan pada controller api ini dan non api. Pertama, return yang di kembalikan ke pada user atau client adalah berbentuk objek, dimana kali ini kita menggunakan json. Json sendiri adalah singkatan dari JavaScript Object Notation, bisa di artikan sebagai standarisasi format pertukaran data untuk memungkinkan terjadinya komunikasi antara mesin. Contoh yang kita implementasikan adalah seperti ini :

return response()->json(['success' => $success], 200);

Lalu untuk fungsi store dan update, di kita akan memanfaatkan fitur validasi bawaan dari laravel (https://laravel.com/docs/7.x/validation), dimana jika validasi yang kita terapkan ternyata tidak sesuai dengan data yang di kirimkan client, maka return nya akan di kembalikan dalam bentuk json pada client berikut dengan pesan error pada validasinya. Contohnya adalah pada bagian ini :

$validatedData = $request->validate([
    'nama_barang' => 'required|max:255',
    'jumlah_barang' => 'required',
]);

Sisanya, hampir tidak ada perbedaan antara controller api dan non api. Berikutnya kita akan coba melakukan pengujian menggunakan postman, silahkan di perhatikan gambar di bawah ini :

Index

Silahkan perhatikan bagian-bagian yang sudah saya highlight dengan warna merah, pertama silahkan di sesuaikan url yang akan di hit dengan postman dan juga sesuaikan http request method-nya. Lalu pindahkan pada bagian Headers dan isi kan sesuai parameter pada gambar, yang perlu menjadi perhatian adalah pada bagain Authorization, value nya harus di sesuaikan dengan token yang kita dapat ketika kita berhasil login, untuk detail lengkapnya silahkan baca kembali tutorial sebelumnya (https://soft-gain.com/2020/06/12/tutorial-laravel-rest-api-menggunakan-otentikasi-passport/), contoh pada aplikasi kita adalah :

Bearer token_string

Dan jika semua sudah terisi tinggal tekan send, jika menerima hasil seperti gambar di atas maka bisa di asumsikan kita telah berhasil membuat web service. Selanjutnya untuk store, edit, update dan delete juga hampir sama, hanya saja pada store dan update kita perlu mengisikan parameter pada tab body kurang lebih seperti ini :

Store

Demikian lah pembahasan kita pada kali ini, source full nya bisa di ambil di repo saya seperti biasa (https://github.com/ImmanuelJL/belajar-laravel), silahkan di ambil dari cabang aplikasi-stok-barang. Untuk postman collection nya bisa di download di sini (https://drive.google.com/file/d/1KlDQc62pYC9p0b27gnMn7gGTCkzceQ-0/view?usp=sharing), tinggal di download saja dan di import pada postman supaya bisa dapat semua collection request yang kita gunakan pada tutorial ini. Terima kasih.

Tutorial Laravel Api Passport, Otentikasi User Pada REST API

tutorial laravel

Pada kesempatan ini kita akan membahas tentang tutorial laravel rest api menggunakan passport sebagai otentikasi user. Apa itu rest api? rest api atau api atau restful api atau web service secara garis besar sama saja, merupakan state transfer protokol berbasis http, dan passport itu sendiri adalah otentikasi api default dari laravel yang di buat berdasarkan library League OAuth2 Server, jadi sebenarnya tidak menggunakan passport dan langsung menggunakan library oauth2 pun sah-sah saja. Baiklah tanpa berbasa-basi lagi, langsung saja kita masuk pada pembahasan Tutorial Laravel REST API, Menggunakan Otentikasi Passport.

By the way, artikel ini adalah kelanjutan dari artikel (https://soft-gain.com/2020/06/10/tutorial-export-excel-laravel-aplikasi-inventory-part-6/), dimana kita akan coba kembangkan aplikasi yang sudah kita buat sebelumnya menjadi serbuah web service.

Pertama-tama kita install terlebih dahulu library laravel/passport pada aplikasi kita, saya di sini menggunakan passport versi 7.5.1 karena latest version-nya sudah tidak support dengan versi laravel yang saya gunakan (laravel 5.8). Ketikan perintah ini pada terminal :

composer require laravel/passport:7.5.1

Lalu kita lakukan migasi untuk mendapatkan table yang akan kita gunakan untuk menampung token, gunakan perintah berikut ini :

php artisan migrate

Selanjutnya ketikan perintah ini :

php artisan passport:install

Mengacu pada dokumentasi resmi (https://laravel.com/docs/7.x/passport), perintah ini akan meng-generate keys yang akan kita gunakan untuk membuat access token nantinya, baik itu personal access ataupun password grant. Apa bedanya? personal access biasa di gunakan untuk 3rd party aplication yang hendak mengakses data dari server kita tanpa harus memasukan credentials user (dengan alasan security), jadi pengguna mempunyai access token masing-masing tanpa harus mengetahui credentials user. Sedangkan password grant biasa di gunakan oleh first party client (seperti pengembangan aplikasi berbasis andriod) karena pengguna memiliki credentials user yang valid, sumber (https://stackoverflow.com/questions/54275082/what-are-the-main-difference-between-personal-access-client-and-password-client).

Selanjutnya kita akan merubah sedikit model user, kurang lebih jadi seperti ini :

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password', 'role',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Berikutnya kita akan merubah AuthServiceProvider.php, kurang lebih jadi seperti ini :

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        Passport::routes();
        //
    }
}

Penambahan Passport::routes(); di atas menjadi penting, karena dengan method ini lah kita akan mendaftar kan routes yang akan di gunakan untuk meng-generate atau revoke access token.

Berikutnya kita akan merubah file config/auth.php, ubah pada bagian guards menjadi seperti ini :

'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
            // 'hash' => false,
        ],
],

Berikutnya kita akan menambahkan router yang hendak kita gunakan untuk meng-handle request api yang masuk pada aplikasi kita. Di laravel versi 5.8 ini sudah di pisahkan route khusus untuk api, jadi tinggal buka saja file api.php dan isi tambahkan baris ini :

Route::post('login', 'Api\AuthController@login');

Selanjutnya kita akan membuat controller, masukan perintah berikut ini pada terminal :

php artisan make:controller Api/AuthController

Kita akan membuat controller dalam folder Api, jadi controller api kita akan pisahkan dengan controller untuk handle request non-api. Tambahkan fungsi login sehingga menjadi seperti ini :

<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
	public function login(){
        if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
            $user = Auth::user();
            $success['token'] =  $user->createToken('myinventory')->accessToken;

            return response()->json(['success' => $success], 200);
        }
        else{
            return response()->json(['error'=>'Unauthorised'], 401);
        }
    }
}

Jika sudah selesai tinggal kita test menggunakan postman, postman ini adalah tools gratis yang bisa kita gunakan untuk testing / develop web service. Masukan parameter dan url seperti gambar di bawah ini :

Login API

Jika kita mendapatkan response sukses maka kita telah berhasil membuat dan mengimplementasikan laravel passport sebagai otentikasi api kita. Token yang kita dapat ini lah yang akan kita gunakan sebagai validasi apakah pengguna berhak mengakses resource dari server kita atau tidak. Demikian, terima kasih.