Laravel: Passing a value of 0 back to controller from frontend - php

I have a boolean field that is represented by 0 and 1 in my database.
if ($request->input('submitted')) {
// do code
}
This has been working because it's only been setting the field to 1 (true) but now there's a new flow that can revert the submission.
It has not been setting it back to 0 when I pass the value 0 in from the frontend and I assume it's because that condition is getting skipped since 0 would eval to null.
Is the best way to handle it:
if (isset($request->input('submitted'))) {
// do code
}
or would strictly checking against null work better:
if ($request->input('submitted') !== null) {
// do code
}

The simply approach parse your input to a boolean.
if ((bool) $request->input('submitted')) {
This will create the following results. Therefor removing your edge case.
(bool) "1" // true
(bool) "1" // false
An alternative approach is to use inbuilt PHP filter, it will parse a lot of cases more notably "true" and "false" to true and false.
if (filter_var($request->input('submitted'), FILTER_VALIDATE_BOOLEAN)) {

Related

Laravel 5.4 - Correct Validation rule for a required parameter that can be zero

I'm trying to validate a request to load stock into a table. Up until now stock has always had a positive value and the following validation rule worked exactly as expected:
[
"value" => "required|integer|min:0"
]
Stock is stored and can have multiple values and now stock can have a value of zero (0), I don't think it works with the 'required' rule.
I have changed it to use 'present' which I thought should suffice however it still fails, and adding 'nullable' also doesn't work:
[
"value" => "present|integer|min:0"
]
Are there validation rules to specify that a field must be present but the value can be zero?
Your initial validation rule just keeps working as desired; required doesn't throw an error on 0:
[
"value" => "required|integer|min:0"
]
From the Laravel documentation:
The field under validation must be present in the input data and not
empty. A field is considered "empty" if one of the following
conditions are true:
The value is null.
The value is an empty string.
The value is an empty array or empty Countable object.
The value is an uploaded file with no path.
So the issue was actually with my use of $request->intersect(...) in that it treats keys with a value of zero (0) as false and therefore removes them from the request data array.
For anyone else who may encounter this issue, here is the solution to treat zero (0) values as truthy while; null values, empty strings, and false will be treated as false.
Nb. $params, $rules, and $messages are arrays. See https://laravel.com/docs/5.4/validation#manually-creating-validators for more information.
return \Validator::make(array_filter($request->only($params), function($param) {
// This is needed to strip out empty values but treat zero (0) as truthy (default array_filter behaviour is
// to treat zero (0) as false) but we want these values to be present in the validated request data array as
// zero (0) in the context of a denomination is valid now that we will hold unactivated stock in the Vault.
return ($param !== null && $param !== false && $param !== '');
}), $rules, $messages);

Symfony Propel Query: setting a non-null value with "false" sets it to "null"

I have the following code:
$stmt->setFlag($this->form->getValue("flag")); // $this->form->getValue("flag") = "false"
Which in my autogenerated Propel class calls the following code:
1 public function setFlag($v)
2 {
3 if ($v !== null) {
4 if (is_string($v)) {
5 $v = in_array(strtolower($v), array('false', 'off', '-', 'no', 'n', '0', '')) ? false : true;
6 } else {
7 $v = (boolean) $v;
8 }
9 }
10 if ($this->flag !== $v) {
11 $this->flag = $v;
12 $this->modifiedColumns[] = TableNamePeer::FLAG;
13 }
14 return $this;
15 }
My schema entry for the flag is as follows:
ALTER TABLE tablename ADD COLUMN flag BOOLEAN NOT NULL DEFAULT false;
My XML entry is as follows:
<table name="tablename" phpName="TableName">
...
<column name="flag" phpName="Flag" type="BOOLEAN" required="true" defaultValue="false"/>
...
</table>
I have verified with XDebug that my form submits the variable using POST with the value false (and definitely not null).
However, the setFlag function receives the variable as null. The function skips over the if branch at line 3 of the setFlag function and then sets the flag to null at line 11 and 12. This yields an error when commiting to the database because the field CANNOT be null.
What is going on here?
EDIT:
Interestingly, if I pass my setFlag function an actual false value, i.e. $stmt->setFlag(false), then setFlag receives the correct value the database commit works. What?
EDIT 2:
It turns out that the Bootstrap switch I was using is using the on value for when the switch/checkbox is clicked, and null otherwise, so it was indeed passing null to the function and I must have made an error somewhere.
Now the question is whether it would be possible to have the switch pass false instead of null when it is not clicked, or whether I have to put in a special check for that flag only. Suggestions for either approach would be welcome.
There was no good solution that I liked, so I ended up solving my problem as such:
$stmt->setFlag((bool) $this->form->getValue("flag"));
The cast is (for my purposes) guaranteed to either yield true or false, which sufficed.
If anyone has a better idea, I am open to suggestions.

when does php json_decode return false?

In the PHP documentation for json_decode it says it can return TRUE,FALSE,NULL.
Could some help me understand when it would return FALSE? I understand invalid JSON will return NULL, but when would the other two be returned if not the actual JSON value?
Thanks
JSON format definition clearly shows all possible values and their representations:
A value can be a string in double quotes, or a number, or true or
false or null, or an object or an array.
Both objects and arrays have special syntax in JSON representation (wrapped in {} and [] respectively), so they can't be mixed up with false in any case. The same goes with string - it's wrapped in "" (double quotation marks). As for Numbers, they have to contain at least one digit - so cannot be confused with false (and true and null) too.
So that leaves us with the only case: when json_encode processes an object having redefined its JSON representation. For example (PHP 5.4+):
class FalsyFoo implements JsonSerializable {
public $foo;
public function __construct($f) {
$this->foo = $f;
}
public function jsonSerialize() {
return false;
}
}
$f = new FalsyFoo(true);
$fj = json_encode($f);
var_dump( $fj ); // string(5) 'false'
var_dump( json_decode($fj) ); // bool(false)
Technically, we still work with false value here, but the source is obviously different.
If you're still not convinced, check the source code of json_decode, which calls php_json_decode_ex after checking the arguments. This, in turn, calls parse_JSON_ex first, which operates over the predefined state transition table; the latter has only one set of states leading to false value as result. If this call fails somehow, value is checked directly:
if (str_len == 4) {
if (!strcasecmp(str, "null")) {
/* We need to explicitly clear the error
because its an actual NULL and not an error */
jp->error_code = PHP_JSON_ERROR_NONE;
RETVAL_NULL();
} else if (!strcasecmp(str, "true")) {
RETVAL_BOOL(1);
}
} else if (str_len == 5 && !strcasecmp(str, "false")) {
RETVAL_BOOL(0);
}
... and that's the only case when return_value is set to boolean.
The documentation says that values true, false and null (case-insensitive) are returned as TRUE, FALSE and NULL respectively. This means that if the booleans true orfalse are in the object to be encoded, they will be shows as TRUE or FALSE, and the same for null. For example:
json_decode('["hello",true]');
would return:
["hello",TRUE]
It doesn't mean that json_decode will return values of true, false, or null

Form validation: only one validator of the chain should check against empty/null values, the rest of the validators should not

I have this id_role input that validates dependent on value of another input internet_access.
id_role's Validator Chain have one Callback validator that must check against empty/null values, others validators from this chain must check against filled values only.
I already made possible checking against empty/null values by $id_role->setContinueIfEmpty(true) but this applies to every validator in the chain. I need it to apply to only Callback validator of the chain.
This is the actual id_role input:
$id_role = new Input('id_role');
$id_role->setContinueIfEmpty(true); //this allows to check against empty/null values
$id_role->getFilterChain()
->attach($FilterInt);
$id_role->getValidatorChain()
->attach(new Validator\Callback(function($value, $context=array()){
return isset($context['internet_access']) && $context['internet_access'] == 1 && $value === 0 ? false : true;
}))
->attach(new Validator\Db\RecordExists(...);
So my problem is that Callback validator works fine but it fails on DbRecordExists because it tries to find a record that is empty. DbRecordExists must try to find a record only when id_role is actually filled.
Is there a way to do what i want in a elegant way (inside Input Filter and/or Input)?
The second parameter of ValidatorChain::attach method is $breakChainOnFailure, default value is false.
Check out docs at http://framework.zend.com/manual/2.2/en/modules/zend.validator.validator-chains.html
You should modify your code as:
$id_role->getValidatorChain()
->attach(
new Validator\Callback(
function($value, $context=array()){
return isset($context['internet_access']) && $context['internet_access'] == 1 && $value === 0 ? false : true;
}
),
true //$breakChainOnFailure
)
->attach(new Validator\Db\RecordExists(....));
Well i think there is no way of checking for empty/null values only in specific validators of the chain, because when i do $id_role->setContinueIfEmpty(true) it affects the whole Validator Chain, not just one specific validator, wich is the correct behavior.
So to accomplish what i needed, i had to put DbRecordExists Validator inside the Callback Validator and validate it manually only when values aren't empty/null:
$id_role = new Input('id_role');
$id_role->setContinueIfEmpty(true);
$id_role->getFilterChain()
->attach($FilterInt);
$id_role->getValidatorChain()
->attach(new Validator\Callback(function($value, $context=array()){
if (isset($context['internet_access']) && $context['internet_access'] == 1 && $value === 0) {
return false;
}
if ($value !== 0) {
$dbRecordExists = new Validator\Db\RecordExists(...);
if (!$dbRecordExists->isValid($value)) {
return false;
}
}
return true;
}));
I don't know if it is the best solution but well, it worked. I hope this can be of some help to others that have the same problem.

Value of option arguments: FALSE or NULL

When you have optional arguments that can have different types, which value is most suited to point out that the argument should not be taken into consideration? False or Null?
null is the value used to represent "no value", whereas false means "no", "bad", "unsuccessful", "don't" etc.
Therefore: null.
For me this depends on what I'm going to do with the value of said argument...
I am writing a database function where I can have default values as NULL
function somedbfunc($id = NULL, $column1 = NULL)
If these values are null my function may insert a blank record..
If I need to stop my function because of a non argument I may use FALSE
function blah($this = FALSE, $that = FALSE)
{
if ( ! $this || ! $that)
{
return FALSE;
....
So I am saying that both are totally valid, but it depends on the situation you find yourself in.
For optional arguments use null (generally).
Use null, if you need to differentiate between boolean values (true/false) and nothing (null). On the other hand if you don't need to check for not-set argument and you are using boolean variable then I'd go for false.
As you are saying that you want to tell the "optional arguments" "not be taken into consideration", I will go for null. False is explicitly saying "no" to the recipient. which is a valid input.

Categories