nschelper/larahelper

辅助包

v1.0.6 2023-08-01 14:15 UTC

This package is not auto-updated.

Last update: 2024-09-25 11:52:12 UTC


README

[安装]

composer require nschelper/larahelper

composer update nschelper/larahelper

注意:不再需要在 config/app.php 中添加任何内容,无论是 providers 还是 aliases

然后通过以下方式发布 langcssjs 文件

php artisan vendor:publish --tag=niascoder-helper

php artisan vendor:publish --tag=niascoder-helper --force

注意:最好避免使用 --force 选项。在发布之前,先选择下面要重新从包仓库中读取的文件。然后不带 --force 选项进行发布。发布不会覆盖已经存在的文件。

生成的文件

config/niascoderhelper.php
lang/id/db.php
lang/id/error.php
lang/id/log.php
lang/id/tooltip.php
lang/id/validation.php
public/js/global.js

[组件]

用于 blade

// -----
// form control
// -----

<x-form-input
    name="nama_lengkap"
    lang-context="db.pegawai.edit">
    </x-form-input>

<x-form-textarea
    name="nama_lengkap"
    lang-context="db.pegawai.edit">
    </x-form-textarea>

<x-form-select
    name="jenis_kelamin"
    lang-context="db.pegawai.edit"
    :options="['L' => 'Laki-laki', 'P' => 'Perempuan']">
    </x-form-select>

<x-form-file
    name="file_upload"
    lang-context="db.pegawai.edit"
    accept=".docx,.pdf"
    multiple="true">
    </x-form-file>

<x-form-recaptcha2
    name="pegawai_captcha"
    site-key="{{ config('recaptcha.api_site_key') }}"
    :modal-form="true">
    </x-form-recaptcha2>

// -----
// collection control
// -----

// menampilkan filter button dan data count
// kalau filter-control-nya hanya 1, gunakan syntax: "(bool) request()->filter1" pada :is-tersaring
<x-collection-filtering
    :collection="$objectList"
    :is-tersaring="request()->filter1 || request()->filter2 || [...]"
    :post-url="route('route_name')">
        <x-form-input
            name="nama_lengkap"
            old-value="{{ request()->filter1 }}"
            lang-context="db.pegawai.index">
            </x-form-input>
        <x-form-input
            name="alamat"
            old-value="{{ request()->filter2 }}"
            lang-context="db.pegawai.index">
            </x-form-input>
    </x-collection-filtering>

// menampilkan hanya data count (misalnya kalau tidak butuh fitur filter)
<x-collection-info
    :collection="$objectList">
    </x-collection-info>

// menampilkan dropdown untuk memilih jumlah baris data per halaman (row per page)
// tidak membutuhkan parameter
<x-collection-rowperpage />

// supaya row per page persist, di controller function
$rowsPerPage = intval(request()->query('rowsperpage', request()->cookie('rowsperpage', config('niascoderhelper.rows_per_page'))));
Cookie::queue('rowsperpage', $rowsPerPage, 360);
// ...
$objectList = ObjectModel::paginate($rowsPerPage)->withQueryString();

// -----
// partial view
// -----

// gunakan partial view ini untuk me-render pagination (bootstrap 5)
// $objectList harus hasil pagination.
// kalau tidak ada page (!$objectList->hasPages()), tidak ada yang di render.
{{ $objectList->links('niascoder-helper::partials.pagination-numbers') }}

用于 lang/id/db.php

return [
    'pegawai.edit.nama_lengkap' => 'Nama lengkap',
    'pegawai.edit.jenis_kelamin' => 'Jenis kelamin',
    'pegawai.index.filter1' => 'Filter A',
    'pegawai.index.filter2' => 'Filter B',
];

[验证器]

在执行验证的控制器函数中

$validator = Validator::make($request->all(), [
    // ...
    'tanggal' => 'required|tglblnthn',
    'nik' => 'required|nik',
    'nomorkk' => 'required|nomorkk',
    // ...
    'g-recaptcha-response' => 'recaptcha',
    // atau bisa juga
    recaptchaFieldName() => recaptchaRuleName(),
    // ...
]);

[将数据保存到数据库]

在输出完整视图的控制器函数中

// ganti $object dengan model eloquent
// ganti table.operation dengan nama tabel dan nama operasi, cth: pegawai.create, atau pegawai.update
try {
    $object->save();
} catch (\Throwable $th) {
    Log::error(__('log.db.error.table.operation'), ['th' => $th, 'db' => AppHelper::attrToArray($object)]);
    return redirect()->back()->withErrors(AppHelper::validatorErrorTh($th, __('log.db.error.table.operation')))->withInput();
}

在输出 JSON 的控制器函数中

