PHP Traits "Method does not exist" - php

I am using laravel-comment to enable Users to comment on each other. Therefor, I need to use both the Commentable and the CanComment trait. But when I use them together, I get an error.
User uses it like this:
use Commentable, CanComment {
Commentable::comments insteadof CanComment;
}
And I am trying to seed the comments like this:
foreach (User::all() as $user) {
$receiver = User::where('id', '!=', $user->id)->inRandomOrder()->get();
$user->comment($receiver, $faker->text(100), 3);
}
Even though the CanComment trait has a method called getCanBeRated, I get an error saying that it doesn't. Why is this happening?

You're getting this error because you're trying to use this method on collection and not on User object. Use first() instead of get() to get an object instead of collection:
$receiver = User::where('id', '!=', $user->id)->inRandomOrder()->first();

Related

Laravel query builder returns object or array?

I'm building a very simple web app with Laravel.
I've built two separate Controllers, which each return two separate views, as follows:
ProfileController:
class ProfileController extends BaseController {
public function user($name)
{
$user = User::where('name', '=', $name);
if ($user->count())
{
$user = $user->first();
$workout = DB::table('workouts')->where('user_id', '=', $user->id)->get();
Return View::make('profile')
->with('user', $user)
->with('workout', $workout);
}
return App::abort(404);
}
}
WorkoutController:
class WorkoutController extends BaseController {
public function workout($name)
{
$workout = DB::table('workouts')->where('name', '=', $name)->first();
if ($workout)
{
Return View::make('add-exercise')
->with('workout', $workout);
}
return App::abort(404);
}
}
What is confusing me is what I had to do in order to pass a single workout object to each view. As you might have noticed the query builders for workout are different:
$workout = DB::table('workouts')->where('user_id', '=', $user->id)->get();
and
$workout = DB::table('workouts')->where('name', '=', $name)->first();
On the profile view, I get an object using the ->get(); method, but on the add-exercise view, I must use ->first(); or I will otherwise get an array with only one index, where I can then access the object, i.e. $workout[0]->name instead of $workout->name.
Why is this? Shouldn't I be able to use either get and/or first in both controllers and expect the same type of result from both since I want the same thing from the same table?
get() returns a collection of objects every time. That collection may have 0 or more objects in it, depending on the results of the query.
first() calls get() under the hood, but instead of returning the collection of results, it returns the first entry in the collection (if there is one).
Which method you use depends on what you need. Do you need the collection of all the results (use get()), or do you just want the first result in the collection (use first())?
Model::find(numeric); returns a object
Model::whereId(numeric)->first(); returns a object
Model::whereId(numeric)->get(); - returns a collection
Model::whereId(numeric); - returns a builder

Laravel 4: Why can I access a model accessor when using first() but not take()?

I'm trying to return a number of recent posts from my database, ordered by date, and I then want to select and return the month the post was made in via my model's getMonthAttribute() accessor method. To accomplish this, I'm using scoped queries. This all works fine when I use first() to return just a single result, but when I use take(1) or take() with any valid numerical input, I receive the following error:
Undefined property: Illuminate\Database\Eloquent\Collection::$month
In my model, I have this month attribute accessor:
public function getMonthAttribute() {
return Carbon::createFromFormat('Y-m-d',$this->date)->format('F');
}
and my scoped query to return a variable number of recent posts (the portion of my code that is not working):
public function scopeRecent($query, $take = 1) {
// Replace take with first and I no longer receive the above error.
return $query->where('status', '=', '1')->orderBy('date', 'DESC')->get()->take($take);
}
Here is how I'm accessing my data in the view:
{{ $post->recent()->month }}
Any suggestions?
This is because ->first() returns an eloquent model. Using the get() method returns an eloquent collection (an array of eloquent models) instead. So you must run a foreach over the collection like so:
#foreach($post->recent() as $recent)
{{$recent->month }}
#endforeach

Laravel 4 model method failed with "Call to undefined method"

