how get many record from an array in laravel - php

I have an array of category , and this categories have many books (belongToMany) how i can get all book
sorry about my English
category model
class category_b extends Model
{
protected $table = 'categoryb';
protected $attributes = array(
'lang'=> 'fa',
);
public function getBooks()
{
return $this->belongsToMany('App\book','categoryb_book');
}
}
my book model
class book extends Model
{
public function getCategory()
{
return $this->belongsToMany('App\category_b','categoryb_book');
}
}
my code
$Category = $user->subscriptions(category_b::class)->pluck('id');
$bookCategory= category_b::whereIn('id',$Category)->get();
$bookCategory = $bookCategory->getBooks;

As #Makdous indicated, different approaches exist, you may take the one that fits your need.
Notice that the loop approach may lead to duplicate books, so after the loop you will have to delete duplicate records.
To avoid that problem, one solution would be to query the Book model directly:
$categoryIds = $user->subscriptions(category_b::class)->pluck('id');
$books = book::whereHas('getCategory', function ($q) use ($categoryIds) {
return $q->whereIn('categoryb.id', $categoryIds);
})
->get();
EDIT:
You may go beyond that and improve the readability of your code by defining a local scope.
In your Book class:
class book extends Model
{
// .....
// .....
// Somewhere in your Book class ...
public function scopeOfCategories($query, $categoryIds = [])
{
return $query->whereHas('getCategory', function ($q) use
($categoryIds) {
return $q->whereIn('categoryb.id', $categoryIds);
});
}
}
Now you can replace the old code snippet with the following:
$categoryIds = $user->subscriptions(category_b::class)->pluck('id');
$books = book::ofCategories($categoryIds)->get();

You can use a foreach as mentioned in the docs to iterate through the books of you're fetched category.
foreach ($bookCategory as $book) {
//access book's attributes
}
Or likewise you can get the categories of a certain book.
$book = Book::find($id);
$categories = $book->getCategory();
foreach ($categories as $category) {
//access category's attributes
}

Related

How to create JSON tree from related objects?

I am trying to create Laravel/Vue project with two models: Category and Article. Vue part haves tree-view, which will display categories and articles tree. Categories may belong to another categories, Article may belong only to Article.
How can i form json tree from these relations?
model Category
public function articles() {
return $this->hasMany(Article::class);
}
public function childs() {
return $this->hasMany(Category::class)->union($this->files()->toBase());
}
but it shows The used SELECT statements have a different number of columns, because there is defferent fields in results.
One solution i see here is to find every article and post and create array, then jsonify it. Maybe any better solutions?
UPDATE
Done it with this code (in api controller):
public function nodes() {
$rootCategories = Category::where('category_id', null)->get();
$out = $this->_nodes($rootCategories);
return response()->json($out);
}
private function _nodes($eCategories) {
$out = [];
foreach($eCategories as $cat) {
$out[$cat->id] = $cat->toArray();
$out[$cat->id]["type"] = "folder";
$out[$cat->id]["childs"] = [];
foreach ($cat->articles as $article) {
$out[$cat->id]["childs"][$article->id] = $article->toArray();
$out[$cat->id]["childs"][$article->id]["type"] = "article";
}
if ($cat->categories) {
$out[$cat->id]["childs"] = $out[$cat->id]["childs"] + $this->_nodesCategory($cat->categories);
}
}
return $out;
}

How to query Eloquent relational tables based on json ids

I have a articles table with a field named article_categories.
I have a categories table with id field.
In my Article Model I have defined:
public function category(){
return $this->hasMany(Category::class,'id','article_categories');
}
the categories in the articles table are saved as json like ["1","3","24"]
in my ArticleController I want to retrieve all categories of a specific article.
In my edit function in the ArticleController I have this function:
public function edit(Article $article)
{
$category_ids = implode(',',json_decode($article->article_categories)) ; //this gives me 1,3,24
/////////
// HERE SHOULD COME THE QUERY WHICH I DON'T KNOW
// $article_categories = ??????????
////////
$categories = Category::all();
return view('article.edit', compact('articles','categories','article_categories'));
}
From what I've researched, there is no way to do this with Laravel but I don't know if this is true or not. I'm using Laravel 8.
Can anyone help me?
First of all you should know that you violated a many-to-many relation in a single column and that's not valid. What you should do is a pivot table article_category or category_article and in both Article and Category models you will define a many-to-many relation
like so
class Article extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
class Category extends Model
{
public function articles()
{
return $this->belongsToMany(Article::class);
}
}
And in your controller you can do
public function edit(Article $article)
{
$categories = Category::all();
return view('article.edit', compact('article','categories'));
}
And in the view you will have direct access to $article->categories
In your current situation you can do this
public function edit(Article $article)
{
$category_ids = json_decode($article->article_categories)
$article_categories = Category::whereIn('id', $category_ids);
$categories = Category::all();
return view('article.edit', compact('article','categories','article_categories'));
}

Model combining two tables in Laravel

