PHPWord 表格克隆多行


<?php

namespace Home\Service;

require_once 'vendor/autoload.php';
// \PhpOffice\PhpWord\TemplateProcessor

/**
 * 自定義 克隆多行
 * Class TemplateProcessor
 * @package Home\Service
 */
class TemplateProcessor extends \PhpOffice\PhpWord\TemplateProcessor
{
    /**
     * 查找字符、字符串第n次出現的位置
     * todo 自行添加
     * @param string $str  原始字符串
     * @param string $find 需要查找的字符、字符串
     * @param int    $start 開始搜索的位置
     * @param int    $num  第幾次出現的字符、字符串
     * @return bool|int 返回第n次出現的位置
     */
    public function strPosNum($str = '', $find = '', $start = 0, $num = 1)
    {
        $pos = false;
        if ($num > 0) {
            $pos = strpos($str, $find, $start);
            
            for ($i = 1; $i < $num; $i++) {
                $pos = strpos($str, $find, $pos + 1);
            }
        }
        
        return $pos;
    }
    
    /**
     * 找到下面幾行的最后行尾的結束位置
     * todo 自行添加
     * @param     $offset 開始搜索的位置
     * @param int $rowNum 復制幾行
     * @return bool|int
     */
    public function findRowEndWithRowNum($offset, $rowNum = 0)
    {
        // </w:tr> 行尾標簽
        return $this->strPosNum($this->tempDocumentMainPart, '</w:tr>', $offset, $rowNum) + 7;
    }
    
    /**
     * 克隆多行
     * todo 自行添加
     * 如果clone的第一行是合並單元格的 就clone變量選擇第一個合並單元格的 如下
     * ---------------------
     *  |     |   B    |
     *  |  A  |--------|
     *  |     | C |  D |
     *  ---------------------
     * @param $search  搜索 這個要選擇克隆多行的第一行的變量
     * @param $numberOfClones 克隆的個數
     * @param int $rowNum 克隆這行下面幾行(包括當前行)
     */
    public function cloneMultiRow($search, $numberOfClones = 0, $rowNum = 1)
    {
        // 搜索的字符串替換成word中使用的變量
        $search = static::ensureMacroCompleted($search);
        
        // 查找 當前變量 字符串首次出現的位置
        $tagPos = strpos($this->tempDocumentMainPart, $search);
        if (!$tagPos) {
            throw new \PhpOffice\PhpWord\Exception\Exception('Can not clone row, template variable not found or variable contains markup.');
        }
        
        // 找到行的開始位置
        $rowStart = $this->findRowStart($tagPos);
        // 需要行尾的結束位置
        $rowEnd = $this->findRowEndWithRowNum($tagPos, $rowNum);
        // 找到 行開始和行結束中間的 xml字符串
        $xmlRow = $this->getSlice($rowStart, $rowEnd);
        
        // 碰到合並單元格的
        // Check if there's a cell spanning multiple rows.
        if (preg_match('#<w:vMerge w:val="restart"/>#', $xmlRow)) {
            // $extraRowStart = $rowEnd;
            $extraRowEnd = $rowEnd;
            while (true) {
                $extraRowStart = $this->findRowStart($extraRowEnd + 1);
                $extraRowEnd = $this->findRowEndWithRowNum($extraRowEnd + 1, $rowNum);
                
                // If extraRowEnd is lower then 7, there was no next row found.
                if ($extraRowEnd < 7) {
                    break;
                }
                
                // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.
                $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd);
                if (!preg_match('#<w:vMerge/>#', $tmpXmlRow) &&
                    !preg_match('#<w:vMerge w:val="continue"\s*/>#', $tmpXmlRow)) {
                    break;
                }
                // This row was a spanned row, update $rowEnd and search for the next row.
                $rowEnd = $extraRowEnd;
            }
            $xmlRow = $this->getSlice($rowStart, $rowEnd);
        }
        
        // 獲取 tempDocumentMainPart 中 開頭到 查找行開始位置的字符串
        $result = $this->getSlice(0, $rowStart);
        // 獲取 clone變量 之后的xml 並拼接
        $result .= implode($this->indexClonedVariables($numberOfClones, $xmlRow));
        // 獲取 行結尾到 xml的結束的字符串 並拼接
        $result .= $this->getSlice($rowEnd);
        
        $this->tempDocumentMainPart = $result;
    }
    
}

 

使用

 
         
$templateFile = 'info.docx';
$templateProcessor = new TemplateProcessor($templateFile);

//
日志
$logList = $data['log_list']; $logListLen = count($logList);
// 重點:5,是循環的多行的行數
$templateProcessor->cloneMultiRow('id', $logListLen, 5);
$templateProcessor->saveAs("b.docx");

 

 

 

word文件中 

 

老早寫的,只是給自己備個份,word其實就是xml文件,可以把word文件修改下后綴名為.zip,解壓可以看到xml文件;看PHPWord的源碼,也可以看到 模板替換主要是 使用的正則

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM