Laravel Flash Session does not work expectedly sometime - php

I am working on a project in which I am using flash session after form submit to display the message. But the problem is that the flash session message sometimes appears and sometime not. I shared the code also here.
this is the function:
public function edit_department(Request $req,$id)
{
$dep = department::where("externalid", $id)->first();
if(!$dep)
{
return ['message' => 'Department Not Found'];
}
$supervisors = member::select("id","name")->whereRelation("get_role","role_code","=","supervisor_13")->get();
if($req->method() == "POST")
{
$req->validate([
'name'=>'required|min:3|max:60',
'supervisor'=>'nullable|exists:members,id',
'time' =>'required|integer|min:1|max:50000',
'description'=>'nullable|max:2999',
]);
try
{
$sup_temp = $dep->supervisor_id;
$dep->name = $req->name;
$dep->ticket_time = $req->time;
$dep->description = $req->description;
$dep->supervisor_id = $req->supervisor;
$desc = "";
if($dep->save())
{
if($dep->wasChanged())
{
$desc = "The department ( ".$dep->name." ) has been updated"." by ".session("cms_member_name")." (".session("cms_member_role_name").")";
$users = array();
$this->mail_subject =" Department Updated";
$this->mail_body['description'] = $desc;
$this->mail_link = "department/profile";
$users = $this->get_mail_members($this->mail_subject, $this->mail_body, $this->mail_link, ['manager_12','super_admin_11'],[],$users);
dispatch(
function () use ($users)
{
$this->send_to_members("","","",$users,"false","2");
}
)->delay(now()->addSeconds(config("app.queue_time")));
return redirect()->back()->with(['form_submit_flag' => 'true', 'form_submit_msg' => 'Department Edited Successfully']);
}
else
{
return redirect()->back()->with(['form_submit_flag' => 'false', 'form_submit_msg' => 'Nothing was changed']);
}
}
else
{
return redirect()->back()->with(['form_submit_flag' => 'false', 'form_submit_msg' => 'Department Was not edited Successfully']);
}
}
catch(Exception $ex)
{
return redirect()->back()->with(['form_submit_flag' => 'false', 'form_submit_msg' => "An Exception Occured. ".$ex->getMessage()]);
}
}
return view("department.edit_department",compact("supervisors","dep"));
}
Now This is the blade code:
#if(Session::has("form_submit_flag"))
#if(session("form_submit_flag") == "true")
<div class="alert alert-success text-dark alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>Message! </strong> {!! session("form_submit_msg") !!}
</div>
#elseif(session("form_submit_flag") == "false")
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>Message! </strong> {!! session("form_submit_msg") !!}
</div>
#endif
#endif
And this is the route.
Route::match(['get','post'],'edit_department/{id}',[DepartmentController::class,"edit_department"])->name("edit_department");
Now you can see that I also have queue code to be executed. Now when I submit the form the flash message in blade sometimes appears and sometime not. But all code works perfectly. No error occurs. Just flash message does not appear. Is there any mistake I am doing?
Any help would be highly appreciated.
Here is the route list
| user_auth |
| | GET|POST|HEAD | edit_department/{id} | edit_department | App\Http\Controllers\DepartmentController#edit_department | web |
| | | | |

I know this is not your issue, but this could help someone else struggling with similar.
If you've specified a middleware web group on top of the route and it's residing in the web.php file, then the web middleware would be loaded twice which has effects on the session data.
I'm guess loading any middleware twice would have similar effects.
See this post for more detail on that issue.
https://laracasts.com/discuss/channels/laravel/session-flash-message-not-working-after-redirect-route

Related

Warning: session_id(): Session ID cannot be changed after headers have already been sent

I have a difficult problem with my project. In localhost environment everything works good, but after deploying on heroku I have an error as logged user:
An exception has been thrown during the rendering of a template ("Warning: session_id(): Session ID cannot be changed after headers have already been sent").
The problem is only on restaurant and comments twig files. After remowing user login check ({% if app.user %} ) everything works fine, but I need such options in my project.
Twig\Error\
RuntimeError
in templates/base.html.twig (line 102)
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav ms-auto">
{% if app.user %}
<a class="nav-link" href="{{ path('app_user_panel') }}">Panel użytkownika</a>
{% endif %}
<a class="nav-link" href="/#aboutus">O nas</a>
<a id="login__button" class="nav-link" href="/{{app.user ? 'wyloguj' : 'logowanie'}}"
#click="isOpen = false">
Link to my project: https://restrank.herokuapp.com/
Link to repository: https://github.com/GrzegorzWanat95/RestRank
enter image description here
I would be grateful for help. I have spend a lot of time to fix it, but I don't have idea. I saw that it was a common problem in PHP, but fixes don't work with Symfony 6.
Update:
I have notice that error is connected with controller function which display list of restaurants searched by name or city. In localhist server it works but after deployment fetching parameters from URL cause error.
Code of my controller which cause error after user login:
#[Route('/szukaj/{type}/{name}', name: 'app_restaurant_query_name', methods: ['GET', 'POST'])]
public function searchByName(RestaurantRepository $restaurantRepository, $type, $name)
{
$values = dump([$type, $name]);
switch ($type){
case 1 :
if($name == null){
return $this->render('restaurant/index.html.twig', [
'restaurants' => $restaurantRepository->findAll(),
]);
}
$restaurants = $restaurantRepository->findBy(
['Name' => $name]
);
return $this->render('restaurant/index.html.twig', [
'restaurants' => $restaurants,
]);
break;
case 2 :
if($name == null){
return $this->render('restaurant/index.html.twig', [
'restaurants' => $restaurantRepository->findAll(),
]);
}
$restaurants = $restaurantRepository->findBy(
['City' => $name]
);
return $this->render('restaurant/index.html.twig', [
'restaurants' => $restaurants,
]);
break;
default:
return $this->render('restaurant/index.html.twig', [
'restaurants' => $restaurantRepository ->findAll(),
]);
break;
}
}
I don't know how to pass parameters from search by URL and avoid this error.
The error was caused by dump function in restaurant controller.
After removing it everything works ok. It should be:
$value = $request->query->get('Type');
$name = $request->query->get('Name');

