Yii 1.1: activeresource

The RESTful equivalent to ActiveRecord
39 followers

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:

  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.

Total 3 comments

#8855 report it
PinkBrainPlan at 2012/07/04 08:50am
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:

<Node>
<subNode>
<element1/>
<element2/>
...

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!

#4410 report it
yasser at 2011/07/06 11:36am
nice idea

nice idea...usefull...

#4409 report it
Asgaroth at 2011/07/06 11:06am
Nice

Havent tried it yet, but it looks really nice, thanks!

Leave a comment

Please to leave your comment.

Create extension
Downloads
No downloadable files yet