Symfony 2 - Call controller from another controller - php

I would like use a method of controller from another bundle, in my controller.
The method this->forward need a Response object, and i don't know how to use it.
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green',
));
// ... further modify the response or return it directly
return $response;
}
And i saw that i can use service but i want to know if its the best solution or they are another.

$this->forward takes arguments in this order:
Logical Name of controller action in string format i.e. 'AcmeHelloBundle:Hello:fancy'
Parameters to be passed as request variables in array format i.e. array(
'name' => $name,
'color' => 'green',
)
These parameters can be accessed in the controller using request access functions.

Sometimes you want to bypass security completely and run a command in another controller despite a user's permissions level. Luckily you can do that fairly easily.
First, run a use Command for your controller at the top of the controller you want to use the data from:
use AppBundle\Controller\MySourceDataController;
Then call that function from within your destination controller:
$response = MySourceDataController::getTheData( $option1, $option2 );
If you need to pass a Request object, you can do it this way:
$response = MySourceDataController::getTheData( new Request( array(
'server' => 'USAServer1',
) ), $option2 );
This returns a Request with the set parameter of server. I also defined a $option2, this would be a variable often defined in the URL such as:
* #Route("/mydata/{server}/", name="api-source-data")
* #param Request $request
* #param $server
Lastly, if you're passing JSON in that controller and want to convert it back to an object, you can run this bit of code on the $response:
if ( 0 === strpos( $response->headers->get( 'Content-Type' ), 'application/json' ) ) {
$response = json_decode( $response->getContent(), true );
}
Voila. Access any controller form any other controller and bypass security notation for the source controller. :)

Related

How to pass parameter using laravel's Request?

Currently we're doing unit testing in Laravel, and I just noticed my colleague this line below (its working fine though). I look for a documentation in Laravel about this but I can't find it. It seems all we're just focusing on getting the request input values in the documentation.
use Illuminate\Http\Request;
// ...more code here
$request = Request::create('/users/all', 'GET');
I just wanna ask how to pass a parameter using the above code line? And someone can give me a documentation about that.
Check the create function at here:
https://github.com/symfony/symfony/blob/5cfe73d95419bac1ffdddc4603db7266e428b454/src/Symfony/Component/HttpFoundation/Request.php#L336
As you can see, you can pass parameteres as third argument:
Example:
Request::create('/users/all', 'GET', ['username' => 'admin']);
Note: Laravel Request extends Symfony Base Request class
The 3rd argument to create is for an array of parameters. Illuminate\Http\Request extends Symfony\Component\HttpFoundation\Request which defines the create method:
public static function create(string $uri, string $method = 'GET', array $parameters = [], array $cookies = [], array $files = [], array $server = [], $content = null)

Silex getBaseUrl and getBasePath empty

