How to get the request parameters in Symfony 2? - php

I am very new to symfony. In other languages like java and others I can use request.getParameter('parmeter name') to get the value.
Is there anything similar that we can do with symfony2.
I have seen some examples but none is working for me. Suppose I have a form field with the name username. In the form action I tried to use something like this:
$request = $this->getRequest();
$username= $request->request->get('username');
I have also tried
$username = $request->getParameter('username');
and
$username=$request->request->getParameter('username');
But none of the options is working.However following worked fine:
foreach($request->request->all() as $req){
print_r($req['username']);
}
Where am I doing wrong in using getParameter() method. Any help will be appreciated.

The naming is not all that intuitive:
use Symfony\Component\HttpFoundation\Request;
public function updateAction(Request $request)
{
// $_GET parameters
$request->query->get('name');
// $_POST parameters
$request->request->get('name');
Update Nov 2021: $request->get('name') has been deprecated in 5.4 and will be private as of 6.0. It's usage has been discouraged for quite some time.

I do it even simpler:
use Symfony\Component\HttpFoundation\Request;
public function updateAction(Request $request)
{
$foo = $request->get('foo');
$bar = $request->get('bar');
}
Another option is to introduce your parameters into your action function definition:
use Symfony\Component\HttpFoundation\Request;
public function updateAction(Request $request, $foo, $bar)
{
echo $foo;
echo $bar;
}
which, then assumes that you defined {foo} and {bar} as part of your URL pattern in your routing.yml file:
acme_myurl:
pattern: /acme/news/{foo}/{bar}
defaults: { _controller: AcmeBundle:Default:getnews }

You can Use The following code to get your form field values
use Symfony\Component\HttpFoundation\Request;
public function updateAction(Request $request)
{
// retrieve GET and POST variables respectively
$request->query->get('foo');
$request->request->get('bar', 'default value if bar does not exist');
}
Or You can also get all the form values as array by using
$request->request->all()

try
$request->request->get('acme_demobundle_usertype')['username']
inspect attribute name of your formular field

Inside a controller:
$request = $this->getRequest();
$username = $request->get('username');

As now $this->getRequest() method is deprecated you need to inject Request object into your controller action like this:
public function someAction(Request $request)
after that you can use one of the following.
If you want to fetch POST data from request use following:
$request->request->get('var_name');
but if you want to fetch GET data from request use this:
$request->query->get('var_name');

Your options:
Simple:
$request->request->get('param') ($_POST['param']) or
$request->query->get('param') ($_GET['param'])
Good Symfony forms with all validation, value transormation and form rendering with errors and many other features:
http://symfony.com/doc/current/book/forms.html
http://symfony.com/doc/current/cookbook/form/index.html
Something in between (see example below)
<?php
/**
* #Route("/customers", name="customers")
*
* #param Request $request
* #return Response
*/
public function index(Request $request)
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setDefaults([
'email' => '',
'phone' => '',
]);
$filter = $optionsResolver->resolve($request->query->all());
/** #var CustomerRepository $customerRepository */
$customerRepository = $this->getDoctrine()->getRepository('AppBundle:Customer');
/** #var Customer[] $customers */
$customers = $customerRepository->findFilteredCustomers($filter);
return $this->render(':customers:index.html.twig', [
'customers' => $customers,
'filter' => $filter,
]);
}
More about OptionsResolver - http://symfony.com/doc/current/components/options_resolver.html

You can do it this:
$clientName = $request->request->get('appbundle_client')['clientName'];
Sometimes, when the attributes are protected, you can not have access to get the value for the common method of access:
(POST)
$clientName = $request->request->get('clientName');
(GET)
$clientName = $request->query->get('clientName');
(GENERIC)
$clientName = $request->get('clientName');

