Resources
Tuesday, 20 April 2010 12:46

We recently had a drive failure on our development server and while going through the steps of re-installing CentOS, I came across an odd problem.

The server in question has 3 drives:

  • Drive has the OS on it
  • Drive 2 and 3 is a software RAID1 with Device Mapper (DM)

The problem: CentOS installer would get to a certain point after selecting Language and keyboard option, then hang. By switching to a virtual console to see the debug messages, the installer was stuck on:

CentOS install hangs with moving (1) to step findrootparts

I tried CentOS 4.4, CentOS 5.4 net install and CentOS 5.0. Every single one had the same problem!

Come to find out, there is a bug with RedHat , which also effects CentOS, that causes the installation to mess up when attempting to detect/enable/whatever the software raid array. Here is a description of bug 517556

The solution is to boot the install with the "nodmraid" option, like so:

At the boot prompt, type:

linux nodmraid

Or if you use text install like me type: 

linux nodmraid text

And that worked! Hope this helps someone

Wednesday, 31 March 2010 03:42

I would like to share with you a little PHP class that makes interacting with the SugarCRM SOAP API using the native SoapClient implementation in PHP5, eliminating the need for NuSoap and subsequently improving performace a little bit. Sugar still uses NuSoap on their end, so you have that to contend with, but anyway..





First we need to create a class with a constructor that automatically initializes the PHP5 SoapClient interface

class SugarTalker
{
    private $url;
    private $username;
    private $password;
    private $soapclient;
    private $sessionId;

    function __construct()
    {
      $this->url = "http://www.yourdomain.com/sugarcrm/soap.php";  // Replace with your location of SugarCRM
      $this->username = "admin";
      $this->password = "password";
            
      $this->soapclient = new SoapClient(null, 
                                         array('location' => $this->url,
                                         'uri'            => 'http://www.sugarcrm.com/sugarcrm',
                                         'soap_version'   => SOAP_1_1,
                                         'trace'          => 1,
                                         'exceptions'     => 0
                                        ));
    }

We deliberately do not use SoapClient in WDSL mode, because after quite a long time of scratching my head over the some odd problems, I found out that PHP's SoapClient does not play well with a NuSoap server in WSDL mode, which SugarCRM uses to implement SOAP. I was having odd SoapFault messages with HTML server errors in them, which apparently SugarCRM was generating. If you are not sure what this means, just copy the above code as is, and appreciate my time on this one ;)





Next we need to establish a working session with SugarCRM. Once we do that, sugar generates and returns a unique session id that we send with all of our subsequent API calls so that we don't have to authenticate every single time we send over a request. This class is designed to authenticate one and automatically store and send the session id. More on that in a sec, for now:

    public function createSession()
    {
      $user_auth = array( 
         'user_name' => $this->username, 
         'password' => md5($this->password),
         'version' => $this->soapclient->get_server_version()
      );
      
      $application = "Some description of your program here";
      $result = $this->soapclient->login($user_auth, $application);
      $session_id = $result->id;    
      $result = $this->soapclient->seamless_login($session_id);
      
      if ($result)
      {
         $this->sessionId = $session_id;
         return $session_id;
      }
      else
      {
         error_log("There is a problem with creating a SugarCRM session: {$result}");
         return FALSE;
      }
   }




You would instantiate the class in the following manner:

$sugar = new SugarTalker();

if (!$sugar->createSession())
{
  // Looks like authentication didn't work..do something
}





Now for some magic. Since our SoapClient "inherits" the methods defined by SugarCRM's API, we want to be able to access them directly from our SugarTalker class, so we implement some method overloading, PHP5 style:


   public function __call($method, $args)
   {
      return call_user_func_array(array($this->soapclient, $method), $args);
   }

That simply means that when we initialize the SugarTalker class and call a method on it, it redirects that call to the soapclient object instead.





We need a few methods to make the overloading really useful. These are just what I consider the common SOAP methods that Sugar has:


   public function get_entry()
   {
      $args = func_get_args();
      array_unshift($args, $this->sessionId);
      return $this->__call("get_entry", $args);
   }
   
   
   public function get_entries()
   {
      $args = func_get_args();
      array_unshift($args, $this->sessionId);
      return $this->__call("get_entries", $args);
   }

   
   public function get_entry_list()
   {
      $args = func_get_args();
      array_unshift($args, $this->sessionId);
      return $this->__call("get_entry_list", $args);
   }
   
   public function set_entry()
   {
      $args = func_get_args();
      array_unshift($args, $this->sessionId);
      return $this->__call("set_entry", $args);
   }
   
   public function set_entries()
   {
      $args = func_get_args();
      array_unshift($args, $this->sessionId);
      return $this->__call("set_entries", $args);
   }

Check it out! Now if we call $sugarTalker->set_entry($var1, $var2) , our class automatically prepends the sugar session id in front of the rest of our arguments to the method. Look at the example below for creating a contact, and notice how we call set_entry() directly on the SugarTalker object, and note how PHP routes this method to the soapclient object.



// Example of how to create a Contact and assign it to a user:

$sugar = new SugarTalker();
$sugar->createSession();

$data = array(array("name" => "first_name",       "value" => "Craig"),
              array("name" => "last_name",        "value" => "McDaniel"),
              array("name" => "assigned_user_id", "value" => "41a3085d-949a-912f-7b12-4baecb6992fe") // a md5 hash
             );

$sugar->set_entry("Contacts", $data);




Sugar has a certain funky way of expecting its input data as an array of associative arrays, each with a key => value pair. "What?" you say? Exactly. Let me show you.


print_r($data)  // yeilds a better explanation of the structure below:

Array
(
    [0] => Array
        (
            [name] => first_name
            [value] => Craig
        )

    [1] => Array
        (
            [name] => last_name
            [value] => McDaniel
        )

    [2] => Array
        (
            [name] => assigned_user_id
            [value] => 41a3085d-949a-912f-7b12-4baecb6992fe
        )

)



The solution is a specific little method that takes a hash, or assoc. array and converts it into the format Sugar likes

   function fromAssoc($array)
   {
      $multi = array();
  
      while(list($name, $value) = each($array))
      {
         $multi[] = array("name" => $name, "value" => $value);
      }
      
   return $multi;
   }



// Which enables you to do the following, which is much easier to read:

$data = array();
$data['first_name'] = "Craig";
$data['last_name'] = "McDaniel";
$data['assigned_user_id'] = "41a3085d-949a-912f-7b12-4baecb6992fe";

$sugar->set_entry("Contacts", $sugar->fromAssoc(data));