Laravel Models Pivot Table 1-1 Relationship should be 1-M - php

I have a problem here with my Laravel model, i'm trying to use a Pivot Table that I already have in my database, here's the layout of the tables I am using
clients
jobs
clients-jobs
I believe the Error is in my model, I don't completely understand the eloquent syntax, I have been trying several other methods though. I would like to keep the primary on the clients-jobs table in order to index it easier.
Here's my models:
Client
protected $table = 'clients';
public $timestamps = true;
protected $primaryKey = "id";
public function clientsjobs() {
return $this->belongsTo('ClientsJobs');
}
Job
protected $table = 'jobs';
protected $fillable = array('first_name', 'last_name', 'email');
protected $primaryKey = "id";
public function clientsjobs() {
return $this->belongsToMany('ClientsJobs');
}
ClientsJobs ( Maybe I should delete this model? Am I using it right? )
protected $table = 'clients-jobs';
protected $primaryKey = "id";
public function clients() {
return $this->hasOne('Client', 'id');
}
public function jobs() {
return $this->hasOne('Job', 'id');
}
The Code I am using to try and display all of the records for the clients-jobs table is this here in one of my controllers (thanks sebastien):
$masterArray = array();
ClientsJobs::with('clients', 'jobs')->chunk(200, function($records) use (&$masterArray) { //Chunk Retrieves 200 Records at a time
foreach ($records as $record) {
$masterArray[] = array(
'id' => $record->id, // id
'client_name' => !empty($record->clients) ? $record->clients->fname : "Unknown",
'job_name' => !empty($record->jobs) ? $record->jobs->name : "Unknown",
'wage' => $record->wage,
'productivity'=> $record->productivity,
);
}
});
return $masterArray;
this code works for the first two records, but "unknown" after that, I'm pretty sure that it's because the application thinks it's a 1:1 relationship ( I only have 2 Users and 2 Jobs as dummy data ).
Thanks in Advance for any suggestions that you can make, also if you see something nasty that I did please let me know

You should delete the ClientsJobs model, it's unnecessary. Laravel's belongsToMany relationship, when set up correctly will deal with the pivot table itself. Take a look at:
http://laravel.com/docs/4.2/eloquent
Many-to-many relations are a more complicated relationship type. An
example of such a relationship is a user with many roles, where the
roles are also shared by other users. For example, many users may have
the role of "Admin". Three database tables are needed for this
relationship: users, roles, and role_user. The role_user table is
derived from the alphabetical order of the related model names, and
should have user_id and role_id columns.
Your pivot table should either be named with Laravel's convention of taking the model name of each (Singular) and joining them together with an underscore character (client_job) or you can specify the name of the pivot table etc. on your relationship. Laravel's documentation gives the following example which allows you to override the default pivot table name and corresponding keys:
return $this->belongsToMany('Role', 'user_roles', 'user_id', 'foo_id');
In your case, if you're after a one to one relationship, you don't really need a pivot table. You can just implement hasMany and belongsTo relationships. That is, a client belongs to a job, but a job can have many clients.

Related

Laravel Many-To-Many relation returns no results

