Eloquent doesn't get the "belongsTo" item - php

I have the Project model and the Contract model. When i execute Project:all() it gets me only the projects without the contract, same for contract. I tried to dd() inside contract and doesn't do anything, like is never executed. I also tried with App\ prefix and without.
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
protected $table = 'project';
public function contract() {
return $this->belongsTo('Contract');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Contract extends Model
{
protected $table = 'contract';
public function project() {
return $this->hasMany('Project', 'ContractID', 'ContractID');
}
}
I try to retrieve them like this:
$projects = Project::all()->take(10);

You have a few problems here.
Project::all()->take(10);
This only returns a collection of projects. You havent specified that you want the contracts also.
$projects = Project::with('contract')->get();
In your belongsTo - You havent specified the column that the table should join on. You need to do this, because you have not used a standard id for primary key and contract_id for foreign key.
unrelated to specific question, but your relationship in contract model is also wrong.
public function project() {
return $this->hasMany('Project', 'ContractID', 'ContractID');
}
If one contract has many projects, then your public function project() should be public function projects();
Finally - Why are you using non-standard table / column naming conventions? What's wrong with contract_id? Are you aware that mysql is non-case sensitive? Also the project table could be renamed projects and the contract table could be renamed contracts. It will make you writing your eloquent relations much easier and makes more sense!
If you used standard naming conventions, then you could just do this to declare your model relations.
namespace App;
use Illuminate\Database\Eloquent\Model;
class Contract extends Model
{
public function projects() {
return $this->hasMany('Project');
}
}
Notice you dont need to specify the table name in the model, or how the table is related to the Project.

Related

Extending Eloquent models, more magic methods

Situation: In my work they have conventions on their database, table and column names, which are a bit long and repetitive. Being used to Eloquent I figured it wouldn't be much trouble to reimplement __get and __set methods, and not making lots of getters. Something like this (toConvention implements company's conventions):
use Illuminate\Database\Eloquent\Model;
class CompanyModel extends Model {
public function __get($key){
return $this->getAttribute($this->toConvention($key));
}
public function __set($key){
return $this->setAttribute($this->toConvention($key));
}
}
Which works well, for retrieving attributes, but not for retrieving relationships. Here are the implementations:
use App\CompanyModel as Model
class Location extends Model
{
protected $table = 'tablename';
protected $primaryKey = 'primarykeycolumn';
//...
public function comissionCurrency(){
return $this->belongsTo('App\Currency', 'foreign', 'other');
}
}
use App\CompanyModel as Model
class Currency extends Model
{
protected $table = 'tablename';
protected $primaryKey = 'primarykeycolumn';
//...
}
When requesting for attributes, like $location->name, or $location->comission_currency_id everything works as expected, retrieving the corresponding column name. But when I try to retrieve the belongsTo relationship, after using toSql() I see almost the correct query formed: select * from table where table.column is null the is null part should be comparing with the corresponding id.
I know it's due to my implementation, because when I use Illuminate\Database\Eloquent\Model everything works ok. Funny thing is that when I use Eloquent's model on the child model and the reimplemented on the other, it works to (but I'm not able to use my magic methods in the child model, in the parent one fetched from the relationship I can...)
I haven't figured out which method to reimplement to make this work by reading Eloquent's code, any ideas, or suggestions?
Thanks in advance.

Intermediate Tables & Laravel

I'm kind of new to the Eloquent (Pivot / Intermediate Tables) idea.
I am using Laravel 5.3 and the docs are making a little sense, but not enough. Unfortunatley!
I have a few scenarios that I'd like to try get data from...
I have the following DB Tables
Companies
Company_Offers
Offers
Company_Attributes
Attributes
In my scenarios the following is said of these DB Tables...
A company can have many offers
A company can have many attributes
An Offer can be associated with many companies
An attribute can be associated with many companies
I have created the 5 models to correspond to the 5 DB Tables.
I am trying to work out, How I get these relationships into my models?
Thank You!
You want to use the belongsToMany relationship. For example:
class Company extends Model
{
public function offers()
{
return $this->belongsToMany(App\Offer::class);
}
}
If you have setup your pivot table with company_id and offer_id this relationship will work automatically, and a pivot table of company_offer (singular version of model name in alphabetical order). If you didn't follow the naming convention you can specify the pivot table and foreign keys like so:
return $this->belongsToMany('App\Offer', 'Company_Offers', 'Company_ID', 'Offer_ID');
Actually in laravel you don't have to create models for pivot tables. So you are down to three models that will look more less like this:
<?php
/* /app/Company.php */
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
/**
* The offers that belong to the company.
*/
public function offers()
{
return $this->belongsToMany('App\Offer');
}
/**
* The attributes that belong to the user.
*/
public function attributes()
{
return $this->belongsToMany('App\Attribute');
}
}
<?php
/* /app/Offer.php */
namespace App;
use Illuminate\Database\Eloquent\Model;
class Offer extends Model
{
public function companies()
{
return $this->belongsToMany('App\Company');
}
}
<?php
/* /app/Attribute.php */
namespace App;
use Illuminate\Database\Eloquent\Model;
class Attribute extends Model
{
public function companies()
{
return $this->belongsToMany('App\Company');
}
}
More on how to use it to select or update those relations you can find here:
https://laravel.com/docs/5.3/eloquent-relationships#many-to-many

