activeresource The RESTful equivalent to ActiveRecord

ActiveResource for Yii

  1. Requirements
  2. NOTES
  3. Changes
  4. Version 0.7 (01-16-2012):

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:

  1. Get the extension at ActiveResource on Github
  2. Add the extension to Yii by placing it in your application's extension folder (for example '/protected/extensions')
  3. Edit your applications main.php config file and add 'application.extensions.EActiveResource.*' to your import definitions
  4. 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'
)
  1. 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

  1. ActiveResource wiki
  2. Forum-thread

NOTES

  1. 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.

24 0
37 followers
250 downloads
Yii Version: 1.1
License: BSD-2-Clause
Category: Web Service
Tags: rest
Developed by: Haensel
Created on: Jul 6, 2011
Last updated: 12 years ago

Related Extensions