Where to put user related get functions - laravel

I have a problem I am working on for quite a while now.
I am using Laravel 5.0 and have relationships set up:
A user can have many itineraries
A itinerary can have many destinations
A user has many destinations through itineraries
Now I am trying to set up a function which I need in many controllers. I have this function in User.php:
public function last_destination() {
return $last_destination =
\App\Destination::where('itinerary_id', auth()->user()->active_itinerary_id)
->orderBy('order_index', 'DESC')
->first();
}
When I try to retrieve the last destination, it works fine, but when I pass the last destination as a variable to a view, it throughs me the error: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
Should I put this function in another class? If so where should I put it to still be able to call it as $user->last_destination()?
I appreciate any help!
Thanks a lot!
Sebastian

You are most likely trying to call $user->last_destination somewhere, as you would if that method returned a Relation.
Try using $user->last_destination() instead. Or updating your method to return a Relation instance.

Related

Illuminate\Database\Eloquent\RelationNotFoundException Call to undefined relationship [user] on model [App\Event]

I'm creating a view list for M-M relationship for Admin view. I want to display every user that has been registered for that particular events. And I'm pretty sure I called it wrong thats the reason why I getting this error. I'm not quite sure on how to fix it. I tried googling and I still don't find any solution yet. So how can I fix this?
The relation name is users not user. Please check using below code
use DB;
use App\Event;
use App\User;
public function show()
{
$events = Event::with('users')->get();
return view('admin.event.user')->with('events', $events);
}

Scope left Join Sub doesn't work - Laravel

I'm new to Laravel I'm making a clone of Twitter. I'm making a scope to get all the likes from the DB, but I get an error from Tinker
I know some basic SQL Queries, but this one is quite complicated, so I've got no idea what to do now.
Tweet model
public function scopeWithLikes(Builder $query)
{
$query->leftJoinSub(
'select tweet_id, sum(liked) likes, sum(!liked) dislikes from likes group by tweet_id',
'likes',
'likes.tweet_id',
'tweet.id'
);
}
Tinker command
App\Tweet::withLikes()->first();
Tinker error
TypeError: Argument 1 passed to App/Tweet::scopeWithLikes() must be an
instance of Illuminate/Database/Query/Builder, instance of
Illuminate/Database/Eloquent/Builder given, called in
C:/wamp64/www/laravel/tweety/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
on line 1164
I hope I explained it well, but if you need more information please ask me.
Thanks for your answer!
i think that you are using the wrong class for your scope, scope use
Illuminate/Database/Query/Builder
as a parameter while you pass
Illuminate/Database/Eloquent/Builder
in your Twit model file, on the top ...
remove:
use Illuminate/Database/Eloquent/Builder;
and paste:
use Illuminate/Database/Query/Builder;
Did this solve the problem? Because I run into exactly the same issue.
When I change Eloquent to Query, the error message is still the same.
Also the source that is given on Git uses use
Illuminate\Database\Eloquent\Builder;
Hubert

Laravel Gate method not being called

In my Laravel 5.4 application users can create Projects and then Posts inside those projects.
I'm trying to prevent users from creating or editing posts inside a project they don't have access to.
To do this I implemented a Gate as explained here: https://laravel.com/docs/5.4/authorization#gates
The gate checks if a user is the owner of the project.
Gate::define('create-post', function ($user, $project) {
Log::info($project) // !!! Never gets called
return $project->owner_id == $user->id;
});
On the PostController I call Gate::denies passing the project as an argument
if (Gate::denies('create-post', $project)) {
abort(403);
}
The problem is the code I defined for the gate never gets called. Instead it always returns false and goes to the 403 error.
However, the code does get called if I don't pass the project as an argument but that makes it useless.
I also want to add that in this case I cannot use a Policy because the create method only takes one argument ($user) and if I try to pass the $project it fails the same way it does with the Gate.
Is this a bug? Is there another, better way to implement this funcionality? Thanks.
I have the same issue. It seems something wrong happens when the second parameter in Gate::allows() is an eloquent model.
If you pass in denies() any other variable (even object, but not eloquent model), your Log::info() will work.
I wasted the whole day with it and switched to $user->can()
I was able to fix it by using a policy. I created the following method in ProjectPolicy:
public function createOrEditPosts(User $user, Project $project)
{
return $project->owner_id == $user->id;
}
Then from PostController I call:
$this->authorize('createOrEditPosts', $project));
I still don't know why the gate approach doesn't work.
I had the same issue.
I replaced Gate::denies() with Gate::allows().
I'm not sure why but this worked for me. The policy framework is a little bit tricky to be honest
first, check to log in to your project then gate work because of the gate when work that you log in to your project.

Search object by slug and not by id

