Establish a 'string' rule on an attribute in a Model (ActiveRecord in my case).
POST a JSON object containing a true for that attribute.
Similarly to how POSTing a false to that attribute will generate an error about the attribute being empty, I would expect the same for a true
The attribute received a '1' as its new value.
I verified the getBodyParam('attribute') is returning the boolean however I noticed in StringValidator.validateAttribute() that the $value is a '1' at that point which is why the attribute is not failing the validation.
| Q | A
| ---------------- | ---
| Yii version | 2.0.11.2
| PHP version | 7.0.13
| Operating system | ubuntu 4.9.5-moby
Wasn't able to reproduce (https://github.com/Kolyunya/yii2/commit/f9041646ddaac6760b727a4fdc6d3e37705e69ef).
Thanks for checking the test on that. Is it possible I have some configuration that is causing the conversion from a true to a '1'?
@SilverFire , this doesn't really help me :-(, I'm putting a 'min' => 2 rule on all my string attributes for now but there's definitely some issue with that automatic conversion. I'm not sure if the unit test captures all that's going on when ActiveRecord and/or yii\rest\Controller is involved.
@Kolyunya , did you run those tests against2.0.11.2?
Before closing, would you all mind testing this in a RESTful way?
@wcjr there's something between when you're getting the value as boolean and when it's passed to validator (validator itself works well as @Kolyunya verified). Probably ->load() of the model or some custom code messes with types.
Before closing, would you all mind testing this in a RESTful way?
Sure. If you'll provide a clean step-by-step way of reproducing the issue or a unit test, we'd check it. Now it's not clear what's failing and guesswork doesn't help.
Thanks @samdark , I'll check the ->load() and see if that's where it's happening. I'm just starting with this framework so I'm not familiar with the processes going on behind the scenes yet. That's a great tip :-)
I suggest to check types:
I'm not sure if there's an associated test for this (I made a comment over on @Kolyunya 's unit test additions about what I'm seeing), but here's what I've verified in my environment.
This is from Validator.validateAttributes() call, line 266 in my version of Yii:
if ($this->when === null || call_user_func($this->when, $model, $attribute)) {
if ($attribute === 'first_name') {
die(var_export($model->$attribute));
}
$this->validateAttribute($model, $attribute);
The value will be true in the output above, however, if I put that code right below the $this->validateAttribute($model, $attribute) call, it will be '1'.
I checked inside the Validator.validateAttribute() call:
public function validateAttribute($model, $attribute)
{
if ($attribute === 'first_name') {
die(var_export($model->$attribute));
}
...
and the value is '1'.
Is this some kind of coercion that PHP does or something? This is definitely where the transformation is occurring.
@wcjr it would help a lot to debug this if you make a fork of the basic app with minimal possible changes that reproduce the issue or a failing unit-test.
Yeah. What @Kolyunya suggested is what would be great to have.
@Kolyunya @samdark I can very much appreciate how having a running example would help. I looked at that basic app and there are no Models as \yii\db\ActiveRecord's and no \yii\web\Controller's, although I'm not sure how those would be changing something, so I'd have to change a lot. May I instead reference my project? It can be setup and run quickly and you'll be able to demonstrate the bug easily then. It utilizes Docker and I have a Makefile so you should only have to clone, tweak a local variable that holds an Authorization token, run make and then POST to a url I can give you. Is that an option you all would consider?
@wcjr sure, I'll definitely have a look at what's going on there.
Thanks!
https://github.com/silinternational/idp-id-broker and checkout the initial-features branch.local.env, you only need these values: [email protected]
ALERTS_EMAIL_ENABLED=false
API_ACCESS_KEY=abc123
make should build everything and start up the docker containers, note: the app will be listening on port :8080 by default, you can change this if you like in the docker-compose.yml.POST to http://localhost:8080/user with the following data:Headers
Content-Type: application/json
Authorization: Bearer abc123
Body
{
"employee_id": "123",
"first_name": true,
"last_name": "TestLastName",
"display_name": "TestFirstName",
"username": "test_username",
"email": "[email protected]",
}
'min' rule currently set in common\models\User.php. You comment out the following and try again:[ // 'min' is needed on any strings until https://github.com/yiisoft/yii2/issues/13701 is resolved.
['employee_id', /*'first_name',*/ 'last_name', 'display_name', 'username', 'email'],
'string', 'min' => 2
],
POST again and you should notice in the results that you get a '1' for the first_name.Thanks for being willing to give it a shot, please let me know if you have any trouble.
@wcjr trim validator you use converts true to '0' and false to an empty string.
yep, you're right! I removed that trim rule, and the 'string' rule worked perfectly. Thank you for calling my attention to that, I'm beginning to appreciate how important the order of the rules is to getting the right behavior.
Thank you for taking the time to help me with this, I really appreciate it!
@wcjr you are welcome. Please consider that if you move trim after string then you may get false-positive and false-negative results for min and max constraints respectively. You may consider implementing a custom trim validator or behavior which will handle non-string values gracefully.
yes, I'll have to think about that. Would it be worthwhile asking for a feature request on that trim rule to not convert bool that way?
@wcjr the trim construct you used is a reference to the PHP trim() built-in. This conversion behavior is expected and well-documented.
A boolean TRUE value is converted to the string "1". Boolean FALSE is converted to "" (the empty string). This allows conversion back and forth between boolean and string values.
Most helpful comment
@wcjr sure, I'll definitely have a look at what's going on there.