Write to hasMany relationship with Eloquent ORM/Laravel - laravel

Question about Laravel's Eloquent ORM. I've had a look on SO already, apologies if I've missed a similar question.
I have a User model, and I'm trying to write an array of Permissions back to the UserPermissions model, via the relationship in the User model.
I've setup the hasMany link already, and can retrieve the correct data from the User object ($user->roles), but can't work out how to write back if it is at all possible.
This is my basic user model:
class User extends Eloquent {
protected $table = 'users';
public $timestamps = false;
protected function roles() {
return $this->hasMany('UserPermission');
}
}
and the UserPermission model:
class UserPermission extends Eloquent {
protected $table = 'users_permissions';
public $timestamps = false;
protected $fillable = ['role_id', 'user_id'];
}
At this stage, I've reverted to saving the User, and then running UserPermission::insert(), which allows an array to be passed, but I'd prefer to do it in one step if possible.
Anyone know if this is possible?
Thanks!
UPDATE:
Table structure is below for your perusal:
users table
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | 0 | auto_increment |
| username | varchar(255) | NO | | | |
+------------------+------------------+------+-----+---------+----------------+
users_roles table
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | 0 | auto_increment |
| name | varchar(255) | NO | | | |
| description | varchar(255) | YES | | NULL | |
| url_access | varchar(255) | NO | | | |
+------------------+------------------+------+-----+---------+----------------+
users_permissions table
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | 0 | auto_increment |
| role_id | int(10) unsigned | NO | | | |
| user_id | int(10) unsigned | NO | | | |
+------------------+------------------+------+-----+---------+----------------+
role_id relates to users_roles.id and user_id relates to users.id
As background logic, the users_roles table has a url_access column which contains a url. If the user is assigned to that role, they have access to the subpages from that url.

I do not really see why you are using hasMany relationship instead of belongsToMany. Actually it seems that your database structure is already such that is utilized by the belongsToMany relationship in Laravel.
My solution:
User.php
<?php
class User extends Eloquent {
public function roles() {
return $this->belongsToMany('Role');
}
protected $table = 'users';
protected $guarded = array('id', 'password');
}
Role.php
<?php
class Role extends Eloquent {
public function users()
{
return $this->belongsToMany('User');
}
protected $table = 'roles';
protected $guarded = array('id');
}
The corresponding database tables should be: users, roles and role_user. These are according to Laravel's naming conventions in order to keelp things simple.
Now you may call the sync method and pass an array to it:
$user->roles()->sync(array(1, 2, 3));
The sync method is briefly described in the Eloquent ORM documentation.

Okay here is what you could try.
Define a many to many relationship in both of the models.
class UserPermission extends Eloquent {
protected $table = 'users_permissions';
public $timestamps = false;
protected $fillable = ['role_id', 'user_id'];
protected function users() {
return $this->belongsToMany('User');
}
}
Then, if you create a user, use laravel attach method to connect a user to a users_permission like so:
$user = User::find(1);
$user->roles()->attach(1);
Attaching the role with an ID of 1 to the user with an ID of 1.
This is how you will be able to either attach a role to a user or attach a user to a role if you are creating a user or updating one.
I really hope that this is of help to you. If not, feel free to ask me further. I have defined many to many relations just a few days ago with photos and tags so I am quite into it I would say.
Also, the laravel docs even have an example with users and roles:
http://laravel.com/docs/eloquent#many-to-many

From reading your question it "sounds like" you are asking the same question I ran into the other day.
I hope this helps enable to you "bulk update" the relationships while maintaining timestamps and avoiding duplicate relationships.
Maybe there is a better way. I'm sure of it. But this worked perfectly for what I was trying to accomplish.
*Warning: this is not tested code. In fact the exact solution I used myself with some search/replace to help relate to your question
Class User extends BaseModel {
// [...]
public function roles() {
return $this->belongsToMany('Role');
}
public function addUserRoles(Array $add_user_role_ids) {
/**
* Prevent Duplicate Relationships
*/
$existing_user_role_ids = $this->roles()->lists('user_role_id');
$add_user_role_ids = array_diff($add_user_role_ids, $existing_user_role_ids);
if ($add_user_role_ids == null) return false;
$add_user_role_ids = UserRole::whereIn('id', $add_user_role_ids)->lists('id');
if ($add_user_role_ids == null) return false;
/**
* Attach (Insert into Pivot Table)
*/
if ( count($add_user_role_ids) > 0 ) {
$this->UserRoles()->attach($add_user_role_ids);
// Update timestamp
$this->touch();
}
// Return successfully added user role ids Array
return $add_user_role_ids;
}
public function removeUserRoles(Array $user_role_ids)
{
$this->touch();
$this->roles()->detach($user_role_ids);
}
// [...]
}
Eloquent Docs
Find me on Twitter: #ErikOnTheWeb

Related

laravel eloquent relation problems belongsToMany 3 Models in pivot table

