How can I use orderBy to order by a model's method?
Consider the model User and the method
public function fullName() {
return $this->firstName . $this->lastName;
}
I want to do something like orderBy('fullName'). Is this possible? I know I can make equivalent code using Query Builder, but I want to keep my Model methods as they are.
I think you have a few options here:
Create a view in your database, which has the column fullName. Then change your model to use the view.
Create a computed column fullName so that on insert if will use the values given from firstName and lastName.
Use Laravel's Collection class. This class provides a sortBy method which you can use an attributes.
If you go with option 2, first define an attribute:
public function getFullNameAttribute()
{
return $this->firstName . $this->lastName;
}
Then using Laravel's Collection:
$items = Model::all()->sortBy('FullName');
Note: The default option for sortBy is ascending, so if you wish to sort descending:
$items = Model::all()->sortByDesc('FullName');
You can read more about accessors here: https://laravel.com/docs/5.7/eloquent-mutators#defining-an-accessor
I've solved the problem with this solution:
$sorted = User::get()
->sortBy('full_name') //appended attribute
->pluck('id')
->toArray();
$orderedIds = implode(',', $sorted);
$result = DB::table('user')
->orderByRaw(\DB::raw("FIELD(id, ".$orderedIds." )"))
->paginate(10);
I've appended fullName attribute to the model, to be used by sortBy.
With this solution I was able to use orderBy to order by an appended attribute of the model, exactly what I wanted to do. So yes, it is possible. And also I was able to use pagination. Thanks to all who tried to help.
$personas = Persona::select('*');
$personas = $personas->addSelect(DB::raw('concat(nombre,\' \',apellido1,\' \',apellido2) as fullname'))
->orderBy('fullname', 'ASC')->paginate(K_LINEAS_X_PAGINA);
I couldn't make it work without the select('*')
Related
$objects = Objects::where("id_host", $hostId)
->orderBy("id", "desc")
->get();
In the collection , each object has a type_id field . How can I use this field to get a record in another model and mix them into this object in the response
First thing is first, in order to show the relationship between the records, you'll need to set up a One-to-Many/Many-to-One relationship. This allows you to readily call those relationships from within Laravel and to load them together.
Without being able to see your Type and Object classes, I really can't give specific advice on this, but it should look something like this:
Objects
public function type(): BelongsTo
{
return $this->belongsTo(Type::class);
}
Type
public function objects(): HasMany
{
return $this->hasMany(Objects::class);
}
Once you've done that, you can add a with(...) call to your Eloquent query to eager load the relationship.
$objects = Objects::where("id_host", $hostId)
->orderBy("id", "desc")
->with('type')
->get();
Alternatively, if you don't want to eager load it for some reason, you can call $object->type to get the Type object.
Im trying to find the users that has commented the product this way:
public function getUserToRate(Product $product)
{
$userIds = DB::table('product_ratings')->where('product_id', $product->id)->pluck('user_id');
return $userIds;
}
But the thing is that $product->id is null. This is what comes out if I do:
DB::table('product_ratings')->where('product_id', $product->id)->toSql():
select * from `product_ratings` where `product_id` = ?
Why is my $product->id null? I have checked and the model exists, but I cant seem to use it inside the query builder.
Can anyone lend me a hand? Thanks
I don't think you need a product model. So ignore Route Model binding like Product $product. Instead you can use your $oroductId. And query the UserIds like this:
public function getUserToRate( $productId)
{
$userIds = ProductRating::where('product_id', $productId)->pluck('user_id');
return $userIds;
}
My controller method like below
public function index($book_id) {
print_r($book_id);
}
I will get the id from view. View like below
I need to get specific row according id on model how can I do that if I use query in controller its not working
If I use like below in controller it gives something else as result
public function index($book_id) {
print_r($book_id);
$this->db->select('*');
$this->db->from('books')->where('book_id', $book_id);
$query = $this->db->get();
print_r($query);
}
but if I use same query in model with hard coded id for testing it gives the expected out put
Please help me with this
You don't need to include "/index" in anchor tag href as controller default method will be index if found. And "print_r($book_id)" should be "echo $book_id" as $book_id is variable not array.
Please try this code (either in model/controller):
$query = $this->db->get_where('books', array('book_id' => $book_id));
$result = $query->row_array();
print_r($result);
After I save a Eloquent model, how am I able to retrieve a relationship with it?
So for example:
$model = new Foo;
$model->save();
dd($model); //return an object of Foo
Let's say I've set an relation to Baz, I should grab the relation like a normal Eloquent Object.
dd($model->with('baz')->get());
But this is returning every Foo record in de database with the relationship.
I just want to be able to get the current Baz model which is related to the saved Foo model.
I could do:
$result = Foo::with('baz')->find($model->id);
dd($result);
But this results in another query, which I want to prevent.
Simply just access it once like this:
$model->baz
And the relationship will be loaded.
Alternatively you can lazy eager load the relation:
$model->load('baz');
The effect is the same, although the first way allows you to actually use the result of the relation directly. If you just want to have the relationship in your array / JSON output I suggest you use the second method, because it's clearer what you're doing.
Depends on how you declare your relationships on your models. Assuming your relationship is declared as One to Many like this:
class Foo extends Eloquent {
public function bazes()
{
return $this->hasMany('Baz');
}
}
Then you can try this:
$results = $model->bazes;
or
$results = Foo::find($id)->bazes
$results is an iterable collection of bazes related directly with foo->id = x
But if you want eager loading with filters, then you can try like this:
$result = Foo::with(array('bazes' => function($query)
{
$query->where('id', $id);
}))->get();
I hope this works for you.
You should eager load on existing models using load().
Try
$model = new Foo;
$model->save();
$model->load('baz');
I have a collection of objects. Let's say the objects are tags:
$tags = Tag::all();
I want to retrieve a certain attribute for each tag, say its name. Of course I can do
foreach ($tags as $tag) {
$tag_names[] = $tag->name;
}
But is there a more laravelish solution to this problem?
Something like $tags->name?
Collections have a lists method similar to the method for tables described by #Gadoma. It returns an array containing the value of a given attribute for each item in the collection.
To retrieve the desired array of names from my collection of tags I can simply use:
$tags->lists('name');
Update: As of laravel 5.2 lists is replaced by pluck.
$tags->pluck('name');
More specifically, the laravel 5.2 upgrade guide states that "[t]he lists method on the Collection, query builder and Eloquent query builder objects has been renamed to pluck. The method signature remains the same."
Yep, you can do it nice and easily. As the Laravel 4 Documentation states, you can do
Retrieving All Rows From A Table
$users = DB::table('users')->get();
foreach ($users as $user)
{
var_dump($user->name);
}
Retrieving A Single Row From A Table
$user = DB::table('users')->where('name', 'John')->first();
var_dump($user->name);
Retrieving A Single Column From A Row
$name = DB::table('users')->where('name', 'John')->pluck('name');
Retrieving A List Of Column Values
$roles = DB::table('roles')->lists('title');
This method will return an array of role titles.
You may also specify a custom key column for the returned array:
$roles = DB::table('roles')->lists('title', 'name');
Specifying A Select Clause
$users = DB::table('users')->select('name', 'email')->get();
$users = DB::table('users')->distinct()->get();
$users = DB::table('users')->select('name as user_name')->get();
EDIT:
The above examples show how to access data with the help of Laravel's fluent query builder. If you are using models you can access the data with Laravel's Eloquent ORM
Because Eloquent is internaly using the query builder, you can without any problem do the following things:
$tag_names = $tags->lists('tag_name_label', 'tag_name_column')->get();
which could be also done with:
$tag_names = DB::table('tags')->lists('tag_name_label', 'tag_name_column')->get();
Here are a few snippets from my own experimentation on the matter this morning. I only wish (and maybe someone else knows the solution) that the Collection had a $collection->distinct() method, so I could easily generate a list of column values based on an already filtered collection.
Thoughts?
I hope these snippets help clarify some alternative options for generating a list of unique values from a Table, Collection, and Eloquent Model.
Using a Collection (Happy)
/**
* Method A
* Store Collection to reduce queries when building multiple lists
*/
$people = Person::get();
$cities = array_unique( $people->lists('city') );
$states = array_unique( $people->lists('state') );
// etc...
Using an Eloquent Model (Happier)
/**
* Method B
* Utilize the Eloquent model's methods
* One query per list
*/
// This will return an array of unique cities present in the list
$cities = Person::distinct()->lists('city');
$states = Person::distinct()->lists('state');
Using an Eloquent Model PLUS Caching (Happiest)
/**
* Method C
* Utilize the Eloquent model's methods PLUS the built in Caching
* Queries only run once expiry is reached
*/
$expiry = 60; // One Hour
$cities = Person::remember($expiry)->distinct()->lists('city');
$states = Person::remember($expiry)->distinct()->lists('state');
I would love to hear some alternatives to this if you guys have one!
#ErikOnTheWeb
You could use array_column for this (it's a PHP 5.5 function but Laravel has a helper function that replicates the behavior, for the most part).
Something like this should suffice.
$tag_names = array_column($tags->toArray(), 'name');