I am getting lot of duplicated queries becuase of this approach. How could i minimize the number of queries
User Class
public function roles()
{
return $this->belongsToMany('App\Models\Role', 'role_user', 'user_id', 'role_id')
->withPivot('id', 'role_id', 'user_id')
->withTimestamps();
}
public function hasAnyRole(String $role)
{
return null !== $this->roles()->where('name', $role)->first();
}
public function hasAnyRoles(array $role)
{
return null !== $this->roles()->whereIn('name', $role)->first();
}
Role Class
public function users()
{
return $this->belongsToMany(User::class);
}
**AuthServiceProvider **
<?php
namespace App\Providers;
use App\Models\User;
use App\Policies\UserPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
// protected $policies = [
// 'App\Models\User' => 'App\Policies\UserPolicy',
// ];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//Item Gates
Gate::define('item-create', function($item) {
return $item->hasAnyRoles(['Item Manager', 'Super Item Manager']);
});
Gate::define('item-read', function($item) {
return $item->hasAnyRoles(['Item Manager', 'Super Item Manager']);
});
Gate::define('item-update', function($item) {
return $item->hasAnyRoles(['Item Manager', 'Super Item Manager']);
});
Gate::define('item-delete', function($item) {
return $item->hasAnyRoles(['Super Item Manager']);
});
// There are around 40+ gates like this
Livewire Component
<?php
namespace App\Http\Livewire;
use App\Models\Item;
use Livewire\Component;
use App\Models\Category;
use Livewire\WithPagination;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class ItemTracker extends Component
{
use WithPagination;
use AuthorizesRequests;
public $sortBy = 'id';
public $sortAsc = false;
public $item;
public $type = '';
public $categories;
public $search;
public $searchCategory = '';
public $perPage = 1000;
public $confirmingItemDeletion = false;
// Table Sort
public function sortBy($field)
{
if($field == $this->sortBy){
$this->sortAsc = !$this->sortAsc;
}
$this->sortBy = $field;
}
// Delete - Show Modal
public function confirmItemDeletion($id)
{
$this->confirmingItemDeletion = $id;
}
// Delete Item
public function deleteItem(Item $item)
{
$this->authorize('item-delete', $item);
$item->delete();
$this->confirmingItemDeletion = false;
return redirect(request()->header('Referer')); //To refresh the page
}
public function cancelDeleteItem()
{
$this->confirmingUserDeletion = false;
return redirect(request()->header('Referer')); //To refresh the page
}
public function updatingSearch()
{
$this->resetPage();
}
public function mount()
{
$this->categories = Category::orderBy('name', 'asc')->get();
}
public function render()
{
$items = Item::with('category')
->when($this->searchCategory != '', function($query){
$query->whereHas('category', function($query) {
$query->where('category_id', $this->searchCategory);
});
})
->where(function ($query) {
$query->where('name', 'LIKE', '%' . $this->search . '%');
})
->orderBy($this->sortBy, $this->sortAsc ? 'ASC' : 'DESC')
->paginate($this->perPage);
// dd($items);
return view('livewire.item-tracker', [
'items' => $items,
]);
}
}
<div class="flex flex-col">
<div class="xl:flex xl:items-center xl:justify-between xl:mx-4 xl:mb-2">
<p class="text-3xl ...">Item Tracker</p>
<div class="xl:w-2/6">
<div class="flex flex-col space-y-2 xl:space-x-2 xl:flex xl:flex-row xl:space-y-0">
<select wire:model="perPage"
class="block border-gray-300 rounded-md shadow-sm 1/6 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
<option>10</option>
<option>100</option>
<option>1000</option>
</select>
<select wire:model="searchCategory"
class="block w-full border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
<option value="">Select a Category</option>
@foreach ($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>
@endforeach
</select>
<x-jet-input wire:model="search" id="search" type="search" class="block w-full" placeholder="Search" autocomplete="off" />
</div>
</div>
</div>
<div class="overflow-x-auto xl:-my-2 sm:-mx-6 lg:-mx-8">
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<div class="overflow-hidden border-b border-gray-200 shadow sm:rounded-lg">
<table id="myTable" class="min-w-full text-center divide-y divide-gray-200">
<thead class="font-bold text-gray-700 bg-gray-50">
<tr>
<th scope="col" class="w-1/12 px-6 py-3 text-xs tracking-wider uppercase">
<div class="flex items-center justify-center">
<button wire:click="sortBy('id')" class="text-xs font-bold tracking-wider uppercase">id</button>
<x-sort-icon icon sort-field="id" :sort-by="$sortBy" :sort-asc="$sortAsc" />
</div>
</th>
<th scope="col" class="w-2/12 px-6 py-3 text-xs tracking-wider uppercase">
<div class="flex items-center justify-center">
<button wire:click="sortBy('name')" class="text-xs font-bold tracking-wider uppercase">name</button>
<x-sort-icon icon sort-field="name" :sort-by="$sortBy" :sort-asc="$sortAsc" />
</div>
</th>
<th scope="col" class="w-2/12 px-6 py-3 text-xs tracking-wider uppercase">
<div class="flex items-center justify-center">
<button wire:click="sortBy('category')" class="text-xs font-bold tracking-wider uppercase">category</button>
<x-sort-icon icon sort-field="category" :sort-by="$sortBy" :sort-asc="$sortAsc" />
</div>
</th>
<th scope="col" class="w-2/12 px-6 py-3 text-xs tracking-wider uppercase">
<div class="flex items-center justify-center">
<button class="text-xs font-bold tracking-wider uppercase"></button>
</div>
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@foreach ($items as $item)
<tr class="h-5 overflow-y-auto">
<td class="px-6 py-2 text-sm text-gray-500 border-2 border-gray-200 whitespace-nowrap">
{{ $item->id }}
</td>
<td class="px-6 py-2 text-sm text-left text-gray-500 border-2 border-gray-200 whitespace-nowrap">
{{ $item->name }}
</td>
<td class="px-6 py-2 text-sm text-left text-gray-500 border-2 border-gray-200 whitespace-nowrap">
{{ $item->category->name }}
</td>
<td class="px-6 py-2 text-sm text-left text-gray-500 border-2 border-gray-200 whitespace-nowrap">
@can('item-update')
<a href="{{ route('employees.items.edit', $item) }}"><x-warning-button>Edit</x-warning-button></a>
@endcan
@can('item-delete')
<x-jet-danger-button wire:click="confirmItemDeletion({{ $item->id }})">Delete</x-jet-danger-button>
@endcan
</td>
</tr>
@endforeach
<!-- More people... -->
</tbody>
</table>
</div>
{{-- Pagination --}}
<div class="mx-4 mt-4">
{{ $items->links() }}
</div>
</div>
</div>
<!-- Delete Item Confirmation Modal -->
@can('item-delete')
<x-jet-dialog-modal wire:model="confirmingItemDeletion">
<x-slot name="title">
{{ __('Delete Item') }}
</x-slot>
<x-slot name="content">
{{ __('Are you sure you want to delete this Item?') }}
</x-slot>
<x-slot name="footer">
<x-jet-secondary-button wire:click="cancelDeleteItem()" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jet-secondary-button>
<x-jet-danger-button class="ml-2" wire:click="deleteItem({{ $confirmingItemDeletion }})" wire:loading.attr="disabled">
{{ __('Delete') }}
</x-jet-danger-button>
</x-slot>
</x-jet-dialog-modal>
@endcan
</div>