I am using league/route to handle routing for my application.
I have a post route:
$router = new RouteCollection;
$router->post('/url', 'MyClass::myMethod');
...$dispatcher->dispatch(...)->send();
In my method:
class MyClass {
public function myMethod(Request $request) {
var_dump($request->request);
}
}
Var dumping the passed request object is just a fresh instance of HttpFoundation\Request, and not the actual request that the application has processed, i.e, there is no post data. To get the post data, I need to do:
$request = Request::createFromGlobals();
Within my method. This makes the passed request object to my method useless. How can I configure Route to pass the actual request so I can get my post data, without having to create my own request object?
The RouteCollection object accepts a dependency of league/container, a dependency injection container. This is where the Request object is pulled from when invoking your controller.
By design the request object is not built for you in case you would like to do anything specific with it yourself, so for this reason, it needs to be defined within the container or will return you a blank request each time. It is planned for this to be remedied in version 2 of the router due in the not too distant future of me posting this.
So something like this is required.
<?php
$container = new League\Container\Container;
$container->add('Symfony\Component\HttpFoundation\Request', function () {
return Symfony\Component\HttpFoundation\Request::createFromGlobals();
});
$router = new League\Route\RouteCollection($container);
$router->post('/url', 'MyClass::myMethod');
// ...
$dispatcher->dispatch(/* ... */)->send();
Related
I'm working with Api-Platform 2.5 and Symfony 4.4 (lts).
I have discovered the API Platform and I understand that there are many "interceptors" that intercept the HTTP requests:
for GET requests: The Data Provider, The Controller, The Serialization Process and finally an "anonymous process" that's setting the response code.
for POST, PUT, PATCH, and DELETE: The serialization process, The Data Provider, The Controller, The Data Persister and finally the "anonymous process" that's setting the response code.
Here I have my Data Persister:
ProductDataPersister:
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use App\Entity\Product;
final class ProductDataPersister implements ContextAwareDataPersisterInterface
{
public function supports($data, array $context = []): bool
{
return $data instanceof Product;
}
public function persist($data, array $context = [])
{
//dd('persist');
return $data;
}
public function remove($data, array $context = [])
{
//dd('remove');
}
}
In this case neither persist nor remove are making the database stuff because it has to be done manually by injecting entity manager etc.
My question is, as we say the remove action with this code never deletes a Product and that's what I want But the response I get to the DELETE request still not overridden and still returns a 204 status code (no content).
I want to override the response type. What other listener gets executed after the Data Persister?
Is it overridable?
If you take a look at Api-Platform event system, it is clear that the event you are looking for, the one you refer as "anonymous process", is the appropriately named RespondListener.
You can see here the exact point where it is setting the response code.
The simplest way to override this would be to register your own event listener/subscriber to be executed after this listener:
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['fooMethod', EventPriorities::POST_RESPOND],
];
}
On fooMethod(ViewEvent $event) you can access the access response object ($event->getResponse() and modify it, or even create your own response object (although that's likely to be even less optimal).
Alternatively, you could decorate the #api_platform.listener.view.respond service, and implement your overriding logic in the decorator.
Can anyone explain if there is a reason why we should not be using getting the authenticated user within a from request authorize method, via the Auth::user() or auth()->user() helpers vs. the $this->user() method as suggested in docs?
https://laravel.com/docs/5.8/validation#authorizing-form-requests
In my case, I am trying to unit test a form request and auth()->user() allows me to retrieve the user whereas $this->user() does not as I am not making a full request. I am just creating the form request object for my test.
public function setUp(): void
{
parent::setUp();
$this->subject = new \App\Http\Requests\OrderStoreRequest();
}
// Acting as has no effect when manually creating the orderStoreRequest object
public function testAuthorize()
{
$this
->actingAs(\factory(User::class)->create())
->assertTrue($this->subject->authorize());
}
ActingAs() is calling the Laravel Auth system, which in the request lifecycle is put into the request (See). Since you are just calling your request without this lifecycle, you will never get anything injected into the Request.
For your code to work, you need to set the UserResolver. This can be done like so.
$this->subject->setUserResolver(function () use($user) {
return $user;
});
For ease of usage, i would highly recommend doing Laravel feature tests instead of unit testing. You are gonna fight your way through a lot of approaches, there is not meant to be called without the Laravel lifecycle. Which you will get doing call() and json() on the app.
I have a controller which is getting an instance of Illuminate\Http\Request injected through the constructor. Now I need to write an unit test that test a call in the controller which uses the values from the Request instance. I have decided to use Faker. How to use Faker to generate an associative array so that I can use the array in my test case like,
$this->post('the_uri','MyFakerArray')
And the dynamic array will automatically be available in my controllers request.
There is no need to fake/mock the Request object.
When you are simulating a request laravel does that for you, it create a request to the url you request and pass the variables, then you get back the response from your application.
For example:
$response = $this->call('POST', '/user', ['name' => 'Taylor']);
now the $response variable has the data to test on.
I think you have:
getContent() // for getting the reponse body
getCode() // for http code: 200, 401 etc
When you do that, your tests should work with the response, you have no need for Faker in this situation.
PSR-7 is going to be standardized soon (I believe). That's got me thinking about middlewares, such as used by Phly, StackPHP, and ConnectJS.
The way ConnectJS works is that it modifies the request object when a middleware needs to add something. For example, cookie-session creates a session property on the req object:
app.use(session({
keys: ['key1', 'key2']
}))
app.use(function (req, res, next) {
var n = req.session.views || 0 // <-- req.session is managed by the session middleware
req.session.views = ++n
res.end(n + ' views')
})
With PSR-7, both our Request and Response objects are (supposed to be) immutable, so how are we supposed to pass along additional data like this? i.e. where would be the best place to store a 'session' object or a 'user' object created by an authentication middleware?
Request and Response objects in PSR-7 are implemented as value objects, hence they are immutable.
Every time you need a different object, you create a new instance from the previous one, like
$newRequest = $oldRequest->withMethod('GET');
and from that point on use the new instance.
In middlewares you would have to pass the new instance to the next() function that calls the next middleware (see here for example).
If you need to store in the request object additional data computed from your current request, in the ServerRequestInterface there are defined the withAttribute and the withAttributes methods that allow you to do exactly that.
A common use case for this is for storing the results of routing, but you can surely use them to store other additional data of the request, like session or user data
Do not store at all. Inject it as parameter into consumer function. For instance:
function doSomething(reqest, response, session, user, foo, bar, ...)
Be explicit.
I need to create my own resource which sends some information to Zend_View instance which depends on currently working controller and action.
I've got this code:
$view = $bootstrap->getResource('layout')->getView();
$front = $bootstrap->getResource('frontController');
$front->setRequest(new Zend_Controller_Request_Http);
$controller = $front->getRequest()->getControllerName();
$action = $front->getRequest()->getActionName();
$view->headTitle(
$this->getPage()
->setController($controller)
->setAction($action)
->getTitle()
);
but $controller and $action are empty. I don't know if I'm doing something wrong or getting access to controller and action names is impossible in resource.
You can't access the request object in a resource because it doesn't exist yet. The request object gets set during dispatch which happens after the application has been bootstrapped. It sounds like this logic should be moved to a controller plugin instead.