Most of the cases like getting query string or form parameters are covered in answers above.
When working with raw data, like a raw JSON string in the body that you would like to give as an argument to json_decode(), the method Request::getContent() can be used.
$content = $request->getContent();
Additional useful informations on HTTP requests in Symfony can be found on the HttpFoundation package's documentation.

For symfony 4 users:
$query = $request->query->get('query');

$request = Request::createFromGlobals();
$getParameter = $request->get('getParameter');

use Symfony\Component\HttpFoundation\Request;
public function indexAction(Request $request, $id) {
$post = $request->request->all();
$request->request->get('username');
}
Thanks , you can also use above code

#www.example/register/admin
/**
* #Route("/register/{role}", name="app_register", methods={"GET"})
*/
public function register(Request $request, $role): Response
{
echo $role ;
}

If you need getting the value from a select, you can use:
$form->get('nameSelect')->getClientData();

Try this, it works
$this->request = $this->container->get('request_stack')->getCurrentRequest();
Regards

public function indexAction(Request $request)
{
$data = $request->get('corresponding_arg');
// this also works
$data1 = $request->query->get('corresponding_arg1');
}

Related

Pass request through method in test

I have a generate() method on my class which is just a shorthand way to create an instance of the class. It accepts a request which is type hinted on the method. I am trying to unit test this and the only way I know how is to make an answer and pass that through. That doesn’t work tho because it is not a request. Is there a work around for this? Here is the method:
public static function generate(Question $question, Request $request): self
{
return self::create([
'user_id' => Auth::user()->getKey(),
'question_id' => $question->getKey(),
'answer_body' => $request->answer_body,
]);
}
Here is the test
/** #test */
public function it_can_generate_a_new_instance()
{
$user = factory(User::class)->create();
$this->actingAs($user);
$question = factory(Question::class)->create();
$answer = factory(Answer::class)->make();
Answer::generate($question, $answer);
$this->assertEquals($user->getKey(), Answer::first()->user_id);
$this->assertEquals($question->getKey(), Answer::first()->question_id);
$this->assertEquals($answer->answer_body, Answer::first()->answer_body);
}
The test passes until I type hint Request in the method.
You can make a new request object with the given property. It's probably a bit flimsy but it should work:
public function it_can_generate_a_new_instance()
{
$user = factory(User::class)->create();
$this->actingAs($user);
$question = factory(Question::class)->create();
$answer = factory(Answer::class)->make();
$request = new Request([ 'answer_body' => $answer->answer_body ]);
Answer::generate($question, $request);
$this->assertEquals($user->getKey(), Answer::first()->user_id);
$this->assertEquals($question->getKey(), Answer::first()->question_id);
$this->assertEquals($answer->answer_body, Answer::first()->answer_body);
}
a request should only be present on a controller, and not in the Model Answer (Or you will encounter errors like that ^^)
If your process require a request, then you should test an http request instead :
/** #test */
public function it_can_generate_a_new_instance()
{
$user = factory(User::class)->create();
$this->actingAs($user);
$question = factory(Question::class)->create();
$answer = factory(Answer::class)->make();
$this->post(route('answer.store'), $answer->toArray());
// Then your answer will be generated in your controller
$this->assertEquals($user->getKey(), Answer::first()->user_id);
$this->assertEquals($question->getKey(), Answer::first()->question_id);
$this->assertEquals($answer->answer_body, Answer::first()->answer_body);
}

How to pass instance of Request from a controller function to another controller function

