Laravel Belongsto many relationship with additional column - php

I have been facing a problem in my project. I have a belongsto many relation with additional field.
For example I have two table User and Social table and a pivot table named social_user. Here my user model is
public function socialinfos() {
return $this->belongsToMany(Social::class)->withPivot('id')->whereNull('deleted_at');
}
And my social_user table is
Schema::create('social_user', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id');
$table->string('social_id')->nullable();
$table->string('url')->nullable();
});
Here I my belongs to many relation has an additional url field which is submitted by user. When I want to add this information in my database it is not working well. It shows error
Array to string conversion (SQL: insert into `social_user` (`social_id`, `url`, `user_id`) values (2, jahid56, 9))
Here is What I tried
$user = Auth::user();
$speakers = $request->get('provider'); // related ids
$pivotData = array_fill(0, count($speakers), ['url' => $request->get('social')]);
$syncData = array_combine($speakers, $pivotData);
if ($request->get('provider')) {
$user->socialinfos()->sync($syncData);
} else {
$user->socialinfos()->sync([]);
}
Please help me solving this

I assume you have this:
Social <--> Social-User['id', 'social_id', 'user_id', 'url'] <--> User
In order to attach a Social to User you need could do this:
Auth::user()->socialInfos()->attach($social_id, ['url' => 'facebokk.com/user']);

Related

Laravel how to get User Profile field from separate table

I am new to Laravel and Eloquent is quite a challenge for me to understand. I have a User and a UserProfile model and table. UserProfile table has user_id (FK to user's id), 'key, and value fields.
I want to get the values of all the UserProfile fields associated with the user_id. Here is my code but nothing works. I am sure I am making some stupid mistakes but still learning :) Laravel.
UserProfile Model
class UserProfile extends Model
{
public $timestamps = FALSE;
protected $fillable = [
'user_id',
'key',
'value',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
User Model method
public function profileFields(){
return $this->hasMany(UserProfile::class);
}
UserProfile Migration
public function up()
{
Schema::create('user_profiles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned();
$table->string('key', 191);
$table->longText('value');
$table->foreign('user_id', 'user_profile_uid_fk')
->references('id')
->on('users')
->onDelete('cascade');
$table->unique(['user_id', 'key'], 'user_profile_unique_key');
});
}
I am trying to get the profile fields for the user using User::findOrFail(10)->profileFields but it is giving me property not defined exception.
Need Help: Can anyone help me to make it work so I can get all user_profiles
fields from the profile table?
Error Output (Tinker)
>>> User::findOrFail(10)->profileFields
Illuminate/Database/QueryException with message 'SQLSTATE[42S02]: Base
table or view not found: 1146 Table 'velvetpaper.user_user_profile'
doesn't exist (SQL: select user_profiles.*,
user_user_profile.user_id as pivot_user_id,
user_user_profile.user_profile_id as pivot_user_profile_id from
user_profiles inner join user_user_profile on user_profiles.id
= user_user_profile.user_profile_id where user_user_profile.user_id = 10)'
The relation between users and user_profiles is a one to many.
You might have not restarted Tinker since you are getting the wrong error, dont forget to exit Tinker after the modification in the code. Once tinker is started, code changes wont affect it.
you can use join to implement this stuff. like this...
this is query builder
$data['profile']=DB::table(usertable)
->where('usertable.id',$id)
->leftjoin('userprofiletable','usertable.id','=','userprofiletable.user_id')
->first();
return view('profile_view',$data)
//view
$profile->fullname
$profile->sex
$profile->phone
...

Laravel many to many relationship returning empty array

