php SoapClient, __soapCall and __getLastRequest / __getLastResponse - php

I used a downloaded tool to auto-create a wrapper for a web service (fedex rate service) as it creates a really handy code base for accessing the service that auto-generates a class map and builds an auto-loading data structure by asking the web service itself for it's requirements and capabilities. It creates this wrapper as an 'extend' of SoapClient itself.
The only problem is, that it makes the separate service calls using an abstract wrapper that utilizes the __soapCall method. The problem that I've noticed with this is that it apparently doesn't populate anything where you can retrieve the XML from the calls themselves. Whenever I call __getLastRequest or __getLastResponse, they just return null even though __soapCall('getRates', $args) returns a php object response from the service.
Short of my re-writing the auto-generated code to call $this->getRates($args) or something similar, is there any trick to seeing the XML used in the request and returned in the response when using __soapCall ?

Nevermind - I thought I had trace defaulted to true, and the reason i was getting back 'null' was that it was defaulting to false.
As long as I create the interface instance with the second argument array('trace'=>1) I'm getting the XML now.

Related

Should a class be able to hold an instance of itself?

I am currently busy with a PSR-7 project with responses and requests.
Currently we are setting up an application in our index.php by doing something like:
$app = new Application();
$app->loadConfiguration(
'../config/global.yml',
);
// Should return the response?
$app->run((new ServerRequestFactory())->createServerRequestFromGlobals());
Here the run method also calls an emit method that is responsible for sending the headers and printing the body of the response.
The request and respons are now linked together in one call which makes it hard to test since you don't want to send the response with the headers straight to PHPUnit.
I have removed the emit call in the chain of the run method and added this to the index after the run method call:
// Send the response.
$app->send();
This way they are decoupled but the downside is I now have to hold a instance of my response in a response property inside my Application.php($app) class.
I want to move the response instance to the response class itself but my co-workers thinks a class should never hold an instance of itself. Yet when I look at frameworks this happens quite a lot. Is he right about this?
What arguments can I make to decouple my request and response besides easier testing?
I am pretty new to unit testing, one of the arguments I have already heard is that I should not test the full application anyways but rather separate components and therefore should not be worried about de-coupling the request and response.

Zend Soap Server / WSDL

I've been working on a project (which I'll keep specific details out of this post with randomized data) that involves integrating our system (PHP 5.3.x+) with an API (they provided a SDK) of a major company. They provided a WSDL and claimed ours needed to match their methods and they provided examples of how output (XML generated by the Soap Server) should look.
Right now, everything has been working as expected. When I send a XML request from SoapUI (an app I'm using to test) it all processes properly and such, but the XML output isn't matching closely with their examples and we believe they said we must be close to their examples.
Basically, we created an agnostic class we initialize with a service name and it initializes into a non-agnostic class which is used via the following:
/**
* The following is used to process Soap Server based on config and any optional settings.
*
* #param string $className
* #param array $options
* #param object $config
* #return Zend_Soap_Server
*/
public static function init($className, Array $options = null, $config = null)
{
// Used to define the class and return object.
$soap_server = new Zend_Soap_Server(null, $options);
$soap_server->setClass($className, null, (isset($config) ? $config : null));
$soap_server->handle();
exit;
}
The problem itself lies within the outputted response. How would you guys suggest we build the XML output if they're very specific about everything?
1.) One of our methods is moneyTransferRequest. When I send the XML over for this, it does find the method and processes it. However, they want it to show the method name, in the response, as moneyTransferResponse but it outputs moneyTransferRequestResponse.
2.) Our output (for variables and such sent back as an object) has multiple variables, we'll say $money for example. The field for this would return as:
<money xsi:type="xsd:string">10.0</money>
They would like it to be:
<ns1:money xsi:type="xsd:string">10.0</money>
in the return.
I appreciate any help and input on the subject.
The key feature of SOAP is that it uses XML, and XML can come in a bunch of different styles but still mean the same.
I think (but I can only guess because you didn't provide details) that your two issues might be non-existing.
1.) The name of the response XML structure should align with the name mentioned in the WSDL. YOU are publishing the WSDL, so you should check if these two match. Note that the important entry point is the SOAP method - everything thereafter is defined in the WSDL itself, any consuming client should be able to figure it out as long as the names mentioned are correctly used.
2.) This is basically the same, but even easier: XML allows to use namespaces, and these can be defined in several locations, with the result being not literally the same, but every XML parser will understand that they are the same. So you should check whether the namespace that is required as "ns1" is mentioned in the XML header of your response. Every XML document has a base namespace, which does not need to be repeated on every element that belongs to it.
This is the case with the <money> element. Your style of writing uses that base namespace, their style of writing uses a namespace shortcut ns1 also introduced in the XML header, but not declared as the base namespace. So as long as there are traces of the correct XML namespace in both responses, I'd assume they are equivalent.
And the bad news would be that you cannot change how the PHP SoapServer generates the XML. You'd need to create your own implementation of a SOAP server, which I'd say is a complete waste of resources.

