├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── example
├── example.html
└── example.php
├── lib
└── HtmlPhpExcel
│ ├── Elements
│ ├── BaseElement.php
│ ├── Cell.php
│ ├── Document.php
│ ├── Element.php
│ ├── Row.php
│ └── Table.php
│ ├── Exception
│ └── InexistentExcelObjectException.php
│ ├── HtmlPhpExcel.php
│ └── Parser
│ └── Parser.php
├── phpunit.xml
├── rector.php
└── tests
├── HtmlPhpExcel
└── Tests
│ ├── HtmlPhpExcelTest.php
│ └── Parser
│ └── ParserTest.php
└── testfiles
└── test.html
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on:
4 | push:
5 | pull_request:
6 |
7 | jobs:
8 | tests:
9 | runs-on: ubuntu-20.04
10 |
11 | strategy:
12 | matrix:
13 | php: ['8.2', '8.3', '8.4']
14 | stability: ['prefer-lowest', 'prefer-stable']
15 |
16 | name: PHP ${{ matrix.php }} - ${{ matrix.stability }}
17 |
18 | steps:
19 | - name: Checkout code
20 | uses: actions/checkout@v2
21 |
22 | - name: Setup PHP
23 | uses: shivammathur/setup-php@v2
24 | with:
25 | php-version: ${{ matrix.php }}
26 | extensions: dom, curl, libxml, mbstring, zip, gd
27 | tools: composer:v2
28 | coverage: none
29 |
30 | - name: Install dependencies
31 | run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress
32 |
33 | - name: Execute tests
34 | run: vendor/bin/phpunit --verbose
35 |
36 |
37 | code_checks:
38 | runs-on: ubuntu-20.04
39 | name: Static code analysis
40 |
41 | steps:
42 | - name: Checkout code
43 | uses: actions/checkout@v3
44 |
45 | - name: Setup PHP
46 | uses: shivammathur/setup-php@v2
47 | with:
48 | php-version: '8.3'
49 | extensions: dom, curl, libxml, mbstring, zip, bcmath, gd
50 | tools: composer
51 | coverage: none
52 |
53 | - name: Get composer cache directory
54 | id: composer-cache
55 | run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
56 |
57 | - name: Cache dependencies
58 | uses: actions/cache@v3
59 | with:
60 | path: ${{ steps.composer-cache.outputs.dir }}
61 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
62 | restore-keys: ${{ runner.os }}-composer-
63 |
64 | - name: Install dependencies
65 | run: composer install --prefer-dist --no-progress
66 |
67 | - name: Check composer files
68 | run: composer validate --strict
69 |
70 | - name: Check coding standard
71 | run: vendor/bin/php-cs-fixer --no-interaction --dry-run --diff -v fix lib/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /composer.lock
3 | .DS_Store
4 | /example/test.xlsx
5 | /example/~$test.xlsx
6 | /.phpunit.result.cache
7 | /.php-cs-fixer.cache
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 – 2019 Ticketpark GmbH / Manuel Reinhard
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HtmlPhpExcel
2 |
3 | [](https://github.com/Ticketpark/HtmlPhpExcel/actions)
4 |
5 | This is a php library based on [FastExcelWriter](https://github.com/aVadim483/fast-excel-writer), simplifying converting html tables to excel files. It allows styling right within the html template with specific attributes.
6 |
7 | ## Installation
8 |
9 | Add HtmlPhpExcel to your composer.json:
10 |
11 | ```
12 | composer require ticketpark/htmlphpexcel
13 | ```
14 |
15 | ## Simple example
16 | ```php
17 |
Column A | Column B |
---|
Value A | Value B |
';
22 | $htmlPhpExcel = new \Ticketpark\HtmlPhpExcel\HtmlPhpExcel($html);
23 |
24 | $htmlPhpExcel->process()->save('myFile.xlsx');
25 |
26 | ```
27 |
28 | For a more complex example see [example directory](example).
29 |
30 | ## Styling
31 | Styles are set with an html attribute `_excel-styles`. The attribute expects the content to be in json format.
32 |
33 | Example:
34 | ```html
35 |
36 |
37 |
38 | Cell value
39 | |
40 |
41 |
42 | ```
43 |
44 | You can use any style supported by `fast-excel-writer`, of which the most common are:
45 |
46 | * border-color
47 | * border-style
48 | * fill-color
49 | * fill-pattern
50 | * font-color
51 | * font-size
52 | * format
53 | * format-text-wrap
54 | * height
55 | * hyperlink
56 | * text-align
57 | * text-color
58 | * text-rotation
59 | * text-wrap
60 | * vertical-align
61 | * width
62 |
63 | More information (though unfortunately limited) is available in the [docs of FastExcelWriter](https://github.com/aVadim483/fast-excel-writer/blob/master/docs/04-styles.md).
64 |
65 | ## Adding links to cells
66 |
67 | Links are treated like styles and added with the `hyperlink` key:
68 |
69 | Example:
70 | ```html
71 |
72 |
73 |
74 | Cell value
75 | |
76 |
77 |
78 | ```
79 |
80 |
81 |
82 | ## Adding comments to cells
83 |
84 | To add comments, use the `_excel-comment` attribute.
85 |
86 | Example:
87 | ```html
88 |
89 |
90 |
91 | Cell value
92 | |
93 |
94 |
95 | ```
96 |
97 | ## History
98 |
99 | * v2.x of this library is based on `FastExcelWriter`
100 | * v1.x of this library was based on `PhpSpreadsheet`
101 | * v0.x of this library was based on `PhpExcel`
102 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ticketpark/htmlphpexcel",
3 | "type": "library",
4 | "description": "A php library to convert html tables to Excel files, including styling.",
5 | "keywords": ["html", "tables", "excel", "phpexcel", "phpspreadsheet", "fastexcelwriter"],
6 | "homepage": "https://github.com/Ticketpark/HtmlPhpExcel",
7 | "license": "MIT",
8 | "authors": [
9 | {"name": "Manuel Reinhard", "email": "manu@sprain.ch"}
10 | ],
11 | "require": {
12 | "php": "~8.2.0|~8.3.0|~8.4.0",
13 | "ext-json": "*",
14 | "ext-dom": "*",
15 | "ext-intl": "*",
16 | "avadim/fast-excel-helper": "^1.0.4",
17 | "avadim/fast-excel-writer": "^4.5|^5.0|^6.0"
18 | },
19 | "require-dev": {
20 | "phpunit/phpunit": "^9.0",
21 | "friendsofphp/php-cs-fixer": "^3.35",
22 | "rector/rector": "^1.2"
23 | },
24 | "autoload": {
25 | "psr-4": { "Ticketpark\\HtmlPhpExcel\\": "lib/HtmlPhpExcel" }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/example/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | An Excel worksheet |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Column A |
17 | Column B |
18 |
19 |
20 |
21 | Left align |
22 | Right align |
23 |
24 |
25 |
26 |
28 | 5 |
29 | 6 |
30 | 0022 |
31 |
32 |
33 |
34 |
35 | =1+1 |
36 | =A5+B5 |
37 | =SUM(A5:B5) |
38 |
39 |
40 |
41 |
42 |
43 | 25 |
44 | 1520.20 |
45 |
46 |
47 |
48 |
49 | Merge cells |
50 |
51 |
52 | No need to fill all cells. |
53 | And no need to care about how many cells there are in each row. |
54 | Ich bin ein Ümläøut. |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/example/example.php:
--------------------------------------------------------------------------------
1 | process()->save(__DIR__ . '/test.xlsx');
7 |
--------------------------------------------------------------------------------
/lib/HtmlPhpExcel/Elements/BaseElement.php:
--------------------------------------------------------------------------------
1 | attributes[$key] = $value;
14 | }
15 |
16 | public function getAttribute(string $key): ?string
17 | {
18 | if (!isset($this->attributes[$key])) {
19 | return null;
20 | }
21 |
22 | return $this->attributes[$key];
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/HtmlPhpExcel/Elements/Cell.php:
--------------------------------------------------------------------------------
1 | value = $value;
15 | }
16 |
17 | public function getValue(): ?string
18 | {
19 | return $this->value;
20 | }
21 |
22 | public function setIsHeader(bool $isHeader): void
23 | {
24 | $this->isHeader = $isHeader;
25 | }
26 |
27 | public function isHeader(): bool
28 | {
29 | return $this->isHeader;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/HtmlPhpExcel/Elements/Document.php:
--------------------------------------------------------------------------------
1 | tables[] = $table;
14 | }
15 |
16 | /**
17 | * @return array
18 | */
19 | public function getTables(): array
20 | {
21 | return $this->tables;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/HtmlPhpExcel/Elements/Element.php:
--------------------------------------------------------------------------------
1 | cells[] = $cell;
14 | }
15 |
16 | /**
17 | * @return array
18 | */
19 | public function getCells(): array
20 | {
21 | return $this->cells;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/HtmlPhpExcel/Elements/Table.php:
--------------------------------------------------------------------------------
1 | rows[] = $row;
14 | }
15 |
16 | /**
17 | * @return array
18 | */
19 | public function getRows(): array
20 | {
21 | return $this->rows;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/HtmlPhpExcel/Exception/InexistentExcelObjectException.php:
--------------------------------------------------------------------------------
1 | ) must have to be parsed.
24 | * Default is none, which results in all rows of a parsed table.
25 | */
26 | private ?string $rowClass = null;
27 |
28 | /**
29 | * The class attribute the rows ( or | ) must have to be parsed.
30 | * Default is none, which results in all cells of a parsed row.
31 | */
32 | private ?string $cellClass = null;
33 |
34 | /**
35 | * The default styles to be applied to all excel cells
36 | */
37 | private array $defaultStyles = [];
38 |
39 | /**
40 | * The default styles additionally to be applied to header cells ( | )
41 | */
42 | private array $defaultHeaderStyles = [];
43 |
44 | /**
45 | * The document instance which contains the parsed html elements
46 | */
47 | private HtmlPhpExcelElement\Document $document;
48 |
49 | /**
50 | * The instance of the Excel creator used within this library.
51 | */
52 | private ?Excel $excel = null;
53 |
54 | public function __construct(
55 | private readonly string $htmlStringOrFile
56 | ) {
57 | }
58 |
59 | public function setTableClass(?string $class): self
60 | {
61 | $this->tableClass = $class;
62 |
63 | return $this;
64 | }
65 |
66 | public function setRowClass(?string $class): self
67 | {
68 | $this->rowClass = $class;
69 |
70 | return $this;
71 | }
72 |
73 | public function setCellClass(?string $class): self
74 | {
75 | $this->cellClass = $class;
76 |
77 | return $this;
78 | }
79 |
80 | public function setDefaultStyles(array $defaultStyles): self
81 | {
82 | $this->defaultStyles = $defaultStyles;
83 |
84 | return $this;
85 | }
86 |
87 | public function setDefaultHeaderStyles(array $defaultHeaderStyles): self
88 | {
89 | $this->defaultHeaderStyles = $defaultHeaderStyles;
90 |
91 | return $this;
92 | }
93 |
94 | public function process(?Excel $excel = null): self
95 | {
96 | $this->excel = $excel;
97 | if (null === $this->excel) {
98 | $this->excel = Excel::create();
99 | }
100 |
101 | $this->parseHtml();
102 | $this->createExcel();
103 |
104 | return $this;
105 | }
106 |
107 | public function download(string $filename): void
108 | {
109 | $filename = str_ireplace('.xlsx', '', $filename);
110 | $this->getExcelObject()->download($filename . '.xlsx');
111 | }
112 |
113 | public function save(string $filename): bool
114 | {
115 | $filename = str_ireplace('.xlsx', '', $filename);
116 |
117 | return $this->getExcelObject()->save($filename . '.xlsx');
118 | }
119 |
120 | public function getExcelObject(): Excel
121 | {
122 | if (null === $this->excel) {
123 | throw new InexistentExcelObjectException('You must run process() before handling the excel object. ');
124 | }
125 |
126 | return $this->excel;
127 | }
128 |
129 | private function parseHtml(): void
130 | {
131 | $parser = new Parser($this->htmlStringOrFile);
132 | $document = $parser->setTableClass($this->tableClass)
133 | ->setRowClass($this->rowClass)
134 | ->setCellClass($this->cellClass)
135 | ->parse();
136 |
137 | $this->document = $document;
138 | }
139 |
140 | private function createExcel(): void
141 | {
142 | // Remove 1st sheet, which might be created automatically with new excel
143 | try {
144 | $this->excel->removeSheet(1);
145 | } catch (\Exception) {
146 | }
147 |
148 | // Loop over all tables in document
149 | foreach ($this->document->getTables() as $table) {
150 |
151 | // Handle worksheets
152 | $sheet = $this->excel->makeSheet($table->getAttribute('_excel-name'));
153 |
154 | // Loop over all rows
155 | $rowIndex = 1;
156 | foreach ($table->getRows() as $row) {
157 | $rowStyles = $this->getStyles($row);
158 | if (!empty($rowStyles)) {
159 | $sheet->setRowStyles(
160 | $rowIndex,
161 | $rowStyles
162 | );
163 | }
164 |
165 | // Loop over all cells in a row
166 | $colIndex = 1;
167 | foreach ($row->getCells() as $cell) {
168 |
169 | // Skip cells within merged range
170 | $excelCellIndex = Helper::colLetter($colIndex).$rowIndex;
171 | while ($this->isMerged($sheet, $excelCellIndex)) {
172 | $colIndex++;
173 | $excelCellIndex = Helper::colLetter($colIndex).$rowIndex;
174 | $sheet->cell($excelCellIndex);
175 | }
176 |
177 | // Write cell
178 | $cellStyles = $this->getStyles($cell);
179 | $sheet->writeCell(
180 | trim((string) $cell->getValue()),
181 | empty($cellStyles) ? null : $cellStyles
182 | );
183 |
184 | if (isset($cellStyles['width'])) {
185 | $sheet->setColWidth($colIndex, $cellStyles['width']);
186 | }
187 |
188 | if (isset($cellStyles['height'])) {
189 | $sheet->setRowHeight($rowIndex, $cellStyles['height']);
190 | }
191 |
192 | $cellComment = $cell->getAttribute('_excel-comment');
193 | if ($cellComment) {
194 | $sheet->addNote(Excel::cellAddress($rowIndex, $colIndex), $cellComment);
195 | }
196 |
197 | // Merge cells, if necessary
198 | $colspan = $cell->getAttribute('colspan');
199 | $rowspan = $cell->getAttribute('rowspan');
200 |
201 | if ($colspan || $rowspan) {
202 | $colspan = $colspan ? $colspan - 1 : 0;
203 | $rowspan = $rowspan ? $rowspan - 1 : 0;
204 |
205 | $mergeCellsTargetCellIndex = Helper::colLetter($colIndex + $colspan).($rowIndex + $rowspan);
206 | $sheet->mergeCells($excelCellIndex . ':' . $mergeCellsTargetCellIndex);
207 | }
208 |
209 | $colIndex++;
210 | }
211 |
212 | $sheet->nextRow();
213 | $rowIndex++;
214 | }
215 | }
216 | }
217 |
218 | private function isMerged(Sheet $sheet, string $cellAddress): bool
219 | {
220 | foreach ($sheet->getMergedCells() as $range) {
221 | if (Helper::inRange($cellAddress, $range)) {
222 | return true;
223 | }
224 | }
225 |
226 | return false;
227 | }
228 |
229 | private function getStyles(HtmlPhpExcelElement\Element $documentElement): array
230 | {
231 | $styles = [];
232 | if ($attributeStyles = $documentElement->getAttribute('_excel-styles')) {
233 | if (!is_array($attributeStyles)) {
234 | try {
235 | $attributeStyles = json_decode($attributeStyles, true, 512, JSON_THROW_ON_ERROR);
236 | } catch (\JsonException) {
237 | }
238 | }
239 | }
240 |
241 | if (is_array($attributeStyles)) {
242 | $styles = $attributeStyles;
243 | }
244 |
245 | return array_merge(
246 | $this->defaultStyles,
247 | ($documentElement instanceof HtmlPhpExcelElement\Cell && $documentElement->isHeader()) ? $this->defaultHeaderStyles : [],
248 | $styles
249 | );
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/lib/HtmlPhpExcel/Parser/Parser.php:
--------------------------------------------------------------------------------
1 | ) must have to be parsed.
25 | * Default is none, which results in all rows of a parsed table.
26 | */
27 | private ?string $rowClass = null;
28 |
29 | /**
30 | * The class attribute the rows ( | or | ) must have to be parsed.
31 | * Default is none, which results in all cells of a parsed row.
32 | */
33 | private ?string $cellClass = null;
34 |
35 | public function __construct(string $htmlStringOrFile)
36 | {
37 | if (PHP_MAXPATHLEN >= strlen($htmlStringOrFile) && is_file($htmlStringOrFile)) {
38 | $this->html = file_get_contents($htmlStringOrFile);
39 | } else {
40 | $this->html = $htmlStringOrFile;
41 | }
42 | }
43 |
44 | public function setTableClass(?string $class): self
45 | {
46 | $this->tableClass = $class;
47 |
48 | return $this;
49 | }
50 |
51 | public function setRowClass(?string $class): self
52 | {
53 | $this->rowClass = $class;
54 |
55 | return $this;
56 | }
57 |
58 | public function setCellClass(?string $class): self
59 | {
60 | $this->cellClass = $class;
61 |
62 | return $this;
63 | }
64 |
65 | public function parse(): Document
66 | {
67 | $dom = new \DOMDocument();
68 | $dom->loadHTML($this->html);
69 |
70 | $xpath = new \DOMXPath($dom);
71 | $htmlTables = $xpath->query('.//table[contains(concat(" ", normalize-space(@class), " "), "'.$this->tableClass.'")]');
72 |
73 | $document = new Document();
74 |
75 | foreach ($htmlTables as $htmlTable) {
76 |
77 | $table = new Table();
78 |
79 | $htmlRows = $xpath->query('.//tr[contains(concat(" ", normalize-space(@class), " "), "'.$this->rowClass.'")]', $htmlTable);
80 | foreach ($htmlRows as $htmlRow) {
81 |
82 | $row = new Row();
83 | $htmlCells = $xpath->query(
84 | './/td[contains(concat(" ", normalize-space(@class), " "), "'.$this->cellClass.'")]
85 | | .//th[contains(concat(" ", normalize-space(@class), " "), "'.$this->cellClass.'")]',
86 | $htmlRow
87 | );
88 |
89 | foreach ($htmlCells as $htmlCell) {
90 | $cell = new Cell();
91 | $cell->setValue($htmlCell->nodeValue);
92 |
93 | foreach ($htmlCell->attributes as $attribute) {
94 | $cell->addAttribute($attribute->name, $attribute->value);
95 | }
96 |
97 | if ('th' == $htmlCell->nodeName) {
98 | $cell->setIsHeader(true);
99 | }
100 |
101 | $row->addCell($cell);
102 | }
103 |
104 | foreach ($htmlRow->attributes as $attribute) {
105 | $row->addAttribute($attribute->name, $attribute->value);
106 | }
107 |
108 | $table->addRow($row);
109 | }
110 |
111 | foreach ($htmlTable->attributes as $attribute) {
112 | $table->addAttribute($attribute->name, $attribute->value);
113 | }
114 |
115 | $document->addTable($table);
116 | }
117 |
118 | return $document;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ./tests
6 |
7 |
8 |
9 |
10 | ./tests
11 |
12 |
13 |
--------------------------------------------------------------------------------
/rector.php:
--------------------------------------------------------------------------------
1 | paths([
10 | __DIR__ . '/lib',
11 | __DIR__ . '/tests',
12 | ]);
13 |
14 | $rectorConfig->sets([
15 | LevelSetList::UP_TO_PHP_84
16 | ]);
17 | };
18 |
--------------------------------------------------------------------------------
/tests/HtmlPhpExcel/Tests/HtmlPhpExcelTest.php:
--------------------------------------------------------------------------------
1 | pathToTestfiles = __DIR__.'/../../testfiles/';
20 | }
21 |
22 | public function testSave()
23 | {
24 | if (!is_writable($this->pathToTestfiles)) {
25 | $this->markTestSkipped(
26 | sprintf('The directory %s must be writable for this test to run.', realpath($this->pathToTestfiles))
27 | );
28 | }
29 |
30 | $file = $this->pathToTestfiles.'test.xlsx';
31 | if (file_exists($file)) {
32 | if (!is_writable($file)) {
33 | $this->markTestSkipped(
34 | sprintf('The file %s must be writable for this test to run.', realpath($file))
35 | );
36 | }
37 | unlink($file);
38 | }
39 |
40 | $htmlphpexcel = new HtmlPhpExcel('');
41 | $htmlphpexcel->process()->save($file);
42 |
43 | $this->assertTrue(file_exists($file));
44 |
45 | unlink($file);
46 | }
47 |
48 | public function testItReturnsExcelInstance()
49 | {
50 | $htmlphpexcel = new HtmlPhpExcel('');
51 | $this->assertInstanceOf(Excel::class, $htmlphpexcel->process()->getExcelObject());
52 | }
53 |
54 | public function testItThrowsExceptionIfProcessIsNotRunBeforeGettingExcelObject()
55 | {
56 | $this->expectException(InexistentExcelObjectException::class);
57 |
58 | $htmlphpexcel = new HtmlPhpExcel('');
59 | $htmlphpexcel->getExcelObject();
60 | }
61 |
62 | public function testItThrowsExceptionIfProcessIsNotRunBeforeSave()
63 | {
64 | $this->expectException(InexistentExcelObjectException::class);
65 |
66 | $htmlphpexcel = new HtmlPhpExcel('');
67 | $htmlphpexcel->save('foo');
68 | }
69 |
70 | public function testItThrowsExceptionIfProcessIsNotRunBeforeDownload()
71 | {
72 | $this->expectException(InexistentExcelObjectException::class);
73 |
74 | $htmlphpexcel = new HtmlPhpExcel('');
75 | $htmlphpexcel->download('foo');
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/HtmlPhpExcel/Tests/Parser/ParserTest.php:
--------------------------------------------------------------------------------
1 | | row1cell1 | row1cell2 | row2cell1 | row2cell2 | |
');
15 | $document = $parser->parse();
16 |
17 | $this->assertEquals(1, count($document->getTables()));
18 | $this->assertEquals(2, count($document->getTables()[0]->getRows()));
19 |
20 | foreach($document->getTables()[0]->getRows() as $row){
21 | $this->assertEquals(2, count($row->getCells()));
22 | }
23 | }
24 |
25 | public function testMultipleTables()
26 | {
27 | $parser = new Parser('
28 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
29 | someotherstuff
30 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
31 | ');
32 | $document = $parser->parse();
33 |
34 | $this->assertEquals(2, count($document->getTables()));
35 | foreach($document->getTables() as $table){
36 | $this->assertEquals(2, count($table->getRows()));
37 |
38 | foreach($table->getRows() as $row){
39 | $this->assertEquals(2, count($row->getCells()));
40 | }
41 | }
42 | }
43 |
44 | public function testMultipleTablesWithTableClass()
45 | {
46 | $parser = new Parser('
47 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
48 | someotherstuff
49 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
50 | ');
51 | $document = $parser->setTableClass('pickme')->parse();
52 |
53 | $this->assertEquals(1, count($document->getTables()));
54 | }
55 |
56 | public function testMultipleTablesWithRowClass()
57 | {
58 | $parser = new Parser('
59 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
60 | someotherstuff
61 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
62 | ');
63 | $document = $parser->setRowClass('pickme')->parse();
64 |
65 | foreach($document->getTables() as $table){
66 | $this->assertEquals(1, count($table->getRows()));
67 | }
68 | }
69 |
70 | public function testMultipleTablesWithCellClass()
71 | {
72 | $parser = new Parser('
73 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
74 | someotherstuff
75 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
76 | ');
77 | $document = $parser->setCellClass('pickme')->parse();
78 |
79 | foreach($document->getTables() as $table){
80 | foreach($table->getRows() as $row){
81 | $this->assertEquals(1, count($row->getCells()));
82 | }
83 | }
84 | }
85 |
86 | public function testMultipleTablesWithMixedClasses()
87 | {
88 | $parser = new Parser('
89 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
90 | someotherstuff
91 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
92 | ');
93 | $document = $parser
94 | ->setTableClass('pickme')
95 | ->setRowClass('pickme')
96 | ->setCellClass('pickme')
97 | ->parse();
98 |
99 | $this->assertEquals(1, count($document->getTables()));
100 | foreach($document->getTables() as $table){
101 | $this->assertEquals(1, count($table->getRows()));
102 |
103 | foreach($table->getRows() as $row){
104 | $this->assertEquals(1, count($row->getCells()));
105 | }
106 | }
107 | }
108 |
109 | public function testMultipleTablesWithMixedClassesAndOtherClasses()
110 | {
111 | $parser = new Parser('
112 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
113 | someotherstuff
114 | row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
115 | ');
116 | $document = $parser
117 | ->setTableClass('pickme')
118 | ->setRowClass('pickme')
119 | ->setCellClass('pickme')
120 | ->parse();
121 |
122 | $this->assertEquals(1, count($document->getTables()));
123 | foreach($document->getTables() as $table){
124 | $this->assertEquals(1, count($table->getRows()));
125 |
126 | foreach($table->getRows() as $row){
127 | $this->assertEquals(1, count($row->getCells()));
128 | }
129 | }
130 | }
131 |
132 | public function testFindsHeaders()
133 | {
134 | $parser = new Parser('row1cell1 | row1cell2 |
---|
row2cell1 | row2cell2 |
');
135 | $document = $parser->parse();
136 |
137 | foreach($document->getTables()[0]->getRows() as $key => $row){
138 | foreach($row->getCells() as $cell){
139 | if (0 === $key) {
140 | $this->assertTrue($cell->isHeader());
141 | } elseif (1 === $key) {
142 | $this->assertFalse($cell->isHeader());
143 | }
144 | }
145 | }
146 | }
147 |
148 | public function testFindsAttributes()
149 | {
150 | $parser = new Parser('row1cell1 | row1cell2 |
row2cell1 | row2cell2 |
');
151 | $document = $parser->parse();
152 |
153 | foreach($document->getTables() as $table){
154 | $this->assertEquals('foo', $table->getAttribute('bar'));
155 |
156 | foreach($table->getRows() as $rowKey => $row){
157 | if (0 === $rowKey) {
158 | $this->assertEquals('foo', $row->getAttribute('bar'));
159 | } else {
160 | $this->assertEquals(null, $row->getAttribute('bar'));
161 | }
162 |
163 | foreach($row->getCells() as $cellKey => $cell){
164 | if (0 === $rowKey && 0 == $cellKey) {
165 | $this->assertEquals('foo', $cell->getAttribute('bar'));
166 | } else {
167 | $this->assertEquals(null, $cell->getAttribute('bar'));
168 | }
169 | }
170 | }
171 | }
172 | }
173 |
174 | public function testWithFile()
175 | {
176 | $parser = new Parser($this->pathToTestfiles . '/test.html');
177 | $document = $parser->parse();
178 | $this->assertEquals(1, count($document->getTables()));
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/tests/testfiles/test.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------