ActiveResource for Yii
This extension could be considered as the "RESTful" equivalent to Yii's CActiveRecord class. While CActiveRecord is using a database to store and manipulate data ActiveResource is using a REST service.
This concept allows you to use Yii's ActiveRecord goodness (like validation, easy formular inputs via ActiveForms etc.) with webservices that expose their resources via REST (e.g.: your own RESTful API)
Basic tests done with Yii 1.1.8 but should work for lower versions too
PHP 5.3 recommended
INSTALL:
'activeresource'=>array( 'class'=>'EActiveResourceConnection', 'site'=>'http://api.aRESTservice.com', 'contentType'=>'application/json', 'acceptType'=>'application/json', 'queryCacheId'=>'SomeCacheComponent' )
class Person extends EActiveResource { /* The id that uniquely identifies a person. This attribute is not defined * as a property * because we don't want to send it back to the service like a name, surname or * gender etc. */ public $id; public static function model($className=__CLASS__) { return parent::model($className); } /* Define the resource property of this class */ public function rest() { return CMap::mergeArray( parent::rest(), array( 'resource'=>'people', ) ); } /* Let's define some properties and their datatypes*/ public function properties() { return array( 'name'=>array('type'=>'string'), 'surname'=>array('type'=>'string'), 'gender'=>array('type'=>'string'), 'age'=>array('type'=>'integer'), 'married'=>array('type'=>'boolean'), 'salary'=>array('type'=>'double'), ); } /* Define rules as usual */ public function rules() { return array( array('name,surname,gender,age,married,salary','safe'), array('age','numerical','integerOnly'=>true), array('married','boolean'), array('salary','numerical') ); } /* Add some custom labels for forms etc. */ public function attributeLabels() { return array( 'name'=>'First name', 'surname'=>'Last name', 'salary'=>'Your monthly salary', ); } }
Usage:
/* GET to http://api.example.com/person/1 and populates a single Person model*/ $person=Person::model()->findById(1); /* GET to http://api.example.com/person and populating Person models */ $persons=Person::model()->findAll(); /* create a resource*/ $person=new Person; $person->name='A name'; $person->age=21; $person->save(); POST request. Returns false if the model doesn't validate /* Updating a resource (sending a PUT request) $person=Person::model()->findById(1); $person->name='Another name'; $person->save(); //PUT request. Returns false if the model doesn't validate //or short version Person::model()->updateById(1,array('name'=>'Another name')); /* DELETE a resource */ $person=Person::model()->findById(1); $person->destroy(); //DELETE to http://api.example.com/person/1 //or short version Person::model()->deleteById(1); //setting attributes $person->attributes=$_POST['Person']; if($person->save()) echo 'yipiie'; //model validated and was saved/updated
Additional information
The EActiveResourceConnection component now only holds information that is used by all resources using it as a connection like site,auth,ssl,contentType,acceptType. Resource specific information has to be defined in the rest() method of each resource.
'activeresource'=>array( 'class'=>'EActiveResourceConnection', 'site'=>'http://api.aRESTservice.com', 'contentType'=>'application/json', 'acceptType'=>'application/json', 'auth'=>array( 'type'=>'basic', //or digest 'username'=>'#####', 'password'=>'#####' ) )), 'queryCacheId'=>'SomeCacheComponent') ///in the resource itself public function rest() { return CMap::mergeArray( parent::rest(), array( 'resource'=>'people', ) ); }
By default all resources use the "activeresource" component. If you want to use more than one service you'll have to define additional components and override the connectionName() method. Here's an example:
'mySecondService'=>array( 'class'=>'EActiveResourceConnection', 'site'=>'http://api.aRESTservice.com', 'contentType'=>'application/json', 'acceptType'=>'application/json', 'auth'=>array( 'type'=>'basic', //or digest 'username'=>'#####', 'password'=>'#####' ) )), 'queryCacheId'=>'SomeCacheComponent') ///in the resource itself public function connectionName() { return 'mySecondService'; }
In previous versions one could cache PUT, DELETE, POST requests which could lead to strange behaviors. By default, caching is only used by the finder methods
All finder methods now fire a beforeFind event before they are executed.
The Connection properties contenttype and accepttype are now called contentType and acceptType according to the known Yii naming convention.
If you don't want to send null values/empty strings you can now define 'allowNullValues'=>false in your connection component configuration. This way all empty strings and null values won't be sent.
Total 3 comments
Hi, I try to use your class to access a sharepoint response... The format is XML and before the "real" elements come, it looks like this:
As I try to use the populateRecords()-Function, it doesn't parse the response correct, or more possible, I just configured the child class wrong!
Can u pls help me with this issue?
Thank you in advance Phil!
nice idea...usefull...
Havent tried it yet, but it looks really nice, thanks!
Leave a comment
Please login to leave your comment.