PHP filter callback with default value - php

Is there a way to define a default value (or to force the callback to be called everytime) when using filter_var_array and FILTER_CALLBACK ?
Example data:
{
"name": "John"
}
Example usage:
$params = filter_var_array($datas_from_above, [
'name' => FILTER_SANITIZE_STRING,
'age' => [
'filter' => FILTER_CALLBACK,
'options' => function ($data) {
// I was thinking $data would be null here
// but this function is not called if the
// param is not present in the input array.
die('stop?');
}
]
], true); // Add missing keys as NULL to the return value
When using other filters, there's the default option. So it shouldn't be supernatural to have a default value for callback filters. Am I missing something obvious?
Thanks

ok so after some comments and digging, filters in php only process what the input array contains.
So if you want to guarantee that a custom callback is always called, even if the input array doesn't contain the key => value pair, you can do:
$partial_input = ["name" => "John"]; // E.g. from a GET request
$defaults = ["name" => null, "age" => null];
$input = array_merge($defaults, $partial_input);
$parsed = filter_var_array($input, [
"name" => FILTER_SANITIZE_STRING,
"age" => [
"filter" => FILTER_CALLBACK,
"options" => function ($data) {
// do something special if $data === null
}
]
]);

Related

Array destructuring assignement with optional values

Is there any solution in PHP to make an array destructuring assignment with associative keys can extract optional values/default values (like the example below)?
Because when I tried, I always get undefined index 'age' (it's because it is not set).
See example:
// implementation
function myFunction(array $params = ['name' => 'user-name', 'age' => 15]){
['name' => $name, 'age' => $age ] = $params;
echo $name.' '.$age;
}
// Execution:
// normal case
myFunction(['name' => 'user', 'age' => 100]);
// Output: user 100
// Wanted case to be released
myFunction(['name' => 'user']);
// Output: user 15 <== i want to get this default age value if i don't set it in the given associative array params.
What about defining an array with default values?
function myFunc(array $params, array $defaults = [ 'name' => 'Marcel', 'age' => 40 ]): string
{
$data = array_merge($defaults, $params);
[
'name' => $name,
'age' => $age
] = $data;
return $name . $age;
}
The array merge overwrites the default values with the given param values. So the return will always be a complete mixture of both values. If you send a name only, the name will be mixed up with the default age. If you give an age only, the age will be mixed up with the default value.
myFunc([ 'name' => 'sohaieb', 'age' => 15 ]); // => sohaieb15
myFunc([ 'name' => 'yadda' ]); // => yadda40
The second parameter $defaults can be changed, if the defaults change in the future. A possible scenario: You set the default values in a config. With this solution the function can take the default settings from the config and don 't has to be touched in the future.
Well, since you pass in a parameter, it will always take that instead of the default one. However, you can use the union operator + to merge it with default values if not present in the originally supplied value during function call.
<?php
function myFunction(array $params = []){
$params = $params + ['name' => 'user-name', 'age' => 15];
['name' => $name, 'age' => $age ] = $params;
echo $name.' '.$age;
}
myFunction(['name' => 'user']);
Because $params is an array, so it overrides the default values even if you pass in an empty array.
One way to do this is to check the value inside your function body.
function myFunction(array $params){
$name = $params['name'] ?? 'user-name';
$age = $params['age'] ?? 15;
echo $name.' '.$age;
}
// Execution:
// normal case
myFunction(['name' => 'user', 'age' => 100]);
// Output: user 100
// Wanted case to be released
myFunction(['name' => 'user']);
Reference
https://wiki.php.net/rfc/isset_ternary

PHP library or helper method to set values of nested associative array

I'm working in PHP with what are essentially JSON objects (Highchart configs to be specific). So I might have something like the following:
$chart = [
'plotOptions' => [
'column' => [
'dataLabels' => [
'enabled' => true
]
]
],
'legend' => [
'enabled' => false
],
'yAxis' => [
'title' => [
'text' => null
]
]
];
I'm writing some code to build these config objects in the PHP and it's a pain to set nested properties because I have to check if the parent exists. For example, if I wanted to add a title to the xAxis to the config above, I'd have to do this:
if(!array_key_exists('xAxis', $chart)){
$chart['xAxis'] = [];
}
$chart['xAxis']['title'] = 'x title';
This is especially annoying when I have a really deep property to set because I have to do a "array_key_exists" for each level.
I'm wondering if anyone has any idea on how to make this simpler and cleaner. Thanks.
You can use a simple function to create associative keys automatically.
function setKey($key, $value, &$array) {
$path = explode('.', $key);
$arrayContext =& $array;
foreach( $path as $segment ) {
if( !isset($arrayContext[$segment]) ) {
$arrayContext[$segment] = [];
}
$arrayContext =& $arrayContext[$segment];
}
$arrayContext = $value;
}
Then use dot notation to set the key value within the array (e.g. "xAxis.title" is the same as $chart['xAxis']['title']):
setKey('xAxis.title', 'x title', $chart);
This can be read as "set the value of the key xAxis -> title to 'x title' in the $chart array variable."

Laravel/PHP renaming associative keys without knowing their names

Given following collection/array:
[
"somename" => "test.test.be"
"anothername" => "test"
"yetanothername" => "testing"
"extrafield" => "extra",
"extrafield" => "extra",
]
When i retrieve this collection i always know the order of them, but i will not know the key-names. So what i want to do is transform this collection and change the keynames to my defined values.
For a non-associative array i would do something like
$trimmedCollection->transform(function ($item) {
return [
'email' => $item[0],
'first_name' => $item[1],
'surname' => $item[2],
];
});
But how would i handle this for the given collection? Also what to do with overflow items. Say i suddenly got 10 key-value pairs but only wrote a transform for 3 how would i transform all the overflow to a default key?
Edit:
For the overflow items i would like to assign all extra fields in the given array to be stored like so.
Below would be the final array:
[
"email" => "test.test.be"
"first_name" => "test"
"surname" => "testing"
"additional_fields" => ["key-name" => "extra","key-name" => "extra"]
]
Where the key-name is the original name of the key i retrieved.
You can use array_shift to remove the 1st element in the array for every known element, and add the remaining array to your additional_fields key:
$trimmedCollection->transform(function ($item) {
return [
'email' => array_shift($item), //$item[0]
'first_name' => array_shift($item), //$item[1]
'surname' => array_shift($item), //$item[2]
'additional_fields' => $item //all remaining items
];
});
You could do something like this to transform your selected keys. This retains the other values with their unchanged keys.
function replace_array_key(array &$item, $oldKey, $newKey)
{
$item[$newKey] = $item[$oldKey];
unset($item[$oldKey]);
}
$trimmedCollection->transform(function ($item) {
replace_array_key($item, 'somename', 'email');
replace_array_key($item, 'anothername', 'first_name');
replace_array_key($item, 'yetanothername', 'surname');
return $item;
});
You can even extend this to an array list of old and new key names and run it through and arrap_map.

Convert PHP to JSON with Nested Array

I have a PHP variable I need to convert to JSON string.
I have following PHP code:
$username="admin";
$password="p4ssword";
$name="Administrator";
$email="myname#smsfree4all.com"
$params=compact('username', 'password','name','email', 'groups');
json_encode($params);
This works fine. But what I am not sure about is how do I encode the properties in PHP with nested key value pairs shown below:
{
"username": "admin",
"password": "p4ssword",
"name": "Administrator",
"email": "admin#example.com",
"properties": {
"property": [
{
"#key": "console.rows_per_page",
"#value": "user-summary=8"
},
{
"#key": "console.order",
"#value": "session-summary=1"
}
]
}
}
What is this with # before key value?
Something like this should do it
$username="admin"; //more variables
$params=compact('username' /* more variables to be compacted here*/);
$params["properties"] = [
"property" => [
[
"#key" => "console.rows_per_page",
"#value"=> "user-summary=8"
],
[
"#key"=> "console.order",
"#value"=> "session-summary=1"
]
]
];
echo json_encode($params);
The manual has more examples you can use
Notice that:
A key~value array is encoded into an object
A regular array (array of arrays here) is encoded into an array
Those are all the rules you need to consider to encode any arbitrary object
Something like this perhaps?
$properties = [
'property' => [
['#key' => 'console.rows_per_page', '#value' => 'user-summary=8'],
['#key' => 'console.order', '#value' => 'session-summary=1']
]
];
It's difficult to tell what you're asking.
You can nest in PHP using simple arrays, very similar to JavaScript objects:
$grandparent = array(
"person1" => array(
"name" => "Jeff",
"children" => array(
array("name" => "Matt"),
array("name" => "Bob")
)
),
"person2" => array(
"name" => "Dillan",
"children" => array()
)
);

Yii2 Arraydataprovider custom value

First of all, I'm really disappointed after all googling and getting nothing!
I have an Arraydataprovider called
$data = [
400 => [
'name' => 'x',
'lesson_1' => '10',
'lesson_2' => '9',
...
],
389 => ...
]
It's generated in a for loop.
I want the values to be shown in a text box :
foreach($lessons as $lid => $name) {
$attrs[] = [
'attribute' => 'lesson_' . $lid,
'label' => $name['name'],
'format' => 'raw',
'value' => function($model, $key, $index) use($lid, &$data) {
return '<input class="txt" data-lid="'.$lid.'" type="text" value="'.$data[$key]['lesson_'.$lid].'"/>';
}
];
}
It gives me error : Undefined index: lesson_49
But I'm sure that $data provider, has the key lesson_49 (proved by var_dump);
what is the problem? :-(
You should check for value is empty or not using isset() or empty():
Use isset() inside value function to check for empty value.
For example,
(isset($data[$key]['lesson_'.$lid]) ? $data[$key]['lesson_'.$lid] : '-';
You can also use var_dump($data).
Try to use var_dump($data) in your value function when !isset($data[$key]['lesson_'.$lid]) and check what's wrong with your data

Categories