Using with() and find() while limiting columns with find cancels relation data - laravel

I have the following code that displays different data depending on if you are the authenticated user looking at your own data or if you are looking at data from another user. The code works but in my opinion is very nasty.
public function showUserDetailed(Request $request, $username)
{
$key = strtolower($username).'-data-detailed';
if(Auth::user()->usenrame === $username) {
$key = $key .'-own';
}
if(Cache::has($key)) {
if($request->wantsJson()) {
return request()->json(Cache::get($key));
} else {
return view('user/detailed', ['user' => Cache::get($key)]);
}
} else {
if(Auth::user()->username === $username) {
$u = User::where('username', $username)->first();
$user = new \stdClass();
$user->username = $u->username;
$user->email = $u->email;
$user->address = $u->address;
$user->city = $u->city;
$user->state = $u->state;
$user->zip = $u->zip;
$user->phone = $u->phone;
$user->follows = $u->follows;
$user->ratings = $u->ratings;
$user->location = $u->location;
} else {
$u = User::where('username', $username)->first(['username', 'city', 'state']);
$user = new \stdClass();
$user->username = $u->username;
$user->city = $u->city;
$user->state = $u->state;
$user->follows = $u->follows;
$user->ratings = $u->ratings;
}
Cache::put($key, $user);
if($request->wantsJson()) {
return response()->json($user);
} else {
return view('user/detailed', ['user' => $user]);
}
}
}
I have tried to use something similar to the following in the model calls.
User::where('username', $username)->with('follows', 'ratings', 'location')->find(['username', 'city', 'state');
However when I specify the columns to get from the user table it negates the relation data so it comes back as empty arrays. Is there a different way I can do this which would be cleaner? I despise having to create a stdClass to be a data container in this situation and feel I may be missing something.
// this works
User::where('username', $username)->with('follows', 'ratings', 'location')->first();
// this also works
User::where('username', $username)->first(['username', 'city', 'state']);
// this does not
User::where('username', $username)->with('follows', 'ratings', 'location')->first(['username', 'city', 'state']);

When you specify columns and want to get the related models as well, you need to include id (or whatever foreign key you're using) in the selected columns.
The relationships execute another query like this:
SELECT 'stuff' FROM 'table' WHERE 'foreign_key' = ($parentsId)
So it needs to know the id of the parent (original model). Same logic applies to all relationships in a bit different forms.

Related

Laravel 6 - validate unique, ignore on two conditions - same user and name. Also $this->id is null on update

I have the following rule so far.
$rules['name'] = [
'required',
'string',
'min:3',
'max:255',
Rule::unique('user_templates', 'name')->ignore($this->id),
];
Users can create records, but all his records must have a unique name (other users can have records with the same name). How can I do this? Also, $this->id on update is always null. What am I doing wrong?
Controller
public function update(UserTemplatesRequest $request, $slug)
{
try {
$model = UserTemplates::where('slug', XSS::clean($slug))
->firstOrFail();
} catch (ModelNotFoundException $err) {
return redirect()->action('UserTemplatesController#index');
}
$data = $request->validated();
if ($model->updateTemplate(XSS::clean($data, ['file']), $request)) {
$message = "There was an error, please try again";
$action = 'index';
$id = '';
} else {
$message = "Category Updated";
$action = 'edit';
$id = $model->id;
}
return redirect()->action("CategoriesController#{$action}", [$id])
->with('message', $message);
}
According to your Rule you can try and use a where clause to narrow it down to one user and not whole project like:
Rule::unique('user_templates', 'name')->where(function (Builder $query) {
return $query->where(
'user_id', '=', $this->user()->id;
})
user_id is the column inside your user_templates table that works as a foreign key with your users table.
About $this->id it should be $this->user()->id to retrieve your user id

How to properly update a array that has only one identifying id

I'm trying to update an array with objects inside something like this, with the current code I have it only saves the first one, I know that's the problem but I don't know how to fix it
array (
0 =>
array (
'option' => 'new',
),
1 =>
array (
'option' => 'ewrwer',
),
),
This is my current code, the line in question is
$option = SurveyQuestionOption::where('survey_question_id', $preg->id)->first();
How do I fix this so it cycles through all in the array questionOptions instead of just the first one? I tried ->get() but then the ->save() doesn't work.
public function update(Request $request, $id)
{
DB::beginTransaction();
$preg = SurveyQuestion::findOrFail($id);
$preg->question = $request->question;
$preg->survey_section_id = $request->survey_section_id;
$preg->response_type_id = $request->response_type_id;
$preg->optional = $request->optional;
$preg->save();
$ids = [];
if ($request->get('questionOptions')) {
foreach ($request->get('questionOptions') as $item) {
$option = SurveyQuestionOption::where('survey_question_id', $preg->id)->first();
if (empty($option)) {
$option = new SurveyQuestionOption();
$option->survey_question_id = $preg->id;
}
$option->option = $item['option'];
$option->save();
}
}
if (count($ids) > 0) {
SurveyQuestionOption::whereNotIn('id', $ids)->where('survey_question_id', $preg->id)->delete();
}
DB::commit();
return back();
}
Basically, when you use get, you get a collection, so you can't really use save on it. you need to do a foreach loop, and save in that. i.e; like this;
$options = SurveyQuestionOption::where('survey_question_id', $preg->id)->get();
foreach($options as $option){
if (empty($option)) {
$option = new SurveyQuestionOption();
$option->survey_question_id = $preg->id;
}
$option->option = $item['option'];
$option->save();
}
Note that you can't save $options if you don't use a foreach loop, as you're not specifying which instance of the collection to save it in.

Single column not being updated in laravel 5

I am tying to update a single column of a table messages and I have the following code:
public function messageSeen(Request $request){
$data = Message::find($request->id);
$success = Message::where('id', $request->id)->update(array('is_seen' => 1));
if($success){
return response()->json(['status'=>'success'], 200);
} else {
return response()->json(['status'=>'Data not updated'], 404);
}
}
I am getting the response Data not updated. If you question, does the column is_seen exists? then yes it does. Even I tried fetching the data having id $request->id, it gives the proper data. I wonder why is the data not being updated? Am I doing right thing to update column or is there an way out to update column in different way?
I tried the other way like the following:
public function messageSeen(Request $request){
$id = $request->id;
$result = Message::find($id);
dd($result->message);
$data = array();
$data['is_seen'] = 1;
$data['message'] = $result->message;
$data['user_id'] = $result->user_id;
$data['conversation_id'] = $result->conversation_id;
$this->messages->fill($data);
$success = $this->messages->save();
if($success){
return response()->json(['status'=>'success'], 200);
} else {
return response()->json(['status'=>'Data not updated'], 404);
}
}
But here I am getting unexpected thing with this method. Here I am being able to do dd($result) and being able to get data like this:
#attributes: array:9 [
"id" => 22
"message" => "How are you?\r\n"
"is_seen" => 0
"deleted_from_sender" => 0
"deleted_from_receiver" => 0
"user_id" => 2
"conversation_id" => 1
"created_at" => "2019-09-29 03:42:39"
"updated_at" => "2019-09-29 03:42:39"
]
however, if I tried to do dd($result->message) then I get null! What am I doing wrong?
I tried the following code:
public function messageSeen(Request $request){
$id = $request->id;
$result = Message::find($id);
$data = array();
$data['is_seen'] = 1;
$data['message'] = $result[0]['message'];
$data['user_id'] = $result[0]['user_id'];
$data['conversation_id'] = $result[0]['conversation_id'];
$this->messages->fill($data);
$success = $this->messages->save();
if($success){
return response()->json(['status'=>'success'], 200);
} else {
return response()->json(['status'=>'Data not updated'], 404);
}
}
and it worked but instead of updating it is adding new column when the message is seen. But first I don't understand why do I have to do $result[0]['key'] in the first place.
You need to specify which fields in your table can be mass assigned, by adding or updating the $fillable property of your model:
protected $fillable = [..., 'is_seen', 'message', ...];
This is required for the create() and update() methods, as those accept "mass" variables in the array you pass in. Whereas with save() you have to manually, explicitly, assign the properties on the model, so there is no risk of accidentally saving something you didn't mean to. And this is exactly the behaviour you are seeing - update() is not working, but save() is.
You should try this
public function messageSeen(Request $request) {
$input = Request::all();
$data = Message::find($input['id']);
if (!empty($data)) {
$update = array();
$update['is_seen'] = 1;
$success = Message::where('id', $input['id'])->update($update);
if ($success) {
return response()->json(['status' => 'success'], 200);
} else {
return response()->json(['status' => 'Something went wrong'], 400);
}
} else {
return response()->json(['status' => 'Data not updated'], 404);
}
}
Value depends on data type of is_seen are string or integer

error while update method on boolean

I am trying to update method in Laravel but error is:
"Call to a member function tradereason() on boolean"
I also check same question of other people asked but there're a lot of different in my process. I have lot tables.
let me show you my create code and update method coding.
Create method code:
public function store(Request $request)
{
$tradeID= Auth::user()->trade()->create($input);
$input = $request->all();
$reasons = $request->input('reason');
//Loop for creating KEY as Value
$data = [];
foreach($reasons as $key => $value) {
$data[] = ['reason_id' => $value];
};
if( $data > 0 ) {
foreach ($data as $datum) {
$tradeID->tradereason()->save(new TradeReason($datum));
}
}
}
this is my tring code for update method:
public function update(Request $request, $id)
{
$tradeID= Auth::user()->trade()->whereId($id)->first()->update($input);
$input = $request->all();
$reasons = TradeReason::whereId($id)->first();
$reasons->update($input);
$reasons->tradereason()->sync($request->input('reason'));
$data = [];
foreach($reasons as $key => $value) {
$data[] = ['reason_id' => $value];
};
if( $data > 0 ) {
foreach ($data as $datum) {
$tradeID->tradereason()->whereId($id)->first()->update($datum);
}
}
}
update returns a boolean. So, don't overwrite $tradeID with the results of update.
$tradeID = Auth::user()->trade()->whereId($id)->first();
$tradeID->update($input);
Calling update on the Builder returns an 'int'. Calling update on the Model returns a 'bool'. They don't return Model instances.
// bool
$tradeID= Auth::user()->trade()->whereId($id)->first()->update($input);
The model instance would be what is returned from the first call:
$tradeID = Auth::user()->trade()->whereId($id)->first(); // assuming it finds a record
You can update that, you can use it in the foreach loop.

updateExistingPivot() not working

I'm trying to update a pivot table like this:
public function updatePermission($id, $permissionId)
{
$permissionValue = Input::get('value');
$user = User::find($id);
$perms = ['value' => $permissionValue];
$user->permissions()->updateExistingPivot($permissionId, $perms);
}
This pivot has been previously created with:
public function attachPermission($id)
{
$permissionId = Input::get('id');
$permissionValue = Input::get('value');
$user = User::find($id);
if (!$user->permissions->contains($permissionId)) {
$user->attachPermissionById($permissionId);
$perms = ['value' => $permissionValue];
$user->permissions()->updateExistingPivot($permissionId, $perms);
} else {
return Response::json(array('error' => 'Permission ' . $permissionId . ' is alreay set for user ' . $user->id));
}
return Response::json(array('role' => User::with(['roles.permissions', 'permissions', 'students'])->find($user->id)));
}
When the updatePermission() method is hit, it passes fine, but it doesn't update the pivot table with the new value. What am I doing wrong here?
I won't tell you why it doesn't work, but I suggest you do this:
public function attachPermission($id)
{
$permissionId = Input::get('id');
$value = Input::get('value');
$user = User::find($id);
$sync = $user->permissions()->sync([$permissionId => compact('value')], false);
return (in_array($permissionId, $sync['updated']))
? Response::json(...) // permission updated
: Response::json(...); // permission added
}
It will add or update new permission for you.

Resources