My models extends "\BaseModel" which in its turn extends the Eloquent.
class BaseModel extends Eloquent {
public function foo($attribute)
{
//some code
}
In my collection, where the model being instanced I'm trying to access the "foo()" method, but it responses me with "Call to undefined method".
$data = IncomeDoc::with('details')
->where('type', '!=', 2)
->get();
$data = $data->foo();
Moreover, I tried to place the method "foo" in the model itself, but there was no difference.
Thanks for all
Basically get() method returns a Collection of instances. Assume more than 1 model satisfy type != 2 condition. If you want to get first model under the condition just use first() instead.
$data = IncomeDoc::with('details')
->where('type', '!=', 2)
->first();
$data = $data->foo();
Otherwise:
$collection = IncomeDoc::with('details')
->where('type', '!=', 2)
->get();
$data = [];
foreach($collection as $item) {
$data[] = $data->foo();
}
Actually get() returns a collection, an instance of Illuminate\Database\Eloquent\Collection and in this collection there is no foo method but to call the method that you declared in your model, you need to access the model, so first model in the collection would be 0 and to get it you may use $data->first() or $data->get(0), to get the second item (model) from the collection you may use $data->get(1) and so on but you may also use a loop, for example:
$data = IncomeDoc::with('details')->where('type', '!=', 2)->get();
$dataArray = array();
$data->each(function($item) use (&$dataArray){
$dataArray[] = $item->foo();
});
return View::make('viewname')->with('data', $dataArray);
Also, you may directly pass the $data to your view and can apply the function call from the view within a loop but not recommended.

Eloquent and Pivot Tables in Laravel 4

I have a Poll table, a Students table, and a pivot table between them that includes a token and their three votes.
public function students()
{
return $this->belongsToMany('Student', 'polls_students')->withPivot('token','first','second','third');
}
While working out saving the poll results, I came across some odd behavior that I don't quite understand. I'm hoping somebody can explain what it is I'm missing:
$poll = Poll::find(Input::get('poll_id'));
foreach($poll->students()->where('students.id', '=', Input::get('student_id'))->get() as $student){
var_dump($student->pivot->token);
}
$student = $poll->students()->where('students.id', '=', Input::get('student_id'))->get();
var_dump($student->pivot->token);
In the above code, the foreach loop will successfully display the token, where the second one throws the exception Undefined property: Illuminate\Database\Eloquent\Collection::$pivot
What am I missing? Are these two calls not logically creating the same object? How is 'pivot' working on the first and not the latter?
You first example:
$poll = Poll::find(Input::get('poll_id'));
foreach($poll->students()->where('students.id', '=', Input::get('student_id'))->get() as $student){
var_dump($student->pivot->token);
}
Here $poll->students() retrieves a collection and because of foreach loop you get a single object in your $student variable and you can use $student->pivot->token
You second example:
$student = $poll->students()->where('students.id', '=', Input::get('student_id'))->get();
var_dump($student->pivot->token);
Here you are doing same thing, using $poll->students() you are getting a collection but this time you are not using a loop and trying to do same thing using $student->pivot->token but it's not working because you didn't define any index from which you want to get the pivot->token, if you try something like this
$student->first()->pivot->token
Or maybe
$student->get(1)->pivot->token
Or maybe you can use first() instead of get() like this
$student = $poll->students()->where('students.id', '=', Input::get('student_id'))->first();
Then you can use
$student->pivot->token
Remember that, get() returns a collection even if there is only one record/model.
$poll = Poll::find(Input::get('poll_id'));
foreach($poll->students as $student){
var_dump($student->pivot->where('student_id',$student->id)->where('poll_id',$poll->id)->first()->token);
}

Query a relationship in Laravel with WHERE method

I have a model called "User", which "belongsToMany" Items.
This relationship works fine, so I can easily do something like this:
User::find(4)->items->find(1)->name
Now, I would like to do something like this:
User::find(4)->items->where('name', '=', 'stick')->get()
I would expect the code to return all the user's items with the name "stick", but unfortunately that is not what happens. I receive this error:
"Call to undefined method Illuminate\Database\Eloquent\Collection::where()"
I also tried to build a query scope:
public function scopeName($query, $name)
{
return $query->whereName($name);
}
The query scope works when I do something like this:
Item::name('SC')->get()
but
User::find(4)->items->name('SC')->get()
still does not work.
Can you help me returning all the user's items, which have the name 'stick'?
If you're looking to just get a single user's items named "stick", this is how you would do it:
$stickItems = Item::whereUserId(4)->whereName('stick')->get();
Here we are using Eloquent's dynamic where methods, but you could rewrite it like so:
$stickItems = Item::where('user_id', '=', 4)->where('name', '=', 'stick')->get();
That should get you what you want.
You have to call the items() method, not use the magic property:
User::find(4)->items()->where('name', 'stick')->get();
// ^^

Categories