// ganti $object dengan model eloquent
// ganti table.operation dengan nama tabel dan nama operasi, cth: pegawai.create, atau pegawai.update
try {
    $object->save();
} catch (\Throwable $th) {
    Log::error(__('log.db.error.table.operation'), ['th' => $th, 'db' => AppHelper::attrToArray($object)]);
    return response()->json(AppHelper::jsonResponseErrorTh($th, __('log.db.error.table.operation')));
}

用于 lang/id/log.php

return [
    // ...
    'db.error.table.operation' => 'Gagal melakukan [operasi] pada [table].',
    // ...
];

[非 AJAX 重定向]

在输出完整视图的控制器函数中

// redirect back dengan Throwable
return redirect()->back()->withErrors(AppHelper::validatorErrorTh($th))->withInput();

// redirect back, ada form input salah
// contoh: menampilkan validasi error di form control #nama_lengkap
return redirect()->back()->withErrors(AppHelper::validatorErrorForm('nama_lengkap', 'Nama ini tidak boleh digunakan.'))->withInput();

// redirect back, menampilkan sweetalert
// contoh: menampilkan pesan khusus lewat sweetalert
return redirect()->back()->withErrors(AppHelper::validatorErrorMessage('Maaf, pendaftaran sudah tutup.'))->withInput();

[AJAX 响应]

在输出 JSON 的控制器函数中

// success
// ganti $redirect_url dengan alamat tujuan redirect. kalau kosong, refresh.
return response()->json(AppHelper::jsonResponseSuccess($redirect_url));

// error dengan Throwable
// ganti $redirect_url dengan alamat tujuan redirect. kalau kosong, refresh.
return response()->json(AppHelper::jsonResponseErrorTh($th, $message, $redirect_url));

// error dengan menampilkan pesan
// ganti $redirect_url dengan alamat tujuan redirect. kalau kosong, refresh.
return response()->json(AppHelper::jsonResponseErrorMessage($message, $redirect_url));

[模型中的 DateTime]

class PegawaiModel
{
    protected function tanggalLahir(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => AppHelper::showTanggal($value, "d-m-Y"),
            set: fn ($value) => AppHelper::parseTanggal($value, "d-m-Y"),
        );
    }
}

[布局]

用于 blade 模板

<script src="//cdn.jsdelivr.net.cn/npm/sweetalert2@11"></script>
<script src="{{ asset('js/global.js') }}"></script>
@stack('scripts')

@error('error_alert')
    <script>
        $(function() {
            Swal.fire('', '{{ $message }}', 'error');
        });
    </script>
@enderror

用于 blade 内容

// -----
// buttons, dengan text
// -----

<a href="{{ route('route_create') }}" class="btn btn-success">Tambah</a>

<a href="{{ route('route_edit', ['id' => $id]) }}" class="btn btn-primary">Edit</a>

<a href="javascript:void(0);" class="btn btn-danger" data-deleteurl="{{ route('route_delete',['id'=> $id]) }}" onclick="sweetDeleteData(this)">Hapus</a>

<button type="submit" class="btn btn-success">Tambah</button>

<button type="submit" class="btn btn-primary">Simpan</button>

<a href="{{ route('route.index') }}" class="btn btn-outline btn-outline-secondary">Batal</a>

// -----
// buttons, dengan icon
// -----

<a href="{{ route('route_detail', ['id' => $id]) }}" title="{{ __('tooltip.btn_detail') }}"><i class='fa-solid fa-magnifying-glass'></i></a>

<a href="{{ route('route_edit', ['id' => $id]) }}" title="{{ __('tooltip.btn_edit') }}"><i class='fa-solid fa-pen-to-square'></i></a>

<a href="javascript:void(0);" data-deleteurl="{{ route('route_delete',['id'=> $id]) }}" onclick="sweetDeleteData(this)" title="{{ __('tooltip.btn_hapus') }}"><i class='fa-solid fa-trash'></i></a>

// -----
// table-index
// -----

<div class="table-responsive">
    <table class="table table-index">
        <thead>
            <tr>
                <th>Kolom 1</th>
                <th>Kolom 2</th>
                <th>Kolom 3</th>
                <th class="col-btn1 || col-btn2 || col-btn3"></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>Data 1</td>
                <td>Data 2</td>
                <td>Data 3</td>
                <td class="col-action">
                    <a href="{{ route('route.detail', ['id' => $id]) }}" title="{{ __('tooltip.detail_button') }}"><i class='fa-solid fa-magnifying-glass'></i></a>
                    <a href="{{ route('route.edit', ['id' => $id]) }}" title="{{ __('tooltip.edit_button') }}"><i class="fa-solid fa-pen-to-square"></i></a>
                    <a href="javascript:void(0);" data-deleteurl="{{ route('route.deletepost', ['id' => $id]) }}" onclick="sweetDeleteData(this)" title="{{ __('tooltip.hapus_button') }}"><i class="fa-solid fa-xmark"></i></a>
                </td>
            </tr>
        </tbody>
    </table>
