I have a problem that has been stressing me out for weeks now and i cannot find a clean solution to it that does not involve recursion.
This is the problem:
Take a flat array of nested associative arrays and group this into one deeply nested object. The top level of this object will have its parent property as null.
This is my solution but i admit it is far from perfect. I am fairly certain this can be done in a single loop without any recursion, but for the life of me i cannot work it out!
//Example single fork
$data = array(
//Top of Tree
0 => array(
"name" => "A",
"parent" => null,
"id" => 1,
),
//B Branch
1 => array(
"name" => "B",
"parent" => "1",
"id" => 2,
),
2 => array(
"name" => "B1",
"parent" => "2",
"id" => 3,
),
3 => array(
"name" => "B2",
"parent" => "3",
"id" => 4,
),
4 => array(
"name" => "B3",
"parent" => "4",
"id" => 5,
),
//C Branch
5 => array(
"name" => "C",
"parent" => "1",
"id" => 6,
),
6 => array(
"name" => "C1",
"parent" => "6",
"id" => 7,
),
7 => array(
"name" => "C2",
"parent" => "7",
"id" => 8,
),
8 => array(
"name" => "C3",
"parent" => "8",
"id" => 9,
),
);
Actual anonymised example
array:7214 [▼
0 => array:3 [▼
"name" => ""
"parent" => null
"id" =>
]
1 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
2 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
3 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
4 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
5 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
6 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
7 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
8 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
9 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
10 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
Another example deeper nesting
{
"name":"top",
"id":xxx,
"children":{
"second":{
"name":"second",
"id":xxx,
"children":{
"Third":{
"name":"third",
"id":xxx,
"children":{
"fourth":{
"name":"fourth",
"id":xxx
}
}
}
}
}
}
}
$originalLength = count($data);
$obj = [];
while ($originalLength > 0) {
foreach ($data as $item) {
$name = $item['name'];
$parent = $item['parent'];
$a = isset($obj[$name]) ? $obj[$name] : array('name' => $name, 'id'=>$item['id']);
if (($parent)) {
$path = get_nested_path($parent, $obj, array(['']));
try {
insertItem($obj, $path, $a);
} catch (Exception $e) {
continue;
//echo 'Caught exception: ', $e->getMessage(), "\n";
}
}
$obj[$name] = isset($obj[$name]) ? $obj[$name] : $a;
$originalLength--;
}
}
echo json_encode($obj['A']);
function get_nested_path($parent, $array, $id_path)
{
if (is_array($array) && count($array) > 0) {
foreach ($array as $key => $value) {
$temp_path = $id_path;
array_push($temp_path, $key);
if ($key == "id" && $value == $parent) {
array_shift($temp_path);
array_pop($temp_path);
return $temp_path;
}
if (is_array($value) && count($value) > 0) {
$res_path = get_nested_path(
$parent, $value, $temp_path);
if ($res_path != null) {
return $res_path;
}
}
}
}
return null;
}
function insertItem(&$array, $path, $toInsert)
{
$target = &$array;
foreach ($path as $key) {
if (array_key_exists($key, $target))
$target = &$target[$key];
else throw new Exception('Undefined path: ["' . implode('","', $path) . '"]');
}
$target['children'] = isset($target['children']) ? $target['children'] : [];
$target['children'][$toInsert['name']] = $toInsert;
return $target;
}
Here's my take on what I believe is the desired output:
function buildTree(array $items): ?array {
// Get a mapping of each item by ID, and pre-prepare the "children" property.
$idMap = [];
foreach ($items as $item) {
$idMap[$item['id']] = $item;
$idMap[$item['id']]['children'] = [];
}
// Store a reference to the treetop if we come across it.
$treeTop = null;
// Map items to their parents' children array.
foreach ($idMap as $id => $item) {
if ($item['parent'] && isset($idMap[intval($item['parent'])])) {
$parent = &$idMap[intval($item['parent'])];
$parent['children'][] = &$idMap[$id];
} else if ($item['parent'] === null) {
$treeTop = &$idMap[$id];
}
}
return $treeTop;
}
This does two array cycles, one to map up the data by ID, then one to assign children to parents. Some key elements to note:
The build of $idMap in the first loop also effectively copies the items here so we won't be affecting the original input array (Unless it already contained references).
Within the second loop, there's usage of & to use references to other items, otherwise by default PHP would effectively create a copy upon assignment since these are arrays (And PHP copies arrays on assignment unlike Objects in PHP or arrays in some other languages such as JavaScript). This allows us to effectively share the same array "item" across the structure.
This does not protect against bad input. It's possible that invalid mapping or circular references within the input data could cause problems, although our function should always just be performing two loops, so should at least not get caught in an infinite/exhaustive loop.
I have an array in an array in an array. How can I search if any of these arrays have a specific key and value? If not remove this array from array.
Example:
array:3 [▼
0 => array:2 [▼
"location" => array:4 [▶]
"promotions" => array:1 [▶]
]
1 => array:2 [▼
"city" => array:4 [▶]
"promotions" => array:2 [▼
0 => array:5 [▶]
1 => array:5 [▼
"distance" => "0.2288511878121104"
"promoid" => 54
"promo" => Promotion {#1259 ▶}
"product" => Products {#1162 ▶}
"productID" => 5
]
]
]
2 => array:2 [▼
"city" => array:4 [▶]
"promotions" => []
]
]
I want to search "productID" with value 5, and I want to remove array in promotions which doesn`t have this value.
SOLVED
foreach ($locations as $key => $location) {
foreach ($location['promotions'] as $item => $promotions) {
if (is_array($promotions)) {
foreach ($promotions as $k => $value) {
if (!is_array($value)) {
if ($k == 'productID' && $value != $id) {
unset($locations[$key]['promotions'][$item]);
}
}
}
}
}
}
You could use a recursive function and unset() the target
<?php
// example code
$a = [
'test' => 'foo',
'bar' => [
'productID' => 5,
'something' => 'else'
],
'bar2' => [
'productID' => 6,
'something2' => 'else'
]
];
function removeItem($array, $search) {
$s = explode(":",$search);
$skey = trim($s[0]);
$sval = trim($s[1]);
foreach ($array as $n => $v) {
if ($n == $skey && $v == $sval) {
unset($array[$n]);
} else {
if (is_array($v)) $v = removeItem($v, $search);
$array[$n] = $v;
}
}
return $array;
}
$a = removeItem($a, 'productID:5');
print_r($a);
example: https://www.tehplayground.com/zJ2bKplP1pDaV8Ss
Nice solve, you can skip the 3er loop, checking if the key is set with isset()
foreach ($arr as $key => $location) {
if (!is_array($location)) { //if child is not an array ignore it
continue;
}
foreach ($location as $item => $promotions) {
if (!is_array($location)) {//if child is not an array ignore it
continue;
}
if (
isset($promotions['productID']) && //3er lvl, Has the key?
$promotions['productID'] == $id //Has the id
) {
continue; //This is a match so, ignore it
} else {
unset($arr[$key][$item]); //This promotion doesn't have it.
}
}
}
And this one checks at all levels, it uses recursive fn
$ans = deepClean($arr, 'productID', 5);
function deepClean($arr, $search_key, $search_value): ?array
{
if (
isset($arr[$search_key]) && //Has the key
$arr[$search_key] == $search_value //Match value
) {
return $arr;
}
//check children
$currentLevel = [];
foreach ($arr as $key => $value) {
if (!is_array($value)) {
continue;
}
$deepArr = deepClean($value, $search_key, $search_value);
if (is_array($deepArr)) { //child has search?
$currentLevel[$key] = $deepArr;
}
}
return $currentLevel === [] ? null : $currentLevel;
}
This question already has answers here:
How to Flatten a Multidimensional Array?
(31 answers)
Closed 3 years ago.
I have an eloquent object with data from the model which I need to convert to an array and have all indexes from the relations at the same array depth.
I tried array_flatten(), map(), filter() and other PHP methods but couldn't get it working correctly.
How I get my relations:
$data = Person::whereIn('id', $this->id[0])->where('school_id', '=',
$this->school)->with(['personinfo'=>function ($query) {
$query->select(
'person_id',
'general_info',
);
}, 'trades'=>function ($query) {
$query->select('person_id', 'trade_id')->with('trades');
}, 'measurements'=>function ($query) {
$query->select(
'person_id',
'measuring_point_1',
'measuring_point_1_date',
);
}])->get();
return $data->toArray();
What results in the array below, this is as close as I could get using different methods.
This is the outcome of the return function:
array:3 [
1 => array:17 [
"school_id" => 6
"birth_date" => null
"sex_id" => 1
"phone_number" => 62452676867897
"mobile_number" => 62398356786787
"email" => "example#example.com"
"personinfo" => array:5 [
"person_id" => 21
"general_info" => null
"health_info" => null
]
"trades" => array:3 [
"person_id" => 21
"trade_id" => 2
"trades" => array:8 [
"school_id" => 2
"name" => "blablabla"
]
]
"measurements" => array:7 [
"person_id" => 21
"measuring_point_1" => null
"measuring_point_1_date" => null
]
]
];
I need the array to be like this:
array:3 [
1 => array:17 [
"school_id" => 6
"birth_date" => null
"sex_id" => 1
"phone_number" => 624176676867897
"mobile_number" => 649498356786787
"email" => "example#example.com"
"person_id" => 21
"general_info" => null
"health_info" => null
"person_id" => 21
"trade_id" => 2
"school_id" => 2
"name" => "blablabla"
"person_id" => 21
"measuring_point_1" => null
"measuring_point_1_date" => null
]
]
];
Basically, I need to convert the multidimensional array to a zero depth array.
Any help would be appreciated.
You can use custom of array flatten with merging the inner with array-merge as:
function arrayFlatten($array) {
$res = array();
foreach ($array as $k => $v) {
if (is_array($v)) $return = array_merge($res, array_flatten($v)); // add recursively
else $res[$k] = $v; // just add
}
return $res;
}
Now just return arrayFlatten($data->toArray());
Simple live example
How i made it work using dWinder's answer
$data = Person::whereIn('id', $this->id[0])->where('school_id', '=', $this->school)->with(['personinfo'=>function ($query) {
$query->select(
'person_id',
'general_info',
);
}, 'trades'=>function ($query) {
$query->select('person_id', 'trade_id')->with('trades');
}, 'measurements'=>function ($query) {
$query->select(
'person_id',
'measuring_point_1',
'measuring_point_1_date',
);
}])->get();
function array_flatten($array)
{
$return = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$return = array_merge($return, array_flatten($value));
} else {
$return[$key] = $value;
}
}
return $return;
}
foreach ($data as $value) {
$result[] = array_flatten($value->toArray());
}
return $result;
I am trying to create a chart from data returned by a databse. The data is stored in a database and there can be multiple charts in this table. Identified by a unique value. (rigname)
array:102 [▼
0 => array:6 [▼
"id" => 2002
"user_id" => "1"
"rigname" => "home"
"data" => "{"hashrate":12.364,"pool":"eu1.ethermine.org:4444","shares":{"valid":"2","invalid":"0"},"gpus":[{"temperature":"56","fanSpeed":"56","hashrates":12.364}]}"
"created_at" => "2018-02-23 10:24:50"
"updated_at" => "2018-02-23 10:24:50"
],
1 => array:6 [▼
"id" => 2019
"user_id" => "1"
"rigname" => "server"
"data" => "{"hashrate":76.612,"pool":"eu1.ethermine.org:4444","shares":{"valid":"736","invalid":"2"},"gpus":[{"temperature":"65","fanSpeed":"67","hashrates":19.804},{"temp ▶"
"created_at" => "2018-02-23 10:25:56"
"updated_at" => "2018-02-23 10:25:56"
]
As you can see there are two possible charts according to the rigname. I want to display the hashrate value of the two rigs on a chart. This works, but, when one rig stops there is no data being submitted to the database from that rig.
The chart displays no 0 value for that rig, the last known data is being used. (duh)
I solved this by modifying my query like this:
$res[$value] = json_decode(MinerStatistics::where('rigname', $value)
->where('created_at','>=', \Carbon\Carbon::now()->subMinutes(20))
->orderBy('created_at', 'desc')
->get()
->toJson(), true
);
Now when the rig is stopped and I query the database, I only get the data from the past x minutes. This is done in a foreach that builds a new multidimensional array with the data sorted per rigname.
This rises a new problem, when I restart the rig and it starts reporting to the database. The values on the chart continue not at the current timestamp, they continue where the rig has stopped. Normally I would compare the timestamp of the last reported data and the previous reported data with the data of the rig that is still running and return 0 every time a running rig reports, but they report different timestamps ( all within 8 sec of each other)
How can I modify the returned mysql data that I end up with something like this:
array:2 [▼
"home" => array:150 [
0 => array:6 [▼
"id" => 2300
"user_id" => "1"
"rigname" => "home"
"data" => "{"hashrate":12.359,"pool":"eu1.ethermine.org:4444","shares":{"valid":"5","invalid":"0"},"gpus":[{"temperature":"57","fanSpeed":"57","hashrates":12.359}]}"
"created_at" => "2018-02-23 10:44:42"
"updated_at" => "2018-02-23 10:44:42"
]
1 => array:6 [▼
"id" => 2298
"user_id" => "1"
"rigname" => "home"
"data" => "{"hashrate":12.367,"pool":"eu1.ethermine.org:4444","shares":{"valid":"5","invalid":"0"},"gpus":[{"temperature":"57","fanSpeed":"57","hashrates":12.367}]}"
"created_at" => "2018-02-23 10:44:34"
"updated_at" => "2018-02-23 10:44:34"
]
2 => array:6 [▼
"id" => 2296
"user_id" => "1"
"rigname" => "home"
"data" => "{"hashrate":12.367,"pool":"eu1.ethermine.org:4444","shares":{"valid":"5","invalid":"0"},"gpus":[{"temperature":"57","fanSpeed":"57","hashrates":12.367}]}"
"created_at" => "2018-02-23 10:44:26"
"updated_at" => "2018-02-23 10:44:26"
]
...
Server stops, no data, should continue like this
3 => [false] ,
4 => [false] ,
5 => [false]
...
rig reports again to the database
36 => array:6 [▼
"id" => 2296
"user_id" => "1"
"rigname" => "home"
"data" => "{"hashrate":12.367,"pool":"eu1.ethermine.org:4444","shares":{"valid":"5","invalid":"0"},"gpus":[{"temperature":"57","fanSpeed":"57","hashrates":12.367}]}"
"created_at" => "2018-02-23 10:44:26"
"updated_at" => "2018-02-23 10:44:26"
],
],
"server" => array:150 [▼ // This keeps running, or visa versa
0 => array:6 [▼
"id" => 2301
"user_id" => "1"
"rigname" => "server"
"data" => "{"hashrate":76.62,"pool":"eu1.ethermine.org:4444","shares":{"valid":"749","invalid":"2"},"gpus":[{"temperature":"64","fanSpeed":"67","hashrates":19.778},{"tempe ▶"
"created_at" => "2018-02-23 10:44:44"
"updated_at" => "2018-02-23 10:44:44"
]
1 => array:6 [▼
"id" => 2299
"user_id" => "1"
"rigname" => "server"
"data" => "{"hashrate":76.68,"pool":"eu1.ethermine.org:4444","shares":{"valid":"749","invalid":"2"},"gpus":[{"temperature":"64","fanSpeed":"65","hashrates":19.815},{"tempe ▶"
"created_at" => "2018-02-23 10:44:36"
"updated_at" => "2018-02-23 10:44:36"
]
2 => array:6 [▼
"id" => 2297
"user_id" => "1"
"rigname" => "server"
"data" => "{"hashrate":76.644,"pool":"eu1.ethermine.org:4444","shares":{"valid":"749","invalid":"2"},"gpus":[{"temperature":"64","fanSpeed":"65","hashrates":19.793},{"temp ▶"
"created_at" => "2018-02-23 10:44:28"
"updated_at" => "2018-02-23 10:44:28"
]
3 => array:6 [▼
"id" => 2295
"user_id" => "1"
"rigname" => "server"
"data" => "{"hashrate":76.105,"pool":"eu1.ethermine.org:4444","shares":{"valid":"749","invalid":"2"},"gpus":[{"temperature":"64","fanSpeed":"65","hashrates":19.793},{"temp ▶"
"created_at" => "2018-02-23 10:44:20"
"updated_at" => "2018-02-23 10:44:20"
]
4 => array:6 [▼
"id" => 2293
"user_id" => "1"
"rigname" => "server"
"data" => "{"hashrate":76.557,"pool":"eu1.ethermine.org:4444","shares":{"valid":"749","invalid":"2"},"gpus":[{"temperature":"64","fanSpeed":"65","hashrates":19.78},{"tempe ▶"
"created_at" => "2018-02-23 10:44:12"
"updated_at" => "2018-02-23 10:44:12"
]
5 => array:6 [▼
"id" => 2291
"user_id" => "1"
"rigname" => "server"
"data" => "{"hashrate":76.562,"pool":"eu1.ethermine.org:4444","shares":{"valid":"749","invalid":"2"},"gpus":[{"temperature":"64","fanSpeed":"65","hashrates":19.794},{"temp ▶"
"created_at" => "2018-02-23 10:44:04"
"updated_at" => "2018-02-23 10:44:04"
]
]
]
The current code I have written:
public function index()
{
// Get the statistics from the database reported by the miner
// Group them by the rig name
$stats = MinerStatistics::where('user_id', Auth::user()->id)
->where('created_at','>=', Carbon::now()->subMinutes(20))
->orderBy('created_at', 'desc')
->take(300)
->get()
->groupBy('rigname');
// Get the rig names
$rigs = (object) [];
foreach($stats as $key => $value) {
$rigs->$key = $key;
}
// For each rig, get the last known stats between now and 10 seconds ago
$table = (object) [];
foreach($rigs as $key => $value) {
$tableData = $stats[$value]
->where('created_at','>=', Carbon::now()->subSeconds(10));
if (isset($tableData[0]) && $tableData !== []) {
$table->$key = (object) $tableData[0];
$table->$key->data = json_decode($tableData[0]['data'], true);
}
}
return view('rigs', [
'rigs' => $table,
'chart' => $this->chart($stats)
]);
}
public function chart($data)
{
$p = [];
foreach($data as $key => $value) {
$x = [];
$time = [];
foreach($value as $k => $v) {
$time[] = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $v['created_at'])->format('H:i:s');
$x[] = json_decode($v['data'], true);
}
$hashrate = [];
foreach($x as $k => $v){
$hashrate[] = $v['hashrate'];
}
$p[$key] = [ 'time' => $time, 'hashrate' => $hashrate ];
}
$datasets = [];
$n = 0;
foreach($p as $key => $value) {
$colors = [
"0, 188, 212",
"244, 67, 54",
"255, 152, 0"
];
$datasets[] = $this->chartData('Hashrate: ' . $key, array_reverse($value['hashrate']), $colors[$n++]);
}
dd($time);
$chart = app()->chartjs
->name('lineChartTest')
->type('line')
->size(['width' => '100%', 'height' => '20%'])
->labels(array_reverse($time))
->datasets($datasets)
->optionsRaw("{
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMin: 0, // minimum will be 0, unless there is a lower value.
beginAtZero: true // minimum value will be 0.
}
}]
}
}");
return $chart;
}
public function chartData($label, $data, $color)
{
return [
"label" => $label,
'backgroundColor' => "rgba(" . $color . ", 0)",
'borderColor' => "rgba(" . $color . ", 0.7)",
"pointBorderColor" => "rgba(" . $color . ", 0, 0.7)",
"pointBackgroundColor" => "rgba(" . $color . ", 0.7)",
"pointHoverBackgroundColor" => "#fff",
"pointHoverBorderColor" => "rgba(220,220,220,1)",
'data' => $data,
];
}
EDIT: I have found the answer, check below.
I've made an array $timeLabels this array contains timestamps from the current time till x minutes/hours ago in intervals of x minutes.
Then I loop over my rigs and compare the created_at with the values in the timeLabels. If it is in the same range (+/-10 sec) the data from the collection goes into an array with the timeLabel as key. When a timeLabel has no value, it gets 0 assigned as data. This actually works, but needs some tuning.
Full example:
<?php
namespace App\Http\Controllers\Rigs;
use Auth;
use Carbon\Carbon;
use App\MinerStatistics;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class RigController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the rigs dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
// Get the statistics from the database reported by the miner
// Group them by the rig name
$stats = MinerStatistics::where('user_id', Auth::user()->id)
->where('created_at','>=', Carbon::now()->subMinutes(60))
->orderBy('created_at', 'desc')
->take(300)
->get()
->groupBy('rigname');
// Get the rig names
$rigs = (object) [];
foreach($stats as $key => $value) {
$rigs->$key = $key;
}
// For each rig, get the last known stats between now and 10 seconds ago
$table = (object) [];
foreach($rigs as $key => $value) {
$tableData = $stats[$value]
->where('created_at','>=', Carbon::now()->subSeconds(10));
if (isset($tableData[0]) && $tableData !== []) {
$table->$key = (object) $tableData[0];
$table->$key->data = json_decode($tableData[0]['data'], true);
}
}
return view('rigs', [
'rigs' => $table,
'chart' => $this->chart($stats)
]);
}
public function chart($data)
{
$start = Carbon::now('Europe/Brussels');
$end = Carbon::now('Europe/Brussels')->subMinutes(60);
$timeLabels = $this->createTimeRange($end, $start);
$chartData = (object) [];
// Go over each returned rig
foreach($data as $key => $value) {
$arr = array(); // Create an empty array to store our results
// Go over all our timeLabels
foreach(array_reverse($timeLabels) as $t => $time) {
// Create a range to match the incomming created_at and timeLabels
// Needs finetuning!!
$start = Carbon::createFromFormat('H:i', $time)->subSeconds(30)->format('H:i:s');
$end = Carbon::createFromFormat('H:i', $time)->addSeconds(30)->format('H:i:s');
foreach ($value as $k => $v) {
// Transform created_at to the same format as $start and $end
$created = Carbon::createFromFormat('Y-m-d H:i:s', $v['created_at'])->format('H:i:s');
if($created >= $start && $created <= $end) {
if(!isset($v->data['hashrate'])){
$hashrate_ = json_decode($v->data,true)['hashrate'];
} else {
$hashrate_ = $v->data['hashrate'];
}
$arr[$time] = $hashrate_;
}
}
// If the set timeLabel has no value set to 0
// Rig is not running...
if (!isset($arr[$time])) {
$arr[$time] = '0';
}
}
$chartData->$key = $arr;
}
$datasets = [];
$n = 0;
foreach($chartData as $key => $value) {
$data = [];
foreach ($value as $k => $v) {
$data[] = $v;
}
$colors = [
"0, 188, 212",
"244, 67, 54",
"255, 152, 0"
];
$datasets[] = $this->chartData('Hashrate: ' . $key, array_reverse($data), $colors[$n++]);
}
$chart = app()->chartjs
->name('lineChartTest')
->type('line')
->size(['width' => '100%', 'height' => '20%'])
->labels($timeLabels)
->datasets($datasets)
->optionsRaw("{
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMin: 0, // minimum will be 0, unless there is a lower value.
beginAtZero: true // minimum value will be 0.
}
}]
}
}");
return $chart;
}
public function chartData($label, $data, $color)
{
return [
"label" => $label,
'backgroundColor' => "rgba(" . $color . ", 0)",
'borderColor' => "rgba(" . $color . ", 0.7)",
"pointBorderColor" => "rgba(" . $color . ", 0, 0.7)",
"pointBackgroundColor" => "rgba(" . $color . ", 0.7)",
"pointHoverBackgroundColor" => "#fff",
"pointHoverBorderColor" => "rgba(220,220,220,1)",
'data' => $data,
];
}
private function createTimeRange($start, $end, $interval = '5 mins', $format = '24') {
$startTime = strtotime($start);
$endTime = strtotime($end);
$returnTimeFormat = ($format == '12')?'g:i A':'G:i';
$current = time();
$addTime = strtotime('+'.$interval, $current);
$diff = $addTime - $current;
$times = array();
while ($startTime < $endTime) {
$times[] = date($returnTimeFormat, $startTime);
$startTime += $diff;
}
$times[] = date($returnTimeFormat, $startTime);
return $times;
}
}
If I do it like this, I could create a dedicated class so I can reuse this logic. The data I get returned to pass to the charts is now formatted like this: (exactly what I needed)
{#3436 ▼
+"home": array:13 [▼
"17:47" => 13.44
"17:42" => 13.417
"17:37" => 13.439
"17:32" => 13.436
"17:27" => 13.438
"17:22" => "0"
"17:17" => "0"
"17:12" => "0"
"17:07" => "0"
"17:02" => "0"
"16:57" => "0"
"16:52" => "0"
"16:47" => "0"
]
+"server": array:13 [▼
"17:47" => "0"
"17:42" => 76.373
"17:37" => 76.514
"17:32" => 76.565
"17:27" => 76.486
"17:22" => "0"
"17:17" => "0"
"17:12" => "0"
"17:07" => "0"
"17:02" => "0"
"16:57" => "0"
"16:52" => "0"
"16:47" => "0"
]
}
Hi im trying to make a xml file with laravel 5.2.
My function What i commented out i tried, wrong xml parse.
public function createXML() {
$maps = Maps::get()->toArray();
// function array_to_xml(array $arr, SimpleXMLElement $xml)
// {
// foreach ($arr as $k => $v) {
// is_array($v)
// ? array_to_xml($v, $xml->addChild($k))
// : $xml->addChild($k, $v);
// }
// return $xml;
// }
function to_xml(SimpleXMLElement $object, array $data)
{
foreach ($data as $key => $value) {
if (is_array($value)) {
$new_object = $object->addChild($key);
to_xml($new_object, $value);
} else {
$object->addChild($key, $value);
}
}
}
// $xmloutput = to_xml($maps, new SimpleXMLElement('<root/>'))->asXML();
$xml = new SimpleXMLElement('<rootTag/>');
to_xml($xml, $maps);
return Response::make($xml->asXML())->header('Content-Type', 'text/xml');
my output array:
array:2 [▼
0 => array:5 [▼
"id" => 1
"name" => "Leeuwarden"
"address" => "Leeuwarden"
"lat" => 53.20132
"lng" => 5.80005
]
1 => array:5 [▼
"id" => 2
"name" => "Assen"
"address" => "Assen"
"lat" => 52.99275
"lng" => 6.56423
]
]
Any suggestions on what i am doing wrong?
i'm trying to make a google maps API map with pointers from the database.
There's a simpler way with this package.
$maps = Maps::get()->toArray();
$httpCode = 200;
$headers = [];
$rootXmlTag = 'rootTag';
return response()->xml($maps, $httpCode, $headers, $rootXmlTag);
1st option: get the right structure directly in maps and name the arrays.
2nd option: if you can'y change the $maps array received, then you can modify the head level by adding check to it:
$maps = [
0 => [
"id" => 1,
"name" => "Leeuwarden",
"address" => "Leeuwarden",
"lat" => 53.20132,
"lng" => 5.80005,
],
1 => [
"id" => 2,
"name" => "Assen",
"address" => "Assen",
"lat" => 52.99275,
"lng" => 6.56423,
]
];
function to_xml(\SimpleXMLElement $object, array $data, $level = 0)
{
foreach ($data as $key => $value) {
if (is_array($value)) {
$new_object = $object->addChild(($level == 0) ? 'marker' : $key);
to_xml($new_object, $value, $level + 1);
} else {
$object->addChild($key, $value);
}
}
}
$xml = new \SimpleXMLElement('<rootTag/>');
to_xml($xml, $maps);
header('Content-type: text/xml');
echo $xml->asXML();
Edit: I checked the docs, it seems, that the 1st level needs to be named marker.