Skip to content

Instantly share code, notes, and snippets.

@susilolab
Created November 14, 2023 08:11
Show Gist options
  • Save susilolab/54213db015e243e45150c51ccf137d96 to your computer and use it in GitHub Desktop.
Save susilolab/54213db015e243e45150c51ccf137d96 to your computer and use it in GitHub Desktop.
Contoh Server Side Processing dengan datatable dan laravel 10
<?php
declare(strict_types=1);
namespace App\Helpers;
use Illuminate\Database\Query\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* DataTable trait
*
* Trait untuk membantu memudahkan memproses client yang menggunakan ext datatable.
*
* @author Agus Susilo <smartgdi@gmail.com>
*/
trait DataTable
{
public function getDataTable(Request $request, string $table, string $primaryKey, array $columns = [])
{
$query = DB::table($table);
$data = $this->limit($query, $request);
$data = $this->order($data, $request, $columns);
$data = $this->filter($data, $request, $columns);
$recordsFiltered = $this->filter($query, $request, $columns)->count($primaryKey);
$recordsTotalQuery = clone $query;
$recordsTotal = $recordsTotalQuery->count($primaryKey);
$rows = $data->get();
$rows = $rows->map(fn ($item) => (array) $item)->toArray();
$rows = $this->createOutput($columns, $rows);
return [
'draw' => (int) $request->get('draw', 0),
'recordsTotal' => $recordsTotal,
'recordsFiltered' => $recordsFiltered,
'data' => $rows,
];
}
protected function createOutput(array $columns, array $data)
{
$out = [];
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = [];
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
if (empty($column['db'])) {
$row[$column['dt']] = $column['formatter']($data[$i]);
} else {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
}
} else {
if (!empty($column['db'])) {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
} else {
$row[$column['dt']] = "";
}
}
}
$out[] = $row;
}
return $out;
}
public function limit(Builder $query, Request $request)
{
$query = clone $query;
$offset = $request->get('start', 0);
$limit = $request->get('length', 10);
$query->limit($limit)->offset($offset);
return $query;
}
public function order(Builder $query, Request $request, array $columns = [])
{
$query = clone $query;
$order = $request->get('order', []);
if (is_array($order) && count($order) == 0) {
return $query;
}
$orderBy = [];
$dtColumns = $this->pluck($columns, 'dt');
for ($i = 0, $ien = count($order); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'asc' ? 'ASC' : 'DESC';
$orderBy[] = [$column['db'], $dir];
}
}
if (count($orderBy)) {
foreach ($orderBy as $val) {
[$columnName, $direction] = $val;
}
$query->orderBy($columnName, $direction);
}
return $query;
}
public function filter(Builder $query, Request $request, array $columns = [])
{
$query = clone $query;
$globalSearch = [];
$columnSearch = [];
$dtColumns = $this->pluck($columns, 'dt');
$search = $request->filled('search') ? $request->get('search') : [];
if ($request->has('search') && isset($search['value']) && $search['value'] != '') {
$str = $search['value'];
for ($i = 0, $ien = count($request['columns']) ; $i < $ien ; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[ $columnIdx ];
if ($requestColumn['searchable'] == 'true') {
if(!empty($column['db'])) {
$globalSearch[] = [$column['db'], 'ilike', '%'.$str.'%'];
}
}
}
}
// Individual column filtering
if ($request->has('columns')) {
$reqColumns = $request->get('columns');
for ($i = 0, $ien = count($reqColumns) ; $i < $ien ; $i++) {
$requestColumn = $reqColumns[$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[ $columnIdx ];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
if(!empty($column['db'])) {
$columnSearch[] = [$column['db'], 'ilike', '%' . $str . '%'];
}
}
}
}
// Combine the filters into a single string
if (count($globalSearch)) {
$query->where(function (Builder $query) use ($globalSearch) {
foreach ($globalSearch as $val) {
[$column, $op, $value] = $val;
$query->orWhere($column, $op, $value);
}
});
}
if (count($columnSearch)) {
foreach ($columnSearch as $val) {
[$column, $op, $value] = $val;
$query->where($column, $op, $value);
}
}
return $query;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
public function pluck(array $a, string $prop): array
{
$out = [];
for ($i = 0, $len = count($a); $i < $len; $i++) {
if (empty($a[$i][$prop])) {
continue;
}
//removing the $out array index confuses the filter method in doing proper binding,
//adding it ensures that the array data are mapped correctly
$out[$i] = $a[$i][$prop];
}
return $out;
}
public function flatten(mixed $a, string $join = ' AND '): string
{
if (! $a) {
return '';
} elseif ($a && is_array($a)) {
return implode($join, $a);
}
return $a;
}
}
<?php
namespace App\Http\Controllers\v1;
use App\Helpers\ValidationHelper;
use App\Http\Controllers\V1Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Helpers\DataTable;
use App\Models\HelloWorld;
class DemoController extends V1Controller
{
use DataTable;
public function __construct(
public ValidationHelper $validationHelper = new ValidationHelper(),
) {
}
/**
* Contoh action untuk data table
*/
public function dataTable(Request $request)
{
$tableName = (new HelloWorld())->getTable();
$pk = 'id';
// Pemetaan kolom dari kolom tabel ke datatable, contoh: kolom `id` dipetakan ke datatable jadi kolom `0` dst.
$columns = [
['db' => 'id', 'dt' => 0],
['db' => 'name', 'dt' => 1],
['db' => 'email', 'dt' => 2],
];
$rows = $this->getDataTable($request, $tableName, $pk, $columns);
return response()->success($rows, customField: [
'draw' => $rows['draw'],
'recordsTotal' => $rows['recordsTotal'],
'recordsFiltered' => $rows['recordsFiltered'],
]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment