Laravel 4: many to many (insertion) - php

I have these tables in DB:
[posts, cats (categories), posts_cats (pivote)]
the relation between posts table and cats is many to many
I declared the relation in the models classes:
//Post.php
public function cats()
{
return $this->belongsToMany('cats');
}
//Cats.php
public function post()
{
return $this->belongsToMany('posts');
}
the question is, How to insert new post with multiple categories?
thanks,

Let's say you know the id of the post then you can attach a single cat like this:
Post::find($post_id)->cats()->attach($cat_id);
Or attach multiple cats like this:
$cat_ids = array(1,2,3,4);
Post::find($post_id)->cats()->attach($cat_ids);
If you got the Post model object in a variable, lets say $post:
$post->cats()->attach($cat_id);
// Or with multiple
$cat_ids = array(1,2,3,4);
$post->cats()->attach($cat_ids);
If you have a single category as an model object in, lets say $model:
$post->cats()->save($model);
Watch out with #Gadoma's answer. Its not wrong, but if you want to add categories to an post that already has categories then you should use attach() instead of sync(). Sync() will delete all others that are not provided to it when used.
edit:
So if you are creating a new Post then you probably are doing something like this:
$post = new Post;
$post->title = 'The title';
$post->something_else = 'Lorem';
$post->save();
//So now you have both the model object (the $post variable) and the id ($post->id).
$post->cats()->attach($cat_ids);

When you insert the post, then itterate over the categories and attach them to the new post. Something like that:
// $categories is an array of the categories to attach
foreach ($category_id in $categories) {
// Get a category object
$category = CategoryModel::find($category_id);
// $post is the new post
$post->cats()->attach($category);
}
I hope it helps you.

From the docs http://laravel.com/docs/eloquent#inserting-related-models
Inserting Related Models (Many To Many)
[...]
You may also use the sync method to attach related models. The sync
method accepts an array of IDs to place on the pivot table. After this
operation is complete, only the IDs in the array will be on the
intermediate table for the model:
And a code example:
$post = new Post(array('field1'=>'value1','fieldN'=>'valueN')) //example create new post
$categoryIds = array(1,3,4,5); //ids of (cats) categories you want the post to go into
$post->cats()->sync($categoryIds); //synchronise pivot table content with $categoryIds

Related

I am trying to mix pivot table values in Laravel

I have three table category and products with its pivot table as category_product
One category has many products
I want the category name in attributes of products with its own field.
$saijal = "Our Products";
$products = Product::orderBy('created_at','DESC')->with('categories')->get();
$abc = new Collection();
foreach($products as $pro)
{
$abc->put($pro->id,$pro);
}
foreach($products as $k => $pro)
{
$abc->get($pro->id)->children = new Collection();
$abc->get($pro->id)->categoryName= $pro->categories->name;
$abc->get($pro->id)->children->push($pro);
unset($pro[$k]);
}
dd($abc);
For example:
If I'm understanding correctly, you want to be able to access an attribute called "categoryName" directly from the product object. In order to do this, simply set up an attribute getter in the Product.php model that looks like this:
public function getCategoryNameAttribute()
{
return $this->category->name;
}
Then you can simply reference the category name like this:
$product->categoryName
The main issue I see is that you are referring to "categories" in your code as if it is plural. If the product belongs to many categories, the solution would be different and your relationships would require a pivot table, as you describe. But if the product just belongs to one category, as your code implies, the solution above should be sufficient and you actually do not need a pivot table. You would just have a category_id column directly in the products table.
If you do want to have multiple categories for each product, you could do something similar but return an array:
public function getCategoryNamesAttribute()
{
return $this->categories->pluck('name');
}
This would return an array of category names associated with this Product, and would be accessible as:
$product->categoryNames
You can add custom attributes to appends array (not attributes array).
class Product extends Model
{
protected $appends = ['category_names'];
public function getCategoryNamesAttribute()
{
return $this->categories->map->name;
}
}
you can access this attribute as,
$product->category_names;
Note
The benefit of adding this to the appends array is. If you don't add this to the appends array, When you call toArray() or toJson() or send this $product via json. you loses this attribute.

Laravel | Eloquent Populate Foreign Data

I have a database which is set out with a news and a news categories tables.
I have news which has a category 1 which links to a foreign key of the categories table where the category value equals the id in the categories table.
I'm trying to make a controller that gets the category name rather than the category ID when returning the results as a JSON response.
So far I have this inside of a model:
public function category()
{
return $this->belongsTo(NewsCategories::class);
}
And then I'm doing this inside of a controller:
public function index()
{
$news = new News();
$news = $news->category()->get();
return response()->json(['data' => $news], 200);
}
But the JSON response that gets returned is empty. I have googled some things but haven't really found anything useful regarding getting the foreign field which is title within the categories table.
This is the response that I get
{
data: [ ]
}
The first issue is that you're under the impression that your new News instance has linked categories:
$news = new News();
This will yield just an empty model instance; it has no database representation yet. Try fetching categories through a populated model instance:
$news = News::first();
// Or:
$news = News::find(1);
and retry the JSON response.
Second issue is that by calling $news->category()->get() you're actually querying the relation. If you only need to access the title, try $news->category->title which will load the associated category record and access the title field for you.
Regarding your comment, read on eager/lazy loading.

Querying a Collection of One-to-Many Relationship

