So, going into the problem straight away. someone told me that we dont need to make a pivot table if we only want to have ids of the table. laravel can itself handle this situation. I dont know how this works. I have a table community and another table idea. relation is like this;
One community can contain many ideas and an idea can be found in many
communities.
Relation in idea Model:
public function community() {
return $this->belongsToMany('App\Community')->withTimestamps();
}
Relation in community Model:
public function idea() {
return $this->belongsToMany('App\idea');
}
Now i want to fetch all the records related to a single community to show on its page Let's say the community is Arts.
Here is Controller function:
public function showCommunities($id) {
$community = Community::findOrFail($id)->community()->get();
return view('publicPages.ideas_in_community', compact('community'));
}
When i attach ->community()->get() to the Community::findOrFail($id) Then it throws the error
SQLSTATE[42S02]: Base table or view not found laravel
Any help would be appreciated.
Edit:
Logically, this piece of code Community::findOrFail($id)->community()->get() should be like this Community::findOrFail($id)->idea()->get(). Now it is true but it has little issue. it throws an error
Fatal error: Class 'App\idea' not found
The way you define the many-to-many relation looks ok - I'd just call them communities() and ideas(), as they'll return a collection of objects, not a single object.
Make sure you use correct class names - I can see you refering to your model classes using different case - see App\Community and App\idea.
In order to find related models, Eloquent will look for matching rows in the pivot table - in your case it should be named community_idea and have 3 fields: community_id, idea_id and autoincrement primary key id.
With that in place, you should be able to get all ideas linked to given community with:
$ideas = Community::findOrFail($communityId)->ideas;
If you need communities linked to given idea, just do:
$communities = Idea::findOrFail($ideaId)->communities;
You can read more about how to use many-to-many relationships here: https://laravel.com/docs/5.1/eloquent-relationships#many-to-many
someone told me that we dont need to make a pivot table if we only want to have ids of the table
The above is not true (unless I've just misunderstood).
For a many-to-many (belongsToMany) their must be the two related table and then an intermediate (pivot) table. The intermediate table will contain the primary key for table 1 and the primary key for table 2.
In laravel, the convention for naming tables is plural for your main tables i.e. Community = 'communities' and Idea = 'ideas'. The pivot table name will be derived from the alphabetical order of the related model names i.e.
community_idea.
Now, if you don't want/can't to follow these conventions that's absolutely fine. For more information you can refer to the documentation: https://laravel.com/docs/5.2/eloquent-relationships#many-to-many
Once you're happy that you have the necessary tables with the necessary fields you can access the relationship by:
$ideas = $community->ideas()->get();
//or
$ideas = $community->ideas;
So you controller would look something like:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
//The below isn't necessary as you're passing the Model to a view
// but it's good for self documentation
$community->load('ideas');
return view('publicPages.ideas_in_community', compact('community'));
}
Alternatively, you could add the ideas to the array of data passed to the view to be a bit more verbose:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
$ideas = $community->ideas
return view('publicPages.ideas_in_community', compact('community', 'ideas));
}
Hope this helps!
UPDATE
I would imagine the reason that you're receiving the App\idea not found is because the model names don't match. It's good practice (and in certain environments essential) to Capitalise you class names so make sure of the following:
Your class name is Idea and it's file is called Idea.php
The class has it's namespace declared i.e. namespace App;
If you've added a new class and it's not being found you might need to run composer dump-autoload from the command line to update the autoloader.
Related
I'm currently struggling with retrieving data towards a parent model. I'll drop my database, classes, and things I've tried before.
I have 4 tables: sales_orders, products, work_orders, and product_sales_order (pivot table between sales_orders and products).
SalesOrder.php
class SalesOrder extends Model
{
public function products()
{
return $this->belongsToMany(Product::class)
->using(ProductSalesOrder::class)
->withPivot(['qty', 'price']);
}
}
ProductSalesOrder.php
class ProductSalesOrder extends Pivot
{
public function work_orders()
{
return $this->hasMany(WorkOrder::class);
}
public function getSubTotalAttribute()
{
return $this->qty* $this->price;
}
}
WorkOrder.php
class WorkOrder extends Model
{
public function product_sales_order()
{
return $this->belongsTo(ProductSalesOrder::class);
}
public function sales_order()
{
return $this->hasManyThrough(
ProductSalesOrder::class,
SalesOrder::class
);
}
}
So, what I want to retrieve sales order data from work order since both tables don't have direct relationship and have to go through pivot table and that is product sales order. I've tried hasOneThrough and hasManyThrough but it cast an error unknown column. I understand that error and not possible to use that eloquent function.
Is it possible to retrieve that sales order data using eloquent function from WorkOrder.php ?
You cannot achieve what you want using hasOneThrough as it goes from a table that has no ID related to the intermediate model.
In your example you are doing "the inverse" of hasOneThrough, as you are going from a model that has the ID of the intermediate model in itself, and the intermediate model has the ID of your final model. The documentation shows clearly that hasOneThrough is used exactly for the inverse.
So you still should be able to fix this, and use a normal relation as you have the sales_orders_id in your model SuratPerintahKerja, so you can use a normal relation like belongsTo to get just one SalesOrder and define it like this:
public function salesOrder()
{
return $this->belongsTo(SalesOrder::class, 'sale_orders_id');
}
If you want to get many SalesOrders (if that makes sense for your logic), then you should just run a simple query like:
public function salesOrders()
{
return $this->query()
->where('sale_orders_id', $this->sale_orders_id)
->get();
}
Have in mind that:
I have renamed your method from sales_order to salesOrder (follow camel case as that is the Laravel standard...).
I have renamed your method from sales_order to salesOrders for the second code as it will return more than 1, hence a collection, but the first one just works with one model at a time.
I see you use sale_orders_id, but it should be sales_order_id, have that in mind, because any relation will try to use sales_order_id instead of sale_orders_id, again, stick to the standards... (this is why the first code needs more parameters instead of just the model).
All pivot tables would still need to have id as primary and auto incremental, instead of having the id of each related model as primary... Because in SuratPerintahKerja you want to reference the pivot table ProdukSalesOrder but it has to use both produks_id (should have been produk_id singular) and sale_orders_id (should have been sales_order_id). So if you were able to use something like produk_sales_order_id, you could be able to have better references for relations.
You can see that I am using $this->query(), I am just doing this to only return a new query and not use anything it has as filters on itself. I you still want to use current filters (like where and stuff), remove ->query() and directly use the first where. If you also want to add ->where('produks_id', $this->produks_id) that is valid and doesn't matter the order. But if you do so, I am not sure if you would get just one result, so ->get() makes no sense, it should be ->first() and also the method's name should be salesOrder.
Sorry for this 6 tip/step, but super personal recommendation, always write code in English and do not write both languages at the same time like produks and sales orders, stick to one language, preferrably English as everyone will understand it out of the box. I had to translate some things so I can understand what is the purpose of each table.
If you have any questions or some of my code does not work, please tell me in the comments of this answer so I can help you work it out.
Edit:
After you have followed my steps and changed everything to English and modified the database, this is my new code:
First, edit ProductSalesOrder and add this method:
public function sales_order()
{
return $this->belongsTo(SalesOrder::class);
}
This will allow us to use relations of relations.
Then, have WorkOrder as my code:
public function sales_order()
{
return $this->query()->with('product_sales_order.sales_order')->first();
}
first should get you a ProductSalesOrder, but then you can access ->sales_order and that will be a model.
Remember that if any of this does not work, change all the names to camelCase instead of kebab_case.
I have 3 tables in a database
Transaction {'id','bill_id','remark'}
Bills {'id','third_party','amount'}
ThirdParty {'id','company_name',remark}
The 'transaction' table has column bill_id coming from 'Bills' and Bills table has 'third_party' column which connected to ThirdParty table column -> 'id'
So here I am trying to fetch company_name using laravel eloquent relation
My Transaction model:
public function Bills()
{
return $this->hasOne('App\Bills','id','bill_id');
}
Bills:
public function third_party()
{
return $this->belongsTo('App\ThirdParty','third_party','id');
}
I am getting null value for company_name
Here is the query i am using
Transaction::with('Bills.third_party')->get();
And i have corrected in question (third_party_name) to company_name column name i wrote here was my old join query name which is visible in screenshot, basically i am trying to fetch company name.
Are you able to show all of your code? How does company_name get set to third_party_name?
You could probably also gain a lot by sticking to the laravel "conventions" or "suggested naming", this will give you a lot of functionality for free, and make your code easier to read, write and debug.
eg. Your relationship method names (Bills(), third_party()), but more importantly if you name your table fields in the "laravel way", you will get easier eloquent relationships as there will be no need to define the foreign keys etc.
I would be setting this up similar to:
Transaction {'id','bill_id','remark'}
Bills {'id','third_party_id','amount'} <- note the third_party_id
ThirdParty {'id','company_name',remark}
class Transaction extends Model
{
public function Bills()
{
return $this->hasOne('App\Bills');
}
}
class Bills extends Model
{
public function ThirdParty()
{
return $this->belongsTo('App\ThirdParty);
}
}
You should also define the inverse relationships.
It would be very beneficial to see the full code to see where the issue is.
I'm trying to create a connection between a JSON field in my database and a table which stores music by ID. So, I have a table called "playlists" which has a field called "songs". In this "songs" field I have a array[] of song ID's e.g. [1,2]. I tried the following code to make a relationship between these two tables:
class Playlist extends Model
{
protected $table = 'playlists';
public function songs()
{
return $this->hasMany('App\Music', 'id');
}
}
I used the foreign_key id because of the songs table which has a id field.
The code I used to retrieve the playlist from the controller is as follows:
$playlist = Playlist::find($id)->songs;
print_r($playlist);
Which outputs:
[1,2]
I most probably did something wrong, not understanding the relationships correctly. Could someone explain how this works? I looked up the documentation but did not get any wiser.
Laravel has no native support for JSON relationships.
I created a package for this: https://github.com/staudenmeir/eloquent-json-relations
If you rename the songs column to song_ids, you can define a many-to-many relationship like this:
class Playlist extends Model
{
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
protected $casts = [
'song_ids' => 'json',
];
public function songs()
{
return $this->belongsToJson('App\Music', 'song_ids');
}
}
class Music extends Model
{
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
public function playlists()
{
return $this->hasManyJson('App\Playlist', 'song_ids');
}
}
Although this is a very old post but I will go ahead and drop my own opinion for my future self and fellow googlers.....
So, If I got this question correctly, you are trying to use a JSON field for a relationship query. This issue I have stumbled across a couple of times, at different occasions for different use-cases. With the most recent being for the purpose of saving a couple of Ids belonging to different tables, in a single JSON field on a given table (While I keep pondering on why the Laravel guy won't just add this functionality already! I Know Pivots, Data Normalization etc....But I'm pleading for the 1%). Until I came across this post on Laracast that worked like a charm.
Apologies for the long intro, let me get right into it....
On your Playlist model (in Laravel 8.0 and a few older versions I can't really keep track of) you can do something like so;
public function songs()
{
$related = $this->hasMany(Song::class);
$related->setQuery(
Song::whereIn('id', $this->song_ids)->getQuery()
);
return $related;
}
I have the really good solution for keeping data in column on json format. It help me on previous project online shop
https://scotch.io/tutorials/working-with-json-in-mysql
How to implement information and information_description tables in laravel Eloquent Model ? Some how it need to set language, because a title should be a one record.
$information = App\Information::find(1);
$information->title
tables structure
You can review how to do this, and plenty more, by reading the documents by Laravel. They are a great help and this particular question has an example and everything. Having said that, I'll help with getting you started.
Define a relationship in either model, information or information_description, or both. For brevity, I'll use information only.
Pass the foreign_key and local_key in the hasMany() relationship since it differs from Laravel's default behavior.
So we have a model that now looks like:
class Information extends Model
{
/**
* Get the descriptions for the Information model.
* Note the 2nd and 3rd arguments in the method
* which define foreign_key and local_key.
*/
public function description()
{
return $this->hasMany('App\InformationDescription', 'information_id', 'information_id');
}
}
Now that you have the relationship defined, you can perform your query.
// Get the description for the information
$information = App\Information::find(1)->description;
// Iterate over the results
foreach ($information as $description) {
$description->title;
}
The table naming convention used is a little odd, but if I understand it correctly, this will work. Hope it helps.
Details
I have 3 tables :
catalog_downloads
export_frequencies
export_frequencies_catalog_downloads (Pivot Table)
Diagram
I am not sure if I set the relation between them correctly.
Please correct me if I am wrong.
Here is what I did
In CatalogDownload.php
public function export_frequencies(){
return $this->belongsToMany('ExportFrequency','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id');
}
In ExportFrequency.php
public function catalog_downloads(){
return $this->belongsToMany('CatalogDownload','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id');
}
Questions
According to my diagram - Did I assign the relationship correctly ?
I hope I didn't mix up between hasMany and belongsTo
Will I need a class or a model for a Pivot Table ?
Thanks
Since export_frequencies is in the CatalogDownload model you have to invert the ID's because the parameters of belongsToMany are as follows:
1. Name of the referenced (target) Model (ExportFrequency)
2. Name of the Pivot table
3. Name of the id colum of the referencing (local) Model (CatalogDownload in this case)
4. Name of the id colum of the referenced (target) Model (ExportFrequency in this case)
what leads to this function:
public function export_frequencies(){
return $this->belongsToMany('ExportFrequency','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id');
}
The other function was correct.
If you had some data in your pivot table, for instance a colum with the name someCounter then you will have to tell the relation to load that column when creating the pivot object like this:
public function export_frequencies(){
return $this->belongsToMany('ExportFrequency','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id')->withPivot('someCounter');
}
That will load the column and make it avalible like this:
$catalogDownload->export_frequencies()->first()->pivot->someCounter;
You will need a separate Pivot Model if you need to do some special handling for the fields or if that pivot itself has a relation of its own but then you might consider using a full blown model instead of a pure Pivot Model.
As an added note to the accepted answer, you are able to set up your many to many relationships without referencing the pivot table and the relevant id's as long as you follow a specific convention.
You can name your pivot table using singular references to the related tables, like 'catalog_download_export_frequency'. Notice the alphabetic order of the singular references.
Then you can simply do:
// CatalogDownload Model
public function exportFrequencies()
{
return $this->belongsToMany('ExportFrequency');
}
// ExportFrequency Model
public function catalogDownloads()
{
return $this->belongsToMany('CatalogDownload');
}
This will then allow you to run queries using the query builder or Eloquent like:
$catalogDownload->exportFrequencies()->get(); // Get all export frequencies for a specific CatalogDownload.
Or
$this->catalogDownload->with('exportFrequencies')->find($id); // Using eager loading and dependency injection, when CatalogDownload is assigned to $this->catalogDownload
Hope this helps!