I want to make Laravel Authorization using gate..Where In user model
User.php
public function hasPermission($name)
{
$permission = Permission::where('name','=', $name)->first();
$permissions = \DB::table('role_permission')
->join('permissions', 'permissions.id', '=', 'role_permission.permission_id')
->select('role_permission.*')
->where('role_permission.permission_id', '=',$permission->id)
->get();
if(! $permissions) {
return false;
}
return !! $permission->intersect($this->$permission)->count();
}
In AuthserviceProvider
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
$gate->before(function($user, $ability) {
return $user->hasPermission($ability);
});
}
My Table structure like.
User has name,email,password,id
permission has name,id
role has name,id
role_permission has role_id,permission_id
can anyone help me to find out what's the error here?
intersect method belongs to Collection class. You can't use intersect method on Model. You may try by:
return !! collect([$permission])->intersect($this->$permission)->count();
$this->$permission should be an array or collection
I guess that's because you can apply intersect to a collection, while you're getting an error saying you that you're calling it over Illuminate\Database\Query\Builder.
I see you're calling it on $permission, that's currently a record (a model) of Permission. Probably that's just a typo, and you want to use $permissions instead of $permission.
Anyway, try to explain better what's the behaviour you're looking for, because it's not clear.
Related
I am a couple of weeks in to learning Laravel and have come across a problem which I can not find the answer to by myself, or online.
I am building a directory website with urls structured like:
directory.co.uk/parks
directory.co.uk/parks/{county-name}
directory.co.uk/parks/{county-name}/{park-name}
As {park-name} is not unique, I am struggling to return the page for an individual park. The controller needs to look up the county.id using the county.slug and then the park.id using the park.county_id and the park.slug.
I have routes in the web.php file such as:
Route::get('/parks','ParksController#index')->name('parks');
Route::get('/parks/{county}/{park}','ParksController#show')->name('park');
I have Parks and Counties models and (belongsTo and hasMany relationships set up between the two).
I have this is in both models:
public function getRouteKeyName()
{
return 'seo_url';
}
Then in my ParksController, I am at a loss. I currently have:
public function show(Counties $county, Parks $park)
{
//return $park;
//dd($park);
return view('parks.park', ['park'=>$park]);
}
I have also tried the non-Eloquent way:
public function show($county_slug,$park_slug)
{
$county = DB::table('counties')->where('seo_url',$county_slug)->get();
$county_id = $county->pluck('id');
$park = DB::table('parks')->where('county_id', $county_id)->where('seo_url', $park_slug)->get();
//dd($county_id);
//return $park;
return view('parks.park', ['park'=>$park]);
}
This returns a 404 error. Any help would be much appreciated. (I have done a lot of reading on Route model binding, but can not see any examples like mine.)
Laravel has an undocumented feature in its explicit model binding, where the callback can be given the current Route the binding is for. This can allow you to access the other parameters and use them to add conditionals.
Router::bind('park', static function ($value, Route $route) {
$query = Parks::where('seo_url', '=', $value);
if ($route->hasParameter('county')) {
$county = $route->parameter('county');
$query->where('county_id', '=', $county instanceof Counties ? $county->id : $county);
}
return $query->first() ?? abort(404);
});
I have this relationship in one of my model classes:
public function userLike()
{
if (Auth::check()) return $this->hasOne('App\Like')->where('user_id', Auth::user()->id);
// RETURN NULL IF RECORD DOESN'T EXIST?
}
As you can see, it checks if the user is logged in and returns the Like record. However, how can I return null if the record doesn't exist?
I tried this:
public function userLike()
{
if (Auth::check()) return $this->hasOne('App\Like')->where('user_id', Auth::user()->id);
return null;
}
But I get the error:
local.ERROR: exception
'Symfony\Component\Debug\Exception\FatalErrorException' with message
'Call to a member function addEagerConstraints() on null' in
/var/www/social/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:680
As a side question, am I doing this right? Is this the correct way of doing this or is there a better way?
I'm not sure it is the right way to do this. In your model you should only declare your relationships:
public function userLike()
{
return $this->hasOne('App\Like');
}
And then in a controller or something you go get the like of your user like this:
class LikesController extends Controller {
public function getLike()
{
$like = null;
if (Auth::check()) {
$like = Like::where('user_id', Auth::user()->id)->first();
}
}
}
So we have a getLike() function that get the like of a user from your model Like where the user_id is equal to the authenticated user's id.
Hope it helps!
I'm not sure! But I think it is possible to use count! When it returns 0 you know that there are no records, so you can return null.
You can just use this style in your Like Model :
// return the number of likes
function userLikes()
{
$count = $this->where('user_id', $this->post_id)->count();
// check if not null
return $count ? $count : 0; // if null return 0
}
Laravel has a built-in method called findOrfail() described here:
Not Found Exceptions
Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. The findOrFail and firstOrFail methods will retrieve the first result of the query. However, if no result is found, a Illuminate\Database\Eloquent\ModelNotFoundException will be thrown:
$model = App\Flight::findOrFail(1);
$model = App\Flight::where('legs', '>', 100)->firstOrFail();
But what if you want to write your own code which deals with no result found. So in my controller I want something like:
public function show($id)
{
$data = JobCardHead::where('JobCardNum', $id)->first();
If no data found then
some code
else
some code
What does Eloquent return in case no model is found for the methods that do not throw an exception? I'm guessing it's either null or false. So, you could check the return value of the first() call:
$data = JobCardHead::where('JobCardNum', $id)->first();
if ($data) {
// found it
} else {
// not found
}
Or, knowing that firstOrFail() throws an exception, you could wrap the call in a try/catch block:
use Illuminate\Database\Eloquent\ModelNotFoundException;
//..
try {
$data = JobCardHead::where('JobCardNum', $id)->first();
} catch (ModelNotFoundException $e) {
// Data not found. Here, you should make sure that the absence of $data won't break anything
}
// Here $data is an instance of the model you wanted
The exact approach you should pick actually depends on your usecase a lot.
UPD. By the way, if $id here is your primary key here, you should simply use find($id) or findOrFail($id), as described here
Laravel returns null on first() calls to your model when no records are returned.
https://github.com/laravel/framework/blob/5.2/src/Illuminate/Database/Query/Builder.php#L1548
So for example you could do this as an even cleaner solution:
public function show($id)
{
if ($job = JobCardHead::where('JobCardNum', $id)->first()) {
// Record was found!
return view('job.show', compact('job'));
}
return view('404');
}
I am creating a forum software using Laravel and I'm trying to access the most recent posts made within a specific topic using latestPost as defined in my model below
public function latestPost() {
return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
}
Here is how the nested relationships are defined in App\Post.php
public function author()
{
return $this->belongsTo('App\User', 'author_id');
}
public function thread()
{
return $this->belongsTo('App\Thread', 'thread_id');
}
public function topic() {
return $this->belongsTo('App\Topic');
}
I have been able to access posts of threads, authors etc no problem, and when I have {{ $topic->latestPost }} in my views, it will list the object including relationships successfully. But as soon as I try to display a specific part such as {{ $topic->latestPost->author->username }} I am getting the following error: Trying to get property of non-object
In this specific view, topics is yet another relationship pulled from Categories like so in the Controller and getting $topics using a #foreach on $categories->topics:
public function index() {
$categories = Category::orderBy('order', 'asc')->get();
return view('welcome', compact('categories'));
}
Here is a dump of $categories: http://dumptext.com/H8Nq16ea
Maybe you want to use nested eager loading.
Change: return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
To this: return $this->hasOne('App\Post')->with('thread.author')->latest();
Also i never heard about latest() and the end of your return statement. Maybe you can try it with orderBy as shown below.
`return $this->hasOne('App\Post')->with('thread.author')->orderBy('id')->first;`
I guess you can use the orderBy('id')->reverse() function if the result is not in the order you want. Let me know if it helped you out.
You should make sure you have author for latest post you want to display. Otherwise if you expect not to have one for each record, you should try:
{{ $topic->latestPost->author ? $topic->latestPost->author->username : 'No author' }}
In addition instead of:
return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
you can use
return $this->hasOne('App\Post')->with('thread','author')->latest();
Suppose I have a model called User where several relations are defined (role and permissions). How can I get directly in my User model related role collection or related permissions collection ?
What I am trying to do :
controller:
if (Auth::user()->hasPermission('test'))
{ // code goes here}
and my model:
public function hasPermission($name)
{
$permission = \Permission::where('name', '=', $name)->get();
$list = ($this->overwrite_permission) ? $this->permissions : $this->role->permissions;
//here I want to have a collection to use contains()
if ($list->contains($permission))
{
return true;
}
return false;
}
You can do this instead of checking collection:
public function hasPermission($name)
{
return ($this->overwrite_permission)
? (bool) $this->permissions()->whereName($name)->first()
: (bool) $this->role->permissions()->whereName($name)->first();
}
First() will fetch the permission model if it's in the related permissions (to the user or the role appropriately) or return null, thus casting to boolean will do the job.
If you want to use your code anyway, this is the line to change:
// it returns Collection, while you need Model (or its id) for contains() method
$permission = \Permission::where('name', '=', $name)->get();
// change to:
$permission = \Permission::where('name', '=', $name)->first();
Rest of the code is ok, $list is indeed a Collection (unless you have not setup relations to permissions correctly)