I am currently learning Laravel and I have an issue which I can't seem to find a solution for. I have a many-to-many relation between two tables that always returns nothing. Let me show you the basic setup:
My posts Model:
// App\Post.php
protected $fillable = [
'name',
'description'
'videopath'
];
public function Tags()
{
return $this->belongsToMany('App\Tag');
}
public function Cats()
{
return $this->belongsToMany('App\Cat');
}
My tags model:
// App\Tag.php
protected $fillable = [
'name',
'description'
];
public function exercises()
{
return $this->belongsToMany('App\Exercise');
}
My posts controller:
// PostController.php
public function show($id)
{
$post = Post::find($id);
return view('posts', ['post'=>$post];
}
The view:
// posts.blade.php
#foreach($post->tags() as $tag)
//do stuff
#endforeach
The intermediate table is called post_tag and contains the post_id and tag_id columns. At first it returned the results as expected but after some while all of my posts didn't return any tags anymore. The cats model looks similar to the tags model. Anyone has an idea?
Check the name of your Tags function. In your view you are calling "tags" instead of "Tags".
Have you created the intermediate table in your database? If so, check the naming convention (alphabetic order) that Laravel uses to find it: in your case it should be tag_post. if not, customize the name of the table when defining the relationship.
Many To Many
Many-to-many relations are slightly more complicated than hasOne and hasMany relationships. An example of such a
relationship is a user with many roles, where the roles are also
shared by other users. For example, many users may have the role of
"Admin". To define this relationship, three database tables are
needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns.
Taking your view:
#foreach($post->tags() as $tag)
//do stuff
#endforeach
$post->tags() will return the relationship instead of the actual collection. You want $post->tags instead or $post->tags()->get().

How to retrieve data from one to one relationship in Laravel 5.4

I have two MSSQL tables so i created two models [Adress] and [Webshop]. The foreign key is Adresse in both tables.
1.Model [Adress]
class Adress extends Model
{
protected $table = "Adress";
protected $primaryKey = 'Adresse';
public $timestamps = false;
public function webshop()
{
return $this->hasOne('App\Webshop', 'Adresse');
}
}
2.Model [WebShop]
class Webshop extends Model
{
protected $table = "Webshop";
protected $primaryKey = 'Adresse';
public $timestamps = false;
public function adress()
{
return $this->belongsTo('App\Adress','Adresse');
}
}
I would like to make a table with some data from the first and second table like the webshopID, mobile is in [Webshop] table and adress in the [Adress] table. I think this is a one to one relationship between this two tables.
in php artisan tinker:
App\Adress::all(); -> this is working
App\Adress::find(2910)->webshop -> this is also working
App\Adress::with('webshop')->get() -> this is NOT working
I would like to retrieve data from this two tables at the same time. Is this possible with a relationship or do i heave to use the joins?
EDIT:
maybe my foreignKeys are wrong
Adress table:
Webshop table:
Please try with this -
use App\Adress;
use App\Webshop;
$result = Webshop::with('Adress')->where('Webshop.id',$id)->get();
or
$result = Adress::with('Webshop')->where('Adress.id',$id)->get();
Hope this will help you.
Try to change your relationship in Address model to
$this->hasOne('App\Webshop', 'Adresse', 'Adresse');
and in Webshop model
$this->belongsTo('App\Address', 'Adresse', 'Adresse');
EDIT
Now to retrieve the relationships you can do
$webshop = App\Address::find($id)->webshop;
$address = App\Webshop::find($id)->address

Laravel relationship with pivot table

I have 3 tables in my database :
users (id);
interests (id);
users_interests (user_id, interests_id);
I want to be able to fetch all the user's interests in this way :
$interests = $user->interests
This is what I wrote in the User.php model, following laravel's doc:
public function interests() {
return $this->hasManyThrough(
'App\Interest', 'App\UserInterest',
'user_id', 'id', 'interest_id'
);
}
but it returns empty even though the user has a game. So there has to be something I'm doing wrong
Anyone to help me ?
I think a belongs to many would do the job:
public function interests() {
return $this->belongsToMany(
'App\Interest',
'users_interests',
'user_id',
'interests_id'
);
}
Quite similar to the example in the docs
If you were to rename users_interests table to interest_user and the column
interests_id to the singular form you would just need the first parameter:
public function interests() {
return $this->belongsToMany(App\Interest::class);
}
From my understanding the hasManyThrough is used to jump forward within a relation (also described in the docs):
The "has-many-through" relationship provides a convenient shortcut for
accessing distant relations via an intermediate relation.

Eloquent relationship where values are formatted differently

We've recently switched to a new permissions system on a project I am working on.
I have completed integration for this, eloquent relationships and all, when the requirements of the integration changed a little.
The permission system integrates with all of our systems across our infrastructure, and when it comes to referencing users from the Laravel project, the value in the permissions system is slightly different; in that it is prefixed with user-.
For example, a user with the username james in my users table is referenced as user-james in the permissions system table.
Is there any way to specify the value the eloquent relationship should look at?
I could just add a column to the users table to store the primary key of this user as it exists in the permissions table, but I wanted to see if there was a way to do this with eloquent.
If we consider relation is one - one we can do something like below:
First extend BelongsTo relation and change condition on where clause:
class CustomBelongsTo extends BelongsTo
{
/**
* #inheritDoc
*/
public function addConstraints()
{
if (static::$constraints) {
// For belongs to relationships, which are essentially the inverse of has one
// or has many relationships, we need to actually query on the primary key
// of the related models matching on the foreign key that's on a parent.
$table = $this->related->getTable();
$this->query->where($table.'.'.$this->otherKey, '=', 'user-'.$this->parent->{$this->foreignKey});
}
}
}
Then override belongsTo method on your model to use this custom relation.
class User extends Model {
protected $table = 'users';
public function permissions(){
return $this->belongsTo(Permission:class, 'username');
}
public function belongsTo($related, $foreignKey = null, $otherKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relationships.
if (is_null($relation)) {
list($current, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$relation = $caller['function'];
}
// If no foreign key was supplied, we can use a backtrace to guess the proper
// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if (is_null($foreignKey)) {
$foreignKey = Str::snake($relation).'_id';
}
$instance = new $related;
// Once we have the foreign key names, we'll just create a new Eloquent query
// for the related models and returns the relationship instance which will
// actually be responsible for retrieving and hydrating every relations.
$query = $instance->newQuery();
$otherKey = $otherKey ?: $instance->getKeyName();
return new CustomBelongsTo($query, $this, $foreignKey, $otherKey, $relation);
}
}
I hope this help.

getting the value of an extra pivot table column laravel

I have a phone_models, phone_problems, and a phone_model_phone_problem pivot table. The pivot table has an extra column 'price'.
PhoneModel:
class PhoneModel extends \Eloquent
{
public function problems()
{
return $this->belongsToMany('RL\Phones\Entities\PhoneProblem')->withPivot('price');
}
}
PhoneProblem:
class PhoneProblem extends \Eloquent
{
public function models()
{
return $this->belongsToMany('PhoneModel')->withPivot('price');
}
}
What I'm trying to do is get the price of a specific phone with a specific problem.
This is how I have it now but I feel like Laravel has a built in Eloquent feature I can't find to do this in a much simpler way:
$model = $this->phoneService->getModelFromSlug($model_slug);
$problem = $this->phoneService->getProblemFromSlug($problem_slug);
all this does is select the specific model and problem from their slug.
then what I do is with those credentials I get the price like so:
$row = DB::table('phone_model_phone_problem')
->where('phone_model_id', '=', $model->id)
->where('phone_problem', '=', $problem->id)
->first();
so now I can get the price like so $row->price but I feel like there needs to be a much easier and more 'Laravel' way to do this.
When using Many to Many relationships with Eloquent, the resulting model automatically gets a pivot attribute assigned. Through that attribute you're able to access pivot table columns.
Although by default there are only the keys in the pivot object. To get your columns in there too, you need to specify them when defining the relationship:
return $this->belongsToMany('Role')->withPivot('foo', 'bar');
Official Docs
If you need more help the task of configuring the relationships with Eloquent, let me know.
Edit
To query the price do this
$model->problems()->where('phone_problem', $problem->id)->first()->pivot->price
To get data from pivot table:
$price = $model->problems()->findOrFail($problem->id, ['phone_problem'])->pivot->price;
Or if you have many records with different price:
$price = $model->problems()->where('phone_problem', $problem->id)->firstOrFail()->pivot->price;
In addition.
To update data in the pivot you can go NEW WAY:
$model->problems()->sync([$problemId => [ 'price' => $newPrice] ], false);
Where the 2nd param is set to false meaning that you don't detach all the other related models.
Or, go old way
$model->problems()->updateExistingPivot($problemId, ['price' => $newPrice]);
And remind you:
To delete:
$model->problems()->detach($problemId);
To create new:
$model->problems()->attach($problemId, ['price' => 22]);
It has been tested and proved working in Laravel 5.1 Read more.
Laravel 5.8~
If you want to make a custom pivot model, you can do this:
Account.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Account extends Model
{
public function users()
{
return $this->belongsToMany(User::class)
->using(AccountUserPivot::class)
->withPivot(
'status',
'status_updated_at',
'status_updated_by',
'role'
);
}
}
AccountUserPivot.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class AccountUserPivot extends Pivot
{
protected $appends = [
'status_updated_by_nice',
];
public function getStatusUpdatedByNiceAttribute()
{
$user = User::find($this->status_updated_by);
if (!$user) return 'n/a';
return $user->name;
}
}
In the above example, Account is your normal model, and you have $account->users which has the account_user join table with standard columns account_id and user_id.
If you make a custom pivot model, you can add attributes and mutators onto the relationship's columns. In the above example, once you make the AccountUserPivot model, you instruct your Account model to use it via ->using(AccountUserPivot::class).
Then you can access everything shown in the other answers here, but you can also access the example attribute via $account->user[0]->pivot->status_updated_by_nice (assuming that status_updated_by is a foreign key to an ID in the users table).
For more docs, see https://laravel.com/docs/5.8/eloquent-relationships (and I recommend press CTRL+F and search for "pivot")

Categories