I have a case with several models. Order Model, Product Model, Port Model, and Logistic Model.
With an Order belongsTo Many Products, Order Belongs To Port with 'to_port_id' ,Order Belongs To Logistic with 'logistic_id', Product belongs To Port with 'from_port_id',
from_port_id , to_port_id ,logistic_id and unit_price combined with a pivot table .
And now I want to ask. How to retrieve an order with different products with corresponding from_port_id,to_port_id,logistic_id to get different unit_price with the eager load as little sql as possible?
Order Model
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| to_port_id | int(11) | NO | | NULL | |
| logistic_id | int(11) | NO | | NULL | |
+--------------+-------------+------+-----+---------+----------------+
Product Model
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| from_port_id | int(11) | NO | | NULL | |
+--------------+-------------+------+-----+---------+----------------+
LogisticPort PivotModel
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+----------------+
| from_port_id | int(11) | NO | PRI | NULL | |
| to_port_id | int(11) | NO | PRI | NULL | |
| logistic_id | int(11) | NO | PRI | NULL | |
| unit_price | decimal(11) | NO | | NULL | |
+--------------+-------------+------+-----+---------+----------------+
----------update -------------------------
class Product extends Model
{
protected $table = 'product';
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function orderTransact(){
return $this->belongsToMany('App\Models\OrderTransact','order_transact_product','product_id','order_transact_id')->withPivot(['unique_order_product_id','order_quantity_in_log','order_product_status_id ','confirmed_delivery_date','expected_ETD','due_at','downpayment','deposit','total','feedback','created_at','updated_at','tracking_no','weight','logistic_cost'])->using('App\Models\OrderTransactProduct')->as('order_product');
}
public function orderProduct(){
return $this->hasMany('App\Models\OrderTransactProduct','product_id','id');
}
public function fromLogisticPort(){
return $this->belongsTo('App\Models\LogisticPort','from_port_id','id');
}
}
class LogisticPort extends Model
{
use HasFactory;
protected $table = 'logistic_port';
public function logisticFrom(){
return $this->belongsToMany('App\Models\Logistic','logistic_port_logistic','from_port_id','logistic_id')->withPivot(['to_port_id','courier_charges_unit'])->using('App\Models\LogisticPortLogistic');
}
public function logisticTo()
{
return $this->belongsToMany('App\Models\Logistic','logistic_port_logistic','to_port_id','logistic_id')->withPivot(['from_port_id','courier_charges_unit'])->using('App\Models\LogisticPortLogistic');
}
public function logisticPortFrom(){
return $this->belongsToMany('App\Models\LogisticPort','logistic_port_logistic','to_port_id','from_port_id')->withPivot(['logistic_id','courier_charges_unit'])->using('App\Models\LogisticPortLogistic');
}
public function logisticPortTo(){
return $this->belongsToMany('App\Models\LogisticPort','logistic_port_logistic','from_port_id','to_port_id')->withPivot(['logistic_id','courier_charges_unit'])->using('App\Models\LogisticPortLogistic');
}
public function toPivotLogisticPort(){
return $this->hasMany('App\Models\LogisticPortLogistic','to_port_id','id');
}
public function product(){
return $this->hasMany('App\Models\Product','from_port_id','id');
}
public function orderTransact(){
return $this->hasMany('App\Models\OrderTransact','from_port_id','id');
}
}
class Logistic extends Model
{
protected $table = 'logistic';
public function orderTransact(){
return $this->hasMany('App\Models\OrderTransact','order_transact_id','id');
}
public function logisticPortFrom(){
return $this->belongsToMany('App\Models\LogisticPort','logistic_port_logistic','logistic_id','from_port_id')->withPivot(['to_port_id','courier_charges_unit'])->using('App\Models\LogisticPortLogistic');
}
public function logisticPortTo(){
return $this->belongsToMany('App\Models\LogisticPort','logistic_port_logistic','logistic_id','to_port_id')->withPivot(['from_port_id','courier_charges_unit'])->using('App\Models\LogisticPortLogistic');
}
}
class OrderTransact extends Model
{
use HasFactory;
use SoftDeletes;
protected $table = 'order_transact';
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function logistic(){
return $this->belongsTo('App\Models\Logistic','logistic_id','id');
}
public function product(){
return $this->belongsToMany('App\Models\Product','order_transact_product','order_transact_id','product_id')->withPivot(['unique_order_product_id','order_quantity_in_log','order_product_status_id','confirmed_delivery_date','expected_ETD','due_at','downpayment','deposit','total','feedback','created_at','updated_at','tracking_no','weight','logistic_cost'])->using('App\Models\OrderTransactProduct')->as('order_product');
}
public function orderProduct(){
return $this->hasMany('App\Models\OrderTransactProduct','order_transact_id','id');
}
public function toLogisticPort(){
return $this->belongsTo('App\Models\LogisticPort','to_port_id','id');
}
}

how can i get around this belongsToMany pivot error

