Announcement

Collapse
No announcement yet.

Advanced API example in PHP

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Advanced API example in PHP

    Since there doesn't appear to be any information on the forums or knowledge base on getting the advanced API to work I thought I would post a complete example that works.

    Many thanks to :
    fbgluck - his code really got the API working in PHP for me(http://forums.3dcart.com/general-con...t-api-xml.html)
    cbsteven - he made an awesome debug tool that has been a great help in work with the DB(http://forums.3dcart.com/general-con...ced-users.html)

    Using the runQuery, this example shows how to take fields from a form, insert a new customer into the customer table, how to do a select to get all customers and to parse the results. There are two files that make up the example, listed below. See the PHP file for more details.
    ************ 3DcartAdvancedAPIExample1.html *******************
    <html>
    <body>

    <form action="3DcartAdvancedAPIExample2.php" method="post">
    First Name: <input type="text" name="firstname"><br>
    Last Name: <input type="text" name="lastname"><br>
    Address: <input type="text" name="address"><br>
    Address2: <input type="text" name="address2"><br>
    City: <input type="text" name="city"><br>
    State: <input type="text" name="state"><br>
    Zipcode: <input type="text" name="zip"><br>
    Phone: <input type="text" name="phone"><br>
    E-mail: <input type="text" name="email"><br>
    <input type="submit">
    </form>

    </body>
    </html>
    ************ 3DcartAdvancedAPIExample2.php *******************
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Example PhP Interface to 3D Advanced API SOAP service</title>
    </head>

    <body>
    <?php
    // This example demonstrates how to use the 3Dcart advanced API. It requires the 3DcartAdvancedAPIExample1.html file.
    // The example will do the following:
    // 1) create the SOAP client to make calls to the API
    // 2) accept values from a FORM(information about a new customer) which calls this PHP code and build tghe SQL statement
    // 3) build a API call to the 3Dcart advanced API passing an SQL statement which inserts a new customer into the customer table
    // 4) parse and display the response of the API call
    // 5) build another API call to get the customer table using a select SQL statement
    // 6) parse and display the response of the API call, which will be all the records in the customer table
    // >>> CREDITS: two people I have to thank that helped me get to this point:
    // >>> fbgluck - his code really got the API working in PHP for me(http://forums.3dcart.com/general-con...t-api-xml.html)
    // >>> in fact about 1/2 the code below is his.
    // >>> cbsteven - he made an awesome debug tool that has been a greater help in work with the DB(http://forums.3dcart.com/general-con...ced-users.html)
    // The code below has been tested on Apache 2.4.7, PHP 5.5.7 and Windows7.
    // Build the Soap XML to submit to the 3D API SOAP service.
    // The PhP reference and examples for soapClient is here: PHP: SoapClient::SoapClient - Manual
    // You can see how your PhP server is configured and what is included by using the simple statement
    // phpinfo();.

    // Turn on some error reporting
    //
    ERROR_REPORTING(E_ALL);
    ini_set('display_errors', true);
    // Now define the SOAP client using the url for the service. This service is from cartAPIAdvanced Web Service
    // The service provides a single interface(runQuery) that allows any SQL statement to be executed against the cart database
    // Click on Service Description to see the WSDL service of the description.

    // 1) create the SOAP client to make calls to the API
    // first, we create a soap client with trace on so that we can later see the results.
    // trace allow us to see the results of the calls later (see below)
    // more informaton on the SimpleXML library for PhP is at PHP: SimpleXML - Manual.
    //
    $client = new soapclient('http://api.3dcart.com/cart_advanced.asmx?WSDL', array('trace' => 1,
    'soap_version' => SOAP_1_1));

    // 2) accept values from a FORM(information about a new customer) which calls this PHP code and build tghe SQL statement
    // Get the form variables and build the INSERT SQL to add new customer to Customer table
    $pfields = "(billing_firstname, billing_lastname, billing_address, billing_address2, billing_city, billing_state, billing_zip, billing_country, billing_phone, email, lastlogindate)";
    $pvalues = "(\"" . $_POST["firstname"] . "\", \"" . $_POST["lastname"] . "\", \"" . $_POST["address"] . "\", \"" . $_POST["address2"] . "\", \"" . $_POST["city"] . "\", \"" . $_POST["state"] . "\", \"" . $_POST["zip"] . "\", \"US\", \"" . $_POST["phone"] . "\", \"" . $_POST["email"] . "\", #1/1/2014#)";
    $psql = "INSERT IGNORE INTO customers" . $pfields . " VALUES" . $pvalues;
    echo "<p>Step 2: Insert SQL to run: " . $psql . "/p><br>";

    // 3) build a API call to the 3Dcart advanced API passing an SQL statement which inserts a new customer into the customer table
    //+++++++++++++++++++++++++++++++++WSDL code++++++++++++++++++++++++++++++++++++++++++++++ ++++++
    $param = array(
    'storeUrl'=>"<yoursite>.3dcartstores.com",
    // your UserKey is set from your admin panel. The API service must be enabled and you
    // have to have a valid key in order to use this service
    'userKey'=>"<yourUserKey>",
    'sqlStatement'=>$psql
    );
    // We then call the service ($client), passing the parameters(SQL) and the name of the operation(runQuery) that we want the server to execute
    // the result is assigned to a variable called $result
    $result = $client->runQuery($param);

    // 4) parse and display the response of the API call
    // Results are returned in an array that contains one item -- a stdClass object.
    // If the call was successful then assess the results
    echo "<p>Step 4: Results of SQL</p><br>";
    if (is_soap_fault($result)) {
    echo "<h2>Fault</h2><pre>";
    print_r($result);
    echo "</pre>";
    } else {
    $netresult = $result->runQueryResult->any;
    $pos = strpos($netresult, "1 affected records");
    if ($pos == false) {
    echo "<h2>Fault</h2><pre>";
    print_r($netresult);
    } else {
    echo "<b>One record added!</b>";
    }
    }

    // 5) build another API call to get the customer table using a select SQL statement
    $psql = "SELECT * FROM customers";
    //+++++++++++++++++++++++++++++++++WSDL code++++++++++++++++++++++++++++++++++++++++++++++ ++++++
    $param = array(
    'storeUrl'=>"<yoursite>.3dcartstores.com",
    // your UserKey is set from your admin panel. The API service must be enabled and you
    // have to have a valid key in order to use this service
    'userKey'=>"<yourUserKey>",
    'sqlStatement'=>$psql
    );
    // We then call the service ($client), passing the parameters(SQL) and the name of the operation(runQuery) that we want the server to execute
    // the result is assigned to a variable called $result
    $result = $client->runQuery($param);

    /* test code
    // Then we use three standard PHP SimpleXML library calls to see the results
    // print the SOAP request
    echo "<h2>SOAP Request</h2><pre>" . htmlspecialchars($client->__getLastRequest(), ENT_QUOTES) . "</pre>";
    // print the SOAP request Headers
    echo "<h2>SOAP Request Headers</h2><pre>" . htmlspecialchars($client->__getLastRequestHeaders(), ENT_QUOTES) . "</pre>";
    // print the SOAP response
    echo "<h2>SOAP Response</h2><pre>" . htmlspecialchars($client->__getLastResponse(), ENT_QUOTES) . "</pre>";
    //print_r("<br>result=" . htmlspecialchars($result, ENT_QUOTES));
    */

    // 6) parse and display the response of the API call, which will be all the records in the customer table
    // Results are returned in an array that contains one item -- a stdClass object.
    // If the call was successful then assess the results
    echo "<p>Step 6: Results of SQL</p><br>";
    if (is_soap_fault($result)) {
    echo "<h2>Fault1</h2><pre>";
    print_r("is_soap_fault: " . htmlspecialchars($result, ENT_QUOTES));
    echo "</pre>";
    } else {
    $pos = strpos($client->__getLastResponse(), "Error");
    if ($pos == true) {
    echo "<h2>Fault2</h2><pre>";
    echo "SQL Error: " . $client->__getLastResponse() . "</pre>";
    } else {
    // The Array contains one stdClass Object called runQueryResult and
    // we want the property "any" which has the response we are interested in.
    $netresult = $result->runQueryResult->any;
    // Convert the XML data into an array and then cycle through the array and print the returned results.
    $arrayresult = new SimpleXMLElement($netresult);
    $i = 1;
    foreach ($arrayresult->runQueryRecord as $element) {
    echo "<br>================= record: " . $i . "===========================<br>";
    foreach($element as $key => $val) {
    echo "{$key}: {$val}";
    }
    $i++;
    }
    }
    }

    ?>
    </body>
    </html>

  • #2
    I took the provided example and converted into a php function. The function, when called, will return a php array of the result set.

    You will need to place your storeurl and api key in the appropriate areas.

    php Function:
    Code:
    function soap_call($sql) {
    	// build parameters for call
    	$param = array(
    	'storeUrl'=>"your-store-name.3dcartstores.com",
    	'userKey'=>"your-api-key",
    	'sqlStatement'=>$sql
    	);
    	// check if soap class is active.  if not, load soap class.
    	if (!isset($client)) {
    		$client = new soapclient('http://api.3dcart.com/cart_advanced.asmx?WSDL', array('trace' => 1,'soap_version' => SOAP_1_1));
    	}
    	$result = $client->runQuery($param);
    	// parse results.  Return error code or array of results.
    	if (is_soap_fault($result)) {
    		$array['0'] = "Soap Fault";
    		$array = array_merge($array, htmlspecialchars($result, ENT_QUOTES));
    	} else {
    		$pos = strpos($client->__getLastResponse(), "Error");
    		if ($pos == true) {
    			$array['0'] =  "SQL Error: " . $client->__getLastResponse();
    		} else {
    			// create an array from soap call.
    			$netresult = $result->runQueryResult->any;
    			$netresult = str_replace("<![CDATA[", '', $netresult);
    			$netresult = str_replace("]]>", '', $netresult);			
    			$array=json_decode(str_replace(':{}',':null', json_encode(simplexml_load_string($netresult,null,LIBXML_NOCDATA))),true);
    		}
    	}
    	if (array_key_exists('0',$array)) {
    		return $array;
    	} elseif (array_key_exists('0',$array['runQueryRecord'])) {
    		return $array['runQueryRecord'];
    	} else {
    		$result_array['0'] = $array['runQueryRecord'];
    		return $result_array;
    	}
    }
    The code within your php to call the function:

    Code:
    // write your SQL statements
    $sql ="select * from products;";
    //
    // call soap function.
    $result = soap_call($sql);
    //
    // checks for result set or error return
    if (is_array($result['0'])) {	
    //Place your code to manipulate the result set here.
    echo "<pre>";
    print_r($result);
    echo "</pre>";
    } else {
    //
    // prints out error message
    echo $result['0'];
    }
    This allows me to focus my code on the task at hand and be able to call the SOAP function to select/update my cart via the API as needed.

    Hope it helps others.

    jeff
    Last edited by jcocking; 02-20-2014, 10:07 PM. Reason: fixed bug in function concerning cdata.
    Jeff

    The Wedding Printer

    Comment


    • #3
      "simplexml_load_string" How much I wish I knew of this function. Thanks for that. :)

      Whats the purpose of the json_decode(json_encode()) part of the code?

      Anyway super helpful stuff :)
      Michael

      JES Restaurant Equipment

      Comment


      • #4
        The conversion to JSON and back handles the removal of the object classes for atribute values.

        It is a down and dirty way of handling simple API results. It will not work on APIs where you have embedded attributes within the xml that are critical to the data.

        Since this is basically a sql query and returning result set, the JSON encode/decode will work.

        jeff
        Last edited by jcocking; 02-04-2014, 10:55 AM.
        Jeff

        The Wedding Printer

        Comment


        • #5
          I found a couple of errors in the above function as I have used it more. They function above has been updated.

          Error 1: The function would not resolve CDATA correctly. This would result in fields that contained html data to be ignored. (i.e. extended description.)

          Fix 1: Added the LIBXML_NOCDATA attribute to simplexml_load_string to process CDATA.

          Error 2: The function would return an empty array with a null xml value. The desired output is for the result to have a null value versus an empty array.

          Fix 2: Inserted a str_replace to the JSON encoding. The str_replaces looks for empty arrays. It replaces empty arrays with a null value. When JSON decodes, the result shows a null value.

          If I find any other errors while using the function, I will let you know. If you find something that appears odd, let me know.

          jeff
          Jeff

          The Wedding Printer

          Comment


          • #6
            I normalized the output so all data is now a multi-dimensional array. The first level array is the record set number and the sub array is the variable=>name data.

            The example to call the function now has a error checking routine. If the API received an error or a non-result set, it will now display the error.

            The function in the post above has been edited and corrected with these changes.

            If you find problems or issues, please let me know.
            Last edited by jcocking; 02-20-2014, 04:58 PM.
            Jeff

            The Wedding Printer

            Comment


            • #7
              Nice work! We've been using one that I made but I like the way you do the soap call better. So I grabbed it and wrapped it into a class and posted it here: https://gist.github.com/mtbottens/9135265

              I think running the query with a callback makes the code a lot cleaner, only problem is you need to be running a newer version of php (5.3?)

              Anyway, Thanks a lot for this :)
              Michael

              JES Restaurant Equipment

              Comment


              • #8
                Originally posted by mtbottens View Post
                Nice work! We've been using one that I made but I like the way you do the soap call better. So I grabbed it and wrapped it into a class and posted it here: https://gist.github.com/mtbottens/9135265
                I placed the wrong code earlier yesterday and updated last night.

                There are a couple of items I would suggest updating in the class:
                1. I would suggest replacing lines 34-36 in your class with the code above. Using LIBXML_NOCDATA is a cleaner way of dealing with CData versus my earlier version.
                2. I would also look at replacing lines 51-56. This provides a way to normalize the results sets (multi row result set versus single row result set). It also provides a different way to trap error messages when calling the function.
                3. I also updated the php that calls the function to look for error messaging.


                I am sorry that my mistake of updating the wrong version of the code, will cause you some rework.
                Jeff

                The Wedding Printer

                Comment


                • #9
                  php blows my mind sometimes.

                  the same code in node is so much simpler.

                  -------------------------------------------
                  var soap = require('soap');

                  var url = "http://api.3dcart.com/cart_advanced.asmx?WSDL";
                  var params = {
                  storeUrl: 'yourstoreurlhere',
                  userKey: 'yourapikeyhere'
                  };


                  exports.sendRawQuery = function(queryString, callback)
                  {
                  params.sqlStatement = queryString;
                  soap.createClient(url, function(err, client)
                  {
                  client.runQuery(params, function(err, result)
                  {
                  callback(result.runQueryResult.runQueryResponse);
                  });
                  })
                  }


                  handle errors how you wish, and just pass a callback function to do whatever you want with the response. blam.

                  Comment


                  • #10
                    Yeah, I've grown to dislike PHP as well. It was the first server side language I learned though.

                    I'm more of a fan of using ruby and the savon gem (Savon (Heavy metal SOAP client) - Welcome)

                    Thanks for the node example though. I may actually end up using it a bit too :)
                    Michael

                    JES Restaurant Equipment

                    Comment


                    • #11
                      i dont know ruby at all, but if you need any help with node hit me up.

                      i write everything in javascript.. its just easier.

                      Comment

                      Working...
                      X