Suppose I have a User model and a Post model.
class Post extends Eloquent
{
}
There are many users, and each User has many Post. All Post belongs to a User.
class User extends Eloquent
{
public function posts()
{
return $this->hasMany('Post');
}
}
I know that I can get a single User with find().
$user = User::find(1);
I know that from a single User, I can get all their posts().
$posts = User::find(1)->posts;
However, suppose now I have multiple users.
$users = User::all();
I wish to access all the posts that this collection of users have. Something along the lines of
$posts = User::all()->posts;
This, of course, doesn't work. However, in theory, it should be functionally equivalent to
$posts = Post::all()
Is there a way to do something similar to the above in Laravel 4.2?
I do not want to use Post::all(). Reason being that it would not be what I want in a more complicated example that involves constraints on User.
$postsByMaleUsers = User::where('gender', '=', 'male')->posts;
Should get all the posts made by male users.
I am also aware that I could simply use a foreach loop.
foreach($users->posts as $post)
{
// Process result here.
}
However, suppose I am trying to return the results instead of processing the results. For example, I could have a public static function postsByMaleUsers() in the User model, and calling User::postsByMaleUsers() should return a collection of posts by male users only. In which case, the foreach loop would not suit me.
Eager load the posts, then use pluck and collapse to get a flat collection of posts:
$users = User::with('posts')->where('gender', 'male')->get();
$posts = $users->pluck('posts')->collapse();

Laravel 4 Model Relationship not working properly. Can't access related column from Model

lets say I have three Models: Chapter, Book, Author.
A Book hasMany Chapter && Chapter belongsTo Book.
Author hasMany Book && Book belognsTo Author.
That means, that the ChapterTable has a book_id and the BookTable has an author_id.
Now I want to count all the chapters, from a specific author. How would I go about it using Blade?
Here is what I am thinking about:
$chapters = Book::where('author_id', $author)->with('chapters')->get();
$chapters = lists('chapter_title');
But those lines are not working properly, because the chapters are saved as an array inside the book_array and I am not able to access the chapters directly as suggested in "lists('chapter_title');"
Of course a solution would be, to give every chapter Table an author_id, and then I just could do:
$chapters = Chapter::where('author_id', $author)->get();
$chapters = lists('chapter_title');
I know this would work, but isn't there the possibility to get above results, without having an authors id on my chapters table?
Regards,
George
Eloquent way using hasManyThrough:
// Author model
public function chapters()
{
return $this->hasManyThrough('Chapter', 'Book');
}
// then
$author->chapters()->count(); // single query for a single author
In order to eager load the count for multiple authors you need for example this:
// Author model
public function chaptersCount()
{
return $this->chapters()->selectRaw('count(*) as aggregate')->groupBy('author_id');
}
public function getChaptersCountAttribute()
{
if ( ! array_key_exists('chaptersCount', $this->relations)) $this->load('chaptersCount');
return $this->getRelation('chaptersCount')->first()->aggregate;
}
Then:
$authors = Author::with('chaptersCount')->get();
$authors->first()->chaptersCount;
// or for a single author
$author->chaptersCount; // load the relation if needed
you might want to look at this http://laravel.com/docs/eloquent#querying-relations
$chapters = Book::has('author', $author)->with('chapters')->get();
$chapters = lists('chapter_title');
and for your chapters you can access them like Book->chapters

Laravel ORM problems

I can't figure how to relate these two tables.
I'm new to Laravel and ORM so it's kind of hard to me.
Here's my 2 tables I'm trying to relate:
Tables are called: posts and post_categories
And here are some of the code:
class Post extends Eloquent {
public function categories()
{
return $this->hasOne('PostCategorie');
}
}
class PostCategorie extends Eloquent {
protected $table = 'post_categories';
public function post()
{
return $this->belongsTo('Post', 'pc_id');
}
}
public function postCreate()
{
$validator = Validator::make(Input::all(), Post::$rules);
if ($validator->fails())
{
return Redirect::action('PostsController#getCreate')->withInput()->withErrors($validator);
}
// Else add to DB
$categories = Input::get('categories');
$post = new Post;
$post->user_id = Auth::user()->id;
$post->title = Input::get('title');
$post->text = Input::get('text');
$post->categories()->id_1 = $categories[0];
$post->save();
}
So as you see. I pass values to post and when I save it's ok... but I can't add categories ID to another table...
And also I created dummie entries, and tried to get Post Categories values:
Route::get('/', function()
{
$post = Post::find(5);
echo $post->title;
echo $post->categories()->id_1;
});
But it failed:
Undefined property: Illuminate\Database\Eloquent\Relations\HasOne::$id_1
OK first things first, You dont have to use PostCatagorie as your model name. Laravel features a pretty good pluralization class and can quite happily deal with Category or PostCategorie. Additionally, if you just call pc_id category_id (assuming a table name of category) you wont have to define any foreign keys which will make life a bit simpler until you get to grips with the basics.
When you create any kind of object (e.g $post) you can check if its relations are attached using dd($post); you can drill down further into these relations with:
echo '<pre>';
print_r($post);
echo '</pre>;
This together will allow you to see if what you are trying to do is actually working and view the structure of your result object.
I'm not entirely sure what you mean by "I cant add categories id to another table", and you seem to be saving the data ok... so I'll skip that bit. Please clarify the question if you need more info.
Once you have got the relationships set up and got some data in there you would have to load the two models together like so to get an object with the attached relationship:
$post = Post::with('Category')->find(5);
You will then be able to access your category object as $post->Category and from there any of its properties, e.g. $post->Category->id

Categories