AWS S3 SDK for PHP 2 - Get HTTP Request/Response Strings

I have a generic HTTP file access API which I use for the system I'm working on. To make it as flexible as possible, it returns request and response data in the form of HTTP strings.
I'm currently implementing a version which interacts with the S3, via the AWS SDK for PHP 2.
Is there an easy way to quickly get the Request and Response HTTP requests which the S3Client makes when performing operations? If not, is there a more piecemeal way which I can use to not have to fake it?
Basically, I'd like the full-text of both the Request and Response on demand, or at least access to relevant data (headers, response codes, URLs, etc) so I can properly populate the return data for my framework.
Thanks.
You can get either the request or response object from a command object. Assuming $s3 holds an instance of Aws\S3\S3Client, you could do something like this:
$command = $s3->getCommand('ListObjects', array('Bucket' => '<bucket-name>'));
$request = $command->getRequest();
$response = $command->getResponse();
Those objects have methods for viewing the body, headers, status codes, etc. and you can cast them to string to see the string form.
If you want to quickly see the request and response as you are executing commands, you can attach the wire logger, and see what comes out on STDOUT (or STDERR)
$s3->addSubscriber(\Guzzle\Plugin\Log\LogPlugin::getDebugPlugin());
$s3->listObjects(array('Bucket' => '<bucket-name>'));
You will need to look into the Guzzle\Http\Client class, which is an ancestor class to S3Client, to have a look at the methods that it makes available. You can always override some of these methods in your own child of S3Client to make accessing this information easier for you.
Ultimately the data you are looking for resides in an object of class Guzzle\Http\Message\Response, which I believe is returned from Guzzle\Http\Client::send().
So perhaps in your own implementation of S3Client you can override the send() method to send the HTTP requests, then process the response data as needed.

Can I use PHP's SoapClient to parse a SOAP response, without making the HTTP request?

I'm currently dealing with an archaic payment processor that makes connecting to their service as hard as possible (including a custom client SSL cert, with a password, plus basic HTTP Auth after that). Long story short, I can't use SoapClient to make the request, but I have been able to do it with cURL.
I now have the response in a string, can I use SoapClient to parse it? I'd rather not have to parse it manually as a regular XML, since I'd have to duplicate a lot of functionality, like throwing a sensible exception when finding a <SOAP:Fault>, for example.
No, you can't.
(just answering this for posterity. Based on the lack of evidence to the contrary, you apparently can't use SoapClient to parse a SOAP response you already have)
You can define context using context option of SoapClient to tell SoapClient to use SSL certificates etc. Context may be created using stream_context_create with lots of options
Let's for a second imagine you had called SoapClient::__doRequest() and it returned your XML SOAP response into a variable called $response.
<?php
//LOAD RESPONSE INTO SIMPLEXML
$xml = simplexml_load_string($response);
//REGISTER NAMESPACES
$xml->registerXPathNamespace('soap-env', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('somenamespace', 'http://www.somenamespace/schema/');
//...REGISTER OTHER NAMESPACES HERE...
//LOOP THROUGH AND GRAB DATA FROM A NAMESPACE
foreach($xml->xpath('//somenamespace:MessageHeader') as $header)
{
echo($header->xpath('//somenamespace:MyData'));
}
//...ETC...
?>
That is just some example/pseudo code (not tested and won't work as-is). My point is that you manually acquired the SOAP response so now all you have to do is parse it. SimpleXML is one solution you could use to do that.

PHP / SOAP / WSDL questions

I'm writing a SOAP API in PHP and I've run into a small problem. The API uses a functions file which contains a function called "GetChallenges()". I'd like my API to have a method with the same name, but since I'm including the functions file, it causes an error saying that I can't redefine that function. I'd really rather not rename the function in the functions file since i'd have to go all through my existing code and change the references. Is there a way to have the name of the function in PHP be something like"GetChallengesApi()" and yet have SOAP be able to run it as just GetChallenges()?

Categories