Restfullyii Custom Attributes

Hi there,

I’m setting up an application using a REST api. Instead of writing one my own, the RestfullYii extension looks quite promising to use! Supports all kind of functionality “out of the box”.

What I’m struggling with, is how to select specific attributes from my model for output to JSON? There are the model.visible.properties and model.hidden.properties events, but these seem only to work with the default


$model->attributes

collection. These attributes are really only the columns of the underlying table, so what if I want to output


$model->myCustomAttribute

optionally via


$model->getMyCustomAttribute()

as well?

We’re struggling with the same issue. We declared our attribute explicit in the model as a class variable


public $fullname

and we added a "safe" rule


array('fullname', 'safe')

but unfortunately neither works.

I assume that the Restfullyii only looks up the database structure and not the model itself.

Has anyone an idea how to solve this?

I hoped this might be solved by using a behavior, but as far as I can see it is not possible to overrule the getAttributes() method with it. So only possibility looks like overriding getAttributes() in the model itself, which looks like an ugly solution.

Perhaps this is a more generic issue, concerning customization of getAttributes()? I can imagine that abstraction of a database via models requires one to be able exactly which attributes are exposed?

Anyhow, for those interested, it is possible to choose which attributes to get from your model via explicitly passing $names (array of attribute names you need) in $model->getAttributes($names).

In the RestfullYii extension there is the widget ERestJSONOutputWidget, in which there is a function that extracts the attributes from the model to process them to JSON, but there is no option to choose which attributes:




public function processAttributes($model, $relation = null)

    {

        $model_as_array = [];

        foreach ($model->attributes as $property => $value) {

            if (!$this->propertyIsVisable($property, $relation)) {

                continue;

            }

            $model_as_array[$property] = $value;

        }

        return $model_as_array;

    }



My personal conclusion:

  1. It would be nice to be able to set some property in a CActiveRecord model with an array of default attributes that is used by getAttributes() and setAttributes().

  2. It would be nice to have some way to choose in the RestfullYii extension which attributes you want to output.

In the meantime, I’m making a workaround that adds 1) to my CActiveRecord models.

We came up with the following solution:

Since all of our models inherit from a TwActiveRecord (which itself inherits from CActiveRecord), we added a new method "getAttributes" to TwActiveRecord




public function getAttributes($names=true)

{

    $attributes = parent::getAttributes($names);


    foreach ($this->getSafeAttributeNames() as $attribute) {

        if (!array_key_exists($attribute, $attributes))

            $attributes[$attribute] = $this->$attribute;

    }


    return $attributes;

}

So we now only need to specify our virtual attributes in the safe array of the model rules.

I am not sure if this comes with good performance or if there is another way to get (only) virtual attributes. But so far it is a working solution…

Now we have the next problem:

We wrote a setter for a virtual attribute


public function setHardwareCost($value)

. But when we try to update a model (PUT request), we get the following error:




{

  "success": false,

  "message": "Parameter 'hardwareCost' is not allowed for model (HardwareType)",

  "data": {

    "errorCode": 406,

    "message": "Parameter 'hardwareCost' is not allowed for model (HardwareType)"

  }

}



Is there a similar approach to overwrite the “safeAttributes”? We tried by extending the getSafeAttributes Method in our model, but this didn’t work…

for do it you cat see my sample

i have some field


{"success":true,"message":"Record Found","data":{"totalCount":1,"messages":{"id":"1","text":"sfsdfsdafasdfsdaf","categories":"1,2,3,5","likecount":"50","reportcount":"0","delete":null,"date":null,"userid":"1","comments":[],"likes":[],"messageCategories":[{"id":"1","message_id":"1","category_id":"1"},{"id":"2","message_id":"1","category_id":"2"},{"id":"3","message_id":"1","category_id":"5"}],"user":{"id":"1","username":"test","password":"123","name":"m","email":"t","email_confirmed":"1","phone":"45465","phone_confirmed":"1","reported_count":"0","profile_picture":null,"cover_picture":null,"created_time":null,"last_visit_time":null,"last_login_time":null,"last_logout_time":null,"deleted":null,"block_start_time":null,"blocked":null}}}}

and i want to dont show user password and i add this code to my controller


public function restEvents() {

        $this->onRest('req.auth.ajax.user', function() {

                    return true;

                });

        $this->onRest('model.visible.properties', function() {

                    return ['user.name'];

                });

    }

you can use model.hidden.properties too

I hope this isn’t too late to help anyone, but I had the same issue. After digging through the code and documentation, I discovered you can override the attributes to include additional attributes. Unfortunately, the forum won’t let me include a link. From the documentation: "We can change the attributes outputted by our model(s) in any given request. We can do this using the “model.YOUR_MODEL_NAME_HERE.override.attributes” event.

Here’s an example:


 

$this->onRest('model.work.override.attributes', function($model) {

   return array_merge($model->attributes, ['job'=>"developer"]);

});