I'm following a Symfony tutorial and am currently on The Event Dispatcher section. In the first code block (after the composer part) I'm instructed to set up the dispatcher
// dispatch a response event
$this->dispatcher->dispatch(new ResponseEvent($response, $request), 'response');
I'm using PHPStorm, and when I create the ResponseEvent class it is asking for 4 arguments
new ResponseEvent($kernel, $request, $requestType, $response)
While I could create a $kernel element by importing the HttpKernelInterface, I'm unsure if this is correct.
I also have no idea where to get the $requestType from, since the ResponseEvent class definition says that this should be of type int and I only know of request types in string format (e.g. 'GET', 'POST' etc).
Here is the full file in case I have made a mistake elsewhere.
The tutorial that you are following wants you to use the Simplex ResponseEvent, that method signature is for the kernel ResponseEvent
At the top of your file you should see something like this:
use Symfony\Component\HttpKernel\Event\ResponseEvent;
Replace it with
use Simplex\ResponseEvent;
Related
Given the following pest test:
it('allows admins to create courses', function () {
$admin = User::factory()->admin()->create();
actingAs($admin);
$this->get('/courses')->assertDontSee('WebTechnologies');
$this->followingRedirects()->post('/courses', [
'course-name' => 'WebTechnologies',
])->assertStatus(200)->assertSee('WebTechnologies');
});
The above should fully work; however, the second request post('/courses')...
fails saying that:
Failed asserting that <...> contains "WebTechnologies".
If I remove the first request:
it('allows admins to create courses', function () {
$admin = User::factory()->admin()->create();
actingAs($admin);
$this->followingRedirects()->post('/courses', [
'course-name' => 'WebTechnologies',
])->assertStatus(200)->assertSee('WebTechnologies');
});
The test passes.
If I remove the second request instead:
it('allows admins to create courses', function () {
$admin = User::factory()->admin()->create();
actingAs($admin);
$this->get('/courses')->assertDontSee('WebTechnologies');
});
It also passes.
So why should the combination of the two cause them to fail? I feel Laravel is caching the original response, but I can't find anything within the documentation supporting this claim.
I have created an issue about this on Laravel/Sanctum as my problem was about authentication an stuff...
https://github.com/laravel/sanctum/issues/377
One of the maintainers of Laravel Said:
You can't perform two HTTP requests in the same test method. That's not supported.
I would have wanted a much clearer explanation on why it's not supported.
but I guess, we would never know. (Unless we dive deep into the Laravel framework and trace the request)
UPDATE:
My guess is that, knowing how Laravel works, for each REAL request Laravel initializes a new instance of the APP...
but when it comes to Test, Laravel Initializes the APP for each Test case NOT for each request, There for making the second request not valid.
here is the file that creates the request when doing a test...
vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php
it's on the call method line: 526 (Laravel v9.26.1)
as you can see...
Laravel only uses 1 app instance... not rebuilding the app...
Line 528: $kernel = $this->app->make(HttpKernel::class);
https://laravel.com/docs/9.x/container#the-make-method
the $kernel Variable is an instance of vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
My guess here is that the HttpKernel::class is a singleton.
P.S. I can do a little more deep dive, but I've procrastinated too much already by answering this question, it was fun thou.
TL;DR.
You can't perform two HTTP requests in the same test method. That's not supported.
UPDATE:
I was not able to stop myself...
I found Laravel initializing Kernel as a singleton
/{probject_dir}/bootstrap/app.php:29-32
Please make sure to not use any classic singleton pattern which isn't invoked with singleton binding or facades.
https://laravel.com/docs/9.x/container#binding-a-singleton
$this->app->singleton(Transistor::class, function ($app) {
return new Transistor($app->make(PodcastParser::class));
});
The Laravel app won't be completely restarted during tests unlike different incoming HTTP requests - even if you call different API endpoints in your tests
I don't understand the semantics of the Symfony Routing Component's API.
From the first code example on the Routing Component documentation page:
$context = new RequestContext('/');
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/foo');
Why is the hostname and HTTP method passed in via $context and the path via a parameter to match()? Or is it? There is also a path parameter in the RequestContext constructor.
One gets the impression match() is supposed to be called multiple times with different paths within one request, which I can't imagine would ever happen.
After integrating the Routing Component into my application, I now have a hunch why
it was done like that.
Most of the properties of the RequestContext - method, request body, get parameters - can be used without modification, but depending on the desired path structure and server configuration (rewrite rules, etc.) there are multiple ways in which the path needs to be preprocessed.
This doesn't explain why the path is passed to the match() function and the request object is passed to the constructor, but it does explain why they are passed in separately.
I do have a legacy PHP application and a Symfony 4.1 application. I need to integrate both by rendering parts of a plain PHP page as the result of a predetermined controller action. That is, no resolving based on request is necessary or wanted and the response body should be inserted in the legacy page.
Put differently: I want Symfony to act on the current request, but in advance tell it to use ExampleController::exampleAction() and get the response (body). What is the cleanest way to achieve that?
Well, this is weird :)
I would try something like this:
1, Get an instance of your kernel. Check public/index.php about how to do that.
$kernel = new Kernel($env, $debug);
2, Create a request manually
$request = new Request([], [], ['_controller' => MyController::class . '::myAction']);
3, Handle the request
$kernel->handle($request);
4, Send the response, and terminate the kernel (like in index.php)
Tested it with a custom front controller, see https://gist.github.com/Padam87/27a7d0825816fa358678bce7a640dd47
If you only need the response body, then use $response->getContent().
I want to upgrade from ZF2 to ZF3 right now and has the following problem with using URL parameter in my PhpRenderer.
In ZF2 I use the HelperPluginManager to get Application, then the MvcEvent and finally the routeMatch:
$routeMatch = $this
->getHelperPluginManager()
->getServiceLocator()
->get('Application')
->getMvcEvent()
->getRouteMatch();
$parameterAction = $routeMatch->getParam('action');
In ZF3 there is a deprecation warning with using the getServiceLocator() (which makes sense, because it only returns the creationContext from the ServiceManager). I want to find a way not trigger the warning.
Configure the Application as a factory-using class (using \Zend\Mvc\Service\ApplicationFactory::class) also not works, because:
Zend\View\HelperPluginManager can only create instances of Zend\View\Helper\HelperInterface and/or callables.
Is there any way to get the Application context in my template (or better even the parameters of the URL)?
Your question title is "ZF3: Read out url parameter in PhpRenderer" while inside your question you asked another one.
You can get this in any controller (get URL parameters in ZF3):
$URLparam = (string)$this->params()->fromQuery('parameter', '');
For routeMatch, if you have a MvcEvent just use;
$event->getRouteMatch()
If you have container;
$container->getApplication()->getMvcEvent()->getRouteMatch();
If you want to access routeMatch in view there's no way except view helper like tasmaniski/zend-current-route
I'm stuck with a problem: I created an event according to the Laravel docs.
I created the files with php artisan event:generate
This command created two files:
Listeners/RevokeOldToken.php
Listeners/PruneOldTokens.php
After that when I hit the API, it returns this error:
Argument 1 passed to App\Listeners\RevokeOldTokens::handle() must be an instance of App\Events\Laravel\Passport\Events\AccessTokenCreated, instance of Laravel\Passport\Events\AccessTokenCreated given
What i am doing wrong? How can I create the instance said by the error?
You need import that two class in listener.
use Laravel\Passport\Events\AccessTokenCreated;
use Laravel\Passport\Events\RefreshTokenCreated;
I think you didn't import them, so laravel think your listener is expecting that two wrong classes, App\Events\Laravel\Passport\Events\AccessTokenCreated and App\Events\Laravel\Passport\Events\AccessTokenCreated
tl;dr
Artisan generates an incorrect use path for the event classes in the listener files so you have to fix them, by removing the App\Events part from the front.
Explanation
The Generating Events & Listeners subsection under the documentation's Registering Events & Listeners section mentions that the event and listener classes are generated based on the app/Providers/EventServiceProvider.php class' listen attribute.
This is a nice feature, but there is a little problem with it: if the array's keys (the event file paths) in the $listen attribute reference an event from the vendor folder (Laravel\Passport\Events in this case) then in the generated listener file, the imported event's path will be prefixed with App\Events\. This is the thing that you have to remove.
Because of this, the use path now references a non existing class that doesn't raise an error like "using non existing class", so when the code gets executed and the event is fired, then thanks to the mappings in the EventServiceProvider.php file, the proper event listener will be found for the event, but when the listener's handle method is called with the event, it will raise a type error (which is a PHP thing), because the argument's type hinting references a different (non existing) class.
Catching the bug in action
If we dig deep into the framework, we can find the Illuminate/Foundation/Console/EventGenerateCommand.php class the gets executed when you call php artisan event:generate. You can see that it parses the EventServiceProvider class' listen attribute then starts to generate event and listener files.
The listener generation will happen in the Illuminate/Foundation/Console/ListenerMakeCommand.php file, that will create the generated file based on the stub found in Illuminate/Foundation/Console/stubs/listener.stub.
The dummy import path will be replaced in the buildClass function. The new path has been calculated just before the replace took place and that is where the error happens:
if (! Str::startsWith($event, [
$this->laravel->getNamespace(),
'Illuminate',
'\\',
])) {
$event = $this->laravel->getNamespace().'Events\\'.$event;
}
In our case $event will start with Laravel\Passport\Events and not with App\, Illuminate or \ so the path will be prefixed with App\Events\. That is the thing you should remove in the generated files.
I hope this is official enough.