Laravel | Eloquent Populate Foreign Data - php

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.

Related

Create conditional in Model methods

Hi guys i wish to create a custom method on my Category Model but i need to create some conditionals with it.
table post:
- id;
- category_id
-name...
table Category:
- id
- parent_id
- name
Imagin that i have a post, and in this post there is a category called SomeSubcategoryName, i my posts table i have a column called category_id.
When i call the post record i have a relation with the Category Model, but i wish to have in my Category Model a method called masterCategory, where i give the mster category by checking if the parent_id is null or not, in case that the record have a parent_id of null great, i return the record but if is not i need to use the parent_id value and search on the Model category column id for the record and return the result.
Imagine this scenario:
$post = Post::find(2);
//this call should return the main category and not the subcategory info.
$post->masterCategory();
In your category model define a relationship on its self:
public function masterCategory()
{
return $this->belongsTo(App\Category::class, 'parent_id', 'id');
}
Eager load the relationships on your Post when you query it:
$post = Post::with(['category', 'category.masterCategory'])->firstOrFail($id);
Access it like this:
$post->category->masterCategory; // will be the mastery category or null
Otherwise us:
$post->category;
Don't over complicate it.
In your Category model you should have something like this
public function master()
{
return $this->belongsTo(Category::class, 'parent_id');
}
public function isMaster()
{
if($this->parent_id)
return false;
else
return true;
}
Now you can check that post's category is master or not :
if($post->category->isMaster())
....
The second way is using relations and eloquent
$post = Post::with(['category', 'category.master'])->first($id);

Laravel - Access subcategory from product (belongsTo) in ajax response data.

One products has one subcategory. In my products table I have subcategory_id field. I have also set-up a belongsTo relationship between Product and Subcategory models.
So I have a method which returns all products with a certain tag id.
Here is my code:
public function getProductsByTag($tag_id)
{
$tag = Tag::find($tag_id);
$products = $tag->products; //belongsTo relationship
return json_encode(['products' => $products]);
}
Then on success in my ajax request I need to access the subcategory of the product like I accessed the products of the tag $tag->products. So in Laravel it would be:
$subcategory = $product->subcategory;
I thought that product.subcategory would do the trick but I get undefined. Here is my ajax success function:
success: function (data) {
$.each(data.products, function (i, product) {
console.log(product.subcategory);
});
},
I get undefined in my console. How can I access relationships in ajax response data?
I found a solution by providing a variable that holds the relationship inside the model I need. I add one variable for subcategory in my Product model and one variable for category in my Subcategory model. Here is what it looks like:
In my Product model:
protected $with = array('subcategory');
In my Subcategory model:
protected $with = array('category');
Now I can access them easily from my ajax success response data.
As I said in my comment, laravel doesn't load automatically all the relations so you have to do that.
if you would like to load every time subcategories into your products so you have to update you model and add a with attribute like so :
//Product model
protected $with = ['subcategory'];
Or if you just want to do this just once, so you have to do something like :
$products = $tag->products()->with('subcategory')->get();

Laravel 4: many to many (insertion)

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

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

How to chain DB relationships in Laravel (multiple has_many?)

I'm using Laravel, which is awesome, but I'm stuck on an issue with the database.
Let's say we have three tables, like so:
TABLE 1: pages
id | route | title
TABLE 2: elements
id | page_id | type
TABLE 3: content
id | element_id | data
I'd like to do a single selection for the page that will in turn select all of the elements with that page id, and for each of the elements it should select all of the content rows with the element id.
I want to have a static load_by_route($route) function in the Page model that, when called, will use the route to load and return the page info as well as the elements and content as described above. Ideally it would return a single object/array with all of this info.
Basically, I'm not sure how to chain the has_many() calls together so that I get the two-level relationship.
Look into eager loading. This should do what you want.
class Page extends Eloquent {
public function elements()
{
return $this->has_many( 'Element' );
}
}
class Element extends Eloquent {
public function contents()
{
return $this->has_many( 'Content' );
}
}
class Content extends Eloquent {}
$page = Page::with( array( 'elements', 'elements.contents' ) )->first();
https://laravel.com/docs/master/eloquent-relationships#eager-loading
Collin James answer gives you one object with all the data. I came here because I just wanted to iterate over all contents that belong to a page. Here is how you get such a collection:
$page = Page::with('elements.contents.element')->has('elements.contents');
$contents = [];
foreach ($page->elements as $element) {
$contents = $element->contents->merge($temp);
}
The with makes sure that you use eager loading and the has makes sure that we only iterate over elements with content.
From each content element you can get the element info from the belongsTo relationship that we also received with eager loading:
class Content extends Eloquent
{
public function element()
{
returh $this->belongsTo('\App\Page');
}
}

Categories