i have the following relationship for a belongsToMany relationship
Table:| users | forums |forum_user (pivot table)
| id | id | id
| name | name | user_id
| email | | forum_id
| | |
and have defined the following relationships
pubic function forums() {
return $this->belongsToMany(Forum::class);
}
on the user model and
pubic function forums() {
return $this->belongsToMany(Forum::class);
}
on the forum model
now when i try to do this
User::first()->forums()->get()
it returns the error
Symfony\Component\Debug\Exception\FatalErrorException
Type of Illuminate\Database\Eloquent\Relations\Pivot::$ must be array (as in class
Illuminate\Database\Eloquent\Model)
how can i get around this error
i'm currently using laravel 6 in my project
try this:
User::first()->forums->get();
And maybe rewrite the relation on User model to:
return $this->belongsToMany(Forum::class, 'forum_user', 'user_id', 'forum_id');
On the forum model shouldnt relation reflect user?
pubic function forums() {
return $this->belongsToMany(Forum::class);
}
Shouldnt this be
pubic function users() {
return $this->belongsToMany(User::class);
}

How to GroupBy in Relationship?

I have post table
| ID | TITLE | SLUG | CONTENT | COMMENTS_COUNT |
and i have post_reactions table
| ID | USER_ID | TYPE | POST_ID |
I want to make a relationship that what reactions that post have
You can directly do it by model.
public function postrelation()
{
return $this->hasMany(PostRelation::class)->groupBy('type');
}
Or
Post::with(['postrelation' => function($q){
$q->groupBy('type');
}])->get();
You can use callback function for grouping your relations describe at below.
Post::with(['post_reactions' => function($query){
$query->groupBy('TYPE');
}])->get();
You can make relation with the help of follwing syntax in the Model Class
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
/**
* Get the phone record associated with the user.
*/
public function phone(){
return $this->hasOne('App\Phone');
}
}

Laravel 5.2 relationships: Trying to get property of non-object

I have two models: Term and Post.
The Term model represents both categories and tags.
A post can belong only to a category and it can have many tags (I use the same db table for categories and tags).
class Term extends Model
{
protected $table = 'mydb_terms';
public $timestamps = true;
public function getRouteKeyName() {
return 'slug';
}
public function posts(){
return $this -> hasMany('Post');
}
}
class Post extends Model
{
use SoftDeletes;
protected $table = 'mydb_posts';
public $timestamps = true;
public function category(){
return $this -> belongsTo('Term','mydb_posts_terms', 'post_id', 'term_id')
-> withPivot('order') -> withTimestamps() -> where('type','category');
}
public function tags(){
return $this -> hasMany('Term') -> where('type','tag');
}
}
In the CategoryController I have:
class CategoryController extends Controller
{
public function getPostsOfCategory($id)
{
$posts = Term::find($id)->posts->get();
}
public function getPostsOfAllCategories()
{
//
}
}
When I try to retrieve the posts of category event with slug event (in the db the category and one post in it exist, and also the corresponding row in mydb_posts_terms) I obtain
Trying to get property of non-object
EDIT
I tried both $posts = Term::find($id)->posts()->get(); by obtaining Call to a member function and $posts = Term::find($id)->posts; by obtaining the same Trying to get property of non-object.
In the db I have:
Table mydb_terms:
| id | name | slug | type | created_at | updated_at
| 1 | event | event | category | 2016-07-01 18:00:00| 2016-07-01 18:00:00
Table mydb_posts:
| id | title | content | created_at | updated_at
| 1 | A title | a content | 2016-07-04 17:20:12| 2016-07-04 17:20:12
Table mydb_posts_terms:
| post_id | term_id | order | created_at | updated_at
| 1 | 1 | 0 | 2016-07-06 14:13:43| 2016-07-06 14:13:43

Laravel 4.2.8 > many to many > create a new related model and attach > error

don´t get it why this error occurs when inserting a new zip-code and relate it to an existing company using laravels eloquent belongsToMany feature.
here is my setup:
Error
file: "...\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php"
line: 411
message: "postcode"
type: "Illuminate\Database\Eloquent\MassAssignmentException"
Insertcode
$postcode = new Postcode(array('postcode' => $data['plz']));
Company::find($data['id'])->postcodes()->save($postcode);
Company Model
class Company extends Eloquent {
public function postcodes()
{
return $this->belongsToMany('Postcode');
}
}
Postcode Model
class Postcode extends Eloquent {
public function companies()
{
return $this->belongsToMany('Company');
}
}
Table postcodes
| id | postcode |
Table company_postcode
| id | postcode_id | company_id |
Table companies
| id | name |
Does anybody know why this isn´t working?
The error says
MassAssignmentException
That is because you are trying to mass assign postcode
new Postcode(array('postcode' => $data['plz']));
So make sure you whitelist the postcode variable as being mass assignable
class Company extends Eloquent {
protected $fillable = array('postcode');
public function postcodes()
{
return $this->belongsToMany('Postcode');
}
}

Resources