<?php
/**
 * ===========================================================================
 * Veitool 快捷开发框架系统
 * Author: Niaho 26843818@qq.com
 * Copyright (c)2019-2025 www.veitool.com All rights reserved.
 * Licensed: 这不是一个自由软件，不允许对程序代码以任何形式任何目的的再发行
 * ---------------------------------------------------------------------------
 */

namespace app\event;

use PhpOffice\PhpSpreadsheet\IOFactory;

/**
 * phpoffice excel导入导出类
 */
class PhpOffice
{
    /****
     * 普通导入
     * @param $filePath
     * @return array
     */
    public static function importexcel($filePath)
    {

        // 加载 Excel 文件
        $spreadsheet = IOFactory::load($filePath);
        $sheet = $spreadsheet->getActiveSheet();
        return $sheet->toArray();

//        // 获取最高行和列
//        $highestRow = $sheet->getHighestRow();
//        $highestColumn = $sheet->getHighestColumn();
//        $data = [];
//        // 读取表头 (第一行)
//        $headers = [];
//        for ($col = 'A'; $col <= $highestColumn; $col++) {
//            $headers[] = $sheet->getCell($col . '1')->getValue();
//        }
//        // 读取数据 (从第二行开始)
//        for ($row = 2; $row <= $highestRow; $row++) {
//            $rowData = [];
//            $colIndex = 0;
//            for ($col = 'A'; $col <= $highestColumn; $col++) {
//                $rowData[$headers[$colIndex]] = $sheet->getCell($col . $row)->getValue();
//                $colIndex++;
//            }
//            $data[] = $rowData;
//        }
//
//        return $data;
    }

    /****
     * 分块导入适合大数据
     * @param $filePath
     * @param $callback
     * @param $chunkSize
     * @return void
     */
    public static function chunkedImportXlsx($filePath, $callback, $chunkSize = 1000)
    {


        // 创建适当的读取器 (自动检测文件类型)
        $reader = IOFactory::createReaderForFile($filePath);
        // 只读取数据，不读取样式信息 (提高性能)
        $reader->setReadDataOnly(true);

        // 获取工作表信息 (特别是总行数)
        $worksheetInfo = $reader->listWorksheetInfo($filePath);
        $totalRows = $worksheetInfo[0]['totalRows'];
        // 计算需要读取的块数
        $chunkCount = ceil($totalRows / $chunkSize);

        // 分块读取
        for ($i = 0; $i < $chunkCount; $i++) {
            $startRow = ($i * $chunkSize) + 1; // +1 因为Excel行从1开始
            $endRow = min((($i + 1) * $chunkSize), $totalRows);

//            // 设置读取过滤器
            $chunkFilter = new ChunkReadFilter($startRow, $endRow);
            $reader->setReadFilter($chunkFilter);

            // 加载当前块的数据
            $spreadsheet = $reader->load($filePath);
            $sheet = $spreadsheet->getActiveSheet();

            // 将数据转换为数组
            $data = $sheet->toArray();

            // 处理数据 (通过回调函数)
            $callback($data, $startRow, $endRow);

            // 重要！清理内存
            $spreadsheet->disconnectWorksheets();
            unset($spreadsheet, $sheet, $data);
        }
    }
}


class ChunkReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter
{
    private $startRow = 0;
    private $endRow = 0;

    public function __construct($startRow, $endRow)
    {
        $this->startRow = $startRow;
        $this->endRow = $endRow;
    }

    public function readCell($column, $row, $worksheetName = ''): bool
    {
        // 只读取指定行范围内的单元格
        return ($row >= $this->startRow && $row <= $this->endRow);
    }
}