I have a Server. I need to prohibit editing the Server to those users who did not create it. But there is a problem, the Server may have many Users who can edit it. I put this in a separate database table ServerUserCreate where server_id and user_id are stored.
It doesn't suit me. Since there is no user_id column in the Server table, because a lot of users can recommend
Gate::define('server-edit', function (User $user, Server $server) {
return $user->id === $server->user_id;
});
I somehow need to compare
ServerUserCreates->server_id === $server->id || Auth::user()->id === ServerUserCreate->user_id
And if they are equal, then access is open. But I don't know how to do it in Gate at all
ServerUserCreate table
Schema::create('server_user_creates', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->id();
$table->unsignedBigInteger('server_id');
$table->unsignedBigInteger('user_id');
$table->index('server_id', 'suc_server_idx');
$table->index('user_id', 'suc_user_idx');
$table->foreign('server_id', 'suc_server_fk')->on('servers')->references('id');
$table->foreign('user_id', 'suc_user_fk')->on('users')->references('id');
$table->timestamps();
});
Considering you have a relationship defined as
public function servers()
{
return $this->hasMany(ServerUserCreate::class);
}
in the Server model, you can simplify your Gate definition a bit further by adding a WHERE condition to the relationship query.
exists() will return a boolean, so that's perfect for your use case.
Gate::define('server-edit', function (User $user, Server $server) {
return $server->servers()->where('user_id', $user->id)->exists();
});
You could also use count() instead of exists(). In PHP, if you cast a number as a boolean, 0 is false, and the rest is true.
Gate::define('server-edit', function (User $user, Server $server) {
return $server->servers()->where('user_id', $user->id)->count();
});
I was able to figure out the problem myself. Maybe it will help someone, here are my solutions
Gate::define('server-edit', function (User $user, Server $server) {
$ServerUsers = $server->servers()->get();
foreach ($ServerUsers as $ServerUser) {
if ($ServerUser->server_id === $server->id && $ServerUser->user_id === $user->id) {
return Response::allow();
}
}
return Response::deny();
});
if (! Gate::allows('server-edit', $server)) {
abort(403, 'Stop Stop!');
}
Server Model
public function servers()
{
return $this->hasMany(ServerUserCreate::class);
}
Related
The debugbar reads
368 statements were executed, 360 of which were duplicated, 8 unique
It turns out that with every check on my user, via auth()->user()->isCustomer() and other similar functions, it's actually looking up the user every time.
i.e.
public function hasRole($role)
{
// If the user has the 'admin' role, always authorize
if ($this->roles()->where('name', 'customer')->first() !== null) {
return true;
}
return null !== $this->roles()->where('name', $role)->first();
}
// Check for admin
public function isCustomer()
{
return $this->hasRole('customer');
}
How do I safely cache this information on the user object so the database isn't being hounded every time?
I also use the 404labfr/laravel-impersonate function on this project (so when you are an Admin, you can impersonate other users).
I think you can decrease queries by half using:
public function hasRole($role)
{
return null !== $this->roles()->whereIn('name', ['customer', $role])->first();
}
I'm trying to get the user with the highest evaluation points based on charisma and persuasion
What i have wrote so far after this i couldn't figure out how to make it work
$user = User::where('commision_id', $data['commision'])->whereHas('role', function ($q) {
$q->where('level', 2);
})->with(['evaluations' => function ($q) {
}]);
The evaluations relation migration
Schema::create('evaluations', function (Blueprint $table) {
$table->id();
$table->boolean('charisma')->default(false);
$table->boolean('persuasion')->default(false);
$table->boolean('politics')->default(false);
$table->boolean('heat')->default(false);
$table->string('title');
$table->integer('hl')->nullable();
$table->integer('exp')->nullable();
$table->unsignedBigInteger('user_id');
$table->timestamps();
$table->index('user_id');
});
So basically i have to sum the exp points based on persuasion and the exp points based on charisma then sum both of those sum values to get the highest ranking user.
You can add up those 2 properties on the fly and simply get the one with the highest attribute.
$user = User::where('commision_id', $data['commision'])->whereHas('role', function ($q) {
$q->where('level', 2);
})->with(['evaluations'])
->get()
->each(function ($u) {
$u->score = $u->evaluations->charisma + $u->evaluations->persuasion
});
$topUser = $user->orderBy('score')->first();
In case one user can have many evaluations, you would do the similar thing:
->each(function ($u) {
$u->score = null;
$charisma = $u->evaluations->pluck('charisma')->sum();
$persuasion = = $u->evaluations->pluck('persuasion')->sum();
$u->score += $charisma;
$u->score += $persuasion ;
});
What made it work is using filter function to filter the boolean values of Charisma and Persuasion, thanks to N L which pointed me to the right direction, i accepted his answer.
$user = User::where('commision_id', $data['commision'])->whereHas('role', function ($q) {
$q->where('level', 2);
})->with(['evaluations'])
->get()
->each(function ($u) {
$u->score = null;
$charisma = $u->evaluations->filter(function($value) {
return $value->charisma == true;
})->sum('exp');
$persuasion = $u->evaluations->filter(function($value) {
return $value->persuasion == true;
})->sum('exp');
$u->score += $charisma;
$u->score += $persuasion;
})->sortByDesc('score')->first();
I am working on a very simple project for my school assignment. So it's a house rent site. Everything seems fine but I want create an automatically invoice like "INV0001" but I don't know how to do that. Maybe you guys can help me fix my controller
This is my controller
public function storeSewa(Request $request){
if ($request->edit=='false') {
$newdata = new Sewa;
} else {
$newdata = Sewa::find($request->id);
if ($newdata) {
//
}else {
$newdata = new Sewa;}}
$newdata->invoice = 'INV/'//idk, how?
$newdata->penyewa_id = $request->penyewa_id;
$newdata->kamar_id = $request->kamar_id;
$newdata->tanggal_masuk = $request->tanggal_masuk;
$newdata->tanggal_keluar = $request->tanggal_keluar;
$newdata->durasi = $request->durasi;
$newdata->status = 'Belum Lunas';
$newdata->save();
if ($newdata) {
session()->flash('status', 'Task was successful!');
session()->flash('type', 'success');
return Redirect::route('account');
}
return 'false';
}
Well, I am very new to laravel, so is there anyone can help fix my problem in the easiest way?
if you are using database you can use sql auto increment, for this feature you have to have this line in your invoice models migration :
Schema::create('invoices', function (Blueprint $table) {
$table->Increments('id');
});
if you want your invoice numbers, not being like 1,2,3, ... you can use libraries like this:
https://github.com/oanhnn/laravel-fakeid
if you are using for test, you can use faker factory:
there is a tutorial here:
https://www.codermen.com/blog/75/how-to-use-faker-with-laravel-5-7-tutorial
I'm creating REST API with Laravel 5.6 (I have to say I'm new because I might have used the wrong terms. I'm sorry about that,I'm improving myself. I need to hear my faults :) )
I have one function for find nearby places in my controller
public function index(\Illuminate\Http\Request $request) {
if($request->has('party_category')){
$parties = Parties::where('party_category', $request->party_category)->get();//your new query here
}
else if($request->has('lat') && $request->has('long')){
$parties = Parties::whereRaw("ACOS(SIN(RADIANS('latitude'))*SIN(RADIANS($request->lat))+COS(RADIANS('latitude'))*COS(RADIANS($request->lat))*COS(RADIANS('longitude')-RADIANS($request->long)))*6380 < 10");
}else {
$parties = Parties::all();
}
return Fractal::includes('places')->collection($parties,new PartyTransformer);
}
and I'm using this url for send current location but when I giving them , laravel showing to me all parties not nearby.I want to show nearby places
http://127.0.0.1:8000/api/parties?lat=37.043237&long=27.392445
but when I sending my parameter to url it showing
{"data":[]}
I can't show any nearby places
also in my database I'm keeping lat and long like this :
public function up()
{
Schema::create('parties', function (Blueprint $table) {
$table->increments('id');
$table->integer('places_id')->unsigned();
$table->string('slug');
$table->string('party_title');
$table->string('party_category');
$table->string('rating')->nullable();
$table->date('party_date');
$table->string("latitude")->nullable();
$table->string("longitude")->nullable();
$table->integer('fav_count')->nullable();
$table->longText('image_path');
$table->longText('party_desp');
$table->timestamps();
});
}
How can I show the nearby ones ?
I fixed , I hope it will help somebody
class PartiesController extends Controller
{
public function index(\Illuminate\Http\Request $request) {
if($request->has('lat') && $request->has('long')){
$lat = $request->lat;
$long = $request->long;
$parties=DB::select(DB::raw("SELECT *,111.045*DEGREES(ACOS(COS(RADIANS(':lat'))*COS(RADIANS(`latitude`))*COS(RADIANS(`longitude`) - RADIANS(':long'))+SIN(RADIANS(':lat'))*SIN(RADIANS(`latitude`)))) AS distance_in_km FROM parties ORDER BY distance_in_km asc LIMIT 0,5"), array(
'lat' => $lat,
'long' => $long
));
$hidacik = Parties::hydrate($parties);
return Fractal::includes('places')->collection($hidacik,new PartyTransformer);
}
else {
$parties = Parties::all();
}
return Fractal::includes('places')->collection($parties,new PartyTransformer);
}
}
In $parties = Parties::whereRaw("ACOS(SIN(RADIANS('latitude'))*SIN(RADIANS($request->lat))+COS(RADIANS('latitude'))*COS(RADIANS($request->lat))*COS(RADIANS('longitude')-RADIANS($request->long)))*6380 < 10");
you are missing ->get(). you need to add get() in order to return a collection which you can then work with
//this returns a collection now since we added get()
$parties = Parties::whereRaw("ACOS(SIN(RADIANS('latitude'))*SIN(RADIANS($request->lat))+COS(RADIANS('latitude'))*COS(RADIANS($request->lat))*COS(RADIANS('longitude')-RADIANS($request->long)))*6380 < 10")->get();
This topic has been discussed a lot here, but I don't get it.
I would like to protect my routes with pivot tables (user_customer_relation, user_object_relation (...)) but I don't understand, how to apply the filter correctly.
Route::get('customer/{id}', 'CustomerController#getCustomer')->before('customer')
now I can add some values to the before filter
->before('customer:2')
How can I do this dynamically?
In the filter, I can do something like:
if(!User::hasAccessToCustomer($id)) {
App::abort(403);
}
In the hasAccessToCustomer function:
public function hasCustomer($id) {
if(in_array($id, $this->customers->lists('id'))) {
return true;
}
return false;
}
How do I pass the customer id to the filter correctly?
You can't pass a route parameter to a filter. However you can access route parameters from pretty much everywhere in the app using Route::input():
$id = Route::input('id');
Optimizations
public function hasCustomer($id) {
if($this->customers()->find($id)){
return true;
}
return false;
}
Or actually even
public function hasCustomer($id) {
return !! $this->customers()->find($id)
}
(The double !! will cast the null / Customer result as a boolean)
Generic approach
Here's a possible, more generic approach to the problem: (It's not tested though)
Route::filter('id_in_related', function($route, $request, $relationName){
$user = Auth::user();
if(!$user->{$relationName}()->find($route->parameter('id')){
App::abort(403);
}
});
And here's how you would use it:
->before('id_in_related:customers')
->before('id_in_related:objects')
// and so on