Laravel 8 - Pass validation errors back to frontend

I am using Laravel Framework 8.62.0.
I am validating a form the following way:
$validator = Validator::make($request->all(), [
'title_field' => 'required|min:3|max:100',
'comment_textarea' => 'max:800',
'front_image' => 'required|mimes:jpg,jpeg,png,bmp,tif',
'back_image' => 'required|mimes:jpg,jpeg,png,bmp,tif',
'price' => "required|numeric|gt:0",
'sticker_numb' => "required|numeric|gt:0",
'terms-checkbox' => "accepted",
]);
if ($validator->fails()) {
// Ooops.. something went wrong
return Redirect::back()->withInput();//->withErrors($this->messageBag);
}
I want to display errors in the frontend the following way:
#if ($errors->any())
<div class="alert alert-danger alert-dismissable margin5">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<strong>Errors:</strong> Please check below for errors
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
However, my $error variable is emtpy, when validation errors exist, so the validation errors do not get shown in my frontend.
Any suggestions what I am doing wrong?
I appreciate your replies!
You should pass the $validator to withErrors like:
if ($validator->fails()) {
// Ooops.. something went wrong
return Redirect::back()->withErrors($validator)->withInput();
}
That's because your not passing errors.
Try this:
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}
As the previous speakers said, you must of course return the errors. but you can also use the Request Validate Helper. it does this automatically.
$request->validate([...])
As soon as an error occurs, it returns a response with the errors.
https://laravel.com/docs/8.x/validation#quick-writing-the-validation-logic

laravel error messages not display after first redirection

If the incoming request parameters do not pass the given validation rules, I redirect the user back to the previous page.
Even though validation error messages exist in session, they aren't displayed after first redirect.
When i refresh page again the error message are displayed.
Blade
#if ($errors->any())
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
#endif
Controller
public function index()
{
$this->validation();
$perpage = request()->input('perpage',10);
$perpage = $perpage<10 ? 10 : $perpage;
$musics = Music::where('title','like','%'.request()->input('title').'%')->paginate($perpage);
$page = request()->input('page',1);
$page_count = intval(ceil($musics->total()/$perpage));
if($page < 1 || (!empty($page_count) && $page > $page_count)){
return redirect(request()->fullUrlWithQuery(['page' => 1]));
}
return view('admin.musics.index',
[
'musics'=>$musics,
'perpage'=>$perpage,
'page'=>$page,
'page_count'=>$page_count
]);
}
private function validation()
{
$validator = Validator::make(request()->all(), [
'title' => 'nullable|max:255',
'page' => 'numeric|min:1',
'perpage' => 'numeric|min:10|in:10,20,30,50,100,200,300,500,1000'
]);
if ($validator->fails()) {
return back()
->withErrors($validator)
->withInput();
}
}
for example, in first image,as you see parameter perpage that should be one of the numbers 10,20,30,50,100,200,300,500,1000 is 22, so error happens, error message exist in session but it isn't displayed!
In second image, I correct the parameter perpage and refresh page, now error is displayed!
I realized that redirect did not work.
When validation fails, redirection doesn't work!
Why it happens?
my route rules is :
Route::namespace('Admin')->prefix('admin')->group(function(){
Route::get('musics','MusicsController#index');
});
I changed return back() to return redirect()->back() and return Redirection::back() , but it doesn't work!
What's the problem?
The point is I use one page (I mean it's not like insert action that I have two method, create method and store method, I don't want to submit form to middle page and then return).
try
return Redirect::back()
->withErrors($validator)
->withInput();

Query from db only once despite method being called many times

