Codeception sendPOST not working with Slim 3 getParam - php

Relatively new to Codeception and trying to hook it up to Slim 3.
Setting up a basic test for a POST request like so:
$I->sendPOST('/user', [
'details' => [
'id' => 0,
'package_id' => 0,
'order_id' => 0
]
]);
On the route itself, I am using Slim 3's getParam to get the details that I sent over like so:
$details = $request->getParam('details', []);
Running the test via --debug, I see that the Request has {"details":{"package_id":0,"order_id":0}
However, it seems as if the details from the getParam are returning nothing.
I've tried sending them separately outside of details but to no avail.
At this point, wondering if it's a PSR-7 compatibility issue between the details I send via Codeception's sendPOST and Slim 3's getParam since the getParam method from Slim came with the comments:
* Fetch request parameter value from body or query string (in that order).
*
* Note: This method is not part of the PSR-7 standard.
Any help is appreciated!

Related

CakePHP 4, AWS Elasticsearch 7 - The security token included in the request is invalid

So I'm running CakePHP 4 on an EC2 instance, AWS ES 7 and I've setup the ElasticSearch plugin in CakePHP.
composer require cakephp/elastic-search "^3.0"
I've added the elastic datasource connection in config/app.php
'elastic' => [
'className' => 'Cake\ElasticSearch\Datasource\Connection',
'driver' => 'Cake\ElasticSearch\Datasource\Connection',
'host' => 'search-DOMAIN.REGION.es.amazonaws.com',
'port' => 443,
'transport' => "AwsAuthV4",
'aws_access_key_id' => "KEY",
'aws_secret_access_key' => "SECRET",
'aws_region' => "REGION",
'ssl' => 'true',
],
.. and I've activated the plugin
use Cake\ElasticSearch\Plugin as ElasticSearchPlugin;
class Application extends BaseApplication
{
public function bootstrap()
{
$this->addPlugin(ElasticSearchPlugin::class);
I've manually added 1 index record to ES via curl from the EC2 instance. So I know the communication between EC2 and ES works.
curl -XPUT -u 'KEY:SECRET' 'https://search-DOMAIN.REGION.es.amazonaws.com/movies?pretty' -d '{"director": "Burton, Tim", "genre": ["Comedy","Sci-Fi"], "year": 1996, "actor": ["Jack Nicholson","Pierce Brosnan","Sarah Jessica Parker"], "title": "Mars Attacks!"}' -H 'Content-Type: application/json'
I also managed to search for this record via curl without any problems.
In the AppController.php I tried this simple search just to see if the plugin works and for the life of me, I can't get it to work.
# /src/Controller/AppController.php
...
use Cake\ElasticSearch\IndexRegistry;
class AppController extends Controller
{
public function initialize(): void
{
parent::initialize();
$this->loadModel('movies', 'Elastic');
$query = $this->movies->find('all');
$results = $query->toArray();
I'm getting the following error:
Client error: POST
https://search-DOMAIN.REGION.es.amazonaws.com/movies/movies/_search
resulted in a 403 Forbidden response: {"message":"The security token
included in the request is invalid."}
Elastica\Exception\Connection\GuzzleException
Seems like the plugin adds the 'Index' name twice for some reason. I looked everywhere for a setting that I might have missed. If I copy and paste the above URL and remove the duplicate Index from the URL in a browser it works fine.
https://search-DOMAIN.REGION.es.amazonaws.com/movies/_search
Am I missing something here?
I've even tried this method, and I get the same problem with duplicated index values in the url.
$Movies = IndexRegistry::get('movies');
$query = $Movies->find('all');
$results = $query->toArray();
I've tried a new/clean CakePHP instance and I get the same problem? Is there something wrong with the plugin? Is there a better approach to communicate with ES via CakePHP?
I'm not familiar with the plugin and Elasticsearch, but as far as I understand, one of the movies is the index name, and one of them is the type name, where the type name - at least according to the documentation - should be singular, ie the path would instead be expected to look like:
/movies/movie/_search
Furthermore, Index classes assume that the type mapping has the singular name of the index. For example the articles index has a type mapping of article.
https://book.cakephp.org/elasticsearch/3/en/3-0-upgrade-guide.html#types-renamed-to-indexes
Whether that would be the correct path with respect to what is supported by the used Elasticsearch version, that might be a different question.
You may want to open an issue over at GitHub.

Laravel dispatch plain json on queue

I have 2 simple questions overall. Im currently looking into some event handling in Laravel and would like to use RabbitMQ as my event store. Therefor i installed this package to start with: https://github.com/php-enqueue/enqueue-dev
To get started i registered it and i am able to push messages on to RabbitMQ:
$job = (new Sendemail())->onQueue('email')->onConnection('interop');
dispatch($job);
The problem however is that Laravel pushes a certain format on the queue and i can't figure out how to change that. An example message would be:
{
"job":"Illuminate\\\\Queue\\\\CallQueuedHandler#call",
"data":{
"command":"O:29:\\"Acme\\Jobs\\FooJob\\":4:{s:11:\\"fooBar\\";s:7:\\"abc-123\\";s:5:\\"queue\\";N;s:5:\\"delay\\";N;s:6:\\"\\u0000*\\u0000job\\";N;}"
}
}
So the question is, how can i change this? The main reason on this is that the consumer side is not even a PHP application which also can not interpret the PHP serialized model. Therefor im looking for a way to push a plain JSON object instead.
From the other hand i would also like to understand how you could build a custom listener? For the listener the same thing happens. Laravel tries to read the method but when i push plain JSON this will never work. Isn't there a way to register a handler on a topic and do further handling of the payload of the message within the handler itself?
There is a simple way for your purpose:
First install this package for rabbit:
vladimir-yuldashev/laravel-queue-rabbitmq
and in controller:
Queue::connection('rabbitmq')->pushRaw('{you can generate a json format here}', 'queue_name');
you can generate a json and put in this command.
There's a laravel-queue library that works with the php-enqueue library you linked to make it compatible with Laravel's built in queue system that Florian mentioned.
By default, it will still use a serialized object, but I think that can be overridden. If you look in Queue.php, createObjectPayload() on line 130 in the core Laravel Framework, that's where the job is being serialized.
If you extend the Queue class in the laravel-queue library, you should be able to change createObjectPayload to look something like this:
protected function createObjectPayload($job, $queue)
{
$payload = $this->withCreatePayloadHooks($queue, [
'displayName' => $this->getDisplayName($job),
'job' => 'Illuminate\Queue\CallQueuedHandler#call',
'maxTries' => $job->tries ?? null,
'timeout' => $job->timeout ?? null,
'timeoutAt' => $this->getJobExpiration($job),
'data' => [
'commandName' => $job,
'command' => $job,
],
]);
return array_merge($payload, [
'data' => [
'commandName' => get_class($job),
'command' => json_encode(clone $job),
],
]);
}
That should JSON encode the job data instead of serializing it. You may even be able to remove the encoding altogether, as I think it's already JSON encoded somewhere up the chain.

Guzzle 6 - How to pass query to redirects

I'm struggling to find out if there is a way to ask Guzzle to pass a query on to redirects. So that if I were to say
$res = $client->request("GET", "https://google.com", [
'allow_redirects' => true,
'timeout' => 2000,
'query' => ['foo'=>'bar'],
]);
And lets say that (for some bizarre reason) google redirected to https://somewhere-else.com, I would like my foobar query to be passed on to that URL too
https://somewhere-else.com?foo=bar
Would love some help with this.
Thanks
There is no standard mechanism in Guzzle to do that, because (as #Calimero already said) the HTTP spec doesn't assume this behaviour.
But you can copy and modify the RedirectMiddleware, that Guzzle uses to handle allow_redirects option.

Laravel 5 REST client CRUD

Is there a way in Laravel 5 to do a CRUD using REST? I have a REST API already using CodeIgniter and I want my Laravel application to communicate with it.
So let's say I have this url to get all gender: http://api.local/api/api_gender/gender
In my controller, it seems I can do something like this:
$results = json_decode(file_get_contents('http://api.local/api/api_gender/gender/'));
But I dont know if this is the right way to do it.
Now, how could I do it if I want to add a new gender in Laravel? In CI, I could simply use Phil's rest library and just use $this->rest->put('http://api.local/api/api_gender/gender/', $parameters)
I would use Guzzle, a very popular, flexible HTTP client for PHP. As far as I know, it is one of the most used packages to make HTTP requests in PHP.
$client = new GuzzleHttp\Client();
$client->put('http://api.local/api/api_gender/gender/', ['json' => ['foo' => 'bar']]);
// or
$client->put('http://api.local/api/api_gender/gender/', ['query' => ['foo' => 'bar']]);

How to avoid sending a Guzzle request after instantiation?

Context: Laravel 5. Guzzle ~5.2. PHP 5.4. I'm building a class to interact with an external API. I'm providing this class with a Guzzle client using a Service Provider, to avoid instantiating the client within a method.
I want to cache the results. If the user is asking for something that is found in the cache, return it instead of performing a request to said API.
Problem: If I build up a Guzzle client and don't perform a request, the application crashes. Not even a stack trace from PHP. Actually, if I'm using Laravel's artisan serve, a Windows error message shows up saying, PHP CLI has stopped working.
For now, I'm passing the Guzzle client to the method on my class, every single time I call it.
Is there a way to just instantiate the Guzzle client without sending a request? What other route would you choose to achieve this? Is that intended behaviour?
tl;dr RTM
Longer version (from the docs):
Creating Requests
You can create a request without sending it. This is useful for building up requests over time or sending requests in concurrently.
$request = $client->createRequest('GET', 'http://httpbin.org', [
'headers' => ['X-Foo' => 'Bar']
]);
// Modify the request as needed
$request->setHeader('Baz', 'bar');
After creating a request, you can send it with the client’s send() method.
$response = $client->send($request);
from here:
http://docs.guzzlephp.org/en/stable/quickstart.html#making-a-request
use GuzzleHttp\Psr7\Request;
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'http://httpbin.org',
// You can set any number of default request options.
'timeout' => 2.0,
]);
$request = new Request('PUT', 'http://httpbin.org/put');
$response = $client->send($request, ['timeout' => 2]);

Categories