Can't eager-load a One-to-One relation in Laravel

In Laravel 5.2 I'm trying to eager load a User along with its Usersettings with this piece of code: App\User::with('usersettings')->get(), but it fails, and I can't seem to figure out why. This is the given error.
BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::usersettings()'
I've read the laravel docs and I've watched a lot of Laracasts, and this worked before, so I get the idea I'm missing something really small and probably obvious.
User.php
<?php
namespace App;
/* User with fields: id, email */
class User extends Illuminate\Database\Eloquent\Model {
protected $table = 'users';
public function usersettings() {
return $this->hasOne("App\Usersettings", "userid");
}
}
Usersettings.php
<?php
namespace App;
/* Settings with fields: id, userid, textcolor */
class Usersettings extends Illuminate\Database\Eloquent\Model {
protected $table = 'usersettings';
public function user() {
return $this->belongsTo('App\User', 'userid');
}
}
//Edit: I already tried lowercasing the s. This typo might have snuck in copying it to SO, but the error was there, and still is there, even after fixing it.
//Edit:
<?php
namespace App;
use App\UserSettings;
class User extends Illuminate\Database\Eloquent\Model {
protected $table = 'users';
public function settings() {
return $this->hasOne(UserSettings::class, "userid");
}
}
If I run php artisan tinker>>> App\User::with('settings')->get(), it works as expected, but below
<?php
namespace App;
use App\UserSettings;
class User extends Illuminate\Database\Eloquent\Model {
protected $table = 'users';
public function usersettings() {
return $this->hasOne(UserSettings::class, "userid");
}
}
gives BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::usersettings()' when I run php artisan tinker >>> App\User::with('usersettings')->get(). Likewise when I rename the method to abc and run php artisan tinker >>> App\User::with('abc')->get() (that fails as well)
You mistyped when defining the relation on the User model:
public function usersettings() {
return $this->hasOne("App\Usersettings", "userid");
}
I would suggest some cleanup:
name the tables 'users' and 'user_settings',
rename the field 'userid' to 'user_id',
rename the 'Usersettings' model to 'UserSettings'.
That way you dont need to explicitly define table names and foreign keys, because you follow the conventions and Laravel can "guess" those.
You can also rename the the relation 'usersettings()' to 'settings()', since its obvious that they're the users' settings. Then you can fetch it like: 'User::with('settings')->get()'.
Did you try running composer dump-autoload after you changed your model relationships?
Just to make sure you're aware of this: you don't actually need to define the relationship in your UserSettings model to achieve what you want, only define the relationship in the User model. This is because you'd only need to get the settings in the context of the User, not the other way around.
Code for the User model:
<?php
namespace App;
use App\UserSettings;
class User extends Illuminate\Database\Eloquent\Model {
public function userSettings() {
return $this->hasOne(UserSettings::class);
}
}
UserSettings model: make sure it's camel case and that userid is present in your migration (the convention in your case would be to have user_id, so I would rename that column in your migration because then Eloquent will pick it up automatically and you don't need the second parameter in your User model's hasOne() definition).
Also, rename your table to user_settings if you can. That's another Eloquent convention, this one being that the model name UserSettings translates the camel case S letter in the middle of the classname to _ (and as a matter of fact, you shouldn't even need to explicitly state the table name if you've used the name user_settings).
Code for the UserSettings model:
<?php
namespace App;
/* Settings with fields: id, userid, textcolor */
class UserSettings extends Illuminate\Database\Eloquent\Model {
protected $table = 'user_settings';
}
Now, you should be able to do the below action. Note that the with parameter needs to be the relation function name from the User model.
$usersThatHaveSettingsIncludedInTheResults = User::with('userSettings')->get();

