I have two tables, 'users' and 'articles'. Articles have a column 'user_id' which is a foreign key that references the user_id in 'users'.
I have in the Articles model this function which should return the user data:
public function user()
{
return $this->belongsTo('App\User');
}
And this works fine when I pass my articles to my viewer and call it in blade template:
#foreach($articles as $article)
<p>{{$article->user->name}}</p>
#endforeach
But I am trying to use the RESTful approach, so I am rather retrieving my data from JS (VueJS)
axios.get('/api/articles')
that should fire my Controller's function:
public function index()
{
$books = bookpost::all();
return $books;
}
So I was wondering if there's a way to append the user names to the JSON array of articles before returning it because in JS I couldn't get to find a way to get the username.
You can use "eager loading" in your query to help:
$books = bookpost::with('user')->get();
You may even eager load nested relationships:
$books = bookpost::with('user.friends')->get();
Have a look at the documentation for further help.
Related
Entity Framework from Database First created the Table model classes having many to many relationships in C# WebApi.
Table ACCOUNTS and table METADATA have a many-to-many relationship between them.
I want to add a new entry on ACCOUNTS table and link this entry with some existing entries from METADATA table. How can I do this using AngularJS to post data?
I am sending this data on $http:
var account: {
Title: 'Title',
User: 'User',
METADATA: [
{
Name: 'value1'
},
{
Name: 'value2'
}]
}
The account variable above is based on ACCOUNTS class which is being read by the C# web api using POST and [FromBody] like this:
[HttpPost]
public async Task<IHttpActionResult> Add([FromBody]ACCOUNTS account)
{
db.ACCOUNTS.Add(account);
await db.SaveChangesAsync();
int accountId = account.AccountId;
return Ok(accountId);
}
I am getting an error of primary key violation of existence of value1 and value2 on table METADATA.
This is correct because the values exist in the table.
But actually I want these values to be linked to the "intermediate table" which links ACCOUNTS and METADATA as many-to-many relationship, and not to be added.
Any solution to this scenario?
Before inserting the passed disconnected account object, you need to map the child METADATA objects to existing database entities. For instance, using something like this:
var medataNames = account.METADATA.Select(e => e.Name);
account.METADATA = db.METADATA.Where(e => metadataNames.Contains(e.Name)).ToList();
db.ACCOUNTS.Add(account);
// ...
I have three tables:
categories
id, title
products
id, name
categories_products
id, category_id, product_id
I have also setup the according models and relationships (both have belongsToMany of the other)
Now I want to get all products belonging to a category
Category::where('title','Electronics')->first()->products()->limit(10)->get(['products.name']);
which works fine, but I also want to include the category title for each product as well:
Category::where('title','Electronics')->first()->products()->limit(10)->get(['products.name','category.title']);
However it returns: Column not found category.title
I thought that the relation would take care of it.
EDIT: Models -->
Category:
class Category extends Model
{
protected $fillable = array('title');
public function products()
{
return $this->belongsToMany('Product', 'categories_products', 'category_id', 'product_id');
}
}
class Product extends Model
{
protected $fillable = array('name');
public function categories()
{
return $this->belongsToMany('Category', 'categories_products', 'product_id', 'category_id');
}
}
The reason you're getting the error is because get() works just like select() and because you're running the category query and then running the product query after there is no categories table to reference for the select.
Look into Eager Loading. It will help with a lot of these kinds of issues. Your query can be written as:
Product::select('id', 'name')
->with(['categories' => function($query) {
return $query->select('id', 'title');
}])
->whereHas('categories', function($query) {
return $query->where('title', 'Electronics');
})
->limit(10)
->get();
Because we are lazy loading you NEED the id column on each model so Laravel knows where to attach the relationships after the queries are run.
The with() method above will eager load the categories relationship and the whereHas() method puts a relationship constraint on the current query.
UPDATE
Similar query from Category model:
$category = Category::where('title','Electronics')
->with(['products' => function($query) {
return $query->select('id', 'name')->limit(10);
}])
->first(['id', 'title']);
Then access the products with:
$category->products
I am a newbie to Laravel 5.2 and am working on a legacy system and am a bit confused regarding eloquent and would appreciate someone giving me the code.
There are 3 tables:
cards
categories
cards2cat
cards can be part many categories which are kept in cards2cat table.
The cards2cat table has the following structure
id (primary key)
image (card)
category
What I want to do is to have a method in the Cards model called something like getCardsWithCategores which returned the cards info plus the names of the categories from the category table.
The categories table has a key of id and a field category.
Thanks!
Go to your Card2Cats model and add this:
public function categories()
{
return $this->hasOne('App\Categories','id','category');
}
public function cards()
{
return $this->hasOne('App\Cards','id','image');
}
For the query you do this:
$cards = Card2Cat::with('categories','cards')->get();
foreach ($cards as $key => $value) {
echo $value->id.', Card:'.$value->cards->name.', Category:'.$value->categories->category.'<br>';
//$value->cards gives you all column of cards and you can do
//$value->cards->colName
// same goes for $value->categories
}
Make sure the spelling of your classes and table column names are correct before running the code :D
I am following this exercise of an "intermediate task list" from Laravel 5.2 documentations and have some difficulty understanding how this piece of code works.
$request->user()->tasks()->create([
'name' => $request->name,
]);
Question 1
Specifically, I am confused at the relation between the user() and tasks() methods. Why and how exactly can we make the user() and tasks() methods available from the $request object?
Question 2
I created a similar app and has Person and Country models. I want to pass the country_id input from a dropdown list, but I can't get the database updated, using the following code.
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'country_id' => 'required|max:3',
]);
$request->user()->people()->create([
'name' => $request->name,
'country_id' => $request->country_id,
]);
return redirect('/people');
}
Why is it that the country_id cannot be saved to the table? I tried changing the user() to country() but the error message says, "class Country" was not found. But why is the 'user()' in the tutorial available then? I am baffled.
The user() method of request is available if the user making the request is authenticated.
Since it uses User model it can also fetch the related model. For tasks() to work Task relationship must be defined in user model.
For country_id to be created(mass assigned) ensure its included in $fillable property of the People model
$fillable = ['country_id']
Please read Eloquent model relationship section in Laravel documentation.
I am trying to get one query work since morning and not able to get it working I have two tables photographers and reviews please have a look at structure and then I will ask the question at the bottom :
Reviews table :
id int(10) unsigned -> primary key
review text
user_id int(10) unsigned foreign key to users table
user_name varchar(64)
photographer_id int(10) unsigned foreign key to photographers table
Photographers table :
id int(10) unsigned -> primary key
name text
brand text
description text
photo text
logo text
featured varchar(255)
Photographers model :
class Photographer extends Model
{
public function reviews()
{
return $this->hasMany('\App\Review');
}
}
Reviews Model :
class Review extends Model
{
public function photographers()
{
return $this->belongsTo('\App\Photographer');
}
}
My logic to query the records
$response = Photographer::with(['reviews' => function($q)
{
$q->selectRaw('max(id) as id, review, user_id, user_name, photographer_id');
}])
->where('featured', '=', 'Yes')
->get();
The question is : I want to fetch all the photographers who have at least one review in the review table, also I want to fetch only one review which is the most latest, I may have more than one review for a photographer but I want only one.
I would add another relationship method to your Photogrpaher class:
public function latestReview()
{
return $this->hasOne('App\Review')->latest();
}
Then you can call:
Photographer::has('latestReview')->with('latestReview')->get();
Notes:
The latest() method on the query builder is a shortcut for orderBy('created_at', 'desc'). You can override the column it uses by passing an argument - ->latest('updated_at')
The with method loads in the latest review.
The has method only queries photographers that have at least one item of the specified relationship
Have a look at Has Queries in Eloquent. If you want to customise the has query further, the whereHas method would be very useful
If you're interested
You can add query methods to the result of a relationship method. The relationship objects have a query builder object that they pass any methods that do not exist on themselves to, so you can use the relationships as a query builder for that relationship.
The advantage of adding query scopes / parameters within a relationship method on an Eloquent ORM model is that they are :
cacheable (see dynamic properties)
eager/lazy-loadable
has-queryable
What you need is best accomplished by a scoped query on your reviews relation.
Add this to your Review model:
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent\Model;
class Review extends Model {
public function scopeLatest(Builder $query) {
// note: you can use the timestamp date for the last edited review,
// or use "id" instead. Both should work, but have different uses.
return $query->orderBy("updated_at", "desc")->first();
}
}
Then just query as such:
$photographers = Photographer::has("reviews");
foreach ($photographers as $photographer) {
var_dump($photographer->reviews()->latest());
}