Targeting one row, not all that has a certain value - laravel

I have a basic adding system, that allows landlords to add tenants, and tenants then have the ability to accept/reject. Accepting is very simple, when the tenant clicks accept, the accept boolean changes to 1. At the moment this is changeing all rows to accepted, not just the one between the landlord and tenant.
This is an example row in the database:
If a tenant clicks accept, the accepted row will change to 1, and request sent will revert to 0. The users are now connected.
However, all rows that have accepted = 0, and request = 1, will be affected, not just the current row.
This is the accepted controller
public function accept(Request $request)
{
Tenancy::where('accepted', 0)
->where('request_sent', 1)
->where('tenant_id', Auth::id())
->update([
'accepted' => 1,
'request_sent' => 0,
]);
return back();
}
Any ideas?
EDIT
Route URL
Route::post('/account/tenancy/{id}/accept', 'AccountController#accept')->middleware('auth');
Entire form and logic for accept/reject
#if($currentUser->userType == "Tenant")
#if($tenancy == null ||$tenancy->accepted == 0 && $tenancy->request_sent == 1 && $tenancy->tenant_id == $currentUser->id)
<form method="POST" action="/account/tenancy/{{$user->id}}/accept">
{{ csrf_field() }}
<input type="submit" class="btn btn-primary" value="Accept Request">
</form>
<form method="POST" action="/account/tenancy/{{$user->id}}/reject">
{{ csrf_field() }}
<input type="submit" class="btn btn-warning" value="Reject Request">
</form>
#endif
dd($tenancy)

Based on your comments/recent edits, i believe this should work:
Change all
action="/account/tenancy/{{$user->id}}/accept"
to
action="/account/tenancy/{{$tenancy->id}}/accept"
and your accept/reject methods in the controller like this:
public function accept(Request $request, string $id)
{
Tenancy::find($id)
->update([
'accepted' => 1,
'request_sent' => 0,
]);
return back();
}

You are missing another where. You are just filtering for the two statuses and the tenant_id, but you want to filter by the landlord_id aswell.
Something like Tenancy::where('accepted', 0)->where('request_sent', 1)->where('tenant_id', Auth::id())->where('landlord_id', $id);.
However, what happens, if there are two tenancies between a landlord and a tenant? You probably want to pass the tenancy id in the request and retrieve the tenancy in your accept function by the id. Important thing to keep in mind here is to make sure, that the current user is allowed to accept the tenancy with the id he passed.
Edit based on your new code in the question:
This would be the approach of my recommendation, not the additional landlord_id.
<form method="POST" action="/account/tenancy/{{$tenancy->id}}/accept">
{{ csrf_field() }}
<input type="submit" class="btn btn-primary" value="Accept Request">
</form>
public function accept(Request $request, $id)
{
Tenancy::find($id)
->update([
'accepted' => 1,
'request_sent' => 0,
]);
return back();
}
You should still keep in mind, that an authorization/check would be needed.

Related

Laravel 9 how to pass parameter in url from one controller to another controller?

I was facing this problem of missing parameter when trying to pass a parameter from one controller to another controller. The parameter is $id whereby the data is originally from post method in details blade.php into function postCreateStepOne However, I want to pass the data into a new view and I return
redirect()->route('details.tenant.step.two')->with( ['id' => $id]
);}
And this is where error occur. However, it works fine if I skip it into a new route and directly return into a view with the compact parameter. For Example,
return view('document.details-step-two', compact('id', 'property'));
However, I would prefer a new url as I was doing multistep form using Laravel.
Error
web.php
Route::get('/document/details/viewing/{id}', 'ViewDetails')->name('details.tenant');
Route::post('/document/details/viewing/{id}', 'postCreateStepOne')->name('post.step-one');
Route::get('/document/details/viewing/step-2/{id}', 'ViewDetailsStep2')->name('details.tenant.step.two');
TenanatController.php
public function viewDetails($id){
$view = Properties::findOrFail($id);
return view('document.details', compact('view'));
}
public function ViewDetailsStep2(Request $request, $id){
$view = Properties::findOrFail($id);
$property = $request->session()->get('property');
return view('document.details-step-two', compact('view', 'property'));
}
public function postCreateStepOne($id, Request $request)
{
$validatedData = $request->validate([
'property-name' => 'required',
]);
if(empty($request->session()->get('property'))){
$property = new Tenancy();
$property->fill($validatedData);
$request->session()->put('property', $property);
}else{
$property = $request->session()->get('property');
$property->fill($validatedData);
$request->session()->put('property', $property);
}
return redirect()->route('details.tenant.step.two')->with( ['id' => $id] );
}
details.blade.php
<form action="{{ route('post.step-one', $view->id) }}" method="POST">
#csrf
<div class="card-body">
<div class="form-group">
<label for="title">Property Name:</label>
<input type="text" value="" class="form-control" id="property-name" name="property-name">
</div>
</div>
<div class="card-footer text-right">
<button type="submit" class="btn btn-primary">Next</button>
</div>
</form>
When you use with on a redirect the parameter is passed through the session. If you want to redirect to a route with a given route parameter you should pass that parameter in the route function itself like e.g.
return redirect()->route('details.tenant.step.two', ['id' => $id]);

