So I've been struggling with using basic eloquent in Slim Framework 2 for quite a while now. This is not my first Eloquent question, but I'm hoping this one actually can be answered unlike my previous one: Using polymorphic relationships in Eloquent to extend model
I'm working on a simple chemical database for tracking for my University. I've got the Chemicals table with column company_id that correlates to a table called company with just 2 columns, id and company. chemicals.company_id is a foreign key referencing company.id.
(This, along with several others, like room, and location, started out as Enums, but it quickly became apparent the users would need to be able to add to them. Editing a DB column to add an enum is obviously not a practical idea.)
In Chemical I have:
public function company()
{
return $this->hasOne('Lab_Chemicals\Chemical\company');
}
And in Company I have:
public function chemical()
{
return $this->belongsTo('Lab_Chemicals\Chemical\chemical');
}
They're both in the same namespace (Lab_Chemicals\Chemical) and on their own I can do a
$chemicals = $app->chemical->get();
and
$company = $app->company->get();
and get the proper list so the basics appear to be setup correctly, but if I try to do this:
$company = chemical::find(1)->company;
I get Slim Application Error:
Type: Illuminate\Database\QueryException
Code: 42S22
Message: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'company.chemical_id' in 'where clause' (SQL: select * from company where company.chemical_id = 1 and company.chemical_id is not null limit 1)
Which brings me to my real question. Isn't this backwards? Why is it looking for chemical_id in company? I know that this is what it says it does in the docs
https://laravel.com/docs/4.2/eloquent#relationships: "Take note that Eloquent assumes the foreign key of the relationship based on the model name. In this case, Phone model is assumed to use a user_id foreign key."
I'd expect it to look for the company where chemical.company_id = company.id. Where is the flaw in my way of thinking and what can I do to make it work as expected?
Thanks
Related
Think I'm missing something obvious here, but I want to define a one way, one to one relationship from table_1 to table_2, e.g. table1 schema:
Schema::create('table1', function (Blueprint $table) {
// Some field definitions
$table->integer('table2_id')->unsigned();
$table->foreign('table2_id')->references('id')->on('table2')->onDelete('cascade');
});
Table 2 doesn't know anything about Table 1, so just has a bunch of fields defined. Model for Table 1 has:
public function table2() // Get table2 record
{
return $this->hasOne('App\Table2');
}
Questions:
a.) Is that relationship in the record necessary just to be able to lookup the relevant table2 record from a table1 record?
b.) How do I set the relationship in my code? Currently my controller code is:
$table_1_record = new Table1();
// What code here to define the relationship, using Eloquent? Or do I just do:
$table_1_record->table2_id = my_table2_record->id;
// But this just sets it manually doesn't it, rather than using Eloquent?
Thing that is confusing me is in here: https://laravel.com/docs/5.6/eloquent-relationships#one-to-one a bit further down from the link, where it says
Eloquent determines the foreign key of the relationship based on the
model name. In this case, the Phone model is automatically assumed to
have a user_id foreign key.
Applying that example to my code, the thing is I don't want to have to define a table1_id in my Table_2 - but sounds from that quote from the docs that I need to, to find a table2 record from table1...?
c.) Is there any point in this line in the migration: $table->foreign('table2_id')->references('id')->on('table2')->onDelete('cascade'); and indeed using Eloquent at all (I want to do things the proper Laravel way), or shall I just simply manually set table2_id as in question b.) above?
Note: I don't want to define the inverse of the relationship, as I don't need to find a table_1 record from a table_2 record.
Thanks for any help.
Relationships in Eloquent only work in the directions that they are defined. If you want to be able to find Table2 based on the foreign key defined in Table1, you would add a relationship to the Table1 model only. You do not need to define relationships on both models in order to go one direction.
Given your table1 schema, you are actually using the inverse of a one-to-one relationship. table1 is considered a child of table2. Your relationship would look like this:
class Table1
{
public function table2()
{
return $this->belongsTo(\App\Table2::class);
}
}
As for setting the relationship, my recommendation is to simply apply the ID from table2 manually when creating the initial record:
`$table1->table2_id = $table2->id;`
If you're updating a Table1 record, you can use associate(). More info on that here in the docs. Note that this does require you to define the other side of the relationship on Table2. If you don't want to do that, just update the column manually when updating also.
Keep in mind that all of this is powered by Eloquent. Just because you're defining a column value manually instead of using a relationship helper method doesn't mean you're doing something ineffectively or incorrectly.
Is there any point in [the foreign key] line in the migration
This creates a foreign key constraint in the database software itself, and has nothing to do with Eloquent. Eloquent doesn't use or care if you have a foreign key defined. There are benefits to using foreign keys, though, and suggest you look into it further to determine if they're a good idea for your application.
The languages table has: id, shortcode
The comments table has id, user_id, comment, language_id (foreign key)
In the Comment Model I defined Language as a hasOne Relationship
In the Language Model I defined Comments as a hasMany Relationship (this is wrong?).
In Tinker I get this error when I try to execute: $comment->language()->get():
Column not found: 1054 Unknown column 'languages.comment_id' in 'where clause' (SQL: select * from `languages` where `languages`.`comment_id` = 7 and `languages`.`comment_id` is not null)'
Why is Laravel searching in the languages table for the comment_id? It seems I misunderstand something completely.
What is the right way to do get the language shortcode? I thought $comment->language()->shortcode should work.
And what is the most efficient way to preload all the language_id and shortcode information without performing duplicate queries since this is used a lot?
Laravel makes assumptions on your key-names in your relationship. Because you use the hasOne relationship, Laravel expects the key to be in the languages table, named comment_id.
Your Comment model should use a belongsTo relationship to Language and drop the hasOne. This way laravel makes the assumption that the foreign-key is actually in the comments table, named language_id, which is the case :).
Using the belongsTo relationship solved the problem.
Afterwards I could access it with $comment->language->shortcode;
thanks everyone!
Im having a problem. I have two tables, places and cuisines, and cuisine_place and in that table I have a column called default (that shows if that cuisine is the default cuisine for that place). But Im having the problem that Im not able to access to that column.
How can I do?
What I want to do is have them in this answer:
$places = Place::all()->with('cuisines')->withPivot('default');
Something like that.
Thanks
You have a many to many relationship between places and cuisines. That relationship would be defined in the following fashion in your models:
public function cuisines(){
return $this->belongsToMany('Cuisine', 'cuisine_place');
}
The above would be a function in your Place class that references its relationship to the cuisines table. By default, Eloquent will pick up the foreign keys in the cuisine_place table (in your case they would probably be called cuisine_id and place_id). If you want to pick up additional columns from that table on calls to the above relationship function, you can use the withPivot function:
public function cuisines(){
return $this->belongsToMany('Cuisine', 'cuisine_place')->withPivot('default');
}
Now, on calls to the cuisines() method in your Place class, you'll receive the default column in the object associated with that table.
Open documentation for Laravel Eloquent Relationships
And read about Retrieving Intermediate Table Columns
You didn't provide your models code so it's difficult to help you with the exact solution
I'm using Eloquent in my PHP application and struggling with a hasManyThrough relationship.
Here's my structure :
Company
id
name
Admin
id
company_id
name
Offer
id
admin_id
name
Application
id
offer_id
candidat_id
Each Admin is part of a Company and can post Offer's, and the candidats can make an Application on that offer.
I'm trying to fetch all the applications that have been made on offers that have been started by admins of that company.
I've tried using the hasManyThrough relationship in my Company model, like so :
public function applications()
{
return $this->hasManyThrough("Application", "Offer");
}
but I get the following error :
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'offers.entreprise_id' in 'field list' (SQL: select `applications`.*, `offers`.`entreprise_id` from `applications` inner join `offers` on `offers`.`id` = `applications`.`offer_id` where `offers`.`entreprise_id` in (1))
Which makes sense, since it's thinking that the Offer is listed to the Company and not to the Admin.
How can I set it up so that it will look for the Admin's of that company, without having to fetch all the admins of the company and then looping through them, getting all the applications for each admins?
This would work, but it seems like a tedious way of doing it when Eloquent provides these relationships that make our lives easier. Is there a more elegant way of achieving what I want?
There is no native relationship for this case.
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class Company extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function applications() {
return $this->hasManyDeep(Application::class, [Admin::class, Offer::class]);
}
}
I have a database schema that goes like this:
Section
id
name
Subsection
id
name
section_id
Category
id
name
subsection_id
SubCategory
id
name
category_id
Product
id
name
subcategory_id
As you can see, each table has a foreign key that references the previous table. The problem comes when I try to get, for example, the Section from the current product or get all products from one section. So far I have tried this:
Section::with('product')->find(1)->product;
But I get this:
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'product.section_id' in 'where clause' (SQL: select *
from products where products.section_id in
(1))
1 - This makes me think I need to set up a section_id in the products table to make this work. Is this correct?
2 - Shouldn't the Laravel ORM automatically go up the table hierarchy from Product to Section and get the results?
3 - Is there a way to do this maintaining my current table structure, I mean, without adding extra fields in the tables for the foreign keys?
Thanks.
No that is one way to do it but it isn't the only way.
No, how would it know that automatically?
I believe so and you can always create a specific query when laravel relationships don't work for you.
Okay first this assumes you have relationships setup on all the models to access the one below it. If that isn't the case you will need to setup the relationships.
Section::with('subsection.category.subcategory.product')->get();
I've never tried such extreme nesting but I believe this will work. The Laravel Docs talk about eager loading and scroll to see the nested example.
Another item that comes to mind is the hasManyThrough relationship. You couldn't do it for this number deep but it may be something you want to look into.
A brief summary from the docs is taking the first three from your example, Section, Subsection, and Category and then in the section class you would have this relationship.
public function category()
{
return $this->hasManyThrough('Category', 'SubSection');
}
The laravel docs with more information.