I'm sort of new to Silex and learning. I'm trying to return the base url inside one of my route controllers to return the new path after inserting a row into a database. No matter what I try it's returning an empty string though. Here's part of that function:
$app->match('/item', function(Request $request) use ($app) {
$method = $request->getMethod();
switch ($method) {
//POST
case 'POST': //insert
$data = array(
'item' => $request->get('item'),
'description' => $request->get('description'),
'quantityOnHand' => $request->get('quantityOnHand'),
'reorderPoint' => $request->get('reorderPoint'),
'supplier_id' => $request->get('supplier_id')
); //before to get supplier_id???? Or do it in ios
$app['db']->insert('inventory', $data);
$newId = (int) $app['db']->lastInsertId(); //cast int
$location = $request->getBaseUrl().'/inventory/id/'.$newId;
return $app->json(array('status' => 201, 'id'=>$newId, 'location' =>$location), 201);
break;
}
}
Everything in the $location variable is working except the base path. Am I missing something? I'm injecting the $request into the controller. When I run this it returns /inventory/item/101 for the location, without my base url.
Based on comments, it seems that what the OP is looking for is the hostname, not the base url, so the getHost method should be used.
Remember, though, that to generate URLs easily you should use the UrlGenerator instead of crafting it manually. Silex has a default provider for this service.

Overriding Symfony Request Class - Where to place the override code?

Symfony has a pretty clear code example on how to override the request class, but I do not know where in my App I should place it. I receive the request object from Symfony in my controller actions and want to get the SpecialRequest Object instead.
I already tried a kernel.request listener, but this seems to be too late. Is there a place where this kind of initialization code would fit?
Request::setFactory(function (
array $query = array(),
array $request = array(),
array $attributes = array(),
array $cookies = array(),
array $files = array(),
array $server = array(),
$content = null
) {
return SpecialRequest::create(
$query,
$request,
$attributes,
$cookies,
$files,
$server,
$content
);
});
http://symfony.com/doc/current/components/http_foundation/introduction.html#overriding-the-request
In the example given, the Request::setFactory method is called immediately prior to calling the Request::createFromGlobals method. This would imply that the appropriate place for calling this method would be in the front controller, e.g. app.php, app_dev.php and any other file used as a front controller.
In fact the Request::createFromGlobals method and the Request::create method check to see whether a callable has been set by the Request::setFactory method, and if so they use this callable to create an object that should extend the Request class.

How to call a controller action in Laravel 4.1 and get the filters executed

So the title describes my problem pretty well I think, but let me explain why I want to do this as theremight be an other solution to my problem that I haven't thought about.
Let's say that I have a route specifying the class of the object it will patch:
Route::patch('{class}/{id}', array(
'as' => 'object.update',
function ($class, $id) {
$response = ...;
// here I want to call the update action of the right controller which will
// be named for instance CarController if $class is set to "car")
return $response;
}
));
This is something pretty easy to do with $app->make($controllerClass)->callAction($action, $parameters); but doing it this way won't call the filters set on the controller.
I was able to do it with laravel 4.0 with the callAction method, passing the app and its router, but the method has changed now and the filters are called in the ControllerDispatcher class instead of the Controller class.
If you have routes declared for your classes then you may use something like this:
$request = Request::create('car/update', 'POST', array('id' => 10));
return Route::dispatch($request)->getContent();
In this case you have to declare this in routes.php file:
Route::post('car/update/{id}', 'CarController#update');
If you Use this approach then filters will be executed automatically.
Also you may call any filter like this (not tested but should work IMO):
$response = Route::callRouteFilter('filtername', 'filter parameter array', Route::current(), Request::instance());
If your filter returns any response then $response will contain that, here filter parameter array is the parameter for the filter (if there is any used) for example:
Route::filter('aFilter', function($route, $request, $param){
// ...
});
If you have a route like this:
Route::get('someurl', array('before' => 'aFilter:a_parameter', 'uses' => 'someClass'));
Then the a_parameter will be available in the $param variable in your aFilter filter's action.
So I might have found a solution to my problem, it might not be the best solution but it works. Don't hesitate to propose a better solution!
Route::patch('{class}/{id}', array(
'as' => 'object.update',
function ($class, $id) {
$router = app()['router']; // get router
$route = $router->current(); // get current route
$request = Request::instance(); // get http request
$controller = camel_case($class) . 'Controller'; // generate controller name
$action = 'update'; // action is update
$dispatcher = $router->getControllerDispatcher(); // get the dispatcher
// now we can call the dispatch method from the dispatcher which returns the
// controller action's response executing the filters
return $dispatcher->dispatch($route, $request, $controller, $action);
}
));

How to get response from action dispatched in phpunit

I am dispatching some POST data to an action of a controller. That action echoes some json-encoded string. I want to verify that the json-encoded string of that action is as I want it. I want to know how I can get that string?
My test looks like this:
$this->request->setMethod('POST')
->setPost(['test' => 'databaseschema_Database']);
$params = ['action' => 'analysis', 'controller' => 'Index', 'module' => 'default'];
$urlParams = $this->urlizeOptions($params);
$url = $this->url($urlParams);
$result = $this->dispatch($url);
$this->assertJsonStringEqualsJsonString(
$result, json_encode(["status" => "Success"])
);
My test is failing and I am getting following message:
1) IndexControllerTest::testAnalysisAction
Expected value JSON decode error - Unknown error
stdClass Object (...) does not match expected type "NULL".
Can any one guide me on how to do this?
If you want to do unit testing, what you really want to do is extract the json encoding into it's own class (or a method inside a utils class or something) and then test those method instead of your whole controller.
The problem with your approach is that when running phpunit, there is not $_POST array. The code above does not show what is happening, but I guess there is different behaviour when run through apache and cli which causes your test to fail.
I would create a TransformerClass and test this in isolation:
class JsonTransformer
{
public function transformPostData(array $postArray)
{
// transformation happening
}
}
class JsonTransformerTest extends \PHPUnit_Framework_TestCase
{
public function testTransformPostData()
{
$transformer = new JsonTransformer();
$data = array('action' => 'analysis', 'controller' => 'Index', 'module' => 'default');
$result = $transformer->transformPostData(data);
$this->assertJsonStringEqualsJsonString($result, json_encode(array("status" => "Success")));
}
}
If you need to test your whole request/response, you would use some kind of HTTPClient, request the url, send the post data and see if the response is what you'd expect.
Everything in between (like faking the post data) leaves you with more problems and more code to maintain than it does you good.

Categories