Laravel stop render Livewire before length is less than 2 characters

I have an input in Laraval Livewire for searching in a model and show the results immediately.
I want 2 way data binding. so I've used wire:model:
<input type="text" wire:model="query">
but the problem is I want to start sending requests after the user entered the third character.
I know we have wire:model.debounce.1000ms but it's not useful for me. because it will start sending a request after 1000 millisecond that we stopped typing.
I know we have wire:model.lazy but it will start sending a request after we clicked another place or unfocused from the current element.
UPDATED
As I mentioned before it is better to use a submit button for that action
another way which I didn't tried it yet is , (try one of them)
class SearchPosts extends Component
{
public $search = '';
protected $queryString = [
'search' => ['except' => fn() => count($this->search) < 3],
//'search' => ['except' => fn($value) => count($value) < 3],
];
public function render()
{
return view('livewire.search-posts', [
'posts' => Post::where('title', 'like', '%'.$this->search.'%')->get(),
]);
}
}
Component
<div>
<input wire:model.debounce="search" type="search" placeholder="Search posts by title...">
<h1>Search Results:</h1>
<ul>
#foreach($posts as $post)
<li>{{ $post->title }}</li>
#endforeach
</ul>
</div>

POST method not supported for route in Laravel 6

I am building a discussion form in Laravel 6. The route I used is a POST method and I checked it in route:list. I get the following error, why?
The POST method is not supported for this route. Supported methods:
GET, HEAD, PUT, PATCH, DELETE
View
<form action="{{ route('replies.store', $discussion->slug) }}" method="post">
#csrf
<input type="hidden" name="contents" id="contents">
<trix-editor input="contents"></trix-editor>
<button type="submit" class="btn btn-success btn-sm my-2">
Add Reply
</button>
</form>
Route
Route::resource('discussions/{discussion}/replies', 'RepliesController');
Controller
public function store(CreateReplyRequest $request, Discussion $discussion)
{
auth()->user()->replies()->create([
'contents' => $request->contents,
'discussion_id' => $discussion->id
]);
session()->flash('success', 'Reply Added.');
return redirect()->back();
}
You passed a disccussion object as parameter in order to store user_id within an array.
I think this is not a good practice to store data.
You might notice that your routes/web.php and your html action are fine and use post but you received:
"POST method not supported for route in Laravel 6". This is runtime error. This probably happens when your logic does not make sense for the compiler.
The steps below might help you to accomplish what you want:
1. Eloquent Model(App\Discussion)
protected $fillable = ['contents'];
public function user(){
return $this->belongsTo('App\User');
}
2. Eloquent Model(App\User)
public function discussions(){
return $this->hasMany('App\Discussion');
}
3. Controller
use App\Discussion;
public function store(Request $request){
//validate data
$this->validate($request, [
'contents' => 'required'
]);
//get mass assignable data from the request
$discussion = $request->all();
//store discussion data using discussion object.
Discussion::create($discussion);
session()->flash('success', 'Reply Added.');
return redirect()->back();
}
4. Route(routes/web.php)
Route::post('/replies/store', 'RepliesController#store')->name('replies.store');
5. View
<form action="{{ route('replies.store') }}" method="post">
#csrf
<input type="hidden" name="contents" id="contents">
<trix-editor input="contents"></trix-editor>
<button type="submit" class="btn btn-success btn-sm my-2">
Add Reply
</button>
</form>

Update table column to 1 and the other rows to 0 at single action in LARAVEL 5.5