I have to call a function from one controller an other controller.
public function getquickviews(Request $request){
$report = new ReportController();
$report ->Applications($request->except('cl_e_start_date'));//it's not working its giving me error that it expect and instance of Request and passed array()
}
public function Applications(Request $request)
{
/*APP USAGE*/
}
and I have to pass instance of Request to Application function. But the issue I don't wanted to pass all the parameter from getquickviews Request like if I am getting email,phone,name on the getquickviews function but I only have to pass phone,email to Application function.
You need to create a new instance of Request.
public function getquickviews(Request $request){
$report = new ReportController();
$content = new Request();
$content->something = $request->something;
$content->somethingElse = $request->somethingElse;
$report ->Applications($content);
}
and then you have to recieve it in:
public function Applications(Request $request)
{
/*APP USAGE*/
}
and that's it.
Regards.
Change this line
$report ->Applications($request->except('cl_e_start_date'));
To
$report ->Applications($request);
try as following (not sure it's gonna work) :
public function getquickviews(Request $request){
$returnedRequest = $request; // do whatever with your request here
return redirect()->route('SecondController.Applications', compact('returnedRequest'));
}
public function Applications(Request $request){
/*APP USAGE*/
}
To be able to create a custom request and thus use it to reference a post method in a controller, you need to first initiate an instance of Request as #martin Carrasco has described above:
the code below is a continuation of martin Carrasco
public function getquickviews(Request $request){
$report = new ReportController();
$content = new Request
([
'firstParam' => $request->param1,
'secondParam' => $request ->param2,
]);
$report ->Applications($content);
}
Try that n hope it works.
I think this will work :
$report ->Applications($request->toArray());
Two ways to get requests into next method or any next level call.
First you can inject Request class depenednacy into that method for an example:
public function store(Request $request)
{
// Form Submits here
}
If you want to pass $request into other method for example to display data after insert you can do this way:
public function showStore(Request $request)
{
dd($request->get());
}
Then you can call this method from store method
$this->showStore($request);
or second is you can use request as metho into showStore or any n level call. Like this:
public function showStore()
{
dd(request()->all());
}
$this->showStore(); // You do not require any injection.
Good Luck!!!
You can keep the particular key and value you want and delete the rest from the $request before passing it to the function. First convert the $request to array by
$request->toArray()
and then delete the unwanted keys by doing
unset($request['key-here']);
and then pass it to the function
$report ->Applications($request);

Laravel polymorphic relations: Passing model to controller

I want to use a single controller to save my comments for multiple models. So I created the CommentController, with the following store method:
public function store(Teacher $teacher, Request $request)
{
$input = $request->all();
$comment = new Comment();
$comment->user_id = Auth::user()->id;
$comment->body = $input['body'];
$teacher->comments()->save($comment);
return redirect()->back();
}
In my view, I have:
{!! Form::open([
'route' => ['teachers.comments.store', $teacher->id]
]) !!}
This is working. If I want to use the same CommentController to store the comments for a school, how should I modify the store method of the controller?
Adam's solution is great, but I would not hard-code the model's namespace that way. Instead, what I would do is make use of Laravel's Relation::morphMap(), you can check it out here: https://laravel.com/docs/5.6/eloquent-relationships#polymorphic-relations
That way, you will also make your database entries more readable. I recommend using a service provider to map the morphs.
Also, the Model base class has a getMorphClass() method, so instead of
$comment->commentable_type = 'App\\Models\\'.$model;
I would use
$comment->commentable_type = $model->getMorphClass();
That way you integrate Laravel's logic into your code.
Im not sure if this is the Laravel convension, but i have done the following:
Made a route:
Route::post('/Comment/{model}/{id}', [
// etc
]);
Then in the controller get the model and check against an array of allowed models, pass the id through and attach:
public function store(Request $request, $model, $id) {
$allowed = ['']; // list all models here
if(!in_array($model, $allowed) {
// return redirect back with error
}
$comment = new Comment();
$comment->user_id = $request->user()->id;
$comment->commentable_type = 'App\\Models\\'.$model;
$comment->commentable_id = $id;
$comment->body = $request->body;
$comment->save();
return redirect()->back();
}
Like I say, there is most likely a much better way to accomplish, but this is how I've done it. It keeps it short and sweet and checks if the model can take a comment.
I implemented this way if you want, according to me it's the one of the bests way to do that.
// Route::post('/comments/{model}/{id}', 'CommentController#store');
class CommentController extends Controller {
protected $model;
public function __construct()
{
$this->model = Relation::getMorphedModel(
request()->route()->parameter('model')
);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
dd($this->model); // return 'App\Post' or null
}
}

Modify input before validation on Laravel 5.1

I'm trying to modify an user submitted input before validation success. I've followed this easy instructions, but when I test it on Laravel 5.1, It's not working. Am I doing something wrong?
This is my Request class on SSHAM\Http\Requests\UserCreateRequest.php
<?php
namespace SSHAM\Http\Requests;
use SSHAM\Http\Requests\Request;
class UserCreateRequest extends Request
{
// Some stuff not related with this problem
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
// Only for debug
$prova = $this->all();
echo "<pre>Inside Request - Before sanitize\n[" . $prova['public_key'] . "]</pre>\n";
// Call a function to sanitize user input
$this->sanitize();
// Only for debug
$prova = $this->all();
echo "<pre>Inside Request - After sanitize\n[" . $prova['public_key'] . "]</pre>\n";
return [
'username' => 'required|max:255|unique:users',
'public_key' => 'openssh_key:public',
];
}
/**
* Sanitizes user input. In special 'public_key' to remove carriage returns
*/
public function sanitize()
{
$input = $this->all();
// Removes carriage returns from 'public_key' input
$input['public_key'] = str_replace(["\n", "\t", "\r"], '', $input['public_key']);
$this->replace($input);
}
}
This is my custom validation rule on SSHAM\Providers\OpenSSHKeyValidatorServiceProvider.php
<?php
namespace SSHAM\Providers;
use Illuminate\Support\ServiceProvider;
class OpenSSHKeyValidatorServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
// Registering the validator extension with the validator factory
\Validator::extend('openssh_key', function ($attribute, $value, $parameters) {
// Some stuff not related with this problem
// Only for debug
echo "<pre>Inside Validator value\n[" . $value ."]</pre>\n";
dd();
return true;
});
}
// Some stuff not related with this problem
}
When I call for debugging I obtain this output:
Inside Request - Before sanitize
[blah
second line
third line]
Inside Request - After sanitize
[blah second line third line]
Inside Validator value
[blah
second line
third line]
Seems that sanitize() is working, but when value is treated on validation class it has not been sanitized.
This is a tricky one. I only figured out one way to achieve what you want.
The main point is, that it has no effect for the Validator if you change the Request Values in the rules() function.
You could do a workaround by adding a function to your UserCreateRequest:
protected function getValidatorInstance() {
$this->sanitize();
return parent::getValidatorInstance();
}
This overrides the parent's getValidatorInstance();
The parent's getValidatorInstance() method includes
return $factory->make(
$this->all(), $this->container->call([$this, 'rules']), $this->messages(), $this->attributes());
Which is reached before your code in the rules() function, so the old values (not affected by the changes in rules()) of $this->all() are used.
If you override that function in your own RequestClass you can manipulate the Request values before calling the actual parent's method.
UPDATE (L5.5)
If you are using the Controllers validate function you could do something like that:
$requestData = $request->all();
// modify somehow
$requestData['firstname'] = trim($requestData['firstname']);
$request->replace($requestData);
$values = $this->validate($request, $rules);
You can do this by modifying the request and setting the input value.
$request->request->set('key', 'value');
Or, if you prefer the request helper method.
request()->request->set('key', 'value');
If you are using a request MyClassRequest for keeping your validation then simply override all() method of Request class
public function all()
{
$attributes = parent::all();
//you can modify your inputs here before it is validated
$attribute['firstname'] = trim($attribute['firstname']);
$attribute['lastname'] = trim($attribute['lastname']);
return $attributes;
}
Hope this helps.
These answers no longer work for me in 5.5
you can use
protected function validationData()
{
$this->request->add([
'SomeField' => '..some code to modify it goes here'
]);
return $this->request->all();
}
the add method on request overwrites any existing input for that key.
You can see why this works in Illuminate\Foundation\Http\FormRequest, if you follow the trail
/**
* Get data to be validated from the request.
*
* #return array
*/
protected function validationData()
{
return $this->all();
}
You can use the prepareForValidation method
protected function prepareForValidation()
{
$this->merge(['field' => 'field value' ]) ;
}