</div>
<div class="mt-3">
    {{ $objectList->links('niascoder-helper::partials.pagination-numbers') }}
</div>

// -----
// table-detail
// -----

<table class="table table-detail">
    <tbody>
        <tr>
            <th width="80px">Label</th>
            <td>Data</td>
        </tr>
        <tr>
            <th>Label</th>
            <td>Data</td>
        </tr>
    </tbody>
</table>

[模态表单]

前端 blade 用于显示表单

<a href="javascript:void(0);" class="btn btn-primary" data-mf-id="modalCreate" data-mf-url="{{ route('data.create') }}" onclick="modalFormShow(this)">Tambah</a>

<div class="modal fade" id="modalCreate" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="true" role="dialog" aria-hidden="true">
    <div class="modal-dialog modal-dialog-scrollable modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title fs-5">Tambah Data</h5>
            </div>
            <div class="modal-body">
            </div>
        </div>
    </div>
</div>

后端 blade 用于渲染表单

<form action="{{ route('data.create_post') }}" method="POST" enctype="multipart/form-data">
    @csrf
    <x-form-input name="id" lang-context="db.data.create"></x-form-input>
    <x-form-input name="nama" lang-context="db.data.create"></x-form-input>
    <x-form-input name="kategori" lang-context="db.data.create"></x-form-input>
    <div class="form-buttons">
        <a href="javascript:void(0);" class="btn btn-outline-primary" id="closeButton">Batal</a>
        <a href="javascript:void(0);" class="btn btn-primary" id="submitButton">Tambah</a>
    </div>
</form>

后端 控制器 用于接收 POST 数据

public function createPost(Request $request)
{
    $validator = Validator::make($request->all(), [
        'id' => 'required',
        'nama' => 'required',
        'kategori' => 'required',
    ]);
    if ($validator->fails()) {
        return AppHelper::jsonResponseErrorValidator($validator);
    }

    // ...
    // proses form disini
    // kalau masih ada error, lempar dengan:
    AppHelper::jsonResponseErrorMessage(__('error.operation'));
    // atau...
    return AppHelper::jsonResponseErrorValidator(AppHelper::validatorErrorForm('nama','Nama ini tidak boleh digunakan.'));
    // ...

    return AppHelper::jsonResponseSuccess();
} // function createPost

[调用 AJAX]

ajaxShowLoading();
$.ajax({
  type: "GET",
  url: url,
  success: function (resultData) {
    if (resultData.status) {
      // ...
      // proses data disini
      // ...
      ajaxReturnJsonTrue(resultData.redirect);
    } else {
      ajaxReturnJsonFalse(resultData.desc);
    }
  },
  error: function () {
    ajaxReturnError();
  },
});

[reCAPTCHA v2]

安装并发布包 biscolab/laravel-recaptcha

composer require biscolab/laravel-recaptcha
php artisan vendor:publish --provider="Biscolab\ReCaptcha\ReCaptchaServiceProvider"

更新 config/recaptcha.php 文件中的 version

return [
    // ...
    'version' => 'v2',
    'default_language' => 'id',
    // ...
];

添加到 .env 文件

RECAPTCHA_SITE_KEY=<YOUR_API_SITE_KEY>
RECAPTCHA_SECRET_KEY=<YOUR_API_SECRET_KEY>
RECAPTCHA_SKIP_IP=<YOUR_IP_LIST>

RECAPTCHA_SKIP_IP 可以为空。

在将显示 reCAPTCHA 的 blade 文件中,在 HTML 的 HEAD 部分插入以下脚本

<html>
    <head>
    // ...
    {!! htmlScriptTagJsApi($configuration) !!}
    // ...
    </head>

然后通过组件显示 reCAPTCHA

<x-form-recaptcha2 name="pegawai_captcha" site-key="{{ config('recaptcha.api_site_key') }}" :modal-form="true"> </x-form-recaptcha2>

modal-form 属性仅在 recaptcha 在模态表单中渲染时使用。

然后在接收表单 POST 数据的控制器中,recaptcha 通过以下方式验证

$validator = Validator::make($request->all(), [
    // ...
    'g-recaptcha-response' => 'recaptcha',
    // atau bisa juga
    recaptchaFieldName() => recaptchaRuleName(),
    // ...
]);

感谢

这是一个包含辅助工具或学习材料的仓库。这些辅助工具可用于理解与 Laravel 开发相关的各种概念和技术。

向一位伟大的 DevOps 专家 Bang Indra 表示无限感激。他在系统开发和运营方面的贡献为许多人提供了灵感和深入的理解。