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)
Requirements ¶
Basic tests done with Yii 1.1.8 but should work for lower versions too
PHP 5.3 recommended
INSTALL: ¶
- Get the extension at ActiveResource on Github
- Add the extension to Yii by placing it in your application's extension folder (for example '/protected/extensions')
- Edit your applications main.php config file and add 'application.extensions.EActiveResource.*' to your import definitions
- Add the configuration for your resources to the main config
'activeresource'=>array(
'class'=>'EActiveResourceConnection',
'site'=>'http://api.aRESTservice.com',
'contentType'=>'application/json',
'acceptType'=>'application/json',
'queryCacheId'=>'SomeCacheComponent'
)
- Now create a class extending EActiveResource like this (don't forget the model() method!):
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 ¶
NOTES ¶
- This is an early release and not perfect. Don't be mad if it is still buggy. Please report bugs at Github instead or drop me a line on Haensel at Twitter. Help would be much appreciated (a "fake" REST API allowing tests would be nice)
Changes ¶
Version 0.7 (01-16-2012): ¶
1. Separation of connection information and resource 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';
}
2. Separation between queries and data manipulating requests ¶
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
3. BeforeFind events ¶
All finder methods now fire a beforeFind event before they are executed.
4. Content type and accept type changed according to the convention ¶
The Connection properties contenttype and accepttype are now called contentType and acceptType according to the known Yii naming convention.
5. Allow or deny null values when sending requests ¶
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.
User Contributed Notes 3
Nice
Havent tried it yet, but it looks really nice, thanks!
nice idea
nice idea...usefull...
Problem with returning XML
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!
Leave a comment
If you have any questions, please ask in the forum instead.
Join the conversation to share a note.