How to get view data during unit testing in Laravel

I would like to check the array given to a view in a controller function has certain key value pairs. How do I do this using phpunit testing?
//my controller I am testing
public function getEdit ($user_id)
{
$this->data['user'] = $user = \Models\User::find($user_id);
$this->data['page_title'] = "Users | Edit";
$this->data['clients'] = $user->account()->firstOrFail()->clients()->lists('name', 'id');
$this->layout->with($this->data);
$this->layout->content = \View::make('user/edit', $this->data);
}
//my test
public function testPostEdit (){
$user = Models\User::find(parent::ACCOUNT_1_USER_1);
$this->be($user);
$response = $this->call('GET', 'user/edit/'.parent::ACCOUNT_1_USER_1);
//clients is an array. I want to get this
//array and use $this->assetArrayContains() or something
$this->assertViewHas('clients');
$this->assertViewHas('content');
}
TL;DR; Try $data = $response->getOriginalContent()->getData();
I found a better way to do it. I wrote a function in the TestCase which returns the array I want from the view data.
protected function getResponseData($response, $key){
$content = $response->getOriginalContent();
$data = $content->getData();
return $data[$key]->all();
}
So to get a value from the $data object I simply use $user = $this->getResponseData($response, 'user');
Inside a test case use:
$data = $this->response->getOriginalContent()->getData();
Example:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class HomeTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function testExample()
{
$data = $this->response->getOriginalContent()->getData();
// do your tests on the data
}
}
Example dumping data so you can see what in data(array) passed to view:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class HomeTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function testExample()
{
$data = $this->response->getOriginalContent()->getData();
dd($data);
}
}
Should get something back like what's in image:
I managed it by doing it in a messy way. I used assertViewHas:
$this->assertViewHas('clients', array('1' => 'Client 1', '6' => 'Client2'));
So looking at how assertViewHas is implemented HERE it looks like, what the method does, is access the view's data after this call:
$response = $this->client->getResponse()->original;
In your code, the line:
$response = $this->call('GET', 'user/edit/'.parent::ACCOUNT_1_USER_1);
essentially returns the same thing as the line above it, namely a \Illuminate\Http\Response (which extends the symfony component \HttpFoundation\Response)
So, inside the assertViewHas function it looks like laravel accesses the data using $response->$key, so I would try to access the clients and 'content' variables through the $response object.
If that doesn't work try searching around the TestCase file in the Laravel framework ... I'm sure the answer is in there somewhere. Also try to dump the $response object and see what it looks like, there should be some clues there.
The first thing I would try, though, is accessing your data through the $response object.
You can access data in the response and it can be checked..
public function testSimpleLastProducts() {
$res = $this->call('GET', '/');
$this->assertResponseOk();
$this->assertViewHas('lastProducts');
$lastProductOnView = $res->original['lastProducts'];
$this->assertEquals(6, count($lastProductOnView));
}
This worked for me:
$response->getSession()->get("errors")
And from there you can check the contents of the message box for whatever error you might want verify.
Looking for something like this in 2019, I got:
$response->getData()->data[0]->...my properties
Still looking for a simpler way to access it.
I have had the same problem, but my case was a bit special, because I push my data to view via view()->share($params); and in such cases the solution: $content = $response->getOriginalContent()->getData(); does not give the data out.
and I could not use $response->assertViewHas(...) because my data was objects (models) and I needed to verify object properties (keys and id-s).
So my solution was
$data = $response->original->gatherData();
$this->assertSame($currency->key, $data['currency']->key);
Tested on Laravel 8

Categories