laravel eloquent relationships issue - php

i'm a litle bit confused and i need some help since im new in laravel !
i have 3 table !! questions , category and theme
a question have a category and a theme
a theme have many categories
a category belong to one theme
what im asked to do is when i will add a question i only choose a category from the list and it will be added with her correspondant theme in the question table !! i hope i explained good my question :)
the category migration
Schema::create('category', function(Blueprint $table)
{
$table->increments('categoryId');
$table->string('categoryName');
$table->integer('themeId')->unsigned();
$table->foreign('themeId')->references('themeId')->on('theme');
});
the theme migration
Schema::create('theme', function(Blueprint $table)
{
$table->increments('themeId');
$table->string('themeName');
});
the questio migration i didn't make relation since i didn't find a way to do it
Schema::create('question', function(Blueprint $table)
{
$table->increments('questionId');
$table->string('question', 200);
$table->string('rightAnswer', 50);
$table->string('explanation', 500);
$table->string('wrongAnswer1', 50);
$table->string('wrongAnswer2', 50);
$table->string('wrongAnswer3', 50);
$table->string('theme');
$table->string('category');
$table->integer('difficulty');
$table->timestamps();
});

Theme Model
class Theme extends Eloquent
{
protected $primaryKey = 'themeId';
protected $guarded = array();
public function category()
{
return $this->hasMany('Category');
}
}
Category Model
class Category extends Eloquent
{
protected $primaryKey = 'categoryId';
protected $guarded = array();
public function theme()
{
return $this->belongsTo('Theme');
}
}
Questions Model
class Question extends Eloquent
{
protected $primaryKey = 'questionId';
protected $guarded = array();
public function category()
{
return $this->belongsTo('Category');
}
}

You do not make the Eloquent relations in the migrations. Migrations are only for creating the database table structure. Rather, the relations in Eloquent are defined in the models you make:
// Theme Model
public function categories()
{
return $this->hasMany('Category');
}
// Category Model
public function theme()
{
return $this->belongsTo('Theme');
}
public function questions()
{
return $this->hasMany('Question');
}
// Question Model
public function category()
{
return $this->belongsTo('Category');
}
These methods in the model define the relationship in Eloquent, and let you do things like this:
// Given an instance of a theme
foreach($theme->categories as $category)
// ...
// Given an instance of a question
echo $question->category->theme->themeName;
That being said, the methods above won't precisely work given your table structure. Eloquent relies also on convention, and the convention is that foreign keys should be named in a specific manner, namely theme_id and category_id (vs themeId as you have in your categories table). You can override this per the documentation using this format:
return $this->belongsTo('Theme', 'themeId');
Though you're probably better off sticking to convention. This convention also states that the primary key of each table should be named id.
As for your question table, you can create a relationship to the category the same as you did for the relationship between the themes and categories: add a column to your questions table that references the category id:
// Your migration:
$table->integer('category_id');
// Add a foreign key as well if you wish, though it is not
// required for the relationship in Eloquent
Then in your Question model place the category method I outlined above. Simple as that.

Related

How to fix Laravel eager loading not working with custom foreign key

Listing and Sub_Category have a one to many relationship. Listing belongs to one sub_category and sub_category has many listings.
I have a column on my listings table 'sub_catgory_id' and I have also specified the foreign key in my relationship
Listing.php Model
public function sub_category()
{
return $this->belongsTo('App\Sub_Category', 'sub_category_id', 'id');
}
Trying to get all listings associated with a sub category
return $sub_category = \App\Sub_Category::with('listing')->get()
I get this error => Column not found: 1054 Unknown column 'listings.sub__category_id' in 'where clause'.
I know eloquent is checking for sub__category_id (double underscore) but I am already far into this project and would like to leave it as sub_category_id (single underscore). Any ideas about how this can be achieved?
I finally figured it out a fix. You can camelCase your model. So in my case I renamed my model from Sub_Category to subCategory so eloquent checks sub_category_id.
I think you should set like :
1.Listening.php:
public function sub_category()
{
return $this->belongsTo('App\Sub_Category', 'id', 'sub_category_id');
}
2.Sub_Category.php :
public function listing()
{
return $this->belongsTo('App\Listening', 'sub_category_id','id');
}
By laravel document in set Relationships we set first foreign_key then local_key like this (Example get from laravel website):
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
You can try below code:
1.Sub_Category.php(Model)
public function listimg() {
return $this->belongsTo('App\Listening');
}
2.Contoller
$sub_category = \App\Sub_Category::with('listing')->get();
For the custom foreign key column you have pass two additional arguments for the function hasMany('Model', 'fk', 'pk') with the foreign key column name and the reference key column name.
class Category extends Model
{
protected $table = 'categories';
public function contents(){
return $this->hasMany('App\Content', 'sub_cat_id', 'id');
}
}
class Content extends Model
{
//
protected $table = 'contents';
public function category(){
return $this->belongsTo('App\Category');
}
}
Schema::create('categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id');
$table->integer('parent_id');
$table->string('title');
$table->timestamps();
});
Schema::create('contents', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('app_id');
$table->integer('cat_id');
$table->bigInteger('sub_cat_id')->unsigned();
$table->integer('content_type');
$table->text('content');
$table->text('title');
$table->timestamps();
$table->foreign('sub_cat_id')->references('id')->
on('categories')->onDelete('cascade');
});