laravel many to many relationship in this case

I have already checked this official example http://laravel.com/docs/eloquent#many-to-many-polymorphic-relations
but I still confused because I may have a different case.
I have a DetailsAttribute model which deals with details_attribute table.
I have a Action model witch deals with action table.
The relationship between them is many to many.
So I created a new table details_attribute_action with model DetailsAttributeAction
My DetailsAttribute model should have:
public function actions(){}
My Actions model should have:
public function detailsAttributes(){}
and my DetailsAttributeAction model should have functions but I don't know what they are.
My question is what is the code inside the previous functions please? and should really the DetailsAttributeAction have functions of not?
What you're looking for is a Many-to-Many relation, not one that is polymorphic.
http://laravel.com/docs/eloquent#many-to-many
Your code should look something like this:
class DetailsAttribute extends Eloquent {
// ...
public function actions()
{
// Replace action_id and details_attribute_id with the proper
// column names in the details_attribute_action table
return $this->belongsToMany('Action', 'details_attribute_action', 'details_attribute_id', 'action_id');
}
}
class Action extends Eloquent {
// ...
public function detailsAttributes()
{
return $this->belongsToMany('DetailsAttribute', 'details_attribute_action', 'action_id', 'details_attribute_id');
}
}
You won't have to worry about how to create the DetailsAttributeAction model in Laravel. It's simply a table to map the Many-to-Many relationships you've created.

Laravel 4 Polymorphic Relationship with Namespaced Models

I created an Seo table with Eloquent's polymorphic relationship. So for Seo table, I have something like this
title
description
seoble_id
seoble_type
timestamps
Then for all the models that will have custom SEO, I added the morphOne relationship while the Seo model will have morphMany relationship. So for Post model I will have something like this
namespace App\Models;
class Post extends Eloquent {
public function seo()
{
return $this->morphOne('App\Models\Seo', 'seoble');
}
}
However, the relationship will only work if I the seoble_type is filled with the fully namespaced model class name. So the seoble_type must be 'App\Models\Post' (model name like 'Post' or table name like 'posts' will not work) for the polymorphic relationship to work. The problem is, if I somehow want to change the namespace, I will have to update all the seo table to update the seoble_type field, which will be a hassle.
Now, before I tried the polymorphic relationship, I usually created the equivalent table something like this:
title
description
object_id
type
timestamps
And for the relationship, for each model I will have something like this:
namespace App\Models;
class Post extends Eloquent {
public function seo()
{
return $this->hasOne('App\Models\Seo', 'object_id')->where('type', 'post');
}
}
My question is, are these 2 methods equivalent?
if you using morph it mean you wish single table can be used as relations to any table with indication by object_id and type_id. so the answer for your question, is not equivalent.
I thought at your case (for save seo table) the recommended ways as my opinions is using morphOne.
and then, for your problem in morph you can fill your seoable_type with whatever do you like, not should fill with your namespace
here is simple code when using morph :
namespace App\Models;
class Seo extends Eloquent {
public function seoable()
{
return $this->morphTo();
}
public function post()
{
return $this->belongsTo('App\Models\Seo', 'seoable_id');
}
}
/*----*/
namespace App\Models;
class Post extends Eloquent {
public function getSeo($type)
{
return $this->morphOne('App\Models\Seo', 'seoable');
}
}
// you can using like this :
$seo = \Seo::where('seoable_type', 'post');
$seo->post->first();
// or like this :
$post = \Post::with('getSeo')->findOrFail($id)->toArray();
wish this helped you.

Categories