summaryrefslogtreecommitdiffstats
path: root/src/Plugin/CellStyleFixer.php
blob: d1173efc23b2adb66e930d4908e4856f8e184186 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?php


namespace PHPExcelFixer\StyleFixer\Plugin;


use PHPExcelFixer\StyleFixer\Util\Book as BookUtil;
use PHPExcelFixer\StyleFixer\Util\Sheet as SheetUtil;
use PHPExcelFixer\StyleFixer\Util\XmlNamespace;

class CellStyleFixer implements Plugin
{
    /**
     * @var \PHPExcelFixer\StyleFixer\Util\Book
     */
    private $bookUtil;

    /**
     * @var \PHPExcelFixer\StyleFixer\Util\Sheet
     */
    private $sheetUtil;

    /**
     * @param BookUtil $bookUtil
     * @param SheetUtil $sheetUtil
     */
    public function __construct(BookUtil $bookUtil = null, SheetUtil $sheetUtil = null)
    {
        $this->bookUtil = $bookUtil ? $bookUtil : new BookUtil;
        $this->sheetUtil = $sheetUtil ? $sheetUtil : new SheetUtil;
    }

    /**
     * 各ワークシート内の各セルに付属している書式設定を修復する
     *
     * @param \ZipArchive $output
     * @param \ZipArchive $template
     */
    public function execute(\ZipArchive $output, \ZipArchive $template)
    {
        // テンプレート側のシート名のマッピング
        $srcSheetMap = $this->bookUtil->makeSheetMap($template);
        // 出力ファイル側のシート名のマッピング
        $distSheetMap = $this->bookUtil->makeSheetMap($output);
        // 出力ファイル側のシートの印刷範囲マッピング
        $distPrintAreas = $this->bookUtil->makePrintAreaMap($output);

        foreach ($distSheetMap as $sheetName => $distSheetPath) {
            $distXml = $output->getFromName($distSheetPath);
            $distDom = new \DOMDocument;
            $distDom->loadXML($distXml);
            $distXPath = new \DOMXPath($distDom);
            $distXPath->registerNamespace('s', XmlNamespace::SPREADSHEETML_NS_URL);

            $srcXml = $template->getFromName($srcSheetMap[$sheetName]);
            $srcDom = new \DOMDocument;
            $srcDom->loadXML($srcXml);
            $srcXPath = new \DOMXPath($srcDom);
            $srcXPath->registerNamespace('s', XmlNamespace::SPREADSHEETML_NS_URL);

            $printArea = null;
            if (isset($distPrintAreas[$sheetName])) {
                list(,$printArea) = explode('!', $distPrintAreas[$sheetName]);
            }

            // セル番地 => スタイル番号
            $styleMap = [];
            foreach ($srcXPath->query('//s:worksheet/s:sheetData/s:row') as $srcRow) {
                /** @var \DOMElement $srcRow */
                if ($srcRow->hasAttribute('s')) {
                    /** @var \DOMElement $distRow */
                    $distRow = $distXPath->query('//s:worksheet/s:sheetData/s:row[@r="'.$srcRow->getAttribute('r').'"]')->item(0);
                    if ($distRow) {
                        $distRow->setAttribute('s', $srcRow->getAttribute('s'));
                    }
                }

                if ($srcRow->hasChildNodes()) {
                    foreach ($srcRow->childNodes as $srcCell) {
                        if ($srcCell instanceOf \DOMElement && $srcCell->tagName == 'c' && $srcCell->hasAttribute('s')) {
                            $styleMap[$srcCell->getAttribute('r')] = $srcCell->getAttribute('s');
                        }
                    }
                }
            }

            foreach ($distXPath->query('//s:worksheet/s:sheetData/s:row/s:c') as $distCell) {
                /** @var \DOMElement $distCell */
                $coordinate = $distCell->getAttribute('r');
                if (isset($styleMap[$coordinate]) && ($this->cellHasValue($distCell) || !$printArea || $this->sheetUtil->inRange($coordinate, $printArea))) {
                    $distCell->setAttribute('s', $styleMap[$coordinate]);
                } else {
                    $distCell->removeAttribute('s');
                }
            }

            $output->addFromString($distSheetPath, $distDom->saveXML());
        }
    }

    /**
     * @param \DOMElement $cell
     * @return bool
     */
    private function cellHasValue(\DOMElement $cell)
    {
        $hasValue = false;

        if ($cell->hasChildNodes()) {
            foreach ($cell->childNodes as $child) {
                if ($child instanceOf \DOMElement && $child->tagName == 'v') {
                    $hasValue = true;
                    break;
                }
            }
        }

        return $hasValue;
    }
}