I'm trying to pass a token from middleware to view and controller. But all the steps I've tried:
Laravel - Passing variables from Middleware to controller/route
Pass variable from middleware to templates
Pass variable from middleware to view via controller in Laravel 5.2
Haven't helped much. Here is my setup:
Requests come in the form of:
https://website.com/reviews?linker=129b08e19014420049da7d6d7aa8fc35fc6279c4
Then gets parsed and checked by middleware:
Middleware
class CheckReviewLink
{
/**
* Check Review Link - granting clients access to submit review
* =================
* Check that user's link matches the 40 character string generated for user
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$url = $_SERVER['REQUEST_URI'];
$parts = parse_url($url);
$data['token'] = parse_str($parts['query'], $query);
$testimonies = Testimony::all();
foreach ($testimonies as $testimony) {
if ($query['linker'] == $testimony->token) {
Session::flash('token', $data);
return $next($request);
}
}
}
}
** View **
<div class="col-lg-6">
<article>
<input disabled type="text" placeholder="{{Session::get('token', $data)}}" id="token" name="token" size="100" class="form-control border-form white font4light">
</article>
</div>
When I go to get the session data within my view/controller, I get the error:
Undefined variable: data
Any ideas anyone?
Session flash storage is for retaining data between execution times of the application, ie passing from one page load to the other. In your case you are only wanting to pass data from one part of the app to the other during a single run, thus vars in the memory will be cleaner and quicker.
This guy answered it already: Laravel Middleware return variable to controller
You now have better and clearer control of the code and can pass through to, if required, your data to the views and don't have to worry about clearing up your old session data.
First of all you don't need first line in your handle method. You aren't using $response variable.
Secondly use $request->url() instead of $_SERVER['REQUEST_URI'].
And your answer is to simply use session('token') to gat token you want.
If you want to retrieve a session data, you just have to call the session() helper method, and give it the key of the data that you want:
$myToken = session('token');
But, in your case, your are storing an associative array to the session, so when you call it, you have to do like this:
$myToken = session('token')['token'];
So in your view, you will end up with:
<div class="col-lg-6">
<article>
<input disabled type="text" placeholder="{{ session('token')['token'] }}" id="token" name="token" size="100" class="form-control border-form white font4light">
</article>
</div>
You don't need to use a variable when you're trying to get data from the session. So, do this instead:
{{ Session::get('token') }}
Or simply:
{{ session('token') }}
Also, instead of flash() method do this:
session(['token' => $data]);
And then delete it manually if needed:
session()->forget('token');
Related
I'm trying to delete city from my db but i really got no clue what to do next.
Since I didnt find anything about deleteing data from db for Laravel 8.* I think this might be usefull for other stackoverflowers too.
My error says clearly that I'm missing some arguments,
Too few arguments to function App\Http\Controllers\CityController::delete(), 0 passed in C:\xampp\htdocs\Laravel1\vendor\laravel\framework\src\Illuminate\Routing\Controller.php on line 54 and exactly 1 expected
While my controller says that he expected type 'object' but only found array
Exoected type 'object'. Found 'array'. intelephense(1006)
#var array $todelete
Here is Route from web.php
Route::delete('cities', [App\Http\Controllers\CityController::class, 'delete'])->name('cities.delete');
And this is form I'm using to delete
<form class="float-right m-0" method="post" action="{{ route('cities.delete') }}">
#method('delete')
#csrf
<div class="form-row">
<input type="hidden" name="cityId" value="{{ $city->id }}">
<button> <i class="fa fa-trash-alt"></i></button>
</div>
</form>
Edit
After solving previous problems, I'm stuck on another error:
Call to a member function delete() on array
Here is how my "CityController"s function looks like after updates
public function delete(Request $request)
{
$cityId = $request->get('cityId', false);
// TODO: Check for validation
$todelte = DB::select('select '.$cityId.' from cities');
$todelte -> delete();
return redirect('frontend/city/index');
}
Correct query to delete stuff:
DB::table('cities')->where('id', $cityId)-> delete();
The issue with not getting the $id parameter passed has to do with your route not accepting any parameters.
Your call is DELETE /cities, which does have any parameters.
If you changed that to DELETE /cities/5, than you could get a parameter passed down the line.
In order to get the parameter to your controller you should change your route as follows:
Route::delete('cities/{id}', [App\Http\Controllers\CityController::class, 'delete'])->name('cities.delete');
This way the {id} part will be passed along to the function specified in the callback. To make your form work with that new route you should change the action-part of you form to direct to the new URL.
I suggest using the 2nd parameter as well so you get:
route('cities.delete', ['id' => $city->id])
Then you can remove the hidden input.
If you do want to keep the existing form you need to use the Request as a parameter in your delete-function. That would look like this:
public function delete(\Illuminate\Http\Request $request)
{
$cityId = $request->get('cityId', false);
// TODO: Check for validation
$todelte = DB::select('select '.$cityId.' from cities');
$todelte -> delete();
return redirect('frontend/city/index');
}
I wanted to put in my controller a second delete button to delete comments but I got lots of error messages like the one from ParamConverter because it did not recognize the class.
So in my controller I have a ParamConverter like this:
/**
* #Route("/delete/{comment_id}", name="comment_delete", methods={"DELETE"})
* #ParamConverter("comment", class="App:Comment", options={"id": "id"})
*/
public function deleteComment(Request $request, BlogPost $blogPost, Comment $comment, $comment_id): Response
{
if ($this->isCsrfTokenValid('delete' . $comment->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($comment);
$entityManager->flush();
return $this->redirectToRoute('/');
}
return $this->render('comments/_delete_form.html.twig', [
'comment' => $comment
]);
}
In my twig, I added this:
<form method="post" action="{{ path('comment_delete', {'comment_id': comment.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ comment.id) }}">
<button class="btn delete">Delete</button>
</form>
But it creates an error message:
"Unable to guess how to get a Doctrine instance from the request information for parameter" comment ".
Usually, Symfony will try to convert the route parameters to entities automatically if you typehint them in the function signature. For example, since you don't use the BlogPost entity, you could just write:
/**
* #Route("/delete/{id}", name="comment_delete", methods={"DELETE"})
*/
public function deleteComment(Comment $comment): Response
You should change the parameter name in your twig function too, of course.
If you want to be more explicit and keep the parameter name as is, for clarity, you can write:
/**
* #Route("/delete/{comment_id}", name="comment_delete", methods={"DELETE"})
* #ParamConverter("comment", options={"id" = "comment_id"})
*/
In order to map the route argument to the column name.
The error you are receiving is because you wrote options={"id": "id"} telling the converter to look up the entity by using the id parameter in the url, and of course there's no id parameter.
I want to send data from the controller to my view without using session to get the data in the view.
In this question, they suggested to use return redirect('home')->with(['data' => $value]); but I have to use Session::get('data') in my view.
I know that it can be solved by using return view('myView')->with('data', 'value') but I want the URL to be changed to www.myurl.com/home when navigating to the home page and I cannot perform this with view('myView')->with('data', 'value').
Thank you !
There's no other way, you really need to use Session::get. However, we can do a workaround it, but it's messy.
// some controller function
return redirect('home')->with(['data' => $value]);
Now in your home controller function, do this:
SomeController#home
...
$data = [];
// if you need to pass other data to view, put it in data[]
// e.g., $data['username'] = Auth::user()->username;
if (Session::has('data')) {
$data['data'] = Session::get('data');
}
return view('myView', compact($data));
There, in your view you can just check if data is set.
<!-- myView.blade.php -->
<span>{{ isset($data) ? $data : '' }}</span>
For me, it's merely the same as accessing the Session from the view, because if you did, this is what your view will look like.
<!-- myView.blade.php -->
<span>{{ Session::has('data') ? Session::get('data') : '' }}</span>
You can also use session() global helper instead of the Session facade.
I've constructed a select list in a dashboard view, which lists id and name of various components. The data is passed to a controller that makes a view using the passed id to pull up the correct component data for that id. Problem is that the controller is constructed to expect an object from which to get the id, so that when I submit the id from the list, I get a "Trying to get property of non-object" error. (It doesn't matter whether I submit to the route or directly to the controller; I get the same error.) Here's the code:
PagesController (that creates list array for the dashboard):
public function showDashboard()
{
$components = Component::lists('name','id');
return View::make('dashboard', array(
'components'=>$components, ...
));
}
Snippet of source code for the select list:
<form method="GET" action="https://..." accept-charset="UTF-8">
<select id="id" name="id"><option value="2">Component Name</option>...
Components Model:
class Component extends Eloquent {
protected $table = 'components'; ... }
ComponentsController:
public function show($id)
{
$component = $this->component->find($id);
return View::make('components.show', array(
'component'=>$component, ...
));
}
dashboard.blade.php:
{{ Form::open(array(
'action' => 'ComponentsController#show',
'method'=>'get'
)) }}
{{ Form::Label('id','Component:') }}
{{ Form::select('id', $components) }}
{{ Form::close() }}
The same controller code is used for other purposes and works fine, for example, when I pass a specific id from a URL, it accepts that id without an error. So, I know this should be something simple involving the form opening, but I can't figure it out. How can I fix this? Thanks!
It will not work because using get method the url will be like this.
http://laravel/puvblic/show?id=2
and laravel will not accept it , rather it accepts a parameter for function in this way
http:/laravel/puvblic/show/2
A better way to do this would be to make your form method as 'POST' . It would be much safer and better this way. and modify your function as.
public function show()
Then , You can get the id in your controller as
Input::get('id')
EDIT:
To make it simple , try this one:
Route::get('{show?}', function()
{
$id = Input::get('id') ;
echo $id; //This will give you the id send via GET
die();
});
Simply follow the GET method , your form will send a GET request and it will come to this route here you can perform your desired function.
I finally figured out the problem, and the solution:
The problem is that the form should (optimally) be sent as POST (not GET), and therefore not changed from the default value provided by Blade. BUT then the route has to be registered correctly as POST, and that's what I wasn't doing before. So,
dashboard.blade.php:
{{ Form::model(null, array('route' => array('lookupsociety'))) }}
{{ Form::select('value', $societies) }} ...
Route:
Route::post('lookupsociety', array('as'=>'lookup society', 'uses'=>'SocietiesController#lookupsociety'));
SocietiesController#lookupsociety:
public function lookupsociety()
{
$id = Input::get('value'); ... // proceed to do whatever is needed with $id value passed from the select list
}
It works perfectly! The key was changing the method in the route to Route::post() instead of Route::get().
I knew it had to be simple -- I simply hadn't stumbled on the solution before :)
I have a resource controller in laravel to manage my users. This creates a route to update users info that takes a request with HTTP PUT method.
This shows artisan route:list command output:
+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
...
| | PUT | users/{users} | users.update | App\Http\Controllers\Users\UsersController#update | auth |
It works correctly on my web browser but when I try to run a test with codeception and I submit the form I get a method not allowed exception and the test fails.
I tried to see why this is happening and it seems to be the request made by codeception. That request is made with POST instead of PUT method preventing Laravel from matching the route.
HTML forms doesn't suport PUT methods so Laravel Form helper class creates the form as follows:
<form method="POST" action="https://myapp.dev/users/172" accept-charset="UTF-8">
<input name="_method" value="PUT" type="hidden">
...
However, it seems that codeception is not reading the _method value.
How can I fix this?
EDIT: Looking deeply on the code I found that test don't override the request method beacause of a constant in th Request class called Request::$httpMethodParameterOverride.
/**
* Gets the request "intended" method.
*
* If the X-HTTP-Method-Override header is set, and if the method is a POST,
* then it is used to determine the "real" intended HTTP method.
*
* The _method request parameter can also be used to determine the HTTP method,
* but only if enableHttpMethodParameterOverride() has been called.
*
* The method is always an uppercased string.
*
* #return string The request method
*
* #api
*
* #see getRealMethod()
*/
public function getMethod()
{
if (null === $this->method) {
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
if ('POST' === $this->method) {
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
$this->method = strtoupper($method);
} elseif (self::$httpMethodParameterOverride) {
$this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
}
}
}
return $this->method;
}
The previous constant value should be true but shomehow, when I run the test its value is false.
I found a solution but I don't think this is the right place to write it.
I added a simple line of code on the Connector\Laravel5 class.
public function __construct($module)
{
$this->module = $module;
$this->initialize();
$components = parse_url($this->app['config']->get('app.url', 'http://localhost'));
$host = isset($components['host']) ? $components['host'] : 'localhost';
parent::__construct($this->app, ['HTTP_HOST' => $host]);
// Parent constructor defaults to not following redirects
$this->followRedirects(true);
// Added to solve the problem of overriding the request method
Request::enableHttpMethodParameterOverride();
}
This solves my problem.
You can not use PUT method in HTML form tag. For that you need to use laravel's blade template format to define form tag.
e.g.
{!! Form::open(['url' => 'users/{users}','method' => 'put','id' => 'form' ]) !!}
Also you can use route attribute to define route instead of url.