public function api($path, $post_data = array())
 {
     $action = null;
     if ($this->cacheAction && isset($this->actionCache[$path])) {
         $action = $this->actionCache[$path];
     }
     // IE: "contact/view"
     $components = explode("/", $path);
     $component = $components[0];
     if (count($components) > 2) {
         // IE: "contact/tag/add?whatever"
         // shift off the first item (the component, IE: "contact").
         array_shift($components);
         // IE: convert to "tag_add?whatever"
         $method_str = implode("_", $components);
         $components = array($component, $method_str);
     }
     if (preg_match("/\\?/", $components[1])) {
         // query params appended to method
         // IE: contact/edit?overwrite=0
         $method_arr = explode("?", $components[1]);
         $method = $method_arr[0];
         $params = $method_arr[1];
     } else {
         // just a method provided
         // IE: "contact/view
         if (isset($components[1])) {
             $method = $components[1];
             $params = "";
         } else {
             return "Invalid method.";
         }
     }
     // adjustments
     $add_tracking = false;
     switch ($component) {
         //case 'list':
         //$component = 'cList';
         //break;
         case 'branding':
             $component = 'design';
             break;
         case 'sync':
             $method = $component;
             $component = 'design';
             break;
         case 'singlesignon':
             $component = 'auth';
             break;
         case 'tracking':
             $add_tracking = true;
             break;
     }
     if ($action === null) {
         $action = new Action(array('method' => $component . '_' . $method, 'output' => $this->output), $this->config);
         if ($this->cacheAction === true) {
             $this->actionCache[$path] = $action;
         }
     }
     $reset = array('data' => $post_data ? $post_data : array(), 'params' => $params ? $params : '');
     if ($action->getOutput() !== $this->output) {
         $reset['output'] = $this->output;
     }
     $action->resetAction($reset);
     return $this->doAction($action);
     //leave original code here, as a todo list
     $class = ucwords($component);
     // IE: "contact" becomes "Contact"
     $class = __NAMESPACE__ . '\\' . $class;
     $class = new $class($this->config, $this->debug);
     // IE: $contact->view()
     if ($add_tracking) {
         $class->track_email = $this->track_email;
         $class->track_actid = $this->track_actid;
         $class->track_key = $this->track_key;
     }
     if ($method == "list") {
         // reserved word
         $method = "list_";
     }
     $class->debug = $this->debug;
     $response = $class->{$method}($params, $post_data);
     return $response;
 }
 /**
  * Alternative, more OO take on this object's curl method
  * basically a copy-paste-rewrite ;)
  * @param Action $todo
  * @param null $customMethod
  * @return mixed
  * @throws \RuntimeException
  */
 public function doAction(Action $todo, $customMethod = null)
 {
     $method = $customMethod;
     if ($customMethod === null) {
         $method = $todo->getMethod();
     }
     $url = $this->getUrl() . (string) $todo;
     $debug_str1 = array();
     $request = curl_init();
     $debug_str1[] = '$ch = curl_init();';
     if ($this->debug) {
         $this->dbg($url, 1, "pre", "Description: Request URL");
     }
     if ($todo->getVerb() === Action::ACTION_GET && $todo->getData()) {
         $url .= '&' . http_build_query($this->formatDateTimeInstances($todo->getData()));
     }
     curl_setopt($request, \CURLOPT_URL, $url);
     curl_setopt($request, \CURLOPT_HEADER, 0);
     curl_setopt($request, \CURLOPT_RETURNTRANSFER, true);
     $debug_str1[] = 'curl_setopt($ch, \\CURLOPT_URL,"' . $url . '");';
     $debug_str1[] = 'curl_setopt($ch, \\CURLOPT_HEADER,0);';
     $debug_str1[] = 'curl_setopt($ch, \\CURLOPT_RETURNTRANSFER,true);';
     $data = $todo->getData();
     if ($todo->getVerb() !== 'GET' && $data) {
         switch ($todo->getVerb()) {
             case 'PUT':
                 curl_setopt($request, \CURLOPT_CUSTOMREQUEST, 'PUT');
                 $debug_str1[] = 'curl_setopt($request, CURLOPT_CUSTOMREQUEST, "PUT")';
                 break;
             case 'POST':
                 curl_setopt($request, \CURLOPT_POST, 1);
                 $debug_str1[] = 'curl_setopt($ch, CURLOPT_POST, 1);';
                 break;
             default:
                 throw new \RuntimeException(sprintf('Request WITH data implies PUT or POST verb in action, %s given', $todo->getVerb()));
         }
         curl_setopt($request, \CURLOPT_HTTPHEADER, array('Expect:'));
         $debug_str1[] = 'curl_setopt($request, \\CURLOPT_HTTPHEADER, array("Expect:"));';
         if ($this->debug) {
             $this->dbg($todo->getData(true), 1, "pre", "Description: POST data");
         }
         curl_setopt($request, \CURLOPT_POSTFIELDS, http_build_query($this->formatDateTimeInstances($data)));
         $debug_str1[] = 'curl_setopt($request, CURLOPT_POSTFIELDS, $data);';
     }
     curl_setopt($request, \CURLOPT_SSL_VERIFYPEER, false);
     curl_setopt($request, \CURLOPT_SSL_VERIFYHOST, 0);
     curl_setopt($request, \CURLOPT_FOLLOWLOCATION, true);
     $debug_str1[] = 'curl_setopt($ch, \\CURLOPT_SSL_VERIFYPEER, false);';
     $debug_str1[] = 'curl_setopt($ch, \\CURLOPT_SSL_VERIFYHOST, 0);';
     $debug_str1[] = 'curl_setopt($ch, \\CURLOPT_FOLLOWLOCATION, true);';
     $response = curl_exec($request);
     $debug_str1[] = 'curl_exec($ch);';
     if ($this->debug) {
         $this->dbg($response, 1, "pre", "Description: Raw response");
     }
     $httpCode = curl_getinfo($request, \CURLINFO_HTTP_CODE);
     $debug_str1[] = '$httpCode = curl_getinfo($ch, \\CURLINFO_HTTP_CODE);';
     if ($this->debug) {
         $this->dbg($httpCode, 1, "pre", "Description: Response HTTP code");
     }
     curl_close($request);
     $debug_str1[] = 'curl_close($ch);';
     if ($this->debug) {
         $this->dbg($response, 1, "pre", "Description: Response object (" . $this->output . ")");
     }
     // add methods that only return a string
     if (in_array($method, self::$StringOnly)) {
         return $response;
     }
     switch ($this->output) {
         case 'json':
             $object = json_decode($response);
             $jError = json_last_error();
             if ($jError !== \JSON_ERROR_NONE) {
                 throw new \RuntimeException(sprintf('An unexpected problem occurred with the API request. Some causes include: invalid JSON or XML returned.
                         URL request was sent to: %s
                         DATA: %s
                         Here is the actual response from the server: ---- %s%s%s
                         JSON errors: %d - %s', $url, $data ? $todo->getData(true) : 'No data', PHP_EOL . '<br>', $response, PHP_EOL . '<br>', $jError, $this->getJSONError($jError)));
             }
             break;
         case 'serialize':
             $object = unserialize($response);
             if (!$object) {
                 throw new \RuntimeException(sprintf('An unexpected problem occurred with the API request. Some causes include: invalid JSON or XML returned.
                         URL request was sent to: %s
                         DATA: %s
                         Here is the actual response from the server: ---- %s%s%s', $url, $data ? $todo->getData(true) : 'No data', PHP_EOL . '<br>', $response, PHP_EOL));
             }
             //ensure instanceof \stdClass through json_decode
             if (!$object instanceof \stdClass) {
                 $object = json_decode(json_encode((array) $object));
             }
             break;
         case 'xml':
             if (function_exists('simplexml_load_string')) {
                 //simpleXML extension is installed
                 $object = $this->parseSimpleXML(simplexml_load_string($response));
                 break;
             }
             $dom = new \DOMDocument();
             $dom->loadXML($response);
             $object = $this->parseXMLDom($dom);
             break;
     }
     if ($this->debug) {
         $debug_str1 = implode(PHP_EOL, $debug_str1);
         //if needs must, do not echo, we're setting headers below!!
         $this->dbBuffer[] = "<textarea style='height: 300px; width: 600px;'>" . $debug_str1 . "</textarea>";
         $this->getDebugBuffer($httpCode);
     }
     /** @var \stdClass $object */
     $object->http_code = $httpCode;
     if (isset($object->result_code)) {
         $object->success = $object->result_code;
         if (!(int) $object->result_code) {
             $object->error = $object->result_message;
         }
     } elseif (isset($object->succeeded)) {
         // some calls return "succeeded" only
         $object->success = $object->succeeded;
         if (!(int) $object->succeeded) {
             $object->error = $object->message;
         }
     }
     return $object;
 }