PHP类内方法间属性更新传递问题(Laravel Excel场景)
解决Laravel Excel中headings()无法获取array()更新后属性的问题
这个问题我之前也踩过坑!核心原因是Laravel Excel的执行顺序——headings()方法会在array()方法之前被调用,所以你在array()循环里对$a_list_only的更新,在headings()执行的时候根本还没发生,自然拿不到最新值。
解决思路
我们需要把生成表头所需的$a_list_only数据的逻辑,提前到array()执行之前完成,比如放到构造函数里,或者单独写一个初始化方法提前处理好,这样headings()就能直接拿到准备好的数据了。
修改后的代码示例
我调整了你的代码,把生成amenity列表的逻辑抽成了单独的方法,并在构造函数里提前执行:
<?php namespace App\Exports; use Maatwebsite\Excel\Concerns\FromArray; use DB; use Maatwebsite\Excel\Concerns\WithHeadings; class MatrixExport implements FromArray, WithHeadings { protected $building_ids = [], $amenities_list = [], $property ; public $a_list_only; public function __construct($building_ids, $amenities_list, $property, $a_list_only = []) { $this->building_ids = $building_ids; $this->amenities_list = $amenities_list; $this->property = $property; // 提前初始化表头需要的amenity列表 $this->initializeAmenityList(); } // 新增方法:提前获取需要的amenity列表 private function initializeAmenityList() { $query = \DB::table('units_amenities_values') ->join('units', 'units.id', 'units_amenities_values.unit_id') ->join('floors', 'floors.id', 'units.floor_id') ->join('buildings', 'buildings.id', 'floors.building_id') ->join('properties', 'properties.id', 'buildings.property_id') ->leftJoin('amenity_values', 'amenity_values.id', 'units_amenities_values.amenity_value_id') ->leftJoin('amenities', 'amenities.id', 'amenity_values.amenity_id') ->leftJoin('categories', 'amenities.category_id', 'categories.id') ->select('amenities.id as amenity_id', 'amenities.amenity_name', 'categories.category_name') ->where('amenities.property_id', $this->property->id) ->whereIn('buildings.id', $this->building_ids) ->whereNull('buildings.deleted_at'); if(!in_array('-1',$this->amenities_list)){ $query->whereIn('amenities.id',$this->amenities_list); } $res = $query ->orderByRaw('LENGTH(amenity_name)', 'ASC') ->orderBy('amenity_name') ->get(); $included_amenity_ids = []; $selected_data = []; foreach($res as $rk => $rv){ if( (!in_array($rv->amenity_id,$included_amenity_ids) && in_array($rv->amenity_id, $this->amenities_list)) || (!in_array($rv->amenity_id,$included_amenity_ids) && in_array('-1', $this->amenities_list)) ){ $included_amenity_ids[] = $rv->amenity_id; $selected_data[$rv->category_id]['category_name'] = $rv->category_name; $selected_data[$rv->category_id]['amenities'][$rv->amenity_id] = $rv->amenity_name; } } ksort($selected_data); $am_lists_only = []; foreach($selected_data as $sk => $sv){ $am_lists_only = $am_lists_only + $sv['amenities']; } // 转换为值数组,对应表头需要的格式 $this->a_list_only = array_values($am_lists_only); } public function array(): array { $non_unit = DB::table('non_units as nu') ->join('buildings as b','b.id','=','nu.building_id') ->where('b.property_id',$this->property->id) ->pluck('nu.id'); $query = \DB::table('units_amenities_values') ->join('units', 'units.id', 'units_amenities_values.unit_id') ->join('floors', 'floors.id', 'units.floor_id') ->join('buildings', 'buildings.id', 'floors.building_id') ->join('properties', 'properties.id', 'buildings.property_id') ->leftJoin('amenity_values', 'amenity_values.id', 'units_amenities_values.amenity_value_id') ->leftJoin('amenities', 'amenities.id', 'amenity_values.amenity_id') ->leftJoin('categories', 'amenities.category_id', 'categories.id'); if ($this->property->availability_file == 1 || $this->property->availability_file == 3) { $query->leftJoin('availabilities', 'availabilities.unit_id', 'units.id'); $query->select('units_amenities_values.id as uav_id', 'units_amenities_values.uav_status', 'units_amenities_values.deleted_at as uav_deleted_at', 'amenities.id as amenity_id', 'amenities.amenity_name', 'amenity_values.initial_amenity_value', 'amenity_values.amenity_value', 'amenity_values.status as av_status', 'floors.floor', 'units.id as unit_id', 'units.unit_number', 'units.unit_rent', 'units.stack', 'units.unit_note', 'amenities.category_id', 'buildings.id as building_id', 'buildings.building_number', 'availabilities.status as avail_status','categories.category_name'); } else { $query->select('units_amenities_values.id as uav_id', 'units_amenities_values.uav_status', 'units_amenities_values.deleted_at as uav_deleted_at', 'amenities.id as amenity_id', 'amenities.amenity_name', 'amenity_values.initial_amenity_value', 'amenity_values.amenity_value', 'amenity_values.status as av_status', 'floors.floor', 'units.id as unit_id', 'units.unit_number', 'units.unit_rent', 'units.stack', 'units.unit_note', 'amenities.category_id', 'buildings.id as building_id', 'buildings.building_number','categories.category_name'); } $query->where('amenities.property_id', $this->property->id) ->whereIn('buildings.id', $this->building_ids) ->whereNull('buildings.deleted_at'); if(!in_array('-1',$this->amenities_list)){ $query->whereIn('amenities.id',$this->amenities_list); } if(!empty($this->building_ids)){ $query->whereIn('buildings.id', $this->building_ids); }else{ $query->where('buildings.property_id', $this->property->id); } $res = $query ->orderByRaw('LENGTH(amenity_name)', 'ASC') ->orderBy('amenity_name') ->get(); $data = $res->groupBy('unit_id'); $ex_data = $item = []; foreach($data as $k => $v){ $item = [ 'Bldg' => $v[0]->building_number, 'Unit' => (is_numeric($v[0]->unit_number))?(int)$v[0]->unit_number:$v[0]->unit_number, 'Floor' =>(is_numeric($v[0]->floor))?(int)$v[0]->floor:$v[0]->floor, 'Stack' => (is_numeric($v[0]->stack))?(int)$v[0]->stack:$v[0]->stack ]; // 直接使用提前初始化好的amenity列表 foreach ($this->a_list_only as $av) { $current_val = ""; foreach ($v as $vk => $vv) { if ($vv->amenity_name == $av) { $current_val = $vv->amenity_value; } } $item[$av] = $current_val; } $ex_data[] = $item; } return $ex_data; } public function headings(): array { $common_header_arr = ['Bldg', 'Unit', 'Floor', 'Stack']; return array_merge($common_header_arr, $this->a_list_only); } }
关键修改点说明
- 提前初始化数据:新增
initializeAmenityList()方法,把原来在array()里生成amenity列表的逻辑移到这里,在构造函数里调用,确保$a_list_only在headings()执行前就已经准备完毕。 - 避免重复逻辑:
array()方法里直接使用已经初始化好的$a_list_only,不需要再往里面追加数据,减少冗余操作。 - 优化查询:
initializeAmenityList()里的查询只选择需要的字段,减轻数据库查询的负担。
另外,如果你担心重复查询数据库,可以考虑把查询结果缓存起来,或者用->distinct()来避免重复数据,进一步优化性能。
内容的提问来源于stack exchange,提问作者Aayush Dahal
相关产品推荐
相关产品推荐

