How use json in php with a 'complex' structure? - php

i want use json + php for my data. I read more document to do this, and the basic function are json_decode() and json_encode(). My problem is that, read more document and read different example of structure have created in me a lot of doubts.
I want create a structure like this begine from the basic to the container:
there is a Base, that have 2 property: id and value
there is a Operations that can have multiple Base
there is a Command that can have multiple Operations (and if possible a property callad name)
the structure in my mind is like this...
[ //The start of Commands
//Can make a property name here like "name":"puls1"
[ //Operation1
{ //Base1
"id":"22398",
"value":"255"
},
{ //Base2
"id":"22657",
"value":"80",
},
{ //Base3
"id":"7928",
"valore":"15"
}
],
[ //Operation2
{ //Base1
"id":"22398",
"value":"0"
},
{ //Base2
"id":"22657",
"value":"0",
},
{ //Base3
"id":"7928",
"valore":"0"
}
],
] //The close of Commands
But i have put the [ and { in the not correct order i think...
How can i make a json structure like this? And after set a command to insert a new Operation or remove Operation?
Thank's at all..
//Ok by answer of i made this code
class Base
{
var $i;
var $value;
function __construct($i,$v)
{
$this->id = $i;
$this->value = $v;
}
}
$a = new Base('1','11');
$b = new Base('2','10');
$c = new Base ('3','20');
$d = new Base ('4','30');
class Operation
{
var $name;
var $values = Array();
function __construct($a)
{
$this->name = $a;
}
public function addArray($a)
{
array_push($this->values,$a);
}
}
$oper1 = new Operation("op1");
$oper1->addArray($a);
$oper1->addArray($b);
$oper2= new Operation("op2");
$oper2->addArray($c);
$oper2->addArray($d);
$commands = Array($oper1,$oper2);
echo json_encode($tot);
Now the problem is how can i make the revert operation? Such a use of json_decode and incapsulate in its appropriate structure?

The json list type [] is equal to a array without keys in php.
The json dictionary type {}is equal to a keyed array in php.
What you want is something like this:
$json = array(
array(
array('id' => $num, 'value' => $val), // Base 1
array('id' => $num_1, 'value' => $val_1), // Base 3
array('id' => $num_2, 'value' => $val_2), // Base 2
),
array(...),
array(...),
);

If you're working with PHP I would construct the objects from native PHP Classes (json_encode works with php objects as well):
class Base {
var $id;
var $value;
}
Then it's just a matter of putting these objects in various arrays, which you can also abstract with methods like addToOperation($baseObj) and addToCommands($operationObj).
You're dealing with native data structures (Arrays), so you can use native methods to remove (array_pop) and add (array_push) data.

Something like this should work
// Build up your data as a mulitdimensional array
$data = array(
'operations' => array(
0 => array(
'bases' => array (
0 => array(
'id' => '22398',
'value' => 'whatever'
),
1 => array(
'id' => 'id goes here',
'value' => 'value goes here'
),
1 => array(
//data for operation 2
)
);
// Then use json_encode
$json = json_encode($data);
My syntax may not be perfect but that should give you the idea. To access it then you would use code like
$operations = json_decode($data);
foreach ($operations as $op) {
foreach ($op->bases as $base) {
//Logic goes here
}
}
Hope this helps.

Related

Get value of dynamic sub-array, in multidimensional array

Not sure if my question is clear, but here's what I'm trying to achieve. Let’s say I have a multidimensional array like so:
$arr['client1']**['dog']['Jack']**
$arr['client2']['cat']['Stacy']
How can I get the second portion of the array (between **), knowing it can be anything. For client 3, it could be a crocodile. For Client 4, it could be a car.
So I'm looking to "build" the structure of the array, dynamically. Something like so:
$arr['client1']{partBetweenThe**InTheExemple}
{partBetweenThe**InTheExemple} would be constructed "on the fly" (hence, the dynamically).
EDIT: Hopefully some clarifications...
The array changes every time. Basically, I'm building an addon to poll any API on the web. The data structure I'm getting can be anything. So what I need to do is build the key combination "on the fly", with variables.
In the exemple above, my variable would be something like $query = ['dog']['Jack'] and to get the value, I would poll it like so (from a logistic perspective, I know this doesn't work):
$arr['client1'][$query] or $arr['client1']$query or $arr['client1']{$query}
You can define the query as an array with each level as an element. Then we can iterate through that and check if we find a matching key in the response:
function findInArray(array $query, array $data)
{
foreach ($query as $key) {
if (!array_key_exists($key, $data)) {
// The key was not found, abort and return null
return null;
}
// Since the key was found, move to next level
$data =& $data[$key];
}
return $data;
}
// Example response
$response = [
'client1' => [
'dog' => [
'Jack' => 'Some value',
],
]
];
// Define the query as an array
$query = ['dog', 'Jack'];
$result = findInArray($query, $response['client1']);
Demo: https://3v4l.org/WjXTn
Edit:
So since the array's structure can't be changed this will return the client if the structure remains ['client']['animal']['name'].
$clients = [
'client1' => [
'dog' => [
'Jack' => []
]
],
'client2' => [
'cat' => [
'Stacy' => []
]
]
];
$animal = 'dog';
$name = 'Jack';
foreach ($clients as $client => $options) {
if (
array_key_exists($animal, $options) &&
array_key_exists($name, $options[$animal])
) {
echo $client;
break;
}
}

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."

PHP Handling uncertain input data

Sometimes we receive input data of varying structure, for example response from online API may include some information but other not, some details are stored in complex nested arrays etc.
I like to parse this data before usage, this way I don't have to use isset() over and over later on, ex.:
$input; // source
$correct_data = arra(); // verified data
$correct_data["option-1"] = (isset($input["option-1"]) ? $input["option-1"] : "");
$correct_data["option-2"] = (isset($input["option-2"]) ? $input["option-2"] : "");
Now I can use:
my_function($correct_data["option-1"]);
my_function2($correct_data["option-2"]);
and I know that there won't be any warnings for uninitialized variables or unknown array keys.
But problem occurs for nested data e.g.
$input = array(
"settings-main" => array(
"option-1" => "val-1",
"option-2" => "val-2",
"sub-settings" => array(
"my-option" => "some val",
"my-option-2" => "some val2",
),
),
"other-settings" => array(
"other" => array(
"option-1" => "a",
"option-2" => "b",
),
),
);
It's difficult to check this on start, later I have to use something like this:
if(isset($input["settings-main"]))
{
if(isset($input["settings-main"]["option-1"]))
$input["settings-main"]["option-1"]; //do something
if(isset($input["settings-main"]["sub-settings"]))
{
if(isset($input["settings-main"]["sub-settings"]["my-option-2"]))
$input["settings-main"]["sub-settings"]["my-option-2"]; //do something
}
}
do you have any suggestions how to handle such situations without using multiple isset() instructions ?
Try this with recursive function call.
function recursive_arr($input){
foreach($input as $val){
if(is_array($val)){
recursive_arr($val);
}else{
echo $val."<br/>";
}
}
}
recursive_arr($input);
Working Example

Include class name when using Doctrine 2 array hydration

In Doctrine 2 is there a way to get the array hydration mode to include the class name of the relevant entity in the output, so instead of:
array(
'id' => 1,
'name' => 'test',
// ...
);
You get:
array(
'__class' => 'MyProject\MyClass',
'id' => 1,
'name' => 'test',
// ...
);
I know the Doctrine\ORM\Internal\Hydration\ArrayHydrator class has access to the relevant information, but I'm trying to work out if this can be done without re-implementing the entire ArrayHydrator?
So creating a custom hydrator that extends ArrayHydrator and overriding the gatherRowData method with this is one potential solution:
protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents)
{
$rowData = parent::gatherRowData($data, $id, $nonemptyComponents);
foreach ($rowData['data'] as $dqlAlias => $data) {
$class = $this->_rsm->aliasMap[$dqlAlias];
$meta = $this->getClassMetadata($class);
if ($meta->discriminatorMap) {
$class = $meta->discriminatorMap[$data[$meta->discriminatorColumn['name']]];
}
$rowData['data'][$dqlAlias]['__CLASS__'] = $class;
}
return $rowData;
}
Be interested to know if there's a better way?

Optimization of an algorithm performed on a big array in PHP

I have a query that populates an array from the database. In some cases, this query returns a great amount of data, (let's say for purpose of an example, 100.000 records). Each row of the database has at least 6 or 7 columns.
$results = [
['id' => 1, 'name' => 'name', 'status' => true, 'date' => '10-01-2012'],
['id' => 2, 'name' => 'name 2', 'status' => false 'date' => '10-01-2013'],
...
]
I need to perform a substitution of some of the data inside the $results array, based on another one that give me some information about how i would change the values in the rows.
$model = [
'status' => ['function' => 'formatStatus', params => ['status']],
'date' => ['function' => 'formatDate', params => ['date']]
]
Now that i have all the data and what do i do with it i have the following routine.
foreach ($results as &$itemResult) {
$oldValues = $itemResult;
foreach ($itemResult as $attribute => &$value) {
if (isset($model[$attribute]['function'])) {
$function = $model[$attribute]['function'];
$params = $model[$attribute]['params'];
$paramsSize = count($params);
for ($i = 0; $i < $paramsSize; $i++) {
$newParams[] = $oldValues[$params[$i]];
}
$itemResult[$attribute] = call_user_func_array([$this, $function], $newParams);
$newParams = null;
}
}
}
So, for each attribute for each row of my data array, i run check for the existence of a function and params information. When the attribute in question needs to be replaced, i call the function via call_user_func_array and replace the value with the function return value.
Also notice that i am replacing the current array, not creating another, by passing the reference &$itemResult inside the loop, so in the end, i have the same array from the beginning but with all columns that needed to be replaced with its new values.
The thing is, for little arrays, this method is quite good. But for big ones, it becomes a pain.
Could you guys provide me some alternative to the problem?
Should i use another data structure instead of the PHP array?

Categories