For those of you who aren't familiar with MindBody ( http://www.mindbodyonline.com ) it is a convenient merchant processing tool for health and wellness centres like the yoga studio I do work for. It can track clients and manage employees and all sorts of great stuff. I have been generating reports using nuSOAP and the MindBody SOAP API v0.4 for a while now. When my client asked me to generate a report that needed the updated MindBody SOAP API v0.5 I decided to drop nuSOAP for PHP5's native SOAP. Then I heard that Zend Soap offers the same speed as the native soap but also has a bunch of other benefits so I wrote the following code.
<?php
require_once 'Zend/Soap/Client.php';
$sourceCredentials = array('SourceName'=>'****', 'Password'=>"****", 'SiteIDs'=>array('****'));
try {
$client = new Zend_Soap_Client('https://api.mindbodyonline.com/0_5/ClientService.asmx?WSDL');
$result = $client->GetClients(array("SourceCredentials"=>$sourceCredentials, "XMLDetail"=>"Basic", "PageSize"=>"10", "CurrentPageIndex"=>"0", "ClientIDs"=>array("100009536")));
echo $client->getLastRequest();
} catch (SoapFault $s) {
die('ERROR: [' . $s->faultcode . '] ' . $s->faultstring);
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
var_dump($client);
var_dump($result);
?>
I'm not sure what I'm doing wrong. The page just keeps loading and loading but never loads. I'm hoping someone can take a look at the WSDL or the API Docs and tell me what I'm missing. Here's the link to the API Docs http://api.mindbodyonline.com/Doc I am trying to use the client service in this example.
If I comment out the $result = $client->GetClients~ line then the page loads and the var_dump of $client returns this
object(Zend_Soap_Client)#1 (28) { ["_encoding:protected"]=> string(5)
"UTF-8" ["_classmap:protected"]=> NULL
["_faultExceptions:protected"]=> array(0) { }
["_soapVersion:protected"]=> int(2) ["_uri:protected"]=> NULL
["_location:protected"]=> NULL ["_style:protected"]=> NULL
["_use:protected"]=> NULL ["_login:protected"]=> NULL
["_password:protected"]=> NULL ["_proxy_host:protected"]=> NULL
["_proxy_port:protected"]=> NULL ["_proxy_login:protected"]=> NULL
["_proxy_password:protected"]=> NULL ["_local_cert:protected"]=> NULL
["_passphrase:protected"]=> NULL ["_compression:protected"]=> NULL
["_connection_timeout:protected"]=> NULL
["_stream_context:protected"]=> NULL ["_features:protected"]=> NULL
["_cache_wsdl:protected"]=> NULL ["_user_agent:protected"]=> NULL
["_wsdl:protected"]=> string(58)
"https://api.mindbodyonline.com/0_5/ClientService.asmx?WSDL"
["_soapClient:protected"]=> NULL ["_lastMethod:protected"]=> string(0)
"" ["_soapInputHeaders:protected"]=> array(0) { }
["_permanentSoapInputHeaders:protected"]=> array(0) { }
["_soapOutputHeaders:protected"]=> array(0) { } }
I'm not sure what the values should be but all those NULLs look bad to me. I have tried different combinations of nesting the arrays passed to $client->GetClients and I've tried accessing different functions other than GetClients as well..
Okay so for anyone who happens to google this and wants the answer. You have to add a user-agent string to your page headers in order to make it work with the API for some reason. Add this code to the top of your PHP page
ini_set("user_agent", "FOOBAR");
then you need to create a Zend_Soap_Client with soap_version set to SOAP_1_1. Create an array of the parameters you are going to send. Then call the function you want and in this case you pass in a array ( "Reqest"=>$params )
$client = new Zend_Soap_Client('https://api.mindbodyonline.com/0_5/ClientService.asmx?WSDL', array("soap_version"=>SOAP_1_1));
$sourceCredentials = array('SourceName'=>'****', 'Password'=>"****", 'SiteIDs'=>array('****'));
$params = array("SourceCredentials"=>$sourceCredentials, "XMLDetail"=>"Basic", "PageSize"=>"10", "CurrentPageIndex"=>"0", "ClientIDs"=>array("123456789","123456789"));
$result = $client->GetClients(array("Request"=>$params));
EDIT: For more information check out the article I'm writing on how to get started with the MINDBODY API in under 30 minutes
Related
I am trying to run the following code with the new Google Business Profile API:
$mybusinessbusinessinformationService = new Google\Service\MyBusinessBusinessInformation($client);
try
{
$locations = $mybusinessbusinessinformationService->accounts_locations->call('list',['parent'=>'accounts/1111111111111111111']);
var_dump($locations);
} catch(Exception $e){
var_dump(print_r($e->getMessage(),1));
}
But I am getting the following error:
(list) missing required param: 'parent'
As far as I can tell it seems that I am parsing the param properly.
For people that are searching for an answer:
Since Google updated its API, it's a requirement to parse readMask as well:
$mybusinessbusinessinformationService = new Google\Service\MyBusinessBusinessInformation($client);
$params = array('readMask'=> "title,name");
$locations = $mybusinessbusinessinformationService->accounts_locations->listAccountsLocations($getAccountName,$params);
var_dump($locations);
You can find the mask parameters here:
https://developers.google.com/my-business/reference/businessinformation/rest/v1/locations
im quite new on XML, i am currently work in PHP and i have a request to other server which normaly and always return the callback with XML
In any case i would not talk about how i get the response, but how to convert the XML reponse.
They are two type of the XML response, we could call it as $response
first :
<BASEELEMENT SCHEMA="RESULT" METHOD="ADD-MBX">
<RETURN_VALUE>4</RETURN_VALUE>
<ERROR_DESCRIPTION>
<![CDATA[Error (7004): Login name already exists. Please use another login name.]]>
</ERROR_DESCRIPTION>
</BASEELEMENT>
and the second one is :
<baseelement schema="TIMEOUT" method="ADD-MBX"></baseelement>
i have searched and i got how to convert the xml reponse to obejct or array, which is
$response = new \SimpleXMLElement($response);
after convert :
object(SimpleXMLElement)#256 (3) {
["#attributes"]=>
array(2) {
["SCHEMA"]=>
string(6) "RESULT"
["METHOD"]=>
string(7) "ADD-MBX"
}
["RETURN_VALUE"]=>
string(1) "4"
["ERROR_DESCRIPTION"]=>
object(SimpleXMLElement)#257 (0) {
}
}
as we can see the ERROR_DESCRIPTION become 0.
So i would like to ask, is there any xml converter else simplexml_load_string() or new \SimpleXMLElement()
i cant use that function because i could not get the ERROR_DESCRIPTION
thank you :)
Loading it as you are with -
$response = new \SimpleXMLElement($response);
You can fetch the value quite simply as...
echo (string)($response->ERROR_DESCRIPTION).PHP_EOL;
If you want the full content (as in an XML version)...
echo $response->ERROR_DESCRIPTION->asXML().PHP_EOL;
Using XPath, you can fetch the values by...
echo (string)$response->xpath("//ERROR_DESCRIPTION")[0].PHP_EOL;
The output you are seeing shows that ERROR_DESCRIPTION is an object of SimpleXMLElement type, not that it isn't loaded.
I am trying to insert a lead into the SOAP web service with this WSDL: http://www.agemni.com/AgemniWebservices/service1.asmx?WSDL
The API is documented here: http://wiki.agemni.com/4Integration_And_API%27s/APIs/Database_API
This web service's back end code seems to be in .NET.
Here is my code:
// Create soap client.
try {
$this->client = new SoapClient("https://www.agemni.com/AgemniWebservices/service1.asmx?WSDL", array('soap_version' => SOAP_1_2, 'cache_wsdl' => 0, "trace" => true));
} catch (Exception $e) {
$this->logMessage('Couldn\'t connect to web service.');
throw $e;
}
// Create parameters.
$dataParams = new \stdClass;
$dataParams->strUsername = 'userman';
$dataParams->strPassword = 'hissecretpassword';
$dataParams->strCompanyName = 'validcompanyname';
$leadCode = 2;
$dataParams->objecttype = $leadCode;
// Create keys.
$dataParams->keys = new \stdClass;
$dataParams->keys->Phone = 'Phone';
// Create values.
$dataParams->values = new \stdClass;
$dataParams->values->Phone = '8011234567';
// Call web service.
$validateResult = $this->client->CreateEntity($dataParams);
Here is the response I receive:
object(stdClass)#27 (1) {
["ValidateEntityResult"]=>
object(SoapVar)#29 (4) {
["enc_type"]=>
int(0)
["enc_value"]=>
object(stdClass)#28 (10) {
["statusCode"]=>
string(9) "Succeeded"
["status"]=>
string(5) "Error"
["description"]=>
string(56) "Phone number is required and needs to be 10 digits long."
["errorNumber"]=>
int(1)
["xmlResult"]=>
string(39) "<?xml version="1.0" standalone="yes" ?>"
["EntityValidated"]=>
bool(false)
["EntityCreated"]=>
bool(false)
["EntityUpdated"]=>
bool(false)
["EntityIDCreated"]=>
int(0)
["isloggedIn"]=>
bool(false)
}
["enc_stype"]=>
string(15) "ExceptionReport"
["enc_ns"]=>
string(44) "http://tempuri.org/AgemniWebService/Service1"
}
}
I found a similar issue on PHPFreaks that was years old and was never successfully answered. I see other similar issues with nesting parameters in the PHP SoapClient, but all of the suggestions I've seen end in the same error message for me.
The authentication is being received just fine, along with the company name. However, I've stabbed at formatting, parsing, and encoding the keys and values parameters in nearly every way I could conceive. I've played with declaring my parameters as SoapVar and SoapParam with every potential constructor parameter I could think of and still have received the same error message.
I'd greatly appreciate any suggestions as to any reason that someone could suppose that the Agemni web service is not accepting my lead's phone number.
Thanks.
Update
I can just generate the XML request I need in a string and send it using cURL, but I'd like to use SoapClient. However, I have a hard time generating the elements within the keys and values nodes to look like this:
<anyType xsi:type="xsd:string">phone</anyType>'
I followed some guides on creating custom complex types in SoapClient, but I couldn't get it to create XML that looks like that.
What is the best way to check if table exists in DynamoDb?
I would appreciate it if the code would be in PHP.
Either active or not.
* Added later as an example to various cases for error code 400
It's very easy to check if the table exist, it can have one of the following
TableStatus => CREATING, ACTIVE, DELETING or UPDATING
but in case i get error 400 it can mean more than one thing.
1) sent null string as a table name by mistake.
[x-aws-body] => {"TableName":""}
)
[body] => CFSimpleXML Object
(
[__type] => com.amazon.coral.validate#ValidationException
[message] => The paramater 'tableName' must be at least 3 characters long and at most 255 characters long
)
[status] => 400
2) syntax error in the command sent to DynamoDB, for example writting tabel_name instead of table_name.
[x-aws-body] => {"TabelName":"test7"}
)
[body] => CFSimpleXML Object
(
[__type] => com.amazon.coral.validate#ValidationException
[message] => The paramater 'tableName' is required but was not present in the request
)
[status] => 400
3) I would guess but didn't check, if I exceed at that same time the provisioned capacity on the table.
You can have a look at "describe_table" of the official PHP SDK. 400 means "does not exist" There is a pretty extensive example in the official documentation. Look at how it is used in the "delete" example, right at the bottom.
http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/LowLevelPHPTableOperationsExample.html
Here is the (stripped) example from the doc
<?php
require_once dirname(__FILE__) . '/sdk/sdk.class.php';
$dynamodb = new AmazonDynamoDB();
$table_name = 'ExampleTable';
$response = $dynamodb->describe_table(array('TableName' => $table_name));
if((integer) $response->status !== 400)
{
$error_type = $response->body->__type;
$error_code = explode('#', $error_type)[1];
if($error_code == 'ResourceNotFoundException')
{
echo "Table ".$table_name." exists.";
}
}
?>
Some of these answers are using the older SDK's and so I thought I'd update this useful question with what I coded up and works well. The newer exceptions really do make this task easier. This function gives you a nice boolean to use in scripts.
use Aws\DynamoDb\Exception\ResourceNotFoundException; // <-- make sure this line is at the top
public function TableExists($tableName) {
$ddb = DynamoDbClient::factory(array('region' => 'us-east-1')); // EC2 role security
try {
$result = $ddb->describeTable(array(
"TableName" => $tableName
));
} catch (ResourceNotFoundException $e) {
// if this exception is thrown, the table doesn't exist
return false;
}
// no exception thrown? table exists!
return true;
}
Hopefully this complete working code helps some of you.
I think the answer that solves this with describeTable is a good one, but fooling around with the status code response makes the code less readable and more confusing.
I chose to check for a tables existence using listTables. Here are the docs
$tableName = 'my_table';
$client = DynamoDbClient::factory(array('region' => 'us-west-2'));
$response = $client->listTables();
if (!in_array($tableName, $response['TableNames'])) {
// handle non-existence.
// throw an error if you want or whatever
}
// handle existence
echo "Table " . $tableName . " exists";
With DynamoDB you need to parse the contents of the error message in order to know what type of error you received since the status code is almost always 400. Here is a sample function that could work to determine if a table exists. It also allows you to specify a status as well if you want to check if it exists and if it is in a certain state.
<?php
function doesTableExist(AmazonDynamoDB $ddb, $tableName, $desiredStatus = null)
{
$response = $ddb->describe_table(array('TableName' => $tableName));
if ($response->isOK()) {
if ($desiredStatus) {
$status = $response->body->Table->TableStatus->to_string();
return ($status === $desiredStatus);
} else {
return true;
}
} elseif ($response->status === 400) {
$error = explode('#', $response->body->__type->to_string());
$error = end($error);
if ($error === 'ResourceNotFoundException') {
return false;
}
}
throw new DynamoDB_Exception('Error performing the DescribeTable operation.');
}
Update: In the AWS SDK for PHP 2, specific exceptions are thrown by the DynamoDB client, making this way easier to handle. Also, there are "Waiter" objects, including one for this use case (see usage in the unit test) that is designed to sleep until the table exists.
The above answers are correct if you just want to know whether the table exist or not. I want to make another helpful point here in case.
One should be very careful in multi-threaded or production level code.
Assuming that one thread deleted the table, then you will still get the answer that the table exists in answer to your query from second thread, until the table is fully deleted. In such case, once the table is deleted, the table handle in second thread is zombie, like the dangling pointer error in C++.
With dynamodb cli you can do it very simple as follows:
aws dynamodb describe-table --table-name "my-table"
If the table exists it returns
0 -- Command was successful. There were no errors thrown by either the CLI or by the service the request was made to.
If the table does not exist it returns
255 -- Command failed. There were errors thrown by either the CLI or by the service the request was made to.
See also:
http://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html
http://docs.aws.amazon.com/cli/latest/topic/return-codes.html
I am using a twitter class to post updates to my account for this I have removed my twitter credentials so I am aware that XXXXX is wrong. I am able to parse the text from the remote xml file. This xml files text always reads "There are no active codes." So in my if statement i said that if the xml file reads "There are no active codes." i dont want to post anything to my twitter, but if it changes to anything else then i would like to parse that information and post it to my twitter. So today when there was an update to the xml file nothing happened. I know that the twitter portion is correct because I have a similar script that does not use an if statement and it posts fine. Once i introduced the if statement i have run into problem of not being able to post. So what can i do to post to twitter only when the xml file changes from "There are no active codes." to anything else?
// Parse Message
$source = file_get_contents('WEBSITE_URL_GOES_HERE');
$dom = new DOMDocument();
#$dom->loadHTML($source);
$xml = simplexml_import_dom($dom);
$match = $xml->xpath("//code_message");
//Twitter class (Updating status)
require_once 'twitteroauth.php';
//Twitter credentials
define("CONSUMER_KEY", "XXXXXX");
define("CONSUMER_SECRET", "XXXXXX");
define("OAUTH_TOKEN", "XXXXXX-XXXXXX");
define("OAUTH_SECRET", "XXXXXX");
// Verify credentials
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, OAUTH_TOKEN, OAUTH_SECRET);
$content = $connection->get('account/verify_credentials');
//If Statement
if ( $match[0] == "There are no active codes." ) {
/* Do Nothing */;
} else {
$connection->post('statuses/update', array('status' => 'New Code Available - ' . $match[0] ));
return $connection;
}
var_dump of the $match array:
array(1) { [0]=> object(SimpleXMLElement)#3 (1) { [0]=> string(32) "There are no active codes." } }
You should probably use a string comparison function.
like strcmp : http://php.net/manual/en/function.strcmp.php
if (strcmp($match,"There are no active codes.") != 0 )
{
$connection->post('statuses/update', array('status' => 'New Code Available - ' . $match[0] ));
return $connection;
}
Why don't you just add some debugging code and check what's going on? Echo you $match[0] and check what's in there. It's hard to imagine "if" being broken, isn't it? Maybe var_dump($match) just to check what's going on. Then you should probably either fix your condition or fix the retrieval of $match.
Check your array: the [0] element is an object, not a string. You need to get the first element of that object, if you know what I mean.
You are comparing:
Object(SimpleXMLElement)#3 (1) { [0]=> string(32) "There are no active codes." }
to
"There are no active codes."
Which is obviously not the same.
I can't test it from here, but check out the manual of simpelXMLElement: http://php.net/manual/en/class.simplexmlelement.php
You should probably get away with a simple call. Just check out what kind of object you have. A simple example would be something like "$match[0]->childname", but I can't quickly see what the childname is. Check out the manual for some sort of getchild or something, shouldn't be too tricky