I have the tables "item", "payment", "join_payment".
The item has an id, the payment has an id. The join_payment has the rows item_id and payment_id.
A payment may contain many items, which would be registered in the join_payment table.
I want to make a log with these items and I am currently doing this in the controller:
$log = Array();
$items = item::where("id",Auth::user()->id)->get();
foreach($items as $item){
$join_payment = join_payment::where("item_id",$item->id)->first();
if(!array_key_exists($join_payment->payment_id,$log){
$log[$join_payment->payment_id] = payment::where("id",$join_payment->payment_id)->first();
}
$log[$join_payment->payment_id][$item->id] = $item;
}
Is there a way to pull this out with the models?
I recommend using Eloquent relationships for this. https://laravel.com/docs/5.5/eloquent-relationships#many-to-many. If you call the join table item_payment it will be even easier:
class Item extends Model {
public function payments(){
return $this->belongsToMany(Payments::class)
}
}
class Payment extends Model {
public function items(){
return $this->belongsToMany(Item::class)
}
}
class ItemPayment extends Model {
public function item(){
return $this->belongsTo(Item::class)
}
public function payment(){
return $this->belongsTo(Payment::class)
}
}
Then you can access the data you need in a bunch of ways:
$items = Item::all();
foreach($items as $item){
$item->payments; //returns all payments belonging to this item
}
$payments = Payment::all();
foreach($payments as $payment){
$payment->items; //returns all items belonging to this payment
}
$itemPayments = ItemPayment::all();
foreach($itemPayments as $itemPayment){
$itemPayment->item; //the item for this join
$itemPayment->payment; //the payment for this join
}
Sorry for changing your class and table names, but these conventions will make your life a ton easier in Laravel
in your Item model use this
public function payment()
{
return $this->hasOne('App\Payment','join_payment','payment_id','item_id');
}
then in you loop check
foreach($items as $item){
dd($item->payment);
}

Laravel Eloquent ORM - return objects thru another objects

I have 3 models: Shop, Products and Tags. Shop and Products are in one to many relation, and Products to Tags many to many.
I want to grab for each Shop all unique Tags (since many products can have same tags).
class Shop extends Eloquent {
public function products() {
return $this->hasMany('Product');
}
}
class Product extends Eloquent {
public function shop() {
return $this->belongsTo('Shop');
}
public function tags() {
return $this->belongsToMany('Tag');
}
}
class Tag extends Eloquent {
public function products() {
return $this->belongsToMany('Product');
}
}
One of the solutions that I came up with is following. Problem is that I don't get unique tags. There is a solution to put another foreach loop to go thru tags array and compare id in tag object. I would like to optimize a little bit, what do you think is better/cleaner solution?
class Shop extends Eloquent {
...
public function getTagsAttribute() {
$tags = array();
foreach($this->products as $product)
{
foreach ($product->tags as $tag)
{
$tags[] = $tag;
}
}
return $tags;
}
}
#WereWolf's method will work for you, however here's a trick that will work for all the relations:
$shop = Shop::with(['products.tags' => function ($q) use (&$tags) {
$tags = $q->get()->unique();
}])->find($someId);
// then:
$tags; // collection of unique tags related to your shop through the products
Mind that each of the $tags will have pivot property, since it's a belongsToMany relation, but obviously you don't rely on that.
Probably you may try this:
$tags = Tag::has('products')->get();
This will return all the Tags that's bound to any Product. If necessary, you may also use distinct, like this, but I think it's not necessary in this case:
$tags = Tag::has('products')->distinct()->get();
Update: Then you may try something like this:
public function getTagsAttribute()
{
$shopId = $this->id;
$tags = Tag::whereHas('products', function($query) use($shopId) {
$query->where('products.shop_id', $shopId);
})->get();
return $tags;
}

get X amount of posts with user from every category - eloquent orm

What's the minimum amount of queries needed for this operation?
category->hasMany(post)
post->belongsTo(user)
The only thing I can come up with is:
$categories = Category::all();
foreach($categories as $category) {
$category->posts = Post::where('category_id', $category->id)->take(4)->get();
}
Say I got 4 categories the output of the query log will print 9 line of queries.
here's a quick example of what I mentioned in the comments. By defining a method on your Category model, you can reduce the number of calls you make for each category to 1:
(note: this is a many-to-many relationship)
Category model (Category.php)
class Category extends Eloquent {
public function posts()
{
return $this->belongsToMany("Post");
}
public function getRecentPosts($n)
{
return $this->posts()->orderBy('created_at')->take($n)->get();
}
}
Posts model (Post.php)
class Post extends Eloquent {
public function categories()
{
return $this->belongsToMany("Category");
}
}
Then you can just call the getRecentPosts($n) method to get $n posts!
foreach (Category::all() as $category)
{
$posts = $category->getRecentPosts(4);
foreach ($posts as $post)
{
echo $post->name . "<br/>";
}
}
You will be making $n + 1 queries.. one to get the Category::all() and then one for the Posts of each Category...
hope it helps!

Categories