Laravel relationship 2 layers - php

I have my database (=model) structure like that:
game:
lot (typeof Lot)
places (array type of Place)
place_id // just a number of a lot in some game
user_id
What should I do to call in everywhere like this:
User::find(1)->games() // returns Game collection where user has places
?
Models are:
class Place extends Model
{
protected $fillable = ['place_id', 'user_id', 'game_id'];
public function user() {
return $this->belongsTo(User::class);
}
public function game() {
return $this->belongsTo(Game::class);
}
}
User:
class User extends Model implements AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'email', 'steam_id', 'avatar'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['remember_token'];
/**
* Get all of the tasks for the user.
*/
public function items()
{
return $this->hasMany(SteamItem::class);
}
public function places() {
return $this->hasMany(Place::class);
}
}
The Game:
class Game extends Model
{
protected $fillable = ['lot_id'];
public function lot() {
return $this->belongsTo(Lot::class);
}
public function places() {
return $this->hasMany(Place::class);
}
}
Now I use this code in my User class:
public function games() {
return Game::with(['places' => function ($query) {
$query->where('user_id', $this->id);
}]);;
}
It doesn't work, because I need to make it as a relationship method, but with method returns a query builder.
In the finals I must call $user->games and it should return me all the games user linked to through place.

Okay. I think I understand now.
User has many Place. Place belongs to User.
Place belongs to Game. Game has many Place.
You can try this:
$user = User::with('places.game.lot')->find(1);
This will fetch the User and eager load all the relationships. Because Place belongsTo a Game, which in turn belongs to Lot, you can then do this:
#foreach ($user->places as $place)
<img src="{{$place->game->lot->imageUrl}}" />
#endforeach
Also, place is actually a pivot table, and you can take advantage of Eloquent's many-to-many relationship, which I would recommend reading about.

Related

Trouble getting hasManyThrough to work in Laravel 9

In my Laravel project I'm having some trouble getting my hasManyThrough relationship to work, these are my models:
Pingtree
BuyerTier
PingtreeEntry
I want to get all of my BuyerTier models through my PingtreeEntry model.
This is my current relationship on my Pingtree model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Pingtree extends Model
{
use HasFactory, SoftDeletes;
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'pingtrees';
/**
* The attributes that should be cast.
*
* #var array<string, string>
*/
protected $casts = [
'is_enabled' => 'boolean',
];
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = [
'is_deleting',
];
/**
* Determine if we're editing the model
*
* #return bool
*/
public function getIsDeletingAttribute()
{
return false;
}
/**
* Get the company that owns the model.
*/
public function tiers()
{
return $this->hasManyThrough(
BuyerTier::class, // final model we want to access
PingtreeEntry::class, // intermediate model
'buyer_tier_id', // foreign key on intermediate model
'id', // foreign key on final model
'id', // local key
'pingtree_id' // local key on intermediate model
)->orderBy('processing_order', 'asc');
}
/**
* Get the pingtree entry model
*/
public function pingtree_entry()
{
return $this->belongsTo(PingtreeEntry::class, 'id', 'pingtree_id');
}
/**
* Get the company that owns the model.
*/
public function company()
{
return $this->belongsTo(Company::class);
}
/**
* Get the user that owns the model.
*/
public function user()
{
return $this->belongsTo(User::class);
}
}
And then I query this in my controller:
$pingtree = Pingtree::where('company_id', $company_id)
->where('id', $id)
->with([
'tiers.buyer',
'tiers.pingtree_entry'
])
->first();
This is what my pingtree_entries table looks like:
Right now, for some reason, despite having multiple tiers on my pingtree ID 3, I'm only ever getting 1 result back in my query, and I should be seeing all 4 tiers on my pingtree, what am I missing?

mocking hasMany relation in laravel 5.1 unit test

For a unit test in laravel 5.1 I am trying to test a cascading delete function of the Client model, which, with the recursive flag set, should also delete all users associated with the client.
I want to use a mock user adn test only wether the delete function on the user is called, so I wont have to use the database, and to apply the same principle to other tests in the future.
at the moment the test fails because I cannot find a way to make the client model retreive the associated user without firing a query.
I think I need to mock the hasMany relation defining function of the client, but i have not found a way.
the client model:
class Client extends Model
{
protected $table = 'clients';
protected $fillable = [];
public function casDelete($recursive = false){
if($recursive) {
$users = $this->users()->get();
foreach($users as $user) {
$user->casDelete($recursive);
}
}
$this->delete();
}
public function users(){
return $this->hasMany('App\User');
}
}
the user model:
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
use Authenticatable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'email', 'password', 'client_id'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function casDelete($recursive = false){
$this->delete();
}
public function client(){
return $this->belongsTo('App\Client');
}
}
the test:
class ClientModelTest extends TestCase
{
use DatabaseTransactions;
function testCasDelete(){
$client = factory(Client::class)->create();
$user = factory(User::class)->make(['client_id' => $client->id]);
$observer = $this->getMock('user');
$observer->expects($this->once())->method('casDelete');
$client->casDelete(true);
}
}
When you are using DatabaseTransactions, this mean you want to persist the data in the database. And when you are using create() from the factory still you are using the database, so either you should not use the database at all or if you want you to use the database then you can simply solve the problem. but what I can suggest is this solution, which I'm not using the database init.
$user = \Mockery::mock();
$user->shouldReceive('casDelete')->andReturnNull();
$queryMock = \Mockery::mock();
$queryMock->shouldReceive('get')->andReturn([$user]);
$clientMock = \Mockery::mock(Client::class)->makePartial();
$clientMock->shouldReceive('users')->andreturn($queryMock);
$clientMock->casDelete(true);
This way you can be sure that you have called casDelete on each user model.
this is a very simple test case, you can extend it in the way you like base on what you want to achieve.

