Updating DB tables based on relationships Laravel 5.8 and Eloquent - php

I have a problem with updating tables that belongTo another table.
I have a users table and a recipes table. The Recipe model belongsTo the User model and the User model hasMany Recipe.
Each recipe is shown in my index view as a small card and on that card, as well as on each individual show page, I am printing recipe->author. When a recipe is created, it takes the username attribute from the users table and sets this as the author attribute on the recipes table. However, when I update the username of a user, the author attribute in the recipes table does not update accordingly.
User Model
public function recipes(){
return $this->hasMany('App\Recipe');
}
Recipe Model
public function user(){
return $this->belongsTo('App\User');
}
Can I possible add some logic in my UserController to account for this when I update a user?
UserController#update
$user = Auth::user();
$this->validate(request(), [
'name' => 'required',
'username' => 'required',
]);
// Handle File Upload
if(request()->hasfile('profile_pic')){
// Get filename with extension
$fileameWithExt = request()->file('profile_pic')->getClientOriginalName();
// Get just filename
$filename = pathinfo($fileameWithExt, PATHINFO_FILENAME);
// Get just extension
$extension = request()->file('profile_pic')->getClientOriginalExtension();
// Filename to store
$fileNameToStore = $filename . '_' . time() . '.' . $extension;
// Upload Image
$path = request()->file('profile_pic')->storeAs('public/profile_pictures', $fileNameToStore);
} else {
$fileNameToStore = 'noimage.jpg';
}
$user->name = request('name');
$user->username = request('username');
$user->description = request('description');
$user->location = request('location');
if(request()->hasFile('profile_pic')){
$user->profile_pic = $fileNameToStore;
}
$user->push();
$user_id = Auth::user()->id;
return redirect()->route('user', ['id' => $user_id]);
}
I have read the Laravel docs and can't find anything that will quite do what I am looking for. Would appreciate any guidance!

You mean you store username in users, and you want to store the exact username in the author of recipes?
Why not you just reference the name using relationship $recipe->user->username. It would query your users table based on your user_id in your recipes and get that username for you.
So that you're not storing duplicating data in your database. There should be only one Single Source of Truth. You can get your user data based on your user_id, there's no point to store another set of data and keep updating it when the source is changed.
If you find querying whole User model a bit of heavy, then you can use Recipe::with('users:id,username')->get() to query only the username.
Or
If you want to maintain the current $recipe->author, you can:
// Recipe class
public function getAuthorAttribute() {
return $this->user->username;
}

If you set up the foreign keys on your migration files, you may add the ->onUpdate('CASCADE') clause to the username foreign on the recipes table migration.
Note: the onCascade foreign constraint would work outside of Laravel too, as it relies only on the database engine's support for foreign keys.
Anyways, be careful with your validation as you have to be sure the new chosen username isn't already used by someone else.
Assuming your User model is connected to the users table and has an id primary key, make sure that you set the username column as unique in the database, and **validate* user input accordingly.
The former is done by editing once again your migration.
The latter is solved by modifying your rules like these ones:
// Do not forget the Rule import at the top of your controller
use Illuminate\Validation\Rule;
// Then in your method
$this->validate(request(), [
'name' => 'required',
'username' => [
'required',
Rule::unique('users', 'username')->ignore($user)
]
]);
Note: if you modify migrations you have to rerun them in order to apply the modification.

Related

How to add pivot table when inserting data to database in Laravel 8