I'm a relative beginner with Laravel (using version 5.2.3) and have been working through tutorials on Laracasts and then doing a bit of my own experimenting.
I successfully set up a route that fetches an item from a table by its ID, as shown below
Route::get('/wiseweasel/{id}', 'WiseweaselController#singleArticle');
For simplicity, the controller simply dd's the article
public function singleArticle($id)
{
$article = ww_articles::find($id);
dd($article);
}
This works absolutely fine - I visit eg /wiseweasel/2 and get the contents of the record with id2.
So, I then wanted to use the slug field from the record instead of the id. Since I know the ID method was working, I've tried just modifying this route and controller (also tried creating anew, neither worked) So I now have:
Route::get('/wiseweasel/{slug}', 'WiseweaselController#singleArticle');
and
public function singleArticle($slug)
{
$article = ww_articles::find($slug);
dd($article);
}
The slug for the second record is "secondarticle". So, visiting the url /wiseweasel/secondarticle, I would expect to see the same record as previously dd'd out. Instead, I end up with null.
Even more oddly, using the original id route (/wiseweasel/2) still returns the record... when I have removed all trace of this from the routes and controller, so I would expect this to fail...
This is making me wonder if this could be some odd caching issue? I've tried
php artisan route:clear
in case the route was being cached. I've also tried restarting both Apache and MySql (I'm using XAMMP for both).
Still no luck though... not sure if I've misunderstood how something works or what's going on... so if anyone has any suggestions as to what I might have done wrong, or anything to try, I would be very grateful! :)
You also have the option of using Route Model Binding to take care of this and inject the resolved instance into your methods.
With the new implicit Route Model Binding you can tell the model what key it should use for route binding.
// routes
Route::get('/wiseweasel/{article}', 'WiseweaselController#singleArticle');
// Article model
public function getRouteKeyName()
{
return 'slug';
}
// controller
public function singleArticle(Article $article)
{
dd($article);
}
Laravel Docs - Route Model Binding
Laravel won't automatically know that for slug it should search record in different way.
When you are using:
$article = ww_articles::find($slug);
you are telling Laravel - find record of www_articles by ID. (no matter you call this id $slug).
To achieve what you want change:
$article = ww_articles::find($slug);
into
$article = ww_articles::where('slug', $slug)->first();
This will do the trick (for slug put the name of column in table in database). Of course remember that in this case slug should be unique in all records or you won't be able to get all the slugs.
Maybe it's a bit late for the answer but there is another way to keep using find method and use slug as your table identifier. You have to set the protected $primaryKey property to 'slug' in your model.
class ww_articles extends Model
{
protected $primaryKey = 'slug';
...
}
This will work because find method internally uses the getQualifiedKeyName method from Model class which uses the $primaryKey property.
If you have both routes like this
Route::get('/wiseweasel/{id}', 'WiseweaselController#singleArticle');
Route::get('/wiseweasel/{slug}', 'WiseweaselController#singleArticle');
it will always use the first one. Obviously, there is no id 'secondarticle', so it returns null (although in this case it doesn't matter, they both point to the same method).
The reason is route will search through possible routes till it finds a matching, which is always the one with {id}. Why? You're not telling Route that {id} must match an integer!
You can make sure {id} is understood as an integer, however I suggest using urls like this is a better option
/wiseweasel/{id}/{slug?}
Another suggestion. Do not use names such as xx_articles for a model, but Article instead. This way you can use the new implicit route binding. So using implicit route binding your url would look like this (assuming your model is called Article)
Route::get('/wiseweasel/{article}', 'WiseweaselController#singleArticle');

Laravel created_by/modified_by relations

I was trying to get this working in a typical belongsTo relation. However it keeps saying that the column is not set in the model, even if looking in the actual database it is there.
I have tried to look at the source code as well as try many approaches to bypass this issue, however nothing seems to do anything.
public function modifiedBy()
{
return $this->belongsTo('\Modules\Users\Model\User', 'modified_by');
}
public function createdBy()
{
return $this->belongsTo('\Modules\Users\Model\User', 'created_by');
}
This is the code inside the model, I use PSR-0 to define modules, better splitting up logic (no issues with that) but using this it would give an error of
Undefined property: \Modules\Module\Model\CurrentModel::$modified_by
This is coming from a seed to push some initial info into the database.
$user = Sentinel::findById(1);
$model = new CurrentModel;
$model->modifiedBy()->associate($user);
$model->save();
This is basically how it goes together, I have tried for some time to figure out what is wrong but I am calling blanks. Any ideas?
Found out a solution. Not a fix though but I would consider this an issue with laravel so I may look into adding it as a bug report (although this could be fixed in laravel 5?).
Basically with modified_by I need to define the column it is using and not let laravel automatically generate it (in order to do this "cleanly"). However the "bug" (only calling it a bug as currently I can only see this as an unintended problem) makes it so you cannot define the column it will be using, you have to let laravel decide it for you.
So I changed the functions to look like this:
public function modifiedby()
{
return $this->belongsTo('\Modules\Users\Model\User');
}
This makes laravel assume the column is modifiedby_id, but by changing my migrations to reflect that there was no more error.

Resources