I'm trying to get the results using laravel many to many relationship but the query is generating wrong therefore it return empty array.
$user->survey()->get() is returning empty array.
$user->survey()->toSql() is returning wrong query:
SELECT
*
FROM
`survey`
INNER JOIN `survey_user` ON `survey`.`id` = `survey_user`.`survey_id`
WHERE
`survey_user`.`user_id` IS NULL
Here, in the end, the user_id should not be null.
Migration for the survey pivot table:
Schema::create('survey_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('survey_id')->unsigned();
$table->string('status', 50)->nullable();
$table->timestamps();
});
Schema::table('survey_user', function (Blueprint $table) {
$table->foreign('user_id')->on('users')->references('id');
$table->foreign('survey_id')->references('id')->on('survey')
->onDelete('cascade')
->onUpdate('cascade');
});
}
here are the two relation:
public function survey()
{
return $this->belongsToMany(Survey::class, 'survey_user')
->withPivot('status')
->withTimestamps();
}
public function user()
{
return $this->belongsToMany(User::class, 'survey_user')
->withPivot('status')
->withTimestamps();
}
I'm just trying to get all the users who have survey assigned in their pivot.
$user = new User();
var_dump($user->survey()->get());
I'm just trying to get all the users who have survey assigned in their pivot.
To get all Users where the survey relationship exists, your code would look like this:
$users = User::has('survey')->get();
If you need the survey relationship loaded on the models when you use them, then add with() to eager load the relationship:
$users = User::has('survey')
->with('survey')
->get();
Here, in the end, the user_id should not be null.
The reason it was searching with a null user id is because you are searching with a new User instance that hasn't been saved to the database. This is your code with the problem:
$user = new User();
var_dump($user->survey()->get());
Since $user is a new object that hasn't been saved to the database it doesn't have an id. When you call $user->survey() it builds a query to search survey_user where the user id is null.

Sync method won't work using many to many relationship Laravel 5.2