maybe someone know how to insert pivot table in Laravel 8 automatically every i insert counselings table?
I have Model Counseling n to n Problem,
Input form
counselings table
problems table
Counselings Model
Problem Model
Controller
public function create()
{
return view('admin.counseling.create', [
'title' => 'Tambah Bimbingan dan Konseling',
'students' => Student::all(),
'problems' => Problem::all()
]);
}
public function find_nis(Request $request)
{
$student = Student::with('student_class', 'counselings')->findOrFail($request->id);
return response()->json($student);
}
public function store(Request $request)
{ dd($request->all());
$counseling = new Counseling();
$counseling->student_id = $request->student_id;
$counseling->user_id = Auth::user()->id;
$counseling->save();
if ($counseling->save()) {
$problem = new Problem();
$problem->id = $request->has('problem_id');
$problem->save();
}
}
You can insert into a pivot table in a few different ways. I would refer you to the documentation here.
Attaching
You may use the attach method to attach a role to a user by inserting
a record in the relationship's intermediate table:
Example:
$problem->counselings()->attach($counseling->id);
Sync
You may also use the sync method to construct many-to-many
associations. The sync method accepts an array of IDs to place on the
intermediate table. Any IDs that are not in the given array will be
removed from the intermediate table.
Example:
$problem->counselings()->sync($counselingsToSync);
Toggle
The many-to-many relationship also provides a toggle method which
"toggles" the attachment status of the given related model IDs. If the
given ID is currently attached, it will be detached. Likewise, if it
is currently detached, it will be attached:
Example:
$problem->counselings()->toggle($counselingsToToggle);
I would change your store() method to something like this :
public function store(Request $request)
{
$counseling = Counseling::create([
'student_id' => $request->student_id,
'user_id' => Auth::user()->id
]);
if($request->has('problem_id'){
$counseling->problems()->attach($request->problem_id);
//return something if problem id is in request
}
//return something if problem id is not there
}

How do I get the user id and using it to post new comment in the store method in laravel?

This code does not seem to capture the user id from the session so I can use it as a foreign key in the database for the place the user is adding a comment to.
public function store(Request $request, $place_id) {
// find place in the database
$place = Place::find($place_id);
// find user in the database
$user = User::find(\Auth::id());
// create review instance
$review = new Review([
'review' => request('review'),
'rating' => request('rating')
]);
// save review (creating relationship) in the places table as reviews
$place - > reviews() - > save($review);
// save review (creating relationship) in the users table as reviews
$user - > reviews() - > save($review);
$reviewData = Review::find($review - > id);
if (request() - > wantsJson()) {
return $reviewData; // Returns JSON, thanks to Laravel Magic™
}
// return view
return view('place');
}
When creating models for relationships, use create instead of save.
$user->reviews()->create($review);
The create method will associate the relevant relationship id.
I can see that you are saving the $review twice. Once in place_reviews and once in user_reviews. Consider changing your database logic, so reviews belongs to User and Place instead. This would be a lot more sensible structure:
Controller
$review = new Review([
'review' => request('review'),
'rating' => request('rating')
]);
$review->user()->associate($user);
$review->place()->associate($place);
$review->save();
Review model
public function user()
{
return $this->belongsTo(User::class);
}
public function place()
{
return $this->belongsTo(Place::class);
}
Review table
$table->unsignedInteger('user_id');
$table->unsignedInteger('place_id');
User and place model
public function reviews()
{
return $this->hasMany(Review::class);
}
You also have the option to use belongs to many relationships, if one Review could relate to multiple Place.
Another tip:
You may also consider using findOrFail to ensure your user is valid. This way your code will throw an Exception if there is no user id, as opposed to proceeding with a null user, which could be cause for hard-to-find errors.
$userId = \Auth::id();
$user = User::findOrFail($userId);
You should do like this.
$user = \Auth::user();
if(!is_null($user)){
$user_id = $user->id;
}

Inputing values into a database with Laravel 5.3

I can't for the life of me find info on how to do this despite my gut telling me its a basic fundamental.
I have a simple boolean that redirects users based on a table value reference_id. I want it to redirect the user after inputting a value in a column in that user's row.
Here is the code: (you can ignore the code I commeneted out. That's for a different implementation)
https://gyazo.com/9f2774cd9069b4678d67b80391f9f276
protected function redirectTo()
{
$id = Auth::id();
$rfid = DB::table('users')->where('id', $id)->value('reference_id');
//$userid = User::find($id);
if ($rfid == ''){
//$clientRole = DB::table('roles')->where('id', '2')->value('slug');
//$userid->attachRole($clientRole); // sets role based on redirect
input 'client' to database 'users' column 'temproles' //dummy code for what I want to do
view('/clientdirect');
}
else {
//$employeeRole = DB::table('roles')->where('id', '3')->value('slug');
//$userid->attachRole($employeeRole); // sets role based on redirect
input 'employee' to database 'users' column 'temproles'
view('/empdirect');
}
}
Again my apologies if this is common knowledge, I couldn't find a reference source anywhere. Either a link to where I can read about this or directions would be great!
If you want to input 'client' on a table called 'users' in a column 'temproles' you should be able to accomplish that by this:
DB::table('users')->insert(
['temprole' => 'client']
);
If you have models created you could do the following:
$user = new User
$user->temproles = 'client';
$user->save();

updating related tables from a controller laravel

Hi I’ve a users and education table. A user can have multiple school or college. So its one to many relationship. education table has school, from_year, to_year and user_id (fk) I want to update the user table as well as education table from a PUT request to users/{id} with email,school, from_year, and to_year fields.
// UsersController.php
public function update(Request $request, $id)
{
$user = User::find($id);
if (!$user) {
return $this->respondNotFound('User not found');
}
$input = $request->all();
$input = array_filter($input, 'strlen');
//$user->update($input);
//Get array of school records
// $user->educatoion->push($records) // don't know what will come here to update the education table
// or may be $user->push(); // don't know
return $this->respond([
'data' => $user,
]);
}
Try to keep it as simple as possible.
If this is your first time updating multiple tables at once, draw up a diagram of the process. This way you can identify the correct order of updates.
Take care to note any formatting that has to done on each value.
Laravel has some great functionality in regards to binding input to a model using ->update($data)
However, when binding to multiple models, you might run into issues with duplicate field names.
Update:
To create a education row from the $user model:
$education = new Education(array('school' => 'Harward', 'from_year' => 1999, 'to_year' => 2016));
User::find($id)->education()->save($education);

Creating an Eloquent Object with relation included

I'm pretty much new to opps and laravel both
So, to insert the values into my users and profiles table which hav OneToOne relationship, Here is how my store() method looks like
public function store(Requests\StoreNewUser $request)
{
// crate an objct of user model
$user = new \App\User;
// now request and assign validated input to array of column names in user table
$user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name');
$user->email = $request->input('email');
$user->password = $request->input('password');
/* want to assign request input to profile table's columns in one go
*/
$user->profile()->user_id = $user->id; // foreign key in profiles table
$user->profile()->mobile_no = $request->input('mobile');
dd($user); // nothing related to profile is returned
}
I'm creating the new record, hence dd() never returns anything related to profile table.
Is this Because the $user object is not including relationship by default?
If yes Can i create the $user object which includes the associated relations in User Model ?
Or do i have to create two separate objects of each table and save() the data But then what is the significance of push() method ?
EDIT 1
P.S. yes, the relationships are already defined in User & Profile model
You may try something like the following. At first save the parent model like this:
$user = new \App\User;
$user->first_name = $request->input('first_name');
// ...
$user->save();
Then create and save the related model using something like this:
$profile = new \App\Profile(['mobile_no' => $request->input('mobile')]);
$user->profile()->save($profile);
Also make sure you have created the profile method in User model:
public function profile()
{
return $this->hasOne('App\Profile');
}
I thought i'd update this answer and make it applicable to Laravel 5 onwards. I'll use #The Alpha answer as a basis.
$profile = new \App\Profile(['mobile_no' => $request->input('mobile')]);
$user->profile()->associate($profile); // You can no longer call 'save' here
$user->profile()->save();
The reason for this is you can no longer call save on the belongsTo relation (or any other), this now returns an instance of Illuminate\Database\Query\Builder.
The clean way to do it now would be having on your User Class file:
public function profile()
{
return $this->hasOne(App\Profile::class);
}
and in your User Controller, the following store method:
public function store(Requests\StoreNewUser $request)
{
$user = App\User::create(
$request->only(
[
'first_name',
'last_name',
'email'
]
)
);
$user->password = Illuminate\Support\Facades\Hash::make($request->password);
//or $user->password = bcrypt($request->password);
$user->profile()->create(
[
'mobile_no' => $request->mobile;
]
);
dd($user);
}
I didn know if u were saving plain text password to you database or using a mutator on password attribute, anyhow the suggested above is a good practice I think
Is this Because the $user object is not including relationship by default? If yes Can i create the $user object which includes the associated relations in User Model ?
Yes you should create the relationship, they're not included by default.
In your User model you'd want to do something like this:
public function profile()
{
return $this->hasOne('App\Profile'); // or whatever your namespace is
}
This would also require you to have a Profile model created.
This would definitely answer your questions regarding inserting related models: http://laravel.com/docs/5.1/eloquent-relationships#inserting-related-models
As The Alpha mentioned, and you also eluded to, I think you need to save your user model first then you can add via relationship.

Categories