how to join two models in laravel 5.2

I have two models as Project and Collaborator this is My tables
Project column
id
project_name
project_note
user_id
Collaborator Model
id
project_id
collaborator_id
I need join this models to get project_name instead project_id of Collaborator Model.
how can I do this. I read www.laravel.com documents but difficult to understand. help me in code...
project Model
<?php
namespace App;
use Auth;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
/*
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['project_name', 'project_notes', 'project_status', 'due_date'];
public function scopePersonal($query)
{
return $query->where('user_id', Auth::user()->id);
}
//
}
collaborator Model
<?php
namespace App;
use Auth;
use Illuminate\Database\Eloquent\Model;
class Collaboration extends Model
{
protected $table = 'project_collaborator';
/*
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['project_id', 'collaborator_id'];
/*
* Get the user that is a collaborator on another project
* #return collection
*/
public function user()
{
return $this->belongsTo(User::class, 'collaborator_id');
}
/*
* Query scope to return information about the current project
* #param $query
* #param int $id
* #return query
*/
public function scopeProject($query, $id)
{
return $query->where('project_id', $id);
}
public function scopeColabo($query)
{
return $query->where('collaborator_id',Auth::user()->id);
}
}
Based on your comment, you need to add a relationship hasOne to your collaboration model:
class Collaboration extends Model
{
.....
public function project()
{
return $this->hasOne('App\Project');
}
.....
}
The method project() will define your relationship with your project model. And then you'll be able to get the collaboration project name like this:
$collaborations = Collaboration::with('project')->get();
foreach ( $collaborations as $collaboration ) {
echo $collaboration->project->project_name;
}
You can read more in the documentation.
In your Collaboration class add the followoing relation:
public function project()
{
return $this->belongsTo('App\Project');
}
And in your User class define a relation as:
public function collaborations()
{
return $this->hasMany('App\Collaboration', 'collaborator_id');
}
Then you can get all the collaborations of logged in user by:
$collaborations = auth()->user()->collaborations()->with('project')->get()
or
To get all collaborations you can so as:
$collaborations = Collaboration::with('project')->get();
In your view file:
#foreach ($collaborations as $collaboration)
{{ $collaboration->project->project_name }}
#endforeach

How to make HasMany Relation ship in Laravel 4.2

I have a user model looks like this
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
public function answer(){
return $this->hasMany('Answer','user_id');
}
public function supplierranking(){
return $this->hasMany('Supplierrank','userid','id');
}
}
Now each user will rank a company in a ranking Model which looks like this
Class Supplierrank extends Eloquent{
public function supplier(){
return $this->belongsTo('Supplier','supplierid','id');
}
public function user(){
return $this->belongsTo('User','userid','id');
}
}
I am able to get the user with the ranking details but I also have to get the details of companies that has been ranked from a Supplier table
which looks like this
Class Supplier extends Eloquent{
public function supplierranks(){
return $this->hasMany('Supplierrank','supplierid');
}
}
My query that I have done looks like this
$usersandranking = User::where('event','=',$exceleve)->with('supplierranking')->orderBy('id')->get();
It gets me user detail and there rankings but not the supplier names
Can any one help me on this

Laravel 4 - Undefined Property when retrieving a field value which belongsTo another table

I'm trying to get the 'name' field of the 'users' table in my Articles (REST) controller.
These are my models:
// models/Article.php
class Article extends Eloquent {
protected $fillable = [];
protected $table = 'articles';
public function user(){
return $this->belongsTo('User','user_id');
}
public function upload(){
return $this->has_one('Upload');
}
}
// models/User.php
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
protected $fillable = array('email','password','name');
public function articles(){
return $this->hasMany('Article','user_id');
}
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
public function getAuthPassword()
{
return $this->password;
}
public function getReminderEmail()
{
return $this->email;
}
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
}
// controllers/ArticlesController.php
class ArticlesController extends \BaseController {
public function index() // GET (all)
{
$articles = Article::all();
foreach ($articles as $article) {
// ** ERROR ** Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$id
var_dump("title: ".$article->titulo." | user: ".$article->user()->id .' | email: '.$article->user()->email );
}
}
// other functions [....]
}
So..How can I get the fields from 'users' table properly?? I've been searching in the Laravel doc and this web and... I haven't' found the error :(
I've set up the database relationships on the migrations files and I've checked out the mysql databases relations diagram and everything is ok.
Have you checked the keys properly. belongsTo's second parameter should be the local key whereas hasMany's second parameter is the foreign key.

Categories