I'm trying to attach the array of items that I have in my form to my junction table. I already given all the values stored in my tables using foreach loop. I loop this all in my select list.
Retrieve all records in tables:
$resultRecipient = DB::table('users')->where('id', '!=', Auth::id())->get();
return view ('document.create')->with('resultRecipient', $resultRecipient);
Form:
<div class = "form-group">
<label for = "recipient_id" class = "control-label">To:</label>
<select name = "recipient_id[]" multiple class = "form-control" id = "myUserList">
#foreach ($resultRecipient as $list)
<option value = "{{ $list->id }}">{{ $list->username }}</option>
#endforeach
</select>
</div>
Migration:
users
-id
-username
-password
documents
-id
-title
-content
-category_id - FK
recipients_documents (junction table)
-id
-senderUserId - FK reference to users
-recipientUserId - FK reference to users
-docu_id - FK reference to documents
My Models:
Document
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Document extends Model
{
public function recipients()
{
return $this->belongsToMany('Models\User');
}
}
User:
<?php
namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
class User extends Model implements AuthenticatableContract
{
use Authenticatable;
public function documents()
{
return $this->belongsToMany('Models\Document');
}
}
DocumentController:
public function postDocuments(Request $request)
{
$this->validate($request,
[
'title' => 'required|alpha_dash|max:255',
'content' => 'required',
'category_id' => 'required',
'recipient_id' => 'required',
]);
$document = new Document();
//Request in the form
$document->title = $request->title;
$document->content = $request->content;
$document->category_id = $request->category_id;
$document->save();
$document->recipients()->sync($request->recipient_id, false);
return redirect()->back();
}
When I'm trying to attach the request in my form which is recipient_id but it error says. I just created a new folder in app named Models
Class 'Models\User' not found
Can anyone tell why I get this error? Any help would appreciated!
Cheers
UPDATE 1
I solved this error followed steps by #jaysingkar. But when I try to sync this after hitting the submit button it gives me a error.
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'webdev.document_user' doesn't exist (SQL: select user_id from document_user where document_id = 15)
But it insert in the document tables but in my juction table won't insert that I want to attach.
UPDATE 2
Thanks #jaysingkar and #mydo47 for the help and tips that you given. I already create document_user table (junction) I added a another Foreign Key which refenreces to users table.
Screenshot:
As you can see here I linked two foreign key in the junction table. I want to insert the current user that logged-in in the user_id column. I have a form here which loop through my database records except the id of the current user that logged in.
Form:
<div class = "form-group">
<label for = "recipient_id" class = "control-label">To:</label>
<select name = "recipient_id[]" multiple class = "form-control" id = "myUserList">
#foreach ($resultRecipient as $list)
<option value = "{{ $list->id }}">{{ $list->username }}</option>
#endforeach
</select>
Migration for junction table:
public function up()
{
Schema::create('document_user',function (Blueprint $table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('recipientUserId')->unsigned();
$table->integer('document_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('recipientUserId')->references('id')->on('users')->onDelete('cascade');
$table->foreign('document_id')->references('id')->on('documents')->onDelete('cascade');
$table->dateTime('dateReceived')->default(DB::raw('CURRENT_TIMESTAMP'));
});
}
Document Controller:
public function postDocuments(Request $request)
{
$this->validate($request,
[
'title' => 'required|alpha_dash|max:255',
'content' => 'required',
'category_id' => 'required',
'recipient_id' => 'required',
]);
$document = new Document();
//Request in the form
$document->title = $request->title;
$document->content = $request->content;
$document->category_id = $request->category_id;
$document->save();
$document->recipients()->sync($request->recipient_id, false);
return redirect()->back();
}
But when I try to submit it says. Is this valid that I can linked PK to two FK? I can insert the selected list in the document_user table but how can I insert the current user? Thanks for the help
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (webdev.document_user, CONSTRAINT document_user_recipientuserid_foreign FOREIGN KEY (recipientUserId) REFERENCES users (id) ON DELETE CASCADE) (SQL: insert into document_user (document_id, user_id) values (27, 10))
UPDATE 3
I already get rid of the error so I created a unsignedInteger this column where the current user id will insert name sender_id
Migration update:
Schema::create('document_user',function (Blueprint $table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('document_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('document_id')->references('id')->on('documents')->onDelete('cascade');
$table->unsignedInteger('sender_id')->nullable();
$table->foreign('sender_id')->references('id')->on('users')->onDelete('cascade');
$table->dateTime('dateReceived')->default(DB::raw('CURRENT_TIMESTAMP'));
});
I can get the id of the current user that logged in. But I'm thinking how can I insert the id based on the submit of the user.
DocumentController:
public function getDocuments()
{
//GETTING ALL THE ID OF THE USERS IN THE DATABASE EXCEPT THE ID OF CURRENT USER.
$resultRecipient = DB::table('users')->where('id', '!=', Auth::id())->get();
//GETTING ALL THE CATEGORIES.
$resultCategory = DB::table('categories')->get();
//VIEW
return view ('document.create')->with('resultRecipient', $resultRecipient)->with('resultCategory', $resultCategory);
if(\Auth::user()->id)
{
echo "You get the id";
}
else
{
echo "Failed";
}
}
Database Screenshot:
Along with #Marcin 's answer,
You would need to use "App\Models\User" instead of "Models\User"
public function recipients()
{
return $this->belongsToMany('App\Models\User');
}
Update for
Base table or view not found:
You would need document_user table to be present in DB in order to work with many-to-many relationship. The table must contain the document_id and user_id columns.
Laravel's documents have explained this here
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.
Add classmap in composer.json :
"classmap" : [
"database",
"app\Models"
]
Change in config\auth.php :
'model' => 'App\Models\User' ,
In User model :
namespace App\Models;
Update composer
Update
Create new table document_user with document_id FK to documents and user_id FK to users.
Fix function recipients():
return $this->belongsToMany('App\Models\User', 'document_user', 'document_id', 'user_id');
Fix function document() :
return $this->belongsToMany('App\Models\Document', 'document_user', 'user_id', 'document_id');
There might be many reasons for that, I would assume you moved User model into Models directory but you haven't changed namespace.
The beginning of file should look like this:
<?php
namespace App\Models;
class User
{
// ...

Laravel 5.1 How to map an array of ids onto their corresponding values in another table?

I have a table column which holds an array of subject ids selected by the user. There is another table for these subjects and their values. I need to return the values corresponding to the ids saved in the subjects column. To make it more clear suppose that a user have chosen 5 subjects out of 34 subjects and the corresponding ids are saved in the subjects column as a string like this: 2,5,11,21,23
Each of these numbers corresponds to the id of a subject in the subjects table.
//This is the subjects table
public function up()
{
Schema::create('subjects', function (Blueprint $table) {
$table->increments('id');
$table->string('subject', 20);
$table->timestamps();
});
}
//and this is the user_info table
public function up()
{
Schema::create('user_info', function (Blueprint $table) {
...
$table->string('subjects');
...
});
}
How can I return an array of subject values to a view?
// Find whichever user
$user = \App\User::find(1);
// Convert the string of subjects from a string to an array
$subjectIds = explode(',', $user->subjects);
// Load all subjects which match the ids within the subjectIds array
$subjects = \App\Subjects::whereIn($subjectIds)->get();
// Do something with the subjects
foreach($subjects as $subject) {
// Output the subject name
var_dump($subject->name);
}
After some searching around I found that maybe the best solution for my problem was to use the Many to Many relationship. So I removed the subjectscolumn from user_info table. Then I created the pivot table subject_user to save the id of user and their subjects ids in this table.
This is the pivot table schema:
Schema::create('subject_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->index();
$table->integer('subject_id')->index();
$table->timestamps();
});
Then in the User and Subject models I established the proper many to many relationship as follows:
//User Model
public function subjects()
{
return $this->belongsToMany('App\Subject')->withTimestamps();
}
//Subject Model
public function users()
{
return $this->belongsToMany('App\User');
}
Finally in the controller i used the attach() and sync() methods to populate or update the pivot table.
//In store method
$user->subjects()->attach($subjects);
//In update method
$user->subjects()->sync($subjects);
The difference between attach and syn is described here.

User Follow/Subscription Relationship Model In Laravel

I am trying to create a youtube style subscription model for my application. I've had small amounts of success so far, that being that you can follow other users and it stores who is following who in the database. However I am having trouble retrieving the list of people the current user is following.
The database:
users table (id, first_name, last_name, email, password, token, timestamps)
subscriptions Table (id, user_id, subscriber_id, timestamps)
user model:
public function subscriptions()
{
return $this->belongsToMany('App\User', 'subscriptions', 'user_id',
'subscriber_id')->withTimestamps();
}
public function subscribers()
{
return $this->belongsToMany('App\User', 'subscriptions', 'subscriber_id',
'user_id')->withTimestamps();
}
I am using this code to retrieve all of the current users subscriptions (aka who they are following)
$subscriber = Auth::user()->id;
$user = User::find($subscriber);
$userids = $user->subscriptions->lists('user_id');
return $userids;
Now, this code is currently returning a null value. On further investigation this makes sense as the query that is being run is incorrect
SQL Query:
select `user_id` from `users` inner join `subscriptions` on `users`.`id` = `subscriptions`.`subscriber_id` where `subscriptions`.`user_id` = 14
My current set up is trying to look for the wrong thing.
If user 1 follows users 2, 3 and 4 then my code should return 2, 3 and 4.
Can somebody please help correct my relationship set up or the code that I am running? It should be looking for the user_id in the subscriptions table based on the current users subscriber_ID.
Laravel 5.3 Eloquent Relationships
If you check the code at the end of the Many-to-Many relationships part, you will see this line of code.
return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
Here, we have the 'role_user' as the pivot (relationship) table, 'user_id' which is the foreign key in relationship table and primary key in user model, and 'role_id' is foreign key in relationship table and primary key in roles model.
So when you try to do this:
public function subscriptions()
{
return $this->belongsToMany('App\User', 'subscriptions', 'user_id',
'subscriber_id')->withTimestamps();
}
You are actually taking 'subscriber_id' as a foreign key in your relationship table and primary key for a subscriber. Since the function is trying to get the subscriptions, reaching to the subscriber id's won't do the work. This is why when you changed them they worked.
The result should look like this:
public function subscribers()
{
return $this->belongsToMany('App\User', 'subscriptions', 'user_id',
'subscriber_id')->withTimestamps();
}
public function subscriptions()
{
return $this->belongsToMany('App\User', 'subscriptions', 'subscriber_id',
'user_id')->withTimestamps();
}
So out of pure chance, I swapped the subscribers() and subscriptions() relationships about and it's now returning the correct data.. I don't understand why but it is definitely returning the ID's that I was expecting.
I'll keep the question open for now in case anyone with a clear solution answers.

Categories