Skip to content

Instantly share code, notes, and snippets.

@SohanChy
Created January 27, 2019 10:35
Show Gist options
  • Save SohanChy/1840b77348d2a5d338a1cdee39e16235 to your computer and use it in GitHub Desktop.
Save SohanChy/1840b77348d2a5d338a1cdee39e16235 to your computer and use it in GitHub Desktop.
ReactAdmin + Laravel
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\JsonRequest;
use App\Helpers\JsonReturn;
use App\Http\Controllers\Controller;
use App\Models\Reading;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class ExampleController extends Controller
{
public function getReadingTypes(Request $request){
return JsonReturn::successWithList(Reading::$readingTypes);
}
public function saveReadings(JsonRequest $request){
list($fails, $messages) = make_api_json_arr_validator($request,Reading::getCreateUpdateValidationRules());
if($fails){
return JsonReturn::error($messages);
}
else {
$readingsList = [];
$messageList = [];
DB::transaction(function () use ($request, &$readingsList, &$messageList) {
foreach ($request->all() as $readingData){
list($reading, $message) = Reading::createOrUpdate($readingData);
$readingsList[] = $reading;
$messageList[] = $message;
}
});
return JsonReturn::successWithList(
$readingsList,
__("api.saved_readings_multiple", ['count' => count($readingsList)]
));
}
}
public function getReadingList(Request $request){
$validator = make_api_validator($request,
$rules = [
'date' => 'required|date',
'reading_type' => [Rule::in(array_keys(Reading::$readingTypes))],
]
);
if ($validator->fails()) {
return JsonReturn::error($validator->messages());
}
$readingList = Reading::date($request->date)->readingType($request->reading_type)->get();
return JsonReturn::successWithList($readingList);
}
public function getReading(Reading $reading){
return JsonReturn::successWithObject($reading);
}
}
import { stringify } from 'query-string';
import {
fetchUtils,
GET_LIST,
GET_ONE,
GET_MANY,
GET_MANY_REFERENCE,
CREATE,
UPDATE,
UPDATE_MANY,
DELETE,
DELETE_MANY,
} from 'react-admin';
/**
* Maps react-admin queries to a simple REST API
*
* The REST dialect is similar to the one of FakeRest
* @see https://github.com/marmelab/FakeRest
* @example
* GET_LIST => GET http://my.api.url/posts?sort=['title','ASC']&range=[0, 24]
* GET_ONE => GET http://my.api.url/posts/123
* GET_MANY => GET http://my.api.url/posts?filter={ids:[123,456,789]}
* UPDATE => PUT http://my.api.url/posts/123
* CREATE => POST http://my.api.url/posts
* DELETE => DELETE http://my.api.url/posts/123
*/
const laravelHttpClient = (url, options = {}) => {
let token = document.head.querySelector('meta[name="csrf-token"]');
if (!options.headers) {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
}
// add your own headers here
options.headers.set('X-CSRF-TOKEN', token.content);
return fetchUtils.fetchJson(url, options);
}
export default (apiUrl, httpClient = laravelHttpClient) => {
/**
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The data request params, depending on the type
* @returns {Object} { url, options } The HTTP request parameters
*/
const convertDataRequestToHTTP = (type, resource, params) => {
let url = '';
const options = {};
switch (type) {
case GET_LIST: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
page: JSON.stringify(page),
perPage: JSON.stringify(perPage),
filter: JSON.stringify(params.filter),
};
url = `${apiUrl}/${resource}?${stringify(query)}`;
break;
}
case GET_ONE:
url = `${apiUrl}/${resource}/${params.id}`;
break;
case GET_MANY: {
const query = {
filter: JSON.stringify({ id: params.ids }),
};
url = `${apiUrl}/${resource}?${stringify(query)}`;
break;
}
case GET_MANY_REFERENCE: {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
page: JSON.stringify(page),
perPage: JSON.stringify(perPage),
filter: JSON.stringify({
...params.filter,
[params.target]: params.id,
}),
};
url = `${apiUrl}/${resource}?${stringify(query)}`;
break;
}
case UPDATE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'PUT';
options.body = JSON.stringify(params.data);
break;
case CREATE:
url = `${apiUrl}/${resource}`;
options.method = 'POST';
options.body = JSON.stringify(params.data);
break;
case DELETE:
url = `${apiUrl}/${resource}/${params.id}`;
options.method = 'DELETE';
break;
default:
throw new Error(`Unsupported fetch action type ${type}`);
}
return { url, options };
};
/**
* @param {Object} response HTTP response from fetch()
* @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
* @param {String} resource Name of the resource to fetch, e.g. 'posts'
* @param {Object} params The data request params, depending on the type
* @returns {Object} Data response
*/
const convertHTTPResponse = (response, type, resource, params) => {
const { headers, json } = response;
switch (type) {
case GET_LIST:
case GET_MANY:
case GET_MANY_REFERENCE:
return {
data: json.data.map(x => x),
total: parseInt(json.total),
};
case CREATE:
case UPDATE:
return { data: { ...json.data, id: json.data.id } };
default:
return { data: json.data };
}
};
/**
* @param {string} type Request type, e.g GET_LIST
* @param {string} resource Resource name, e.g. "posts"
* @param {Object} payload Request parameters. Depends on the request type
* @returns {Promise} the Promise for a data response
*/
return (type, resource, params) => {
// simple-rest doesn't handle filters on UPDATE route, so we fallback to calling UPDATE n times instead
if (type === UPDATE_MANY) {
return Promise.all(
params.ids.map(id => {
return httpClient(`${apiUrl}/${resource}/${id}`, {
method: 'PUT',
body: JSON.stringify(params.data),
});
}
)
).then(responses => ({
data: responses.map(response => response.json),
}));
}
// simple-rest doesn't handle filters on DELETE route, so we fallback to calling DELETE n times instead
if (type === DELETE_MANY) {
return Promise.all(
params.ids.map(id =>
httpClient(`${apiUrl}/${resource}/${id}`, {
method: 'DELETE',
})
)
).then(responses => ({
data: responses.map(response => response.json),
}));
}
const { url, options } = convertDataRequestToHTTP(
type,
resource,
params
);
return httpClient(url, options).then(response =>
convertHTTPResponse(response, type, resource, params)
);
};
};
<?php
namespace App\Traits;
trait ReactAdminDataProviderDialect
{
public function scopeFilter($query,$filter)
{
$filters = json_decode($filter,true);
if(!$filters){
return $query;
}
if(array_has($filters,"id")){
$query->whereIn('id', $filters["id"]);
}
return $query;
}
public function scopeSort($query,$sort)
{
if($sort){
list($sortKey,$sortType) = json_decode($sort,true);
$query->orderBy(strtolower($sortKey), strtolower($sortType));
}
return $query;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment