evan108108 / RESTFullYii

RESTFull API for your Yii application
http://evan108108.github.com/RESTFullYii/
320 stars 114 forks source link

Add content to render, like HATEOAS #83

Closed lordlele closed 10 years ago

lordlele commented 10 years ago

Hi, what's the best practice to add content to a REST request that was not a model attributes?

Like, for example, hypermedia url ( http://en.wikipedia.org/wiki/HATEOAS ). My working solutions was this, however I'm not sure if it's really a best practice:

In my model I extend this method:

    /**
     * Get attributes
     * @param $names mixed
     * @return array of attributes
     */
    public function getAttributes($names = true) {
        $names = parent::getAttributes($names);
        // If application start as REST, this constant was defined
        if (defined("APPLICATION_REST")) {
            $names['url'] = array(
                'myUrl1'  => Yii::app()->createAbsoluteUrl("api/myController/REST.GET", array('someparam' => somevalue)),
                …
            );
        }
        return $names;
    }

In this way, if application was in REST MODE my model will return an url key with all resource related url (like does github api).

Is this the correct approach?

evan108108 commented 10 years ago

Yeah, This is the way I have been doing it, but it always feels a bit "hacky", especially when you have to alter the global state!

How do you feel about creating an event that would allow adding additional non DB properties to your models JSON output? It would allow you to add any model properties or model method (output) to your results...

lordlele commented 10 years ago

How do you feel about creating an event that would allow adding additional non DB properties to your models JSON output? It would allow you to add any model properties or model method (output) to your results...

Yes this was a great solution. However, with this event I can add additional property to main response, to every row of data response or both? Maybe create two events, the first for adding properties to global response (at the level of totalCount for example) and the second for adding properties to each row of model.

What do you think?

evan108108 commented 10 years ago

Yes I like that idea. Let's implement!

lordlele commented 10 years ago

Ehm... are you implementing this? Or did you expect a pull request from me? :eyes:

evan108108 commented 10 years ago

Sorry that was unclear. I will implement, unless you have already started work on it or just want to do it.

lordlele commented 10 years ago

Ok, I think it's better you do this because you know well the code :smile:

lordlele commented 10 years ago

Ehm... I do not want to sound arrogant, so forgive me, but do you have any news about this new feature? Can I help you in any way?

I find this library so much fun to use that I'm eager to try new features.

evan108108 commented 10 years ago

@lordlele I am very sorry that I have not had time to work on this feature. I have left it open because I think it will make a great addition to RESTFullYii.

lordlele commented 10 years ago

Don't worry... We are all really busy :smile: If you can left this open I can try to add this features when I have time.

miteshsc commented 10 years ago

@evan108108 @lordlele

80#issuecomment-46523711, It would be cool if we have additional info event.

kaushikkapil commented 10 years ago

Hi Evan.......any plans to resolve this soon? I can surely try to help, but may need some pointers to get my hands dirty.

evan108108 commented 10 years ago

I have plans on resolving this, however some overhaul is needed to make it work seamlessly. First of all we will need at least two new events; Something like:

These are the minimum, but we could very easily create

Even these might not be enough because what does "model" mean here? Does this apply to every model or a specific model or do we need both? If we decide that for completeness we need both then our events might look something like this:

This is getting a little unwieldy no? I would suggest we go down a different road then the one being discussed here. What if we simply made 'post.filter' events work for 'req.[get, put, post, delete].resources.render'. It would require a small rewrite but it would allow users to catch the output before render and transform it as they see fit.

@lordlele, @kaushikkapil, @miteshsc and everyone, what do you guys think?

miteshsc commented 10 years ago

@evan108108: I am agree with "What if we simply made 'post.filter' events work for 'req.[get, put, post, delete].resources.render'. It would require a small rewrite but it would allow users to catch the output before render and transform it as they see fit"

Before rendering, we can four events

render.get.additional.properties render.post.additional.properties render.put.additional.properties render.delete.additional.properties

which pushes extra information + model properties(if any) to final resource render event.

evan108108 commented 10 years ago

@miteshsc how do you imagine the additional.properties would work? You said "+ model properties(if any)". How would you add model props here? Would these model props be a specific model (related model), or just the resource model, or both?

I am not opposed to this solution but lets work out these details and perhaps some sudo-code would be illuminating.

What I am envisioning is simply this

   $this->onRest('post.filter.req.(get, put, post, delete).resource(s).render', function($json) {
      return CJSON::encode($this->aply_some_custom_modification(CJSON::decode($json)))
   })

Or maybe to keep this to one event (although this is not exactly standard)

$this->onRest('post.filter.req.render', function($json, $http_verb) {
     //if($http_verb == 'GET') //If verb checking is needed
     return CJSON::encode($this->aply_some_custom_modification(CJSON::decode($json)))
})
miteshsc commented 10 years ago

Okay, Here is sudo-code for what i mean

class foo {
    private $a;
    public $b = 1;
    public $c;
    private $d;
    static $e;      
}
  $this->onRest('post.filter.req.(get, put, post, delete).resource(s).render', function($json) {

      $modelProperties = "Read all model properties/variables ( $a, $b, $c, $d, $e)"; // Using get_class_vars()
      $customArrayWithExtraInfo = array("p"=>"p", "q"=>"q");      
      $additionalInfoArray = array_merge($modelProperties, $customArratWithExtraInfo);

      return CJSON::encode($additionalInfoArray); // Probably we need one more variable/field in RestfullYii.widgets.ERestJSONOutputWidget to handle additional Info.

   });

I am not sure about properties of relational model as i haven't needed relational model's properties as of now but would like to know input from @kaushikkapil @lordlele and others as well.

may be we can have PR for requirement and will discuss it there.

evan108108 commented 10 years ago

@miteshsc @lordlele @kaushikkapil :> I have created a new branch for this issue issue-83. In this branch I have implemented the solution I proposed and thus made post filtering 'req.(get, put, post, delete).resource(s).render' possible.

Here is an example of adding a global property to all requests

array_map(function($event){
    $this->onRest($event, function($json) {
        $j = CJSON::decode($json);
        $j['new_prop'] = 'I am the value of a new prop';
        return $j;
    });
}, [
    'post.filter.req.get.resource.render',
    'post.filter.req.get.resources.render', 
    'post.filter.req.put.resource.render', 
    'post.filter.req.post.resource.render', 
    'post.filter.req.delete.resource.render',
    'post.filter.req.get.subresource.render',
    'post.filter.req.get.subresources.render', 
    'post.filter.req.put.subresource.render', 
    'post.filter.req.post.subresource.render', 
    'post.filter.req.delete.subresource.render',
]);

Since you now have access to the entire JSON output pre-final render you can of course add properties to the model or related models as you see fit.

$this->onRest('post.filter.req.get.resource.render', function($json) {
   $j = CJSON::decode($json);
   $j['data']['some_prop'] = 'new_prop_value';
   $j['data']['RelatedModels'] = array_map(function($rmodel) {
      $rmodel['r_new_prop'] = 'some new related value';
      return $rmodel;
   }, $j['data']['RelatedModels']);
   return $j;
});

Remove a global property

$this->onRest('post.filter.req.get.resource.render', function($json) {
   $j = CJSON::decode($json);
   unset($j['success']);
   return $j;
});

Of course this approach has it's shortcomings and puts the work on the user to transform the JSON but it is the most flexible and I believe should be a part of the library whether or not we implement additional events for this feature.

I would love it if you guys would checkout this branch and give me some feedback.

kaushikkapil commented 10 years ago

@evan108108 , @miteshsc : my apologies for the delay in response. I did not check this thread yesterday. @evan108108 : The solution that you proposed is good, and should work fine for a single resource (I will try out the code and respond by EOD today)

However, when we talk about 'post.filter.req.get.resources.render', the current solution complicates the life a bit. Typically for multiple resources or subresources we may want to override the attributes for each individual resource, which means that with the current scenario, we would need to do something like this:

    foreach($j[data] as $row) {
        $attributes = $j['data'][$row];
        $additional_attributes = array("p"=>"p", "q"=>"q"); 
        $attributes = array_merge($attributes, $additional_attributes);
        $j[$data][$row] = $attributes;
    }

Given that the additional attributes are indeed a model level property, I was thinking whether it makes sense to provide an option at the model level.

So, if we look at the problem again, I believe we have two problems that we are trying to solve:

I wanted to discuss if a hybrid approach is possible to solve the problem, i.e. in addition to whatever you have mentioned above, if we can provide a way to override the model attributes also:

You have already solve a similar problem with relations, i.e. here:

    $this->onRest('model.with.relations', function($model) {
        ......
    });

On same lines, can we have an event for attributes, say something like this:

    $this->onRest('model.override.attributes', function($model, {
        //write your custom code here and return the following array:
        $attributes = $model->attributes;
        $additional_attributes = array("attribute1" => "value1", "attribute2" => "value");
        return array_merge($attributes, $additional_attributes);
    });

I think even after we do this, we'll probably need to update some of the rendering code in the following function in "ERestJSONOutputWidget.php" file:

    public function processAttributes($model, $relation=null)
        {
                $schema = $model->getTableSchema();
                $model_as_array = [];
                //here below we may need some way to pick up the overriden attributes as well
                foreach($model->attributes as $property => $value) {
                    if (!$this->propertyIsVisible($property, $relation)) {
                            continue;
                    }
                    if(array_key_exists($property, $schema->columns) && $this->isBinary($schema->columns[$property]->dbType, $value)) {
                        $value =  bin2hex($value);
                    }
                    $model_as_array[$property] = $value;
                }
                return $model_as_array;
        }

p.s.: If you guys think whatever I have mentioned is not making much sense, then please attribute it to my limited understanding of the framework so far. I am trying to learn and understand as much by looking through the code, but some gaps persist.

evan108108 commented 10 years ago

@kaushikkapil :> I think you are basically correct and this approach will work well for the main resource model, however to make it work for all models in your response (i.e. related models) we would need to do something like:

$this->onRest('model.your_model_name_here.override.attributes', function($model) {
   //This will be triggered for every instance of the model (main resource, or related models).
   //So this event may well be called many many times in a single request.
   return array_merge($model->attributes, ["attribute1" => "value1", "attribute2" => "value"]);
});

The implementation is a bit tricky because for the most part I do not like (or have avoided) emitting events inside other events but that is just a detail.

@lordlele, @miteshsc, @kaushikkapil : What do you all think?

lordlele commented 10 years ago

This solutions was not bad at all, however I have a question: If I want to add a specific attribute foreach row, and that attribute must be created by a model method, how I can invoke that method?

Take for example my first post: I want to add an URL on each model and the URL will be created at model level; how I can accomplish the same thing with the new proposed events?

evan108108 commented 10 years ago

@lordlele :> I think it would be easy... You will have all the data for each model so you would simply have to pass that data to your method. And if we look at the latest proposed sample code it gets far simpler because every instance of your model will be passed to this event.

Lets take the use case you just mentioned. We have a model named "Work". The "Work" model has a non-active-record property named "url", which I assume is defined like this in your model code.

class Work extends CActiveRecord
{
   public function getUrl()
   {
      return "/media/work/{$this->id}.jpg";
   }
}

So how can we get this property into the JSON output for each instance of the model "Work"?

Lets first do it the harder way. This is with the "post.filter" approach.

//This code will work right now with the branch I created for this issue.
$this->onRest('post.filter.req.get.resources.render', function($json) {
   $j = CJSON::decode($json);
   $j['data'] = array_map(function($work_data){
      $work = Work::model();
      $work->setAttributes($work_data);
      $work_data['url'] = $work->url;
      return $work_data;
   }, $j['data'])
   return $j;
});

Now lets do it the easy way and take a look at my latest proposal based on @kaushikkapil input

//This event will be called whenever and wherever the "Work" model is referenced.
//If you have a list of 100 "Work" models in your output this method is called 100 times 
//Each instance of "Work" will be passed into the event.
$this->onRest('model.work.override.attributes', function($model) {
   return array_merge($model->attributes, ['url'=>$model->url]);
});

Personally, I am fine with the "harder way" as it is the most flexible and (to me at least) is not overly burdensome. With that being said the "easy way" is a lot slicker and more reusable especially in the global context, so it would be a great addition.

Deos that help?

I would love to hear your ideas as well.

lordlele commented 10 years ago

Ok, now it's clear! :+1: I think that, if possible, both solutions should be implemented and documented like this:

Easy way

//This event will be called whenever and wherever the "Work" model is referenced.
//If you have a list of 100 "Work" models in your output this method is called 100 times 
//Each instance of "Work" will be passed into the event.
$this->onRest('model.work.override.attributes', function($model) {
   return array_merge($model->attributes, ['url'=>$model->url]);
});

Complete way

//This code will work right now with the branch I created for this issue.
$this->onRest('post.filter.req.get.resources.render', function($json) {
   $j = CJSON::decode($json);
   $j['data'] = array_map(function($work_data){
      $work = Work::model();
      $work->setAttributes($work_data);
      $work_data['url'] = $work->url;
      return $work_data;
   }, $j['data'])
   return $j;
});

And specify the differences between and when use one or another.

kaushikkapil commented 10 years ago

I agree with @lordlele , I think both the approaches have valid use cases, and it would be beneficial to have both of them, as different people have different requirements :)

@evan108108 I tried working with the issue-83 branch....for some reason, I am always getting the "$json" object in my request as NULL. Am I missing something?

evan108108 commented 10 years ago

@kaushikkapil :> can you try pulling that branch again? If you are still getting this error let me know as the branch is still very much a work in progress and your input would help. It is working for me but I may have forgot to commit something...

miteshsc commented 10 years ago

@evan108108 : I tried working with issue-83 branch and added both events in my controller, but events are not getting trigger. am i missing anything?

@lordlele , @kaushikkapil : is it working for you guys?

I searched POST_FILTER_REQ_GET_RESOURCES_RENDER event but couldn't find event implementation.

kaushikkapil commented 10 years ago

@evan108108 @miteshsc I tried with the issue-83 branch with the following two events in my controller, and it worked just fine for me: POST_FILTER_REQ_GET_RESOURCE_RENDER POST_FILTER_REQ_GET_RESOURCES_RENDER

I was able to successfully override the default json and add additional parameters to it !

miteshsc commented 10 years ago

@kaushikkapil : I have also added both events in my controller and i am calling following route using GET method but still none of them is getting trigger.

URL:http://localhost/project/api/user/1
Method: GET

can you please add your event code?

kaushikkapil commented 10 years ago

@miteshsc Please find my code below:

public function restEvents() {
        $this->onRest(ERestEvent::POST_FILTER_REQ_GET_RESOURCE_RENDER, function($json) {
            $j = CJSON::decode($json);
            $j['data']['mydata']['new_flag'] = true;
            return $j;
        });
    }
URL: http://localhost/test/sample/mydata/1
Method: GET
miteshsc commented 10 years ago

@kaushikkapil : Thanks for your code. both are working for me now.

post.filter.req.get.resources.render
post.filter.req.get.resource.render

But want to check with you

$this->onRest('model.work.override.attributes', function($model) {
   return array_merge($model->attributes, ['url'=>$model->url]);
});

did you try this event? let me know if it works for you :)

It is really helpful as i have same kinda requirement(i want to fetch record and before sending it back i want to alter specific attribute value. @evan108108 : did you push override.attribute event?

evan108108 commented 10 years ago

This : 'model.work.override.attributes' is not implemented yet... But will be soon. I will let you all know when it is...

miteshsc commented 10 years ago

:) looking forward to check it !

evan108108 commented 10 years ago

@lordlele @miteshsc @kaushikkapil :> I have fully implemented the feature as we have discussed it on branch issue-83. I hope you will all pull and test it out before I write documentation and merge it into master.

Note: In 'model.your-model-name.override.attributes' 'your-model-name' must be lowercase.

:metal:

kaushikkapil commented 10 years ago

@evan108108 thanks a lot Evan...will check and revert back by tomorrow !

miteshsc commented 10 years ago

Hi @evan108108 :

I have checked model.profile.override.attributes event with following code. Presently it works fine with string value, but when i tried to replace value with an array code is breaking. is it possible to handle array as well?

    $this->onRest('model.profile.override.attributes', function($model) {
                $temp = array();
                if(array_key_exists("category", $model->attributes) && strtolower($model->attributes['category']) == 'address'){
                    $temp['field_value'] = explode("#####", $model->attributes['field_value']);
                }

                return array_merge($model->attributes, $temp);
        });
strlen() expects parameter 1 to be string, array given

D:\xampp\htdocs\project\protected\extensions\starship\RestfullYii\widgets\ERestJSONOutputWidget.php(258)

246         /**
247          * isBinary
248          *
249          * Helper to convert binary to hex when binary/blob field types are larger then 1 digit
250          *
251          * @param (String) (property_type) the data type of the given property
252          * @param (Mixed) (value) the value of the given property
253          *
254          * @return (Bool) returns true if the property is a binary that should be converted to hex false if not
255          */
256         public function isBinary($property_type, $value)
257         {
258             if(strlen($value) < 2) { // binarys with a length of 1 do not need to be converted to hex to render properly
259                 return false;
260             }
261             if(strpos($property_type, "binary") !== false) { //if we have a binary
262                 return true;
263             }
264             if(strpos($property_type, "blob") !== false) { //if we have a binary blob
265                 return true;
266             }
267         }
268         
269 }
evan108108 commented 10 years ago

Good find. I will fix that...

On Monday, July 7, 2014, Mitesh Chavda notifications@github.com wrote:

Hi @evan108108 https://github.com/evan108108 :

I have checked model.profile.override.attributes event with following code. Presently it works fine with string value, but when i tried to replace value with an array code is breaking. is it possible to handle array as well?

$this->onRest('model.profile.override.attributes', function($model) {
            $temp = array();
            if(array_key_exists("category", $model->attributes) && strtolower($model->attributes['category']) == 'address'){
                $temp['field_value'] = explode("#####", $model->attributes['field_value']);
            }

            return array_merge($model->attributes, $temp);
    });

strlen() expects parameter 1 to be string, array given

D:\xampp\htdocs\project\protected\extensions\starship\RestfullYii\widgets\ERestJSONOutputWidget.php(258)

246 /* 247 * isBinary 248 249 * Helper to convert binary to hex when binary/blob field types are larger then 1 digit 250 251 * @param (String) (property_type) the data type of the given property 252 * @param (Mixed) (value) the value of the given property 253 254 * @return (Bool) returns true if the property is a binary that should be converted to hex false if not 255 */ 256 public function isBinary($property_type, $value) 257 { 258 if(strlen($value)

— Reply to this email directly or view it on GitHub https://github.com/evan108108/RESTFullYii/issues/83#issuecomment-48142980 .

kaushikkapil commented 10 years ago

@evan108108 :+1: The code worked fine for me

@miteshsc I couldn't understand the scenario you are talking about....

evan108108 commented 10 years ago

@miteshsc :> By the way this works just fine:

$this->onRestt('model.post.override.attributes', function($model) {
   return array_merge($model->attributes, ['next_ids'=>[1,2,3,4]]);
});

However, I do understand what your trying to do and you are correct that it is not currently working for this use case (when adding an array to an already existing AR property). I am writing a fix for this now. Standby...

evan108108 commented 10 years ago

@miteshsc :> All should now be fixed! I update ERestJSONOutputWidget and added a new test for your use case. If you pull the latest code from this branch it should work for you.

:fireworks:

miteshsc commented 10 years ago

@evan108108: Thank you for the fix. It is working fine when we add new property in AR.

But still having a problem while changing existing AR property value with array type value, below is the test case which is not working for me.

This is output of $model->attributes.

Array
(
    [id] => 18
    [user_id] => 2
    [category] => address
    [field_label] => home
    [field_value] => street=street string#####zipcode=zipcode string#####state=state string#####country=country string
    [creation_ts] => 2014-07-07 09:28:50
    [last_update_ts] => 0000-00-00 00:00:00
)

Here is i am trying to modify existing AR property.

$this->onRest('model.profile.override.attributes', function($model) {
        $alteredAddress = array();
        $alteredAddressTemp = array();
        if(array_key_exists("category", $model->attributes) && strtolower($model->attributes['category']) == 'address'){
            $alteredAddressTemp = explode("#####", $model->attributes['field_value']);
            $alteredAddress['field_value'] = array_reduce($alteredAddressTemp, function ($result, $value) {
                $valueArray = explode("=",$value);
                $result[$valueArray[0]] = $valueArray[1];
                return $result;
            });
        }
        return array_merge($model->attributes, $alteredAddress);
    });

Expected output

Array
(
    [id] => 18
    [user_id] => 2
    [category] => address
    [field_label] => home
    [field_value] => Array
        (
            [street] => street string
            [zipcode] => zipcode string
            [state] => state string
            [country] => country string
        )
    [creation_ts] => 2014-07-07 09:28:50
    [last_update_ts] => 0000-00-00 00:00:00
)

ERestJSONOutputWidget > processAttributes: I have updated following code, then after it is working fine.

if(array_key_exists($property, $schema->columns) && !is_array($value) && $this->isBinary($schema->columns[$property]->dbType, $value)  ) {
                    $value =  bin2hex($value);
                }

is it right way to solve this problem?

@kaushikkapil : i hope above scenario gives you a better idea!

evan108108 commented 10 years ago

No way you have the latest code if you are still seeing this issue. I fixed exactly this and it's test covered as well...

On Tuesday, July 8, 2014, Mitesh Chavda notifications@github.com wrote:

@evan108108 https://github.com/evan108108: Thank you for the fix. It is working fine when we add new property in AR.

But still having a problem while changing existing AR property value with array type value, below is the test case which is not working for me.

This is output of $model->attributes.

Array ( [id] => 18 [user_id] => 2 [category] => address [field_label] => home [field_value] => street=street string#####zipcode=zipcode string#####state=state string#####country=country string [creation_ts] => 2014-07-07 09:28:50 [last_update_ts] => 0000-00-00 00:00:00 )

Here is i am trying to modify existing AR property.

$this->onRest('model.profile.override.attributes', function($model) { $alteredAddress = array(); $alteredAddressTemp = array(); if(array_key_exists("category", $model->attributes) && strtolower($model->attributes['category']) == 'address'){ $alteredAddressTemp = explode("#####", $model->attributes['field_value']); $alteredAddress['field_value'] = array_reduce($alteredAddressTemp, function ($result, $value) { $valueArray = explode("=",$value); $result[$valueArray[0]] = $valueArray[1]; return $result; }); } return array_merge($model->attributes, $alteredAddress); });

Expected output

Array ( [id] => 18 [user_id] => 2 [category] => address [field_label] => home [field_value] => Array ( [street] => street string [zipcode] => zipcode string [state] => state string [country] => country string )

[creation_ts] => 2014-07-07 09:28:50
[last_update_ts] => 0000-00-00 00:00:00

)

ERestJSONOutputWidget > processAttributes: I have updated following code, then after it is working fine.

if(array_key_exists($property, $schema->columns) && !is_array($value) && $this->isBinary($schema->columns[$property]->dbType, $value) ) { $value = bin2hex($value); }

is it right way to solve this problem?

@kaushikkapil https://github.com/kaushikkapil : i hope above scenario gives you better idea!

— Reply to this email directly or view it on GitHub https://github.com/evan108108/RESTFullYii/issues/83#issuecomment-48273259 .

miteshsc commented 10 years ago

yes, i have downloaded latest code from issue-83 branch.

What i can see is, it is happening because of

strlen($value)

where $value is an array.

evan108108 commented 10 years ago

@miteshsc :> Seriously you do not have the latest codebase. Here is a link to the lines of code we are talking about ERestJSONOutputWidge line 256. And here is the code:

public function isBinary($property_type, $value)
{
    try {
        if(strlen($value) < 2) { // binarys with a length of 1 do not need to be converted to hex to render properly
            return false;
        }
        if(strpos($property_type, "binary") !== false) { //if we have a binary
            return true;
        }
        if(strpos($property_type, "blob") !== false) { //if we have a binary blob
            return true;
        }
    } catch(Exception $e) {
        return false;
    }
    return false;
}

As you can see it is wrapped in a Try-Catch block and will no longer throw this error. Please update your code and try again...

miteshsc commented 10 years ago

@evan108108 : I have latest code only.. did you try changing existing attributes string value with an array, because this is only happening while changing it. In my earlier comment i had given an example as well.

Please produce same scenario at your end. :) I am sure it won't work.

Comment Edited: I have tried with basic try n catch block but it doesn't catching up an exception.

@kaushikkapil : any input from your side?

evan108108 commented 10 years ago

Not only did I try it, but I even created a unit test that guarantees that it works and that test is passing! You simply cannot have the latest code as the error you are getting is not possible because the offending line is wrapped in a try catch block.

On Thursday, July 10, 2014, Mitesh Chavda notifications@github.com wrote:

@evan108108 https://github.com/evan108108 : I have latest code only.. did you try changing existing attributes string value with an array. because this is only happening while changing it. in my earlier comment i had given example as well.

Please produce same scenario at your end. :) I am sure it won't work.

— Reply to this email directly or view it on GitHub https://github.com/evan108108/RESTFullYii/issues/83#issuecomment-48565698 .

miteshsc commented 10 years ago

restfullyii_error For your reference!

evan108108 commented 10 years ago

@miteshsc :> Ha! It seems I owe you an apology, you are using the latest code.

But..., this is a warning and not an error and that is down to your "ini" configuration and/or how you choose to handle warnings. You can also register a global warning handler (which you should do in production). In any case, I in my current setup I do not see this warning, but I believe I can suppress this for you with one '@' char (See here).

Pull the latest from issue-83

miteshsc commented 10 years ago

Agree with you, but would it be good to suppress by putting @ instead of checking is_array

if(array_key_exists($property, $schema->columns) && !is_array($value) && $this->isBinary($schema->columns[$property]->dbType, $value)  ) {
                    $value =  bin2hex($value);
                }

Thanks for the solution, it works!

Can go ahead and merge it to master for all to use!

miteshsc commented 10 years ago

do you have thought to develop attribute override event for relational model?

kaushikkapil commented 10 years ago

@miteshsc sorry to revert back late...had been quite occupied since last two days. Good to see that the issue is already resolved....thanks a lot Evan for some awesome work there !

evan108108 commented 10 years ago

@miteshsc well the suppression in this case is better because Array is not the only type that can cause this warning. And the suppression evals to Null so when we do Null < 2 return false. It does return false which is what we want...

miteshsc commented 10 years ago

Excellent explanation! I appreciate it. any planning to create same event for relational model?