I'm quite new to laravel and I'm trying to update a record which I called STATUS. In my view blade I havel list of data with action button named "Set to default" What I want to accomplish is, once you click "set to default", the status(column) of that record will update to 1 and the rest of the rows should be updated to 0.
since I am new to this platform I really don't know what to do. But upon following some tuts out there I was able to create a BASIC CRUD with no other conditions.
here's my action button located in my views\currencies\index.blade.php
{!! Form::model($currency, ['method' => 'POST', 'route' => ['currencies.update', $currency] ]) !!}<br/>
{!! Form::hidden('status', 1) !!}<br/>
{!! Form::submit('set default', ['class' => 'btn btn-primary']) !!}<br/>
{!! Form::close() !!}
views\currencies\index.blade.php
to explain further. here's my update.blade.php. it updates the name and acronym in my "currencies" table.
<form action="{{ route('currencies.update', $currency) }}" method="post">
{{ csrf_field() }}
{{ method_field('PUT') }}
<input type="hidden" name="status" value="{{ $currency->status}}">
<input type="text" name="name" value="{{ $currency->name }}"><br/>
<input type="text" name="acronym" value="{{ $currency->acronym }}"><br/>
<input type="submit">
</form>
and currently here's my edit and update function in my CurrenciesController.
public function edit(Currencies $currency)
{
return view('currencies.edit', compact('currency'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Currencies $currencies
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Currencies $currency)
{
$currency->update($request->only('name','acronym','status'));
return redirect()->route('currencies.index');
}
it only captures the data from my add.blade and edit.blade.
now the button that displayed on views\currencies\index.blade.php which I also provided above should only update the status of the record.
What I want to achieve is once I click that button, it will pass the id to my currenciesController, then update the status from 0 to 1 and update the previous record which has '1' to '0'. the bottom line is there should be only one record which has a value of '1' in its status column.
Thank you so much in advance!
All you have to do is execute two queries,
one for update status 0 where status is 1
Currencies::where('status', 1)->update(['status' => 0]);
and other for change status 0 to 1 for the id you received
Currencies::where('id', $request->id)->update(['status' => 1]);

Delete A Record From A Relationship

I want to delete a record: remove a routine,that belongs to a user, on button click (hasMany). I have set up the view, models and relationship within,delete route, and the controller method to delete.
When I try to click the button to remove the routine from the db, it does nothing. why does it not removing the record?
Here's my code: route:
Route::post('routine/delete', 'RoutineController#delete'); // Delete a routine for a user.
Controller:
public function delete(Request $request)
{
$id = $request->input("id"); // Getting the id via. the ajax request.
$routine = \App\Routine::find($id); //Fetching the routine object from the db ifentified by the id passed via ajax
if ($routine)
{
$routine->delete();
}
return ["status" => "success"];
}
View:
<div class="col-lg-2">
<!-- When this button is clicked, we determine which routine to remove. -->
<button class="btn btn-danger remove_routine" data-id="{{$routine->id}}" data-token="{{csrf_token()}}" style="display:inline">Delete</button>
</div>
User Model:
public function routine()
{
return $this->hasMany('App\Routine');
}
Routine model:
public function user()
{
return $this->belongsTo('App\User');
}
Thanks in advance!
Don't know if it exactly answers your question, and I don't use AJAX, but I always do my deletes like this:
View
#foreach($database-thing as $item)
<form method="POST" action="$yourActionHere" style="display:inline" >
<input name="_method" type="hidden" value="DELETE">
<button type="submit" class="btn btn-danger btn-xs"><i class="fa fa-trash"></i> Delete</button>
</form>
#endforeach
// Even easier with laravelcollective/forms
#foreach($database-thing as $item)
{!! Form::open([
'method'=>'DELETE',
'url' => [$yourUrl, $item->id // <-- Very important],
'style' => 'display:inline'
]) !!}
{!! Form::button('<i class="fa fa-trash"></i> Verwijder', ['type' => 'submit', 'class' => 'btn btn-danger btn-xs']) !!}
{!! Form::close() !!}
#endforeach
Controller
public function destroy($id)
{
YourModel::destroy($id);
// All your other logic like redirects and stuff
}
Working delete, based on the code above and this updated controller function:
public function delete(Request $request,$id)
{
$user=Auth::user();
$routine = \App\Routine::findOrFail($id); // find or throw an error if you don't find the routine id in db.
// Makes if() statement redundant, since it checkes for that id already.
// Need to check that the owner of the routine is the current authenticated user.
if ($user->id != $routine->user->id)
{
Session::flash('flash_message', 'No routine found.');
}
else
{
$routine->delete();
Session::flash('routine_deleted','Routine deleted!');
}
// No need to return $routine since I am deleting it, otherwise it will throw and error of trying to get property of non-object.
return redirect()->back()->with('user') ;
//return view('view_routine')->with('user', 'routine');
}
There you go
$remove = 2;
$filtered = $c->filter(function ($value, $key) use($remove){
return $value['id']!=$remove;
});

Resources