laravel relationship backwards - php

I have a test site where I've got a recipes, ingredients, and ingredient_uses tables. Each recipe "uses" ingredients in different quantities and prepared differently (eg. chopped, sliced, minced, grated), so the ingredient_uses table tracks the recipe_id and the ingredient_id with the other variable info.
The relationships look like this:
Recipe model:
public function ingredients()
{
return $this->hasManyThrough('App\Ingredient', 'App\IngredientUse');
}
public function ingredientUses()
{
return $this->hasMany('App\IngredientUse');
}
Ingredient_Use model:
public function ingredient()
{
return $this->hasOne('App\Ingredient');
}
public function recipe()
{
return $this->belongsTo('App\Recipe');
}
Ingredient model:
public function recipe()
{
return $this->belongsToMany('App\Ingredient');
}
I thought I wanted a hasManyThrough relationship from the recipe to the ingredient table, using the ingredient_uses as the middle table. But the sql is wrong:
SELECT `ingredients`.*, `ingredient_uses`.`recipe_id`
FROM `ingredients`
INNER JOIN `ingredient_uses`
ON `ingredient_uses`.`id` = `ingredients`.`ingredient_use_id`
WHERE `ingredient_uses`.`recipe_id` = 1
This is what I think I want:
SELECT `ingredients`.*, `ingredient_uses`.`recipe_id`
FROM `ingredients`
INNER JOIN `ingredient_uses`
ON `ingredient_uses`.`ingredient_id` = `ingredients`.`id`
WHERE `ingredient_uses`.`recipe_id` = 1
Is there a more appropriate relationship that I should be using?

First thing - you don't need Ingredient_Use model. Model examples:
class Ingredient extends Model
{
/**
* #var string
*/
protected $table = 'ingredients';
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function recipes()
{
return $this->belongsToMany(Recipe::class, 'recipes_ingredients', 'ingredient_id');
}
}
class Recipe extends Model
{
/**
* #var string
*/
protected $table = 'recipes';
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function ingredients()
{
return $this->belongsToMany(Ingredient::class, 'recipes_ingredients', 'recipe_id')->withPivot('additional', 'fields');
}
}
Access to additional fields example
$recipe->pivot->additional;

in Ingredient model
class Ingredient extends Model
{
public function recipe(){
return $this->belongsToMany(Recipe::class, 'ingredient_uses', 'ingredient_id', 'recipe_id');
}
}
other models will be empty thats mean there would not be any function inside Recipe model and Ingredient model .
u can see documentation about this
https://laravel.com/docs/5.3/eloquent-relationships#many-to-many

Related

Query on Pivot relation

