我有一个这样的JSON文件
{
"20":{
"0":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"1":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"2":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"3":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"4":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"5":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"6":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
}
},
"21":{
"0":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"1":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"2":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"3":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"4":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"5":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
},
"6":{
"period":[
{
"open": 350,
"close": 600
},
{
"open": 660,
"close": 900
}
]
}
}
并且我有一个action
正在将这个JSON
解码为数组,并逐步传递foreach
-es,获取该数据,然后将其存储在数据库中。 / p>
一个人说我可以重构所有动作,所以我不会绝对(或近似)任何foreach或if。他还说这称为representative/functional
编程。
因此,我发现了这个概念以及所有这些东西,但也弄不清楚该怎么做。
我的imperial
代码:
$processingFile = file_get_contents(storage_path('hours.txt'));
$decodedFile = json_decode($processingFile, true);
$data = [];
$i = 0;
$batch = 10000;
foreach ($decodedFile as $business => $days) {
foreach ($days as $dayOfWeek => $periods) {
if (count($periods)) {
foreach ($periods['period'] as $key => $value) {
$i++;
$tmp = [
'business_id' => $business,
'day_of_week' => $dayOfWeek,
'open_periods_mins' => $value['open'],
'close_periods_mins' => $value['close'],
];
array_push($data, $tmp);
if($i === $batch) {
BusinessHour::insert($data);
$data = [];
$i = 0;
}
}
}
}
}
if( count($data) ) {
BusinessHour::insert($data);
}
我不知道如何逐步parse
并使用Laravel Collections
或其他任何方法declarative paradigm
将其全部切掉。
有人可以出于教学目的解释/重写该代码吗? 谢谢!
答案 0 :(得分:0)
我不确定是否有适用于您的情况的通用方法,因为您将信息处理到最终数组中的方法不是通用的(例如,字符串“ period”或数字键都不在最终输出中的任何地方都没有使用 period 数组,而使用了其他键,并且最后两个子元素组合成一个记录,等等。
在您的示例中,这里有一些技巧性的方法来准备$data
,其中this answer中的方式为“ PHP在串联键的同时将嵌套数组转换为单个数组?”被采用。
这样,它仅使用一个foreach
(考虑到最终转换是非通用的,我认为不可避免要进行一级循环)。请注意,它假定输入JSON没有不规则结构。
$string = http_build_query($decodedFile);
$string = urldecode($string);
$string = str_replace(
array('[',']'),
array('_','') ,
$string
);
parse_str($string, $flat_array);
$data = [];
$tmp = [];
foreach ($flat_array as $ky => $val) {
$ary = explode('_', $ky);
$tmp[$ary[4] . '_periods_mins'] = $val;
if ($ary[4] == 'close') {
array_push($data, $tmp);
$tmp = [];
continue;
}
$tmp['business_id'] = $ary[0];
$tmp['day_of_week'] = $ary[1];
}
答案 1 :(得分:0)
您可以使用collect()帮助器来实现此目的,该帮助器会将数组添加到集合实例并允许您使用其方法。
$processingFile = file_get_contents(storage_path('hours.txt'));
$data = json_decode($processingFile, true);
$insertData = [];
collect($data)
->each(function ($business, $businessKey) use (&$insertData) {
collect($business)
->each(function ($day, $dayKey) use ($businessKey, &$insertData) {
foreach ($day['period'] as $period) {
$insertData[] = [
'business_id' => $businessKey,
'days_of_week' => $dayKey,
'open_periods_mins' => $period['open'],
'close_periods_mins' => $period['close'],
];
}
});
});
if (count($insertData)) {
BusinessHour::insert($insertData);
}
首先,我们获得$processingFile
并将其解码为$data
变量。 $insertData
被创建为一个新的空数组,将在以后使用。
然后将$data
变量包装在collect()
帮助器中。对于每个business
,我们都会通过参考变量$insertData
。这是为了在集合闭包之外更新变量。
在每个business
中,我们有days
,因此我们收集了$business
(实际上是days
),并且对于每个day
,都经过{{ 1}}和$businessKey
变量的引用。
此后,我们使用普通的$insertData
用新数据更新foreach
数组。
在该过程结束时,然后将所有数据$insertData
insert()
放入记录中。
我希望这会有所帮助。
答案 2 :(得分:0)
Laravel 集合在这种情况下非常有用,您可以将代码分解成部分使其可读,同时获得功能性编程外观。
$data = file_get_contents(storage_path('hours.txt'));
$data = collect(json_decode($data, true));
$batch = 5;
$data = $this->initMap($data);
$data = $this->finMap($data, $data->count(), $batch);
if ($data->count() > 0){
BusinessHour::insert($data->toArray());
};
这是初始的地图函数,它只是准备所有必要的数据,以便以后处理。
public function initMap($data){
return $data->flatmap(function($data, $bId) {
return collect($data)
->map(function($data, $day) use ($bId) {
return collect([
'business_id' => $bId,
'day_of_week' => $day,
'open_periods_mins' => $data['period'][0]['open'],
'close_periods_mins' => $data['period'][0]['close']
]);
});
});
}
这里是数据的最终确定。此计算是否需要根据 $batch 变量保存数据,如果不需要,剩余的数据仍将保存在最后。
PS:代码基于 OP 初始代码,我使用 laravel 8。
public function finMap($data, $total, $batch){
$this->insertData = [];
return $data->map(function($data, $index) use ($total, $batch) {
if (($total - $index) > ($total % $batch)){
$this->insertData[] = collect($data);
if (($index % $batch) == 0){
BusinessHour::insert($this->insertData);
}
}else{
return $data;
}
})->filter(function($data){
return $data;
});
}