I am trying to create a Poll (quiz) app, now I am doing a functionality that gets random questions from the database and returns in a poll (test)
I am displaying the answers 1 by 1 and when a user clicks submit answer a request is ran and the next answer is displayed
The problem is that every time a user submits the controller gets called again and the db query as well (when he clicks the next question button
This means that the query will get different random questions now and because of that same questions appears twice sometimes
I want to make sure that the query that gets the questions only gets called once
Model:
private $random_questions;
public function getRandomQuestions($questions_count)
{
if (!$this->random_questions)
{
$this->random_questions = Question::orderByRaw('RAND()')->take($questions_count)->get();
}
return $this->random_questions;
}
public function nextQuestionLink($questions_count, $question_number) {
$nextQuestionLink = [];
if ($questions_count != $question_number && $questions_count > $question_number) {
$nextQuestionLink['url'] = '/polls/random/'.$questions_count.'/'.++$question_number;
$nextQuestionLink['text'] = 'Следващ въпрос';
$nextQuestionLink['class'] = 'btn-default';
} else {
$nextQuestionLink['url'] = '/result';
$nextQuestionLink['text'] = 'Приключи';
$nextQuestionLink['class'] = 'btn-primary';
}
return $nextQuestionLink;
}
Controller:
public function getRandomQuestions($questions_count, $question_number)
{
$question = Question::Instance();
$questions = $question->getRandomQuestions($questions_count);
$nextQuestionLink = $question->nextQuestionLink($questions_count,
$question_number);
return view('polls.random_questions_poll')->with([
'question' => $questions[$questions_count-1],
'next' => $nextQuestionLink,
]);
}
View:
#section('content')
<div id="quiz-wrapper">
<h1>{{ $question->question }}</h1>
{!! Form::open(array( 'id' => 'message')) !!}
{!! csrf_field() !!}
#foreach($question->answers->shuffle() as $answer)
<h3>
<div class="form-group">
<div class="radio">
{{Form::radio('result', "$question->id-$answer->id") }}
{{ Form::label('result', $answer->name) }}
</div>
</div>
</h3>
#endforeach
<a class="next-question-button btn {{ $next['class'] }}" href="{{ $next['url'] }}" style="display: block;" role="button">{{ $next['text'] }}</a>
<p id="validation-error-container"></p>
{!! Form::close() !!}
</div>
#endsection
Since php by default is stateless, you will need to store the initial set of questions in persistent storage and retrieve them from that for all later requests.
You can do this quite succinctly with sessions in your controller:
public function getRandomQuestions($questions_count, $question_number)
{
//attempt to retrieve from session
$questions = session('questions', function(){
//if not found in session, generate from DB,
$questions = Question::Instance()->getRandomQuestions($questions_count);
//and store in session for next request.
session(['questions' => $questions]);
return $questions;
});
$nextQuestionLink = $question->nextQuestionLink($questions_count,
$question_number);
return view('polls.random_questions_poll')->with([
'question' => $questions[$questions_count-1],
'next' => $nextQuestionLink,
]);
}

How to display message success or failed use respond on view ? (Laravel 5.3)

My destory method on controller is like this :
public function destroy($id)
{
try{
if($this->product_service->destroy($id)){
return $this->respond(['status' => 'success']);
}else{
return $this->respond(['status' => 'failed']);
}
}catch (\Exception $e){
return $this->respondWithError();
}
}
My view is like this :
#if (session('status')=='success')
<div class="alert alert-success">
<ul>
<li>Delete Success</li>
</ul>
</div>
#elseif (session('status')=='failed')
<div class="alert alert-warning">
<ul>
<li>Delete Failed</li>
</ul>
</div>
#endif
After the destroy method executed, it not display status success or failed
Why it does not work?
UPDATE
My controller extend ApiController
And in ApiController exist method like this :
public function respond($data, $headers=[])
{
return response()->json($data,$this->getStatusCode(), $headers);
}
I would suggest you to use this package for that:
https://github.com/laracasts/flash
Please read the documentation there, it is very well explained.
OR
If you want to do that using custom code:
Controller
public function destroy($id)
{
if($this->product_service->destroy($id)){
return view('viewname', ['class' => 'success', 'message' => 'Delete Success']);
} else{
return view('viewname', ['class' => 'success', 'message' => 'Delete Failed']);
}
}
View:
<div class="alert alert-{{ $class }}">
<ul>
<li>{{ $message }}</li>
</ul>
</div>
You can simply call:
return \Redirect::back()->with('status', 'your status here...');
and that should be it.
Or you can use Response:json if you desire to return a json object, convenient with AJAX as followed:
return \Response::json(['status' => 'your status here...'], 200);
and then you can catch status on the view using ajax as followed:
errorsHtml = '<div class="alert alert-danger"><ul>';
$.each(responseText, function(k, v){
errorsHtml += '<li>' + v + '</li>';
});
errorsHtml += '</ul></div>';
$("#feedback").append(errorsHtml);
Notice that you can pass any other data within \Response::json method:
return \Response::json(['status' => 'your status here...', 'data' => $data], 200);
Use :
$request->session()->flash('status', 'Task was successful!');
https://laravel.com/docs/5.4/session#flash-data

Categories