Laravel Create Collection of a certain Model and add Objects manually - laravel

I got a list of IDs and need to get a Collection (Let's say of the type "Book") and add Single Books to this Collection by Hand.
Example:
$ids = array(1,5,7,12);
$books = ???
foreach($ids as $id){
$books->add(Book::find($id)); }
Or is there a easier way to get what I want?
Thank you

You could write something like this I think:
$books = Book::whereIn('id', $ids)->get();
$books will be a Collection containing all your books.

Related

Getting all items with another Eloquent query ID in Laravel

I have something like this:
$items = Item::whereIn("name", $request["names"])->get();
Now I want to get a list of shops that have any of those items. Something like this:
$shops = Shop::whereIn("item_id", $items)->get();
This does not work, because items is an eloquent collection (obviously). I could do some loop and get all the ids like this:
foreach ($items as $item){
$itemIds[] = $item
}
And then use it, but I feel there must be a cleaner way.
Any help?
Use ->pluck('id') and whereIn():
$items = Item::where('name', $request['names'])->get();
$shops = Shop::whereIn('item_id', $items->pluck('id'))->get();
Eloquent Collections have access to many of the same functions of Laravel's Collection Class:
https://laravel.com/docs/9.x/collections#available-methods
->pluck('id') will return an array of all items.id records, which you can then use to query via ->whereIn('item_id', ...);

Detach on eloquent collection not working

In a Post model I have:
public function tags()
{
return $this->morphToMany(\App\Models\Tag::class, 'taggable');
}
But when I then do:
$posts = Post::all();
$posts->tags()->detach();
I get
Method Illuminate\Database\Eloquent\Collection::inputs does not exist.
Based on your code, it seems like you're trying to remove all the tags from all the existing posts in your application.
If this is what you're trying to do, then follow #A.A Noman comment: you should detach them by iterating the collection, one by one.
Another option is to just clear the intermediate table containing the relations.
If what you're trying to do here is detaching all the tags from a single Post, you can search the post and then detach all the tags:
$post = Post::find($id);
$post->tags()->detach();
UPDATE
To iterate the collection and remove all the Tags from all the Posts:
$posts = Post::all();
foreach ($posts as $post) {
$post->tags()->detach();
}
Use Laravel's with()
https://laravel.com/docs/8.x/eloquent-relationships
To bring the tags related to this collection
Example:
$posts = Post::with('tags');
$posts->tags()->detach();
Likewise, if you want to remove a particular entity relationship from the pivot table, you can use the detach method.
For example, if you want to remove a certain author from a book, you can do so.
$book->authors()->detach($authorId);
Or you can pass multiple IDs as an array.
$book->authors()->detach([4, 5, 8]);
Or, if you want to remove all authors from a book, use detach without passing any arguments.
$book->authors()->detach();

collections and eloquent results

I have a set of row returned from a function and stored in a variable called $topics. Each topic contains a set of articles. so for the variable $topics if we do $topics[0]->articles we get several articles, and if we do $topics[1]->articles we get another set of articles. What i want to do is to put all these articles in one variable lets call it $articles so that I can do operations such as
$articles->where('author', 'Jone Doe')->get();
I tried to do this:
$articles = new collection();
foreach( $topics as $topic) {
foreach( $topic->articles as $article)
$articles->push($article);
But this unfortunately destroys the actual structure of the articles. like I can't do $articles->translations where i use a translation package. but i can do $topics[0]->articles->translations. basically i want to get all the articles in one collection as if they were returned from doing something like
$articles = Article::all()->get();
Thanks
Just use the pluck method on your collection
$articles = $topics->pluck('articles');
And if you wish a 1-dimension articles collection
$articles = $topics->flatMap(function ($topic) {
return $topic->articles;
});

Grab relation of saved Eloquent model

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');

Laravel 4 - Get Array of Attributes from Collection

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');

Resources