unable to get attributes in an accessor method - laravel eloquent

Okay I want to have custom field that does not exist as a column in my db table.
I followed, last part :
http://laravel.com/docs/4.2/eloquent#accessors-and-mutators
My model code:
class Car extends Eloquent{
protected $fillable = array('driverID', 'fuelRemaining');
protected $appends = array('is_driver');
public function user(){
return $this->belongsTo('user');
}
public function getIsDriverAttribute(){
return ($this->attributes['driverID'] == Auth::user()->id);
}
}
Car table:
Schema::create('cars', function(Blueprint $table)
{
$table->increments('id');
$table->integer('driverID');
$table->integer('fuelRemaining');
$table->mediumtext('desc');
$table->timestamps();
});
As you can see i want an extra field which is "is_driver" to be returned, but when I run this, this field is used to determine whether current signed in user is the driver himself by comparing the IDs.
it will output this error:
Undefined index: driverID
Not sure what am I doing wrong here, please advice.
Ah I have found why. This is a reference for future readers
In my controller I only get these two
$car = Car::where('fuelRemaining', 0)->get(array('id', 'desc'));
When i added authorID to the get array
$car = Car::where('fuelRemaining', 0)->get(array('id', 'desc', 'authorID'));
I am able to get the authorID attribute in my custom accessor mentioned in the question.

How to return one property of a belongsTo model with the child model in Laravel resource controller

