Created
November 14, 2023 08:11
-
-
Save susilolab/54213db015e243e45150c51ccf137d96 to your computer and use it in GitHub Desktop.
Contoh Server Side Processing dengan datatable dan laravel 10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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