tags:

views:

72

answers:

3

Hello all,

I have the following class:

class Apiconnect {

  const URL = 'https://someurl.com/api.php';
  const USERNAME = 'user';
  const PASSWORD = 'pass';

/**
*
* @param <array> $postFields
* @return SimpleXMLElement
* @desc this connects but also sends and retrieves the information returned in XML
*/

 public function Apiconnect($postFields)
 {
   $postFields["username"] = self::USERNAME;
   $postFields["password"] = md5(self::PASSWORD);
   $postFields["responsetype"] = 'xml';
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, self::URL);
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_TIMEOUT, 100);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
   curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
   $data = curl_exec($ch);
   curl_close($ch);
   $xml = new SimpleXMLElement($data);
   if($xml->result == "success")
   {
     return $xml;
   }
   else
   {  
    return $xml->message;
   }
 }
} 

Now I would like to use this connection class on other methods on other classes that will use it.

So, I was thinking about doing a class (not sure if abstract is appropriate here), like this:

abstract class ApiSomething
{
  protected $_connection;
  protected $_postFields = array();

  /**
   * @desc - Composition.
   */

  public function __construct()
  {
     require_once("apiconnect.php");
     $this->_connection = new Apiconnect($this->_postFields);
  }

  public function getStuff()
  {

   //this is the necessary field that needs to be send. 
   //Containing the action that the API should perform.
   $this->_postFields["action"] = "dosomething";
   ...
   }

} 

I need to use the property $_connection on getStuff() method so that the "action" is send into the API. Not sure however, how can that be accomplish.

Any help please?

+2  A: 

Why not extend your object instead of including something. APIConnect should be the abstract class and API something should extend it.

abstract class ApiConnect {
    protected $_something;
    protected $_something2;
    protected $_curlResource;
    function __construct($param1){
        /* do curl setup here and save it to $this->_curlResource */
    }
}

class ApiSomething extends ApiConnect {
    protected $_paramForBase;
    function __construct(){
        super($this->_paramForBase);
        echo "Var from base: ".parent::_something;
        /* do more things with curl here, through parent::_curlResource */
    }

    function setParamsForCurlCall(){
        /* add curl parameters with curl here, through parent::_curlResource */
    }

    function execCurl(){
        /* do your final curl call here */
    }
}

Then you can do whatever you want with your abstract class, and you can API something can have all the control logic for the base class. Granted you would only want to do this if your going to extend ApiConnect in more than one class.

gwagner
Probably the abstract usage was a miss lead from my part. :( To be honnest I will not need to abstract the curl usage on this application - that will be the only curl usage that I will make. Connection/Retrieve/Send no need to abstract send methods, or other things. Not even in the farest futures so, I believe that abstract was a miss lead. :(
MEM
A: 

Hello,

First of all I think that Apiconnect should be a singleton (you need just one authentication) and you should rename it to something like APIConnection if you want to use it as a resource in other classes. Extending it would also be an option, but it depends on what your other class does (you other class should also be a singleton if you choose to extend). Making it abstract or not depends only if it can be used as is.

Inside your APIConnection (I prefer naming it like this) you should have a call method doPost or something of the sort that makes a request to the API (keep it as general as possible). In the constructor call the login API method if you want to authenticate when instantiating. When you need to call other API methods do that directly through the doPost you just created.

Alin Purcaru
Well abstract seems to be out of equation as far as I can see. About the fact that I should keep the doPost as general as possible, I'm not sure if I can do this, because, the API expects to have, with the curl, some array to play with and return the XML. So, I believe it's just the way they need perhaps...
MEM
A: 

You can improve your design by following these rules:

-don't do real work in the constructor (see APIConnect)
-favor composition
-inject the dependencies in the constructor
-meaningful class/interface names
-single responsibility

I would refactor this more like this:

interface APIConnection { // responsible for the connection
    public function connect();
}
class FacebookConnection implements APIConnection {
    public function __construct($url, $name, $pass, $params) {
         // set only connection parameters here. NO WORK DONE, NO CONNECTING
    }
    public function connect() {
         // curl stuff
    }
}
class FacebookFarmer {
    public function __construct(APIConnection $connection) {} // inject dependency, composition
    public function harvest() {} // responsible for the actions having the connection
    public function milkCows() {}
}
class FacebookFarmController { // translates what user requests to do to an action
    public function __construct(FacebookFarmer $farmer) {} // injection again, composition
    public function doAction($request) {
        // eg $action = $request['action'];
        // then $this->famer->$action() if exists
    }
}

I don't know whether this is an example of something you could use because APIThis and APIThat is a bit difficult to understand. If I misunderstood please clarify your intentions.

koen
Will the interface be of a good use if we need to connect other API's as well? On this case, however, all 1 API will be required for all life long of this application. Is this additional information of some use? I'm not sure what is the difference between implementing an interface of extending a class, worry not, I will read about it. I didn't know about injection and it's relations with composition, I have however, one question, how does , on your example, FarmController uses the connection?
MEM
It's used the same way as in your example. Since I didn't really understood how I just assumed it needed it. You can regard the interface as a responsability. In this case it says "I'm responsible to create a connection". Different classes can implement the responsibility in a different way without the client class caring how.
koen