I'm using Laravel as a REST API for a SPA. I have a relationship where families have multiple contributions. The contributions table has a foreign key reference to family's id. I can call on the contributions route with the hasMany/belongsTo set up, and every contribution gets the entire family model it belongs to. But I don't need all that data, I just need a single field from the family table (not the id, but a different field) with each contribution.
Here are my models and resource controller:
class Family extends Eloquent {
protected $table = 'families';
// relationships
public function contributions() {
return $this->hasMany('Contribution');
}
}
class Contribution extends Eloquent {
protected $table = 'contributions';
// relationships
public function family() {
return $this->belongsTo('Family');
}
public function other_field() {
return $this->belongsTo('Family')->select('other_field');
}
}
class ContributionController extends BaseController {
public function index()
{
// works - but returns the entire family with every contribution
$contributions = Contribution::with('family')->get();
// returns other_field == null with every contribution
$contributions = Contribution::with('other_field')->get();
return Response::json($contributions->toArray(),
200);
}
Where am I going wrong with selecting this single field from the belongsTo relationship?
You can use query constraints on the relationship if you use eager loading.
Family::with(['contributions', function($query)
{
$query->select('column');
}])->get();

Querying with relationship not working

I am trying to grab an InvoiceDetails record and the matching Product record via the product foreign key.
This isn't working:
$r = InvoiceDetail::with('products')->find(52184)->toArray();
The 2 database calls are
SELECT * FROM `invoice_details` WHERE `id` = '52184' LIMIT 1
SELECT * FROM `products` WHERE `products`.`id` in ('0')
Where am I going wrong?
Table Structure of invoice details:
Schema::create('invoice_details', function (Blueprint $table) {
$table->increments('id');
$table->integer('invoice_id')->unsigned();
$table->integer('product_id')->unsigned();
$table->integer('quantity');
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict')->onUpdate('cascade');
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade')->onUpdate('cascade');
});
Table structure for Products:
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
});
Products Model:
class Product extends \Eloquent
{
public function products()
{
return $this->hasMany('InvoiceDetail');
}
}
Invoice Details Model:
class InvoiceDetail extends \Eloquent
{
public function details()
{
return $this->belongsTo('Invoice');
}
public function products()
{
return $this->belongsTo('Product');
}
}
Your relationships are weird. (Okay, that wasn't really any longer.)
Assuming that an Invoice can belong to many Products (with specific details about each such as quantity), and that a Product can belong to many Invoices, you have a classic pivot table scenario. In which case, you're doing extra work and making life more difficult for yourself than it has to be.
If that's the case, there are a few steps you can take to reduce your code and make life easier:
Remove the InvoiceDetails model. Laravel can handle pivot tables on its own pretty well. So unless you have something really custom that you need the pivot table model to handle, you don't need it.
Update your Product model. You have a products() method in the Product model. That doesn't really make any sense. Don't products belong to invoices? Let's fix that.
class Product extends Eloquent
{
public function invoices()
{
return $this->belongsToMany('Invoice', 'invoice_details', 'product_id', 'invoice_id');
}
}
The additional parameters indicate the pivot table name, the column name for the Product model identifier, and the column name for the Invoice model identifier, respectively.
Update your Invoice model. You didn't paste it here, but I'll assume it has a relationship for invoice details. If not, well, oops! Because an invoice can belong to many products, essentially the inverse of the products relationship we just defined, it's defined it pretty much the exact same way.
class Invoice extends Eloquent
{
public function products()
{
return $this->belongsToMany('Product', 'invoice_details', 'invoice_id', 'product_id');
}
}
You now have a many-to-many relationship between Products and Invoices, that is retrieved using intuitive relationship methods! Huzzah.
Hey wait, where's my quantity?
You'll have to figure that one out on your own. :)
Got the answer (there is 2 hours of my life I'm never getting back) I had to manually add the fk and pk. So in my InvoiceDetails model it should have looked like this
public function products()
{
return $this->belongsTo('Product', 'product_id', 'id');
}

How to link data from one table to another using Laravel 4?

I have a customers migration table
Schema::create('customers', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('address');
$table->string('phone');
$table->string('email');
});
and a tripsheet migration table which goes like this
Schema::create('tripsheets', function(Blueprint $table) {
$table->increments('id');
$table->integer('tripsheet_num');
$table->integer('customer_id');
$table->string('date');
$table->string('customer_name');
$table->string('customer_address');
$table->string('customer_phone');
$table->string('rep_address');
$table->string('rep_phone');
});
I have also created a customer eloquent,
class Customer extends Eloquent {
public $timestamps = true;
public $table = 'customers';
protected $fillable = ['name', 'address', 'phone', 'email'];
public function tripsheets(){
return $this->belongsTo('Tripsheet', 'name', 'address', 'phone');
}
}
and a tripsheet model,
class Tripsheet extends Eloquent {
public $timestamps = true;
public $table = 'tripsheets';
protected $fillable = [];
public function customer(){
return $this->hasMany('Customer', 'name', 'address', 'phone');
}
}
and my routes.php goes like this,
Route::get('/', function()
{
return View::make('hello');
});
Route::controller('/customers', 'CustomerController');
Route::controller('/tripsheets', 'TripsheetController');
I would like to link the customer_name, customer_address, customer_phone from the tripsheet table to the name, address, phone of the customer table. I also want to know how to route them and fetch them as a json data to be used by angular JS to display the result.
now should i create a third table to link these two? Or should i call it with Customer::with('tripsheets')->all();in the routes/controller?
I also want to know how to route them and fetch them as a json data to be used by angular JS to display the result.?
I overlooked your code and after user315.. answer I see the problem. The belongsTo and hasMany has wrong arguments.
You need to change your code to the following to make it work:
class Customer extends Eloquent {
public function tripsheets(){
return $this->belongsTo('Tripsheet', 'tripsheet_num');
}
}
class Tripsheet extends Eloquent {
public function customer(){
return $this->hasMany('Customer', 'tripsheet_num');
}
}
The problem is that you have the field tripsheet_num in the table tripsheets. Laravel tries to find a field called tripsheet_id inside the tripsheets table when you use the belongsTo(Tripsheet) on Customer. In your case this key field is named different and is not found, and so the relation is not set.
Same goes for hasMany() only then it looks in the other table for the key field.
See the relation documentation for more info: One-to-one relation & hasMany
You only need the first argument in your belongsTo and hasMany method. The others are likely the reason why it's not working. They are meant for telling Eloquent what the foreign key is, and if you are specifying the foreign key as name, then it's obviously not going to work right.
Since you have proper naming conventions, Eloquent can accurately guess what they should be and you shouldn't need them.

Categories