mirror of
https://github.com/snipe/snipe-it.git
synced 2026-08-18 11:15:42 +00:00
fixes ##19235 We were seeing multiple count queries (two or three) against our database when using the API. With this change we are now seeing one query and, for us, it saves on average 300ms.
284 lines
10 KiB
PHP
284 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Actions\Suppliers\DestroySupplierAction;
|
|
use App\Exceptions\ItemStillHasAccessories;
|
|
use App\Exceptions\ItemStillHasAssets;
|
|
use App\Exceptions\ItemStillHasComponents;
|
|
use App\Exceptions\ItemStillHasConsumables;
|
|
use App\Exceptions\ItemStillHasLicenses;
|
|
use App\Exceptions\ItemStillHasMaintenances;
|
|
use App\Helpers\Helper;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\FilterRequest;
|
|
use App\Http\Requests\ImageUploadRequest;
|
|
use App\Http\Transformers\SelectlistTransformer;
|
|
use App\Http\Transformers\SuppliersTransformer;
|
|
use App\Models\Supplier;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class SuppliersController extends Controller
|
|
{
|
|
/**
|
|
* Display a listing of the resource.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
*
|
|
* @since [v4.0]
|
|
*
|
|
* @return Response
|
|
*/
|
|
public function index(FilterRequest $request): array
|
|
{
|
|
$this->authorize('view', Supplier::class);
|
|
$allowed_columns = [
|
|
'id',
|
|
'name',
|
|
'address',
|
|
'address2',
|
|
'city',
|
|
'state',
|
|
'country',
|
|
'zip',
|
|
'phone',
|
|
'contact',
|
|
'fax',
|
|
'email',
|
|
'image',
|
|
'assets_count',
|
|
'licenses_count',
|
|
'accessories_count',
|
|
'components_count',
|
|
'consumables_count',
|
|
'tag_color',
|
|
'url',
|
|
'notes',
|
|
];
|
|
|
|
$suppliers = Supplier::select(
|
|
['id', 'name', 'address', 'address2', 'city', 'state', 'country', 'fax', 'phone', 'email', 'contact', 'created_at', 'created_by', 'updated_at', 'deleted_at', 'image', 'notes', 'url', 'zip', 'tag_color'])
|
|
->withCount('assets as assets_count')
|
|
->withCount('licenses as licenses_count')
|
|
->withCount('accessories as accessories_count')
|
|
->withCount('components as components_count')
|
|
->withCount('consumables as consumables_count')
|
|
->with('adminuser');
|
|
|
|
// This invokes the Searchable model trait scopeTextSearch and will handle input by search or by advanced search filter
|
|
if ($request->filled('filter') || $request->filled('search')) {
|
|
$suppliers->TextSearch($request->input('filter') ? $request->input('filter') : $request->input('search'));
|
|
}
|
|
|
|
if ($request->filled('name')) {
|
|
$suppliers->where('name', '=', $request->input('name'));
|
|
}
|
|
|
|
if ($request->filled('address')) {
|
|
$suppliers->where('address', '=', $request->input('address'));
|
|
}
|
|
|
|
if ($request->filled('address2')) {
|
|
$suppliers->where('address2', '=', $request->input('address2'));
|
|
}
|
|
|
|
if ($request->filled('city')) {
|
|
$suppliers->where('city', '=', $request->input('city'));
|
|
}
|
|
|
|
if ($request->filled('zip')) {
|
|
$suppliers->where('zip', '=', $request->input('zip'));
|
|
}
|
|
|
|
if ($request->filled('country')) {
|
|
$suppliers->where('country', '=', $request->input('country'));
|
|
}
|
|
|
|
if ($request->filled('fax')) {
|
|
$suppliers->where('fax', '=', $request->input('fax'));
|
|
}
|
|
|
|
if ($request->filled('email')) {
|
|
$suppliers->where('email', '=', $request->input('email'));
|
|
}
|
|
|
|
if ($request->filled('url')) {
|
|
$suppliers->where('url', '=', $request->input('url'));
|
|
}
|
|
|
|
if ($request->filled('notes')) {
|
|
$suppliers->where('notes', '=', $request->input('notes'));
|
|
}
|
|
|
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
|
$total = $suppliers->count();
|
|
$offset = ($request->input('offset') > $total) ? $total : app('api_offset_value');
|
|
$limit = app('api_limit_value');
|
|
|
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
|
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
|
|
|
switch ($request->input('sort')) {
|
|
case 'created_by':
|
|
$suppliers->OrderByCreatedByName($order);
|
|
break;
|
|
default:
|
|
$suppliers->orderBy($sort, $order);
|
|
break;
|
|
}
|
|
|
|
$suppliers = $suppliers->skip($offset)->take($limit)->get();
|
|
|
|
return (new SuppliersTransformer)->transformSuppliers($suppliers, $total);
|
|
}
|
|
|
|
/**
|
|
* Store a newly created resource in storage.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
*
|
|
* @since [v4.0]
|
|
*/
|
|
public function store(ImageUploadRequest $request): JsonResponse
|
|
{
|
|
$this->authorize('create', Supplier::class);
|
|
$supplier = new Supplier;
|
|
$supplier->fill($request->all());
|
|
$supplier = $request->handleImages($supplier);
|
|
|
|
if ($supplier->save()) {
|
|
return response()->json(Helper::formatStandardApiResponse('success', $supplier, trans('admin/suppliers/message.create.success')));
|
|
}
|
|
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, $supplier->getErrors()));
|
|
|
|
}
|
|
|
|
/**
|
|
* Display the specified resource.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
*
|
|
* @since [v4.0]
|
|
*
|
|
* @param int $id
|
|
*/
|
|
public function show($id): array
|
|
{
|
|
$this->authorize('view', Supplier::class);
|
|
$supplier = Supplier::findOrFail($id);
|
|
|
|
return (new SuppliersTransformer)->transformSupplier($supplier);
|
|
}
|
|
|
|
/**
|
|
* Update the specified resource in storage.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
*
|
|
* @since [v4.0]
|
|
*
|
|
* @param int $id
|
|
*/
|
|
public function update(ImageUploadRequest $request, $id): JsonResponse
|
|
{
|
|
$this->authorize('update', Supplier::class);
|
|
$supplier = Supplier::findOrFail($id);
|
|
$supplier->fill($request->all());
|
|
$supplier = $request->handleImages($supplier);
|
|
|
|
if ($supplier->save()) {
|
|
return response()->json(Helper::formatStandardApiResponse('success', $supplier, trans('admin/suppliers/message.update.success')));
|
|
}
|
|
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, $supplier->getErrors()));
|
|
}
|
|
|
|
/**
|
|
* Remove the specified resource from storage.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
*
|
|
* @since [v4.0]
|
|
*
|
|
* @param int $id
|
|
*/
|
|
public function destroy(Supplier $supplier): JsonResponse
|
|
{
|
|
$this->authorize('delete', $supplier);
|
|
try {
|
|
DestroySupplierAction::run(supplier: $supplier);
|
|
} catch (ItemStillHasAssets $e) {
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_assets', [
|
|
'asset_count' => (int) $supplier->assets_count, 'item' => trans('general.supplier'),
|
|
])));
|
|
} catch (ItemStillHasMaintenances $e) {
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_maintenances', [
|
|
'asset_maintenances_count' => $supplier->asset_maintenances_count, 'item' => trans('general.supplier'),
|
|
])));
|
|
} catch (ItemStillHasLicenses $e) {
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_licenses', [
|
|
'licenses_count' => (int) $supplier->licenses_count, 'item' => trans('general.supplier'),
|
|
])));
|
|
} catch (ItemStillHasAccessories $e) {
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_accessories', [
|
|
'accessories_count' => (int) $supplier->accessories_count, 'item' => trans('general.supplier'),
|
|
])));
|
|
} catch (ItemStillHasConsumables $e) {
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_consumables', [
|
|
'consumables_count' => (int) $supplier->consumables_count, 'item' => trans('general.supplier'),
|
|
])));
|
|
} catch (ItemStillHasComponents $e) {
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.bulk_delete_associations.assoc_components', [
|
|
'components_count' => (int) $supplier->components_count, 'item' => trans('general.supplier'),
|
|
])));
|
|
} catch (\Exception $e) {
|
|
report($e);
|
|
|
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.something_went_wrong')));
|
|
}
|
|
|
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/suppliers/message.delete.success')));
|
|
}
|
|
|
|
/**
|
|
* Gets a paginated collection for the select2 menus
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
*
|
|
* @since [v4.0.16]
|
|
* @see SelectlistTransformer
|
|
*/
|
|
public function selectlist(Request $request): array
|
|
{
|
|
|
|
$this->authorize('view.selectlists');
|
|
|
|
$suppliers = Supplier::select([
|
|
'id',
|
|
'name',
|
|
'image',
|
|
'tag_color',
|
|
]);
|
|
|
|
if ($request->filled('search')) {
|
|
$suppliers = $suppliers->where('suppliers.name', 'LIKE', '%'.$request->input('search').'%');
|
|
}
|
|
|
|
$suppliers = $suppliers->orderBy('name', 'ASC')->paginate(50);
|
|
|
|
// Loop through and set some custom properties for the transformer to use.
|
|
// This lets us have more flexibility in special cases like assets, where
|
|
// they may not have a ->name value but we want to display something anyway
|
|
foreach ($suppliers as $supplier) {
|
|
$supplier->use_text = $supplier->name;
|
|
$supplier->use_image = ($supplier->image) ? Storage::disk('public')->url('suppliers/'.$supplier->image, $supplier->image) : null;
|
|
}
|
|
|
|
return (new SelectlistTransformer)->transformSelectlist($suppliers);
|
|
}
|
|
}
|