CRUD Manajemen Artikel - Refaktor Form Tambah dan Ubah Artikel

8 Maret 2025
  ·  

6 menit  ·   4 kali baca

Setelah sebelumnya kita berhasil membuat fitur menambah dan mengubah artikel, kini saatnya kita melakukan sedikit refaktor agar kode menjadi lebih rapi, efisien, dan mudah dikelola.

Pada artikel ini, kita akan menyatukan form tambah dan edit artikel ke dalam satu tampilan yang fleksibel. Selain itu, kita juga akan mengelola beberapa variabel umum langsung dari constructor agar tidak perlu dimuat pada masing-masing method controller.

Yuk, langsung kita mulai dengan menyatukan form-nya!

Menyatukan Form

Terdapat banyak kesamaan antara file View create.blade.php dan edit.blade.php. Untuk mengurangi duplikasi kode dan membuat kode jadi lebih mudah dipelihara, kita dapat membuat kode View form ini jadi lebih sederhana.

Kita akan menggabungkan kedua file View form menjadi satu file view saja, yaitu file edit.blade.php seperti berikut:

Untuk menggabungkan, kita mempertahankan kode yang sama dari kedua view dan membuat kondisi percabangan (if / else) pada bagian yang berbeda.

Mungkin muncul pertanyaan, “Bagaimana cara membedakan antara Create dan Edit? Apakah terdapat kondisi penentu atau pembeda antara keduanya?”

Pertanyaan bagus! Jawabannya: kita bisa cek model $article!

Untuk membedakan mode Create dan Edit, kita cukup memeriksa apakah model $article memiliki ID. Berikut perbandingannya:

Kondisi
Nilai $article->id
Createnull — Model Article belum memiliki nilai id karena data belum tersimpan pada database.
EditAda nilai id karena data sudah tersimpan pada database.

Agar lebih jelas, mari sesuaikan Controller menjadi seperti berikut:

📄 app/Http/Controllers/ArticleController.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/** ... **/

    /**
     * Show the form for creating a new resource.
     */
    public function create(): View
    {
        $article = new Article;

        $statusList = Article::STATUS_LIST;

        return view('pages.articles.edit', compact('article', 'statusList'));
    }

/** ... **/
  • Baris 8
    Membuat instance baru dari model Article.
  • Baris 12
    • Menggunakan View edit.blade.php, bukan create.blade.php.
    • Menambahkan argumen article ke dalam compact untuk mengirimkan model $article yang baru dibuat ke View.

Selanjutnya, sesuaikan file View form menjadi:

📄 resources/views/pages/articles/edit.blade.php

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
@php
    $isEditMode = $article->id;
@endphp

@extends('layouts.app')

@section('title', ($isEditMode ? 'Edit' : 'Tambah') . ' Artikel')

@section('content')
    <div id="content" class="container">
        {{ html()->form($isEditMode ? 'PUT' : 'POST', $isEditMode ? route('articles.update', $article->id) : route('articles.store'))->acceptsFiles()->autocomplete(false)->open() }}
        @php html()->model($article); @endphp

        <div class="row">
            <div class="col-lg-8">
                <div class="mb-3">
                    @php
                        $name = 'title';
                        $placeholder = 'Judul';
                    @endphp

                    {{ html()->text($name)->class('form-control fs-3' . ($errors->has($name) ? ' is-invalid' : ''))->placeholder($placeholder) }}

                    @error($name)
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>

                <div class="mb-3">
                    @php
                        $name = 'slug';
                        $placeholder = 'Slug';
                    @endphp

                    <div class="input-group">
                        <div class="input-group-prepend">
                            <div class="input-group-text">{{ route('articles.index') }}/</div>
                        </div>

                        {{ html()->text($name)->class('form-control' . ($errors->has($name) ? ' is-invalid' : ''))->placeholder($placeholder) }}

                        @error($name)
                            <div class="invalid-feedback">{{ $message }}</div>
                        @enderror
                    </div>
                </div>

                <div class="mb-3">
                    @php $name = 'content'; @endphp

                    {{ html()->textarea($name)->class('form-control' . ($errors->has($name) ? ' is-invalid' : '')) }}

                    @error($name)
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>
            </div>

            <div class="col-lg-4">
                <div class="card mb-3">
                    @php
                        $name = 'feature_image_url';
                        $placeholder = 'Gambar Pilihan';
                    @endphp

                    <div class="card-header">{{ $placeholder }}</div>
                    <div class="card-body">
                        {{ html()->file($name)->class('form-control' . ($errors->has($name) ? ' is-invalid' : '')) }}

                        @error($name)
                            <div class="invalid-feedback">{{ $message }}</div>
                        @enderror
                    </div>
                </div>

                <div class="card mb-3">
                    <div class="card-body">
                        <div class="mb-2">
                            @php
                                $name = 'status';
                                $placeholder = 'Status';
                            @endphp

                            {{ html()->select($name, $statusList, $isEditMode ? $article->getRawOriginal($name) : null)->class('form-select' . ($errors->has($name) ? ' is-invalid' : ''))->placeholder($placeholder) }}

                            @error($name)
                                <div class="invalid-feedback">{{ $message }}</div>
                            @enderror
                        </div>

                        <div class="mb-2">
                            @php $name = 'published_at'; @endphp

                            {{ html()->datetime($name, $isEditMode ? \Carbon\Carbon::parse($article->{$name})->format('Y-m-d\TH:i') : null)->class('form-control' . ($errors->has($name) ? ' is-invalid' : '')) }}

                            @error($name)
                                <div class="invalid-feedback">{{ $message }}</div>
                            @enderror
                        </div>
                    </div>
                </div>

                {{ html()->submit($isEditMode ? 'Update' : 'Simpan')->class('btn btn-primary') }}
            </div>
        </div>

        {{ html()->form()->close() }}
    </div>
@endsection

@push('scripts')
    <script type="module">
        $('[name=title]').on('input', function() {
            $('[name=slug]').val($(this).val().replace(/\s+/g, '-').replace(/[^a-z0-9-]/gi, '').toLowerCase());
        });

        new FroalaEditor('textarea[name=content]', {
            htmlRemoveTags: ['div'],
        });
    </script>
@endpush
  • Baris 1-3
    Membuat sebuah flag $isEditMode untuk membedakan Create atau Edit berdasarkan ada/tidaknya ID. Nilai $article->id bernilai null (falsy) pada kondisi Create dan bernilai 3 / 25 / 41 sesuai ID artikel (truthy) pada kondisi Edit.
  • Baris 7
    Menyesuaikan judul halaman.
  • Baris 11
    Menyesuaikan method dan action form.
  • Baris 12
    Memungkinkan semua input form otomatis terisi dengan nilai dari model $article saat mode Edit.
  • Baris 84
    Menyesuaikan nilai default field status saat Edit.
  • Baris 94
    Menyesuaikan nilai default field published_at saat Edit.
  • Baris 103
    Menyesuaikan teks pada tombol submit.

Mengelola Beberapa Variabel Umum Langsung dari Constructor

Variabel $statusList pada Method create() dan edit()

  1. Pada file controller, tambahkan properti $statusList dan isi method constructor sebagai berikut:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    /** ... **/
    
    class ArticleController extends Controller
    {
        private array $statusList;
    
        public function __construct()
        {
            $this->statusList = Article::STATUS_LIST;
        }
    
    /** ... **/
    
  2. Sesuaikan method create() dan edit() menjadi sebagai berikut:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    /** ... **/
    
        public function create(): View
        {
            $article = new Article;
    
            return view('pages.articles.edit', [
                ...compact('article'),
                'statusList' => $this->statusList,
            ]);
        }
    
        /** ... **/
    
        public function edit(Article $article): View
        {
            return view('pages.articles.edit', [
                ...compact('article'),
                'statusList' => $this->statusList,
            ]);
        }
    
    /** ... **/
    

Variabel $storagePath pada Method store() dan update()

  1. Pada file controller, tambahkan properti $storagePath dan isi method constructor sebagai berikut:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    /** ... **/
    
    class ArticleController extends Controller
    {
        private array $statusList;
        private string $storagePath;
    
        public function __construct()
        {
            $this->statusList = Article::STATUS_LIST;
            $this->storagePath = Article::IMAGE_STORAGE_PATH;
        }
    
    /** ... **/
    
  2. Sesuaikan method store() dan update() menjadi sebagai berikut:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    /** ... **/
    
        public function store(ArticleRequest $request): RedirectResponse
        {
            /** ... **/
            $file->storeAs($this->storagePath, $fileName, 'public');
            /** ... **/
        }
    
        /** ... **/
    
        public function update(ArticleRequest $request, Article $article): RedirectResponse
        {
            try {
                $input = $request->validated();
    
                if ($request->hasFile('feature_image_url')) {
                    if ($article->feature_image_url) {
                        $oldFilePath = "$this->storagePath/$article->feature_image_url";
    
                        if (Storage::disk('public')->exists($oldFilePath)) {
                            Storage::disk('public')->delete($oldFilePath);
                        }
                    }
    
                    /** ... **/
    
                    $file->storeAs($this->storagePath, $fileName, 'public');
    
            /** ... **/
        }
    
    /** ... **/
    

Hasil Refaktor

Apabila kita melihat lagi tampilan Create & Edit, kita akan melihat bahwa View dapat berfungsi dengan baik pada kondisi Create maupun Edit seperti semula:

Kondisi Create

Kondisi Edit


Apabila sebelumnya kita memiliki dua file View, …

… kini hanya tersisa satu saja.

Dengan ini, jika kita ingin mengubah form, cukup ubah di satu file saja. Tidak perlu lagi mengubah di dua tempat yang berbeda. Kode jadi lebih rapi dan mudah dipelihara!



Dengan pendekatan ini, kita tidak hanya membuat kode menjadi lebih DRY (Don’t Repeat Yourself), tetapi juga meningkatkan konsistensi tampilan dan pengalaman user secara keseluruhan. Jauh lebih rapi dan tentu lebih menyenangkan untuk dikelola ke depannya!

Pada artikel berikutnya, kita akan membahas fitur delete untuk menyempurnakan proses CRUD. Semangat terus, yaa! ✨

CRUD Manajemen Artikel - Refaktor Form Tambah dan Ubah Artikel
Top