I would like to query pivot model relation using Eloquent.
I've my User model :
class User extends Authenticatable
{
public function preferences(): BelongsToMany
{
return $this->belongsToMany(Preference::class, 'user_preference')
->using(UserNotificationPreference::class) //Custom Pivot model
->withPivot([enabled, channel_id]);
}
}
Here is the custom pivot model :
class UserNotificationPreference extends Pivot
{
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'enabled' => 'boolean'
];
/**
* Channel relation.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function channel(): BelongsTo
{
return $this->belongsTo(Channel::class);
}
}
And the preference model :
class Preference extends Model
{
// protected $connection = "apodis";
/**
* The users that belong to the preference.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(Preference::class, 'user_channel_notification_preference')
->using(UserNotificationPreference::class) //custom pivot
->withPivot(['preference_id', 'user_id', 'enabled', 'channel_id']);
}
}
From a User model, i would like to retrieve Preferences after querying custom pivot table relationship (Channel::class) ,
something like :
$user->preferences()
->wherePivot('enabled', true)
->whereHasPivot('channel', function(Builder $query) {
//doesn't exists
})->get()
There is a way to achieve this ?
(Products Model Laravel) public function products() {
return $this->belongsToMany('App\Product');
} (Shop Model Laravel)public function shops(){ return $this->belongsToMany('App\Shop');} you can specify the actual field names of that pivot table public function products(){ return $this->belongsToMany('App\Product','products_shops', 'shops_id', 'products_id');}possibility to get those values in our loops foreach ($shop-products as $product){echo $product->pivot->price;}

How to deploy relationship in pivot of three model in laravel?

I'm developing a role and permissions based on laravel framework.
I have 3 models :
Weblog
User
Permissions
This is pivot table
user_id , weblog_id , permission_id
Now, a user can have a weblog with permission id 1,2 and another weblog with permission 1,2,3,4
How can I deploy relationships? and how can I check user permissions when managing a weblog. (middleware and ...)
With the fact that Permission are specific to Weblog
Say the pivot table is called permission_user_weblog
class User extends Model
{
public function weblogs()
{
return $this->belongsToMany(Weblog::class, 'permission_user_weblog');
}
public function permissionsFor(int $weblogId)
{
$permissionIds = null;
$this->weblogs()
->where('id', $weblogId)
->with('permissions')
->get()
->each(function($weblog) use(&$permissionIds) {
$permissionIds = $weblog->permissions->pluck('id');
});
return $permissionIds;
}
}
class Weblog extends Model
{
public function users()
{
return $this->belongsToMany(User::class, 'permission_user_weblog');
}
public function permissions()
{
return $this->belongsToMany(Permission::class, 'permission_user_weblog');
}
}
class Permission extends Model
{
public function weblogs()
{
return $this->belongsToMany(Weblog::class, 'permission_user_weblog');
}
}
Then you can check anywhere for whether logged in user has specific permission for a specific weblog
public function update(Request $request, $weblogId)
{
$user = auth()->user();
$permissions = $user->permissionsFor($weblogId);
//Check whether the logged in user has permission identified by id 1 or 4 for weblog
$can = !! $permissions->intersect([1,4])->count();
//Do rest of processing
}
your Weblog,User,Permission has ManyToMany Relation, its a kind of odd but if you want to have this kind of relation its not a problem.
just consider each pair a ManyToMany. and every one of those can have a hasMany to Pivot (i named it Access) too (based on your needs).
User model:
class User extends Model{
/**
* retrive weblogs
*
* #return BelongsToMany weblogs
*/
public function weblogs()
{
return $this->belongsToMany(App\WebLog::class,'accesses_table')
->withPivot("permission_id")
->using(App\Access::class);
}
/**
* retrive permissions
*
* #return BelongsToMany permissions
*/
public function permissions()
{
return $this->belongsToMany(App\Permission::class,'accesses_table')
->withPivot("weblog_id")
->using(App\Access::class);
}
/**
* retrive access
*
* #return hasMany [description]
*/
public function accesses()
{
return $this->hasMany(App\Access::class, "user_id");
}
}
Weblog model:
class Weblog extends Model{
/**
* retrive users
*
* #return BelongsToMany users
*/
public function users()
{
return $this->belongsToMany(App\User::class,'accesses_table')
->withPivot("permission_id")
->using(App\Access::class);
}
/**
* retrive permissions
*
* #return BelongsToMany permissions
*/
public function permissions()
{
return $this->belongsToMany(App\Permission::class,'accesses_table')
->withPivot("user_id")
->using(App\Access::class);
}
/**
* retrive access
*
* #return hasMany [description]
*/
public function accesses()
{
return $this->hasMany(App\Access::class, "weblog_id");
}
}
Permission model:
class Permission extends Model{
/**
* retrieve users
*
* #return BelongsToMany users
*/
public function users()
{
return $this->belongsToMany(App\User::class,'accesses_table')
->withPivot("weblog_id")
->using(App\Access::class);
}
/**
* retrieve weblogs
*
* #return BelongsToMany weblogs
*/
public function weblogs()
{
return $this->belongsToMany(App\Weblog::class,'accesses_table')
->withPivot("user_id")
->using(App\Access::class);
}
/**
* retrive access
*
* #return hasMany [description]
*/
public function accesses()
{
return $this->hasMany(App\Access::class, "permission_id");
}
}
and you can have a model for your pivot, which i named it Access :
Illuminate\Database\Eloquent\Relations\Pivot;
class Access extends Pivot
{
public $incrementing = true;
public function user()
{
return $this->belongsTo(App\User::class);
}
public function weblog()
{
return $this->belongsTo(App\Weblog::class);
}
public function permission()
{
return $this->belongsTo(App\Permission::class);
}
}

How to use one model for multiple tables in laravel 5.6

I am looking for solutions, but can't really understand. I'm new in Laravel and I want a simple instruction on how to use one model for multiple tables like CodeIgniter as follows:
Controller myController:
public function shipBuilding()
{
$data = $this->input->post();
$response = $this->MyModel->shipbuildingSave($data);
}
public function contact()
{
$data = $this->input->post();
$response = $this->MyModel->contactSave($data);
}
Model MyModel:
public function shipbuildingSave($data){
$this->db->insert('tbl_shipbuilding', $data);
return $this->db->insert_id();
}
public function contactSave($data){
$this->db->insert('tbl_contact', $data);
return $this->db->insert_id();
}
This is not how models work in Laravel. each model should be a representation of one single table.
You could, however, change the table name on booting the model up:
class Flight extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'example';
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope(new AgeScope);
// Set the $this->table depending on some logic.
}
}
But again, this is probably not recommended for your case.

Laravel relationship 2 layers

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.

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