Improve HTML Writer (#1464)

There are a number of situations where HTML write was producing
HTML which could not be validated. These include:

  - inconsistent use of backslash terminating META, IMG, and COL tags
  - @page style tags in body rather than header. Aside from being
    non-standard, HTML Reader treats those as spreadsheet data.
  - <div style="page-break-before:always" />, a construct which is
    usually better handled through css anyhow.
  - no alt tag for images (drawings and charts)

Other problems:

  - Windows file names not handled correctly for images
  - Memory drawings not handled in extendRowsForChartsAndImages
  - No handling of different values for showing gridlines
    for screen and print
  - Mpdf and Dompdf do not require the use of inline css.
    Tcpdf remains a holdout in the use of this inferior approach.
  - no need to chunk base64 encoding of embedded images
  - support for colors in number format was buggy (html tags
    run through htmlspecialchars)

Code has been refactored when practical to reduce the number of
very large functions.

Coverage is now 100% for the entire HTML Writer module,
from 75% lines and 39% methods beforehand.

All functions dealing only with charts
are bypassed for coverage because the version of Jpgraph available in
Composer is not suitable for PHP7. The code will, nevertheless,
run successfully, but with warning messages. I have confirmed that
the code is entirely covered, without warnings, when the current
version of Jpgraph is used in lieu of the one available in Composer.
I will be glad to revisit this when the Jpgraph problem is resolved.

Directory PhpSpreadsheetTests/Writer/Html was created to house
the new tests. It seemed logical to move HtmlCommentsTest to
the new directory from PhpSpreadsheetTests/Functional.

A function to generate all the HTML is useful, especially for testing,
but also in lieu of the multiple other generate* functions. I have
added and documented generateHTMLAll.

The documentation for the generate* functions (a) produces invalid html,
(b) produces html which cannot be handled correctly by HTML reader,
and (c) even if those were correct, does not actually affect
the display of the spreadsheet. The documentation has been replaced
by a valid, and more instructive, example.

The (undocumented) useEmbeddedCss property, and the functions
to test and set it are no longer needed. Rather than breaking
existing code by deleting them, I marked the functions deprecated.

This change borrows a change to LocaleFloatsTest from
pull request 1456, submitted a little over a week before this one.


## Improve NumberFormat Support

First phase of this change included correcting NumberFormat handling
in HTML Writer. Certain complex formats could not be handled without
changes to Style/NumberFormat, and I did not wish to combine those changes.

Once the original change had been pushed, I took this part of it back up.
HTML Writer can now handle conditions in formats like:
[Blue][>=3000.5]$#,##0.00;[Red][<0]$#,##0.00;$#,##0.00
In testing, I discovered several errors and omissions
in handling of some other formats.
These are now corrected, and tests added.
This commit is contained in:
oleibman 2020-05-17 20:43:18 -07:00 committed by GitHub
parent 4f6d4af396
commit 97a80f383c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1845 additions and 638 deletions

View File

@ -681,35 +681,26 @@ Supported methods:
- `generateStyles()` - `generateStyles()`
- `generateSheetData()` - `generateSheetData()`
- `generateHTMLFooter()` - `generateHTMLFooter()`
- `generateHTMLAll()`
Here's an example which retrieves all parts independently and merges Here's an example which retrieves all parts independently and merges
them into a resulting HTML page: them into a resulting HTML page:
``` php ``` php
<?php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet); $writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
echo $writer->generateHTMLHeader(); $hdr = $writer->generateHTMLHeader();
?> $sty = $writer->generateStyles(false); // do not write <style> and </style>
$newstyle = <<<EOF
<style> <style type='text/css'>
<!-- $sty
html { html {
font-family: Times New Roman; background-color: yellow;
font-size: 9pt;
background-color: white;
} }
<?php
echo $writer->generateStyles(false); // do not write <style> and </style>
?>
-->
</style> </style>
EOF;
<?php echo preg_replace('@</head>@', "$newstyle\n</head>", $hdr);
echo $writer->generateSheetData(); echo $writer->generateSheetData();
echo $writer->generateHTMLFooter(); echo $writer->generateHTMLFooter();
?>
``` ```
#### Writing UTF-8 HTML files #### Writing UTF-8 HTML files

View File

@ -0,0 +1,14 @@
<?php
use PhpOffice\PhpSpreadsheet\Writer\Html;
require __DIR__ . '/../Header.php';
$spreadsheet = require __DIR__ . '/../templates/sampleSpreadsheet.php';
$filename = $helper->getFilename(__FILE__, 'html');
$writer = new Html($spreadsheet);
$callStartTime = microtime(true);
$writer->setEmbedImages(true);
$writer->save($filename);
$helper->logWrite($writer, $filename, $callStartTime);

View File

@ -35,6 +35,7 @@ $drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG);
$drawing->setMimeType(MemoryDrawing::MIMETYPE_DEFAULT); $drawing->setMimeType(MemoryDrawing::MIMETYPE_DEFAULT);
$drawing->setHeight(36); $drawing->setHeight(36);
$drawing->setWorksheet($spreadsheet->getActiveSheet()); $drawing->setWorksheet($spreadsheet->getActiveSheet());
$drawing->setCoordinates('C5');
// Save // Save
$helper->write($spreadsheet, __FILE__, ['Xlsx', 'Html']); $helper->write($spreadsheet, __FILE__, ['Xlsx', 'Html']);

View File

@ -537,7 +537,15 @@ class NumberFormat extends Supervisor
$adjustedDecimalPart = $decimalPart / $GCD; $adjustedDecimalPart = $decimalPart / $GCD;
$adjustedDecimalDivisor = $decimalDivisor / $GCD; $adjustedDecimalDivisor = $decimalDivisor / $GCD;
if ((strpos($format, '0') !== false) || (strpos($format, '#') !== false) || (substr($format, 0, 3) == '? ?')) { if ((strpos($format, '0') !== false)) {
$value = "$sign$integerPart $adjustedDecimalPart/$adjustedDecimalDivisor";
} elseif ((strpos($format, '#') !== false)) {
if ($integerPart == 0) {
$value = "$sign$adjustedDecimalPart/$adjustedDecimalDivisor";
} else {
$value = "$sign$integerPart $adjustedDecimalPart/$adjustedDecimalDivisor";
}
} elseif ((substr($format, 0, 3) == '? ?')) {
if ($integerPart == 0) { if ($integerPart == 0) {
$integerPart = ''; $integerPart = '';
} }
@ -653,9 +661,12 @@ class NumberFormat extends Supervisor
private static function formatAsNumber($value, $format) private static function formatAsNumber($value, $format)
{ {
if ($format === self::FORMAT_CURRENCY_EUR_SIMPLE) { // The "_" in this string has already been stripped out,
return 'EUR ' . sprintf('%1.2f', $value); // so this test is never true. Furthermore, testing
} // on Excel shows this format uses Euro symbol, not "EUR".
//if ($format === self::FORMAT_CURRENCY_EUR_SIMPLE) {
// return 'EUR ' . sprintf('%1.2f', $value);
//}
// Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols // Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols
$format = str_replace(['"', '*'], '', $format); $format = str_replace(['"', '*'], '', $format);
@ -717,6 +728,89 @@ class NumberFormat extends Supervisor
return $value; return $value;
} }
private static function splitFormatCompare($value, $cond, $val, $dfcond, $dfval)
{
if (!$cond) {
$cond = $dfcond;
$val = $dfval;
}
switch ($cond) {
case '>':
return $value > $val;
case '<':
return $value < $val;
case '<=':
return $value <= $val;
case '<>':
return $value != $val;
case '=':
return $value == $val;
}
return $value >= $val;
}
private static function splitFormat($sections, $value)
{
// Extract the relevant section depending on whether number is positive, negative, or zero?
// Text not supported yet.
// Here is how the sections apply to various values in Excel:
// 1 section: [POSITIVE/NEGATIVE/ZERO/TEXT]
// 2 sections: [POSITIVE/ZERO/TEXT] [NEGATIVE]
// 3 sections: [POSITIVE/TEXT] [NEGATIVE] [ZERO]
// 4 sections: [POSITIVE] [NEGATIVE] [ZERO] [TEXT]
$cnt = count($sections);
$color_regex = '/\\[(' . implode('|', Color::NAMED_COLORS) . ')\\]/';
$cond_regex = '/\\[(>|>=|<|<=|=|<>)([+-]?\\d+([.]\\d+)?)\\]/';
$colors = ['', '', '', '', ''];
$condops = ['', '', '', '', ''];
$condvals = [0, 0, 0, 0, 0];
for ($idx = 0; $idx < $cnt; ++$idx) {
if (preg_match($color_regex, $sections[$idx], $matches)) {
$colors[$idx] = $matches[0];
$sections[$idx] = preg_replace($color_regex, '', $sections[$idx]);
}
if (preg_match($cond_regex, $sections[$idx], $matches)) {
$condops[$idx] = $matches[1];
$condvals[$idx] = $matches[2];
$sections[$idx] = preg_replace($cond_regex, '', $sections[$idx]);
}
}
$color = $colors[0];
$format = $sections[0];
$absval = $value;
switch ($cnt) {
case 2:
$absval = abs($value);
if (!self::splitFormatCompare($value, $condops[0], $condvals[0], '>=', 0)) {
$color = $colors[1];
$format = $sections[1];
}
break;
case 3:
case 4:
$absval = abs($value);
if (!self::splitFormatCompare($value, $condops[0], $condvals[0], '>', 0)) {
if (self::splitFormatCompare($value, $condops[1], $condvals[1], '<', 0)) {
$color = $colors[1];
$format = $sections[1];
} else {
$color = $colors[2];
$format = $sections[2];
}
}
break;
}
return [$color, $format, $absval];
}
/** /**
* Convert a value in a pre-defined format to a PHP string. * Convert a value in a pre-defined format to a PHP string.
* *
@ -745,50 +839,12 @@ class NumberFormat extends Supervisor
// Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal) // Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal)
$sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format); $sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format);
// Extract the relevant section depending on whether number is positive, negative, or zero? [$colors, $format, $value] = self::splitFormat($sections, $value);
// Text not supported yet.
// Here is how the sections apply to various values in Excel:
// 1 section: [POSITIVE/NEGATIVE/ZERO/TEXT]
// 2 sections: [POSITIVE/ZERO/TEXT] [NEGATIVE]
// 3 sections: [POSITIVE/TEXT] [NEGATIVE] [ZERO]
// 4 sections: [POSITIVE] [NEGATIVE] [ZERO] [TEXT]
switch (count($sections)) {
case 1:
$format = $sections[0];
break;
case 2:
$format = ($value >= 0) ? $sections[0] : $sections[1];
$value = abs($value); // Use the absolute value
break;
case 3:
$format = ($value > 0) ?
$sections[0] : (($value < 0) ?
$sections[1] : $sections[2]);
$value = abs($value); // Use the absolute value
break;
case 4:
$format = ($value > 0) ?
$sections[0] : (($value < 0) ?
$sections[1] : $sections[2]);
$value = abs($value); // Use the absolute value
break;
default:
// something is wrong, just use first section
$format = $sections[0];
break;
}
// In Excel formats, "_" is used to add spacing, // In Excel formats, "_" is used to add spacing,
// The following character indicates the size of the spacing, which we can't do in HTML, so we just use a standard space // The following character indicates the size of the spacing, which we can't do in HTML, so we just use a standard space
$format = preg_replace('/_./', ' ', $format); $format = preg_replace('/_./', ' ', $format);
// Save format with color information for later use below
$formatColor = $format;
// Strip colour information
$color_regex = '/\[(' . implode('|', Color::NAMED_COLORS) . ')\]/';
$format = preg_replace($color_regex, '', $format);
// Let's begin inspecting the format and converting the value to a formatted string // Let's begin inspecting the format and converting the value to a formatted string
// Check for date/time characters (not inside quotes) // Check for date/time characters (not inside quotes)
@ -809,7 +865,7 @@ class NumberFormat extends Supervisor
// Additional formatting provided by callback function // Additional formatting provided by callback function
if ($callBack !== null) { if ($callBack !== null) {
[$writerInstance, $function] = $callBack; [$writerInstance, $function] = $callBack;
$value = $writerInstance->$function($value, $formatColor); $value = $writerInstance->$function($value, $colors);
} }
return $value; return $value;

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
namespace PhpOffice\PhpSpreadsheet\Writer; namespace PhpOffice\PhpSpreadsheet\Writer;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup; use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
@ -38,13 +37,6 @@ abstract class Pdf extends Html
*/ */
protected $paperSize; protected $paperSize;
/**
* Temporary storage for Save Array Return type.
*
* @var string
*/
private $saveArrayReturnType;
/** /**
* Paper Sizes xRef List. * Paper Sizes xRef List.
* *
@ -127,8 +119,9 @@ abstract class Pdf extends Html
public function __construct(Spreadsheet $spreadsheet) public function __construct(Spreadsheet $spreadsheet)
{ {
parent::__construct($spreadsheet); parent::__construct($spreadsheet);
$this->setUseInlineCss(true); //$this->setUseInlineCss(true);
$this->tempDir = File::sysGetTempDir(); $this->tempDir = File::sysGetTempDir() . '/phpsppdf';
$this->isPdf = true;
} }
/** /**
@ -244,20 +237,9 @@ abstract class Pdf extends Html
*/ */
protected function prepareForSave($pFilename) protected function prepareForSave($pFilename)
{ {
// garbage collect
$this->spreadsheet->garbageCollect();
$this->saveArrayReturnType = Calculation::getArrayReturnType();
Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_VALUE);
// Open file // Open file
$this->openFileHandle($pFilename); $this->openFileHandle($pFilename);
// Set PDF
$this->isPdf = true;
// Build CSS
$this->buildCSS(true);
return $this->fileHandle; return $this->fileHandle;
} }
@ -267,7 +249,5 @@ abstract class Pdf extends Html
protected function restoreStateAfterSave(): void protected function restoreStateAfterSave(): void
{ {
$this->maybeCloseFileHandle(); $this->maybeCloseFileHandle();
Calculation::setArrayReturnType($this->saveArrayReturnType);
} }
} }

View File

@ -61,11 +61,7 @@ class Dompdf extends Pdf
$pdf = $this->createExternalWriterInstance(); $pdf = $this->createExternalWriterInstance();
$pdf->setPaper(strtolower($paperSize), $orientation); $pdf->setPaper(strtolower($paperSize), $orientation);
$pdf->loadHtml( $pdf->loadHtml($this->generateHTMLAll());
$this->generateHTMLHeader(false) .
$this->generateSheetData() .
$this->generateHTMLFooter()
);
$pdf->render(); $pdf->render();
// Write to file // Write to file

View File

@ -81,12 +81,10 @@ class Mpdf extends Pdf
$pdf->SetKeywords($this->spreadsheet->getProperties()->getKeywords()); $pdf->SetKeywords($this->spreadsheet->getProperties()->getKeywords());
$pdf->SetCreator($this->spreadsheet->getProperties()->getCreator()); $pdf->SetCreator($this->spreadsheet->getProperties()->getCreator());
$pdf->WriteHTML($this->generateHTMLHeader(false)); $html = $this->generateHTMLAll();
$html = $this->generateSheetData();
foreach (\array_chunk(\explode(PHP_EOL, $html), 1000) as $lines) { foreach (\array_chunk(\explode(PHP_EOL, $html), 1000) as $lines) {
$pdf->WriteHTML(\implode(PHP_EOL, $lines)); $pdf->WriteHTML(\implode(PHP_EOL, $lines));
} }
$pdf->WriteHTML($this->generateHTMLFooter());
// Write to file // Write to file
fwrite($fileHandle, $pdf->Output('', 'S')); fwrite($fileHandle, $pdf->Output('', 'S'));

View File

@ -2,11 +2,23 @@
namespace PhpOffice\PhpSpreadsheet\Writer\Pdf; namespace PhpOffice\PhpSpreadsheet\Writer\Pdf;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup; use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PhpOffice\PhpSpreadsheet\Writer\Pdf; use PhpOffice\PhpSpreadsheet\Writer\Pdf;
class Tcpdf extends Pdf class Tcpdf extends Pdf
{ {
/**
* Create a new PDF Writer instance.
*
* @param Spreadsheet $spreadsheet Spreadsheet object
*/
public function __construct(Spreadsheet $spreadsheet)
{
parent::__construct($spreadsheet);
$this->setUseInlineCss(true);
}
/** /**
* Gets the implementation of external PDF library that should be used. * Gets the implementation of external PDF library that should be used.
* *
@ -75,11 +87,7 @@ class Tcpdf extends Pdf
// Set the appropriate font // Set the appropriate font
$pdf->SetFont($this->getFont()); $pdf->SetFont($this->getFont());
$pdf->writeHTML( $pdf->writeHTML($this->generateHTMLAll());
$this->generateHTMLHeader(false) .
$this->generateSheetData() .
$this->generateHTMLFooter()
);
// Document info // Document info
$pdf->SetTitle($this->spreadsheet->getProperties()->getTitle()); $pdf->SetTitle($this->spreadsheet->getProperties()->getTitle());

View File

@ -45,4 +45,18 @@ class NumberFormatTest extends TestCase
{ {
return require 'tests/data/Style/NumberFormatDates.php'; return require 'tests/data/Style/NumberFormatDates.php';
} }
public function testCurrencyCode()
{
// "Currency symbol" replaces $ in some cases, not in others
$cur = StringHelper::getCurrencyCode();
StringHelper::setCurrencyCode('€');
$fmt1 = '#,##0.000\ [$]';
$rslt = NumberFormat::toFormattedString(12345.679, $fmt1);
self::assertEquals($rslt, '12,345.679 €');
$fmt2 = '$ #,##0.000';
$rslt = NumberFormat::toFormattedString(12345.679, $fmt2);
self::assertEquals($rslt, '$ 12,345.679');
StringHelper::setCurrencyCode($cur);
}
} }

View File

@ -0,0 +1,192 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Tcpdf;
use PhpOffice\PhpSpreadsheetTests\Functional;
class AllOrOneSheetTest extends Functional\AbstractFunctional
{
public function testWriteAllSheets()
{
$spreadsheet = new Spreadsheet();
$sheet1 = $spreadsheet->getActiveSheet();
$sheet1->setCellValue('A1', 'first');
$sheet2 = $spreadsheet->createSheet();
$sheet2->setCellValue('A1', 'second');
$writer = new Html($spreadsheet);
self::assertFalse($writer->getEmbedImages());
$writer->writeAllSheets();
self::assertTrue($writer->getGenerateSheetNavigationBlock());
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('ul'); // sheet navigation
self::assertCount(1, $divs);
$divs = $body->getElementsByTagName('div');
self::assertCount(2, $divs);
self::assertEquals('page: page0', $divs->item(0)->getAttribute('style'));
$tbl = $divs->item(0)->getElementsByTagName('table');
self::assertEquals('sheet0', $tbl->item(0)->getAttribute('id'));
self::assertEquals('sheet0 gridlines', $tbl->item(0)->getAttribute('class'));
$tbl = $divs->item(1)->getElementsByTagName('table');
self::assertEquals('page: page1', $divs->item(1)->getAttribute('style'));
self::assertEquals('sheet1', $tbl->item(0)->getAttribute('id'));
self::assertEquals('sheet1 gridlines', $tbl->item(0)->getAttribute('class'));
$this->writeAndReload($spreadsheet, 'Html');
}
public function testWriteAllSheetsNoNav()
{
$spreadsheet = new Spreadsheet();
$sheet1 = $spreadsheet->getActiveSheet();
$sheet1->setCellValue('A1', 'first');
$sheet2 = $spreadsheet->createSheet();
$sheet2->setCellValue('A1', 'second');
$writer = new Html($spreadsheet);
$writer->writeAllSheets();
$writer->setGenerateSheetNavigationBlock(false);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('ul'); // sheet navigation
self::assertCount(0, $divs);
$divs = $body->getElementsByTagName('div');
self::assertCount(2, $divs);
self::assertEquals('page: page0', $divs->item(0)->getAttribute('style'));
$tbl = $divs->item(0)->getElementsByTagName('table');
self::assertEquals('sheet0', $tbl->item(0)->getAttribute('id'));
self::assertEquals('sheet0 gridlines', $tbl->item(0)->getAttribute('class'));
$tbl = $divs->item(1)->getElementsByTagName('table');
self::assertEquals('page: page1', $divs->item(1)->getAttribute('style'));
self::assertEquals('sheet1', $tbl->item(0)->getAttribute('id'));
self::assertEquals('sheet1 gridlines', $tbl->item(0)->getAttribute('class'));
$this->writeAndReload($spreadsheet, 'Html');
}
public function testWriteAllSheetsPdf()
{
$spreadsheet = new Spreadsheet();
$sheet1 = $spreadsheet->getActiveSheet();
$sheet1->setCellValue('A1', 'first');
$sheet2 = $spreadsheet->createSheet();
$sheet2->setCellValue('A1', 'second');
$writer = new Mpdf($spreadsheet);
$writer->writeAllSheets();
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('ul'); // sheet navigation
self::assertCount(0, $divs);
$divs = $body->getElementsByTagName('div');
self::assertCount(2, $divs);
self::assertEquals('page: page0', $divs->item(0)->getAttribute('style'));
$tbl = $divs->item(0)->getElementsByTagName('table');
self::assertEquals('sheet0', $tbl->item(0)->getAttribute('id'));
self::assertEquals('sheet0 gridlines', $tbl->item(0)->getAttribute('class'));
$tbl = $divs->item(1)->getElementsByTagName('table');
self::assertEquals('page: page1', $divs->item(1)->getAttribute('style'));
self::assertEquals('sheet1', $tbl->item(0)->getAttribute('id'));
self::assertEquals('sheet1 gridlines', $tbl->item(0)->getAttribute('class'));
}
public function testWriteOneSheet()
{
$spreadsheet = new Spreadsheet();
$sheet1 = $spreadsheet->getActiveSheet();
$sheet1->setCellValue('A1', 'first');
$sheet2 = $spreadsheet->createSheet();
$sheet2->setCellValue('A1', 'second');
$writer = new Html($spreadsheet);
$writer->setSheetIndex(1);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('ul'); // sheet navigation
self::assertCount(0, $divs);
$divs = $body->getElementsByTagName('div');
self::assertCount(1, $divs);
self::assertEquals('page: page1', $divs->item(0)->getAttribute('style'));
$tbl = $divs->item(0)->getElementsByTagName('table');
self::assertEquals('sheet1', $tbl->item(0)->getAttribute('id'));
self::assertEquals('sheet1 gridlines', $tbl->item(0)->getAttribute('class'));
$this->writeAndReload($spreadsheet, 'Html');
}
public function testPageBreak()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setShowGridlines(true)->setPrintGridlines(true);
$sheet->setCellValue('A1', 1);
$sheet->setCellValue('A2', 'before page break');
$sheet->setBreak('A2', \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW);
$sheet->setCellValue('A3', 'after page break');
$sheet->setCellValue('A4', 4);
$sheet = $spreadsheet->createSheet();
$sheet->setCellValue('A1', 'new sheet');
$writer = new Html($spreadsheet);
$writer->writeAllSheets();
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
self::assertCount(3, $divs);
$sty = $divs[0]->getAttribute('style');
$cls = $divs[0]->getAttribute('class');
self::assertEquals('page: page0', $sty);
self::assertEquals('', $cls);
$sty = $divs[1]->getAttribute('style');
$cls = $divs[1]->getAttribute('class');
self::assertEquals('page: page0', $sty);
self::assertEquals('scrpgbrk', $cls);
$sty = $divs[2]->getAttribute('style');
$cls = $divs[2]->getAttribute('class');
self::assertEquals('page: page1', $sty);
self::assertEquals('', $cls);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testTcpdfPageBreak()
{
$spreadsheet = new Spreadsheet();
$sheet1 = $spreadsheet->getActiveSheet();
$sheet1->setCellValue('A1', 'First sheet');
$sheet2 = $spreadsheet->createSheet();
$sheet2->setCellValue('A2', 'Second sheet');
$sheet2->setCellValue('A2', 'before page break');
$sheet2->setBreak('A2', \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW);
$sheet2->setCellValue('A3', 'after page break');
$writer = new Tcpdf($spreadsheet);
$writer->writeAllSheets();
$html = $writer->generateHtmlAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
self::assertCount(5, $divs);
self::assertEquals('page: page0', $divs[0]->getAttribute('style'));
self::assertEquals('page: page1', $divs[2]->getAttribute('style'));
self::assertEquals('page: page1', $divs[4]->getAttribute('style'));
self::assertEquals('page-break-before:always', $divs[1]->getAttribute('style'));
self::assertEquals('page-break-before:always', $divs[3]->getAttribute('style'));
}
}

View File

@ -0,0 +1,199 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheetTests\Functional;
class GridlinesTest extends Functional\AbstractFunctional
{
public function testGridlines()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setShowGridlines(true)->setPrintGridlines(true);
$sheet->setCellValue('A1', 1);
$sheet = $spreadsheet->createSheet();
$sheet->setShowGridlines(true)->setPrintGridlines(false);
$sheet->setCellValue('A1', 1);
$sheet = $spreadsheet->createSheet();
$sheet->setShowGridlines(false)->setPrintGridlines(true);
$sheet->setCellValue('A1', 1);
$sheet = $spreadsheet->createSheet();
$sheet->setShowGridlines(false)->setPrintGridlines(false);
$sheet->setCellValue('A1', 1);
$writer = new Html($spreadsheet);
$writer->writeAllSheets();
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
self::assertCount(4, $divs);
$tbl = $divs[0]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('sheet0 gridlines gridlinesp', $cls);
$tbl = $divs[1]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('sheet1 gridlines', $cls);
$tbl = $divs[2]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('sheet2 gridlinesp', $cls);
$tbl = $divs[3]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('sheet3', $cls);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testGridlinesInline()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setShowGridlines(true)->setPrintGridlines(true);
$sheet->setCellValue('A1', 1);
$sheet = $spreadsheet->createSheet();
$sheet->setShowGridlines(true)->setPrintGridlines(false);
$sheet->setCellValue('A1', 1);
$sheet = $spreadsheet->createSheet();
$sheet->setShowGridlines(false)->setPrintGridlines(true);
$sheet->setCellValue('A1', 1);
$sheet = $spreadsheet->createSheet();
$sheet->setShowGridlines(false)->setPrintGridlines(false);
$sheet->setCellValue('A1', 1);
$writer = new Html($spreadsheet);
$writer->writeAllSheets();
$writer->setUseInlineCss(true);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
self::assertCount(4, $divs);
$tbl = $divs[0]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('gridlines gridlinesp', $cls);
$tbl = $divs[1]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('gridlines', $cls);
$tbl = $divs[2]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('gridlinesp', $cls);
$tbl = $divs[3]->getElementsByTagName('table')[0];
$cls = $tbl->getAttribute('class');
self::assertEquals('', $cls);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testRichText()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$emc2 = new \PhpOffice\PhpSpreadsheet\RichText\RichText();
$part1 = $emc2->createTextRun('e=mc');
$part1->getFont()->getColor()->setARGB(Color::COLOR_BLUE);
$part2 = $emc2->createTextRun('2');
$font = $part2->getFont();
$font->getColor()->setARGB(Color::COLOR_DARKGREEN);
$font->setSuperScript(true);
$sheet->setCellValue('A1', $emc2);
$h2o = new \PhpOffice\PhpSpreadsheet\RichText\RichText();
$h2o->createTextRun('H');
$part2 = $h2o->createTextRun('2');
$font = $part2->getFont();
$font->setSubScript(true);
$font->getColor()->setARGB(Color::COLOR_RED);
$h2o->createTextRun('O');
$sheet->setCellValue('A2', $h2o);
$h2so4 = new \PhpOffice\PhpSpreadsheet\RichText\RichText();
$h2so4->createTextRun('H');
$part2 = $h2so4->createTextRun('2');
$font = $part2->getFont();
$font->setSubScript(true);
$h2so4->createTextRun('SO');
$part4 = $h2so4->createTextRun('4');
$part4->getFont()->setSubScript(true);
$sheet->setCellValue('A3', $h2so4);
$sheet->setCellValue('A4', '5');
$sheet->getCell('A4')->getStyle()->getFont()->setSuperScript(true);
$sheet->setCellValue('A5', '6');
$sheet->getCell('A5')->getStyle()->getFont()->setSubScript(true);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
self::assertCount(1, $divs);
$tabl = $divs[0]->getElementsByTagName('table');
$tbod = $tabl[0]->getElementsByTagName('tbody');
$rows = $tbod[0]->getElementsByTagName('tr');
self::assertCount(5, $rows);
$tds = $rows[0]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(2, $spans);
self::assertEquals('e=mc', $spans[0]->textContent);
$style = $spans[0]->getAttribute('style');
self::assertEquals(1, preg_match('/color:#0000FF/', $style));
$style = $spans[1]->getAttribute('style');
self::assertEquals(1, preg_match('/color:#008000/', $style));
$sups = $spans[1]->getElementsByTagName('sup');
self::assertCount(1, $sups);
assert('2' == $sups[0]->textContent);
$tds = $rows[1]->getElementsByTagName('td');
assert(1 == count($tds));
$spans = $tds[0]->getElementsByTagName('span');
assert(3 == count($spans));
assert('H' == $spans[0]->textContent);
$style = $spans[1]->getAttribute('style');
assert(1 == preg_match('/color:#FF0000/', $style));
$subs = $spans[1]->getElementsByTagName('sub');
assert(1 == count($subs));
assert('2' == $subs[0]->textContent);
assert('O' == $spans[2]->textContent);
$tds = $rows[2]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(4, $spans);
self::assertEquals('H', $spans[0]->textContent);
$subs = $spans[1]->getElementsByTagName('sub');
self::assertCount(1, $subs);
self::assertEquals('2', $subs[0]->textContent);
self::assertEquals('SO', $spans[2]->textContent);
$subs = $spans[3]->getElementsByTagName('sub');
self::assertCount(1, $subs);
self::assertEquals('4', $subs[0]->textContent);
$tds = $rows[3]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(0, $spans);
$sups = $tds[0]->getElementsByTagName('sup');
self::assertCount(1, $sups);
self::assertEquals('5', $sups[0]->textContent);
$tds = $rows[4]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(0, $spans);
$subs = $tds[0]->getElementsByTagName('sub');
self::assertCount(1, $subs);
self::assertEquals('6', $subs[0]->textContent);
$this->writeAndReload($spreadsheet, 'Html');
}
}

View File

@ -1,11 +1,12 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Functional; namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheetTests\Functional;
class HtmlCommentsTest extends AbstractFunctional class HtmlCommentsTest extends Functional\AbstractFunctional
{ {
private $spreadsheet; private $spreadsheet;

View File

@ -0,0 +1,209 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheetTests\Functional;
class HtmlNumberFormatTest extends Functional\AbstractFunctional
{
private $decsep;
private $thosep;
protected function setUp(): void
{
$this->decsep = StringHelper::getDecimalSeparator();
StringHelper::setDecimalSeparator('.');
$this->thosep = StringHelper::getThousandsSeparator();
StringHelper::setThousandsSeparator(',');
}
protected function tearDown(): void
{
StringHelper::setDecimalSeparator($this->decsep);
StringHelper::setThousandsSeparator($this->thosep);
}
public function testColorNumberFormat()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', -50);
$sheet->setCellValue('A2', 3000);
$sheet->setCellValue('A3', 0);
$sheet->setCellValue('A4', '<br>');
$fmt = '[Blue]$#,##0;[Red]$#,##0;$#,##0';
$sheet->getStyle('A1:A4')->getNumberFormat()->setFormatCode($fmt);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tabl = $divs[0]->getElementsByTagName('table');
$tbod = $tabl[0]->getElementsByTagName('tbody');
$rows = $tbod[0]->getElementsByTagName('tr');
self::assertCount(4, $rows);
$tds = $rows[0]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(1, $spans);
$style = $spans[0]->getAttribute('style');
self::assertEquals(1, preg_match('/color:red/', $style));
self::assertEquals('$50', $spans[0]->textContent);
$tds = $rows[1]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(1, $spans);
$style = $spans[0]->getAttribute('style');
self::assertEquals(1, preg_match('/color:blue/', $style));
self::assertEquals('$3,000', $spans[0]->textContent);
$tds = $rows[2]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(0, $spans);
self::assertEquals('$0', $tds[0]->textContent);
$tds = $rows[3]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(0, $spans);
self::assertEquals('<br>', $tds[0]->textContent);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testColorNumberFormatComplex()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', -50);
$sheet->setCellValue('A2', 3000.75);
$sheet->setCellValue('A3', 0);
$sheet->setCellValue('A4', 3000.25);
$fmt = '[Blue][>=3000.5]$#,##0.00;[Red][<0]$#,##0.00;$#,##0.00';
$sheet->getStyle('A1:A4')->getNumberFormat()->setFormatCode($fmt);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tabl = $divs[0]->getElementsByTagName('table');
$tbod = $tabl[0]->getElementsByTagName('tbody');
$rows = $tbod[0]->getElementsByTagName('tr');
self::assertCount(4, $rows);
$tds = $rows[0]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(1, $spans);
$style = $spans[0]->getAttribute('style');
self::assertEquals(1, preg_match('/color:red/', $style));
self::assertEquals('$50.00', $spans[0]->textContent);
$tds = $rows[1]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(1, $spans);
$style = $spans[0]->getAttribute('style');
self::assertEquals(1, preg_match('/color:blue/', $style));
self::assertEquals('$3,000.75', $spans[0]->textContent);
$tds = $rows[2]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(0, $spans);
self::assertEquals('$0.00', $tds[0]->textContent);
$tds = $rows[3]->getElementsByTagName('td');
self::assertCount(1, $tds);
$spans = $tds[0]->getElementsByTagName('span');
self::assertCount(0, $spans);
self::assertEquals('$3,000.25', $tds[0]->textContent);
$this->writeAndReload($spreadsheet, 'Html');
}
/**
* @dataProvider providerNumberFormat
*
* @param mixed $expectedResult
* @param mixed $val
* @param mixed $fmt
*/
public function testFormatValueWithMask($expectedResult, $val, $fmt)
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('A1')->setValue($val)->getStyle()->getNumberFormat()->setFormatCode($fmt);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tabl = $divs[0]->getElementsByTagName('table');
$tbod = $tabl[0]->getElementsByTagName('tbody');
$rows = $tbod[0]->getElementsByTagName('tr');
$tds = $rows[0]->getElementsByTagName('td');
$nbsp = html_entity_decode('&nbsp;');
self::assertEquals($expectedResult, str_replace($nbsp, ' ', $tds[0]->textContent));
$this->writeAndReload($spreadsheet, 'Html');
}
public function providerNumberFormat()
{
return require __DIR__ . '/../../../data/Style/NumberFormat.php';
}
/**
* @dataProvider providerNumberFormatDates
*
* @param mixed $expectedResult
* @param mixed $val
* @param mixed $fmt
*/
public function testFormatValueWithMaskDate($expectedResult, $val, $fmt)
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('A1')->setValue($val)->getStyle()->getNumberFormat()->setFormatCode($fmt);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tabl = $divs[0]->getElementsByTagName('table');
$tbod = $tabl[0]->getElementsByTagName('tbody');
$rows = $tbod[0]->getElementsByTagName('tr');
$tds = $rows[0]->getElementsByTagName('td');
$nbsp = html_entity_decode('&nbsp;');
self::assertEquals($expectedResult, str_replace($nbsp, ' ', $tds[0]->textContent));
$this->writeAndReload($spreadsheet, 'Html');
}
public function providerNumberFormatDates()
{
return require __DIR__ . '/../../../data/Style/NumberFormatDates.php';
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheetTests\Functional;
class ImagesRootTest extends Functional\AbstractFunctional
{
public function testImagesRoot()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$drawing->setName('Test');
$drawing->setDescription('Test');
$root = 'http://www.example.com';
$newdir = __DIR__ . '/../../../data/Reader/HTML';
$stub = 'image.jpg';
$imagePath = "./$stub";
$curdir = getcwd();
chdir($newdir);
self::assertFileExists($imagePath);
$drawing->setPath($imagePath);
$desc = 'Test <img> tag';
$drawing->setDescription($desc);
$drawing->setHeight(36);
$drawing->setWorksheet($spreadsheet->getActiveSheet());
$drawing->setCoordinates('A1');
$sheet->setCellValue('A2', 'Image Above?');
$writer = new Html($spreadsheet);
$writer->setImagesRoot($root);
$html = $writer->generateHTMLAll();
chdir($curdir);
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tabl = $divs[0]->getElementsByTagName('table');
$tbod = $tabl[0]->getElementsByTagName('tbody');
$rows = $tbod[0]->getElementsByTagName('tr');
self::assertCount(2, $rows);
$tds = $rows[0]->getElementsByTagName('td');
self::assertCount(1, $tds);
$img = $tds[0]->getElementsByTagName('img');
self::assertCount(1, $img);
self::assertEquals("$root/$stub", $img[0]->getAttribute('src'));
self::assertEquals($desc, $img[0]->getAttribute('alt'));
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
use PhpOffice\PhpSpreadsheetTests\Functional;
class InvalidFileNameTest extends Functional\AbstractFunctional
{
public function testEmptyFileName()
{
$this->expectException(WriterException::class);
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Cell 1');
$writer = new Html($spreadsheet);
$writer->save('');
}
public function testEmptyFileNamePdf()
{
$this->expectException(WriterException::class);
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Cell 1');
$writer = new Mpdf($spreadsheet);
$writer->save('');
}
public function testEmptyTempdirNamePdf()
{
$this->expectException(WriterException::class);
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Cell 1');
$writer = new Mpdf($spreadsheet);
$writer->setFont('Helvetica');
self::assertEquals('Helvetica', $writer->getFont());
$writer->setPaperSize(PageSetup::PAPERSIZE_LEDGER);
self::assertEquals($writer->getPaperSize(), PageSetup::PAPERSIZE_LEDGER);
self::assertEquals(File::sysGetTempDir() . '/phpsppdf', $writer->getTempDir());
$writer->setTempDir('');
}
public function testWinFileNames()
{
self::assertEquals('file:///C:/temp/filename.xlsx', Html::winFileToUrl('C:\\temp\filename.xlsx'));
self::assertEquals('/tmp/filename.xlsx', Html::winFileToUrl('/tmp/filename.xlsx'));
self::assertEquals('a:bfile', Html::winFileToUrl('a:bfile'));
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheetTests\Functional;
class RepeatedRowsTest extends Functional\AbstractFunctional
{
public function testWriteRepeats()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getPageSetup()->setRowsToRepeatAtTop([1, 2]);
$sheet->setCellValue('A1', 'Repeat1');
$sheet->setCellValue('A2', 'Repeat2');
for ($row = 3; $row <= 100; ++$row) {
$sheet->setCellValue("A$row", $row);
}
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLall();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tbl = $divs->item(0)->getElementsByTagName('table');
self::assertEquals('', $tbl->item(0)->getAttribute('style'));
$thd = $divs->item(0)->getElementsByTagName('thead');
self::assertCount(1, $thd);
$trw = $thd->item(0)->getElementsByTagName('tr');
self::assertCount(2, $trw);
$tbd = $divs->item(0)->getElementsByTagName('tbody');
self::assertCount(1, $tbd);
$trw = $tbd->item(0)->getElementsByTagName('tr');
self::assertCount(98, $trw);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testWriteNoRepeats()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
//$sheet->getPageSetup()->setRowsToRepeatAtTop([1, 2]);
$sheet->setCellValue('A1', 'Repeat1');
$sheet->setCellValue('A2', 'Repeat2');
for ($row = 3; $row <= 100; ++$row) {
$sheet->setCellValue("A$row", $row);
}
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLall();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tbl = $divs->item(0)->getElementsByTagName('table');
$thd = $tbl->item(0)->getElementsByTagName('thead');
self::assertCount(0, $thd);
//$trw = $thd->item(0)->getElementsByTagName('tr');
//self::assertCount(2, $trw);
$tbd = $divs->item(0)->getElementsByTagName('tbody');
self::assertCount(1, $tbd);
$trw = $tbd->item(0)->getElementsByTagName('tr');
self::assertCount(100, $trw);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testWriteRepeatsInline()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getPageSetup()->setRowsToRepeatAtTop([1, 2]);
$sheet->setCellValue('A1', 'Repeat1');
$sheet->setCellValue('A2', 'Repeat2');
for ($row = 3; $row <= 100; ++$row) {
$sheet->setCellValue("A$row", $row);
}
$writer = new Html($spreadsheet);
self::assertFalse($writer->getUseInlineCss());
$writer->setUseInlineCss(true);
$html = $writer->generateHTMLall();
$dom = new \DOMDocument();
$dom->loadHTML($html);
$body = $dom->getElementsByTagName('body')[0];
$divs = $body->getElementsByTagName('div');
$tbl = $divs->item(0)->getElementsByTagName('table');
self::assertEquals('border-collapse:collapse', $tbl->item(0)->getAttribute('style'));
$thd = $divs->item(0)->getElementsByTagName('thead');
self::assertCount(1, $thd);
$trw = $thd->item(0)->getElementsByTagName('tr');
self::assertCount(2, $trw);
$tbd = $divs->item(0)->getElementsByTagName('tbody');
self::assertCount(1, $tbd);
$trw = $tbd->item(0)->getElementsByTagName('tr');
self::assertCount(98, $trw);
$this->writeAndReload($spreadsheet, 'Html');
}
}

View File

@ -0,0 +1,111 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheetTests\Functional;
class VisibilityTest extends Functional\AbstractFunctional
{
public function testVisibility1()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 1);
$sheet->setCellValue('A2', 2);
$sheet->setCellValue('A3', 3);
$sheet->setCellValue('B1', 4);
$sheet->setCellValue('B2', 5);
$sheet->setCellValue('B3', 6);
$sheet->setCellValue('C1', 7);
$sheet->setCellValue('C2', 8);
$sheet->setCellValue('C3', 9);
$sheet->getColumnDimension('B')->setVisible(false);
$sheet->getRowDimension(2)->setVisible(false);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
$reg = '/^\\s*table[.]sheet0 tr { display:none; visibility:hidden }\\s*$/m';
$rowsrch = preg_match($reg, $html);
self::assertEquals($rowsrch, 0);
$reg = '/^\\s*table[.]sheet0 tr[.]row1 { display:none; visibility:hidden }\\s*$/m';
$rowsrch = preg_match($reg, $html);
self::assertEquals($rowsrch, 1);
$reg = '/^\\s*table[.]sheet0 [.]column1 [{] display:none [}]\\s*$/m';
$colsrch = preg_match($reg, $html);
self::assertEquals($colsrch, 1);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testVisibility2()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 1);
$sheet->setCellValue('A2', 2);
$sheet->setCellValue('A3', 3);
$sheet->setCellValue('B1', 4);
$sheet->setCellValue('B2', 5);
$sheet->setCellValue('B3', 6);
$sheet->setCellValue('C1', 7);
$sheet->setCellValue('C2', 8);
$sheet->setCellValue('C3', 9);
$sheet->getDefaultRowDimension()->setVisible(false);
$sheet->getColumnDimension('B')->setVisible(false);
$sheet->getRowDimension(1)->setVisible(true);
$sheet->getRowDimension(3)->setVisible(true);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
$reg = '/^\\s*table[.]sheet0 tr { height:15pt; display:none; visibility:hidden }\\s*$/m';
$rowsrch = preg_match($reg, $html);
self::assertEquals($rowsrch, 1);
$reg = '/^\\s*table[.]sheet0 tr[.]row1 { display:none; visibility:hidden }\\s*$/m';
$rowsrch = preg_match($reg, $html);
self::assertEquals($rowsrch, 0);
$reg = '/^\\s*table[.]sheet0 [.]column1 [{] display:none [}]\\s*$/m';
$colsrch = preg_match($reg, $html);
self::assertEquals($colsrch, 1);
$this->writeAndReload($spreadsheet, 'Html');
}
public function testDefaultRowHeight()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 1);
$sheet->getStyle('A1')->getFont()->setStrikethrough(true);
$sheet->setCellValue('A2', 2);
$sheet->setCellValue('A3', 3);
$sheet->getStyle('A3')->getFont()->setStrikethrough(true)->setUnderline(Font::UNDERLINE_SINGLE);
$sheet->setCellValue('B1', 4);
$sheet->setCellValue('B2', 5);
$sheet->setCellValue('B3', 6);
$sheet->setCellValue('C1', 7);
$sheet->setCellValue('C2', 8);
$sheet->setCellValue('C3', 9);
$sheet->getStyle('C3')->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
$sheet->getDefaultRowDimension()->setRowHeight(20);
$sheet->getRowDimension(2)->setRowHeight(25);
$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
self::assertEquals(1, substr_count($html, 'height:20pt'));
self::assertEquals(1, substr_count($html, 'height:25pt'));
$rowsrch = preg_match('/^\\s*table[.]sheet0 tr [{] height:20pt [}]\\s*$/m', $html);
self::assertEquals(1, $rowsrch);
$rowsrch = preg_match('/^\\s*table[.]sheet0 tr[.]row1 [{] height:25pt [}]\\s*$/m', $html);
self::assertEquals(1, $rowsrch);
$rowsrch = preg_match('/^\\s*td[.]style1 [{].*text-decoration:line-through;.*[}]\\s*$/m', $html);
self::assertEquals(1, $rowsrch);
$rowsrch = preg_match('/^\\s*td[.]style2 [{].*text-decoration:underline line-through;.*[}]\\s*$/m', $html);
self::assertEquals(1, $rowsrch);
$rowsrch = preg_match('/^\\s*td[.]style3 [{].*text-decoration:underline;.*[}]\\s*$/m', $html);
self::assertEquals(1, $rowsrch);
$this->writeAndReload($spreadsheet, 'Html');
}
}

View File

@ -103,6 +103,11 @@ return [
12345.678900000001, 12345.678900000001,
'#,##0.000\ [$€-1]', '#,##0.000\ [$€-1]',
], ],
[
'12,345.679 $',
12345.678900000001,
'#,##0.000\ [$]',
],
[ [
'5.68', '5.68',
5.6788999999999996, 5.6788999999999996,
@ -177,6 +182,21 @@ return [
5.25, 5.25,
'???/???', '???/???',
], ],
[
'0 3/4',
0.75,
'0??/???',
],
[
'3/4',
0.75,
'#??/???',
],
[
' 3/4',
0.75,
'? ??/???',
],
// Complex formats // Complex formats
[ [
'(001) 2-3456-789', '(001) 2-3456-789',
@ -302,4 +322,24 @@ return [
-2, -2,
'[Green]"Positive";[Red]"Negative";[Blue]"Zero"', '[Green]"Positive";[Red]"Negative";[Blue]"Zero"',
], ],
[
'<=3500 red',
3500,
'[Green][=17]"=17 green";[Red][<=3500]"<=3500 red";[Blue]"Zero"',
],
[
'=17 green',
17,
'[Green][=17]"=17 green";[Red][<=3500]"<=3500 red";[Blue]"Zero"',
],
[
'<>25 green',
17,
'[Green][<>25]"<>25 green";[Red]"else red"',
],
[
'else red',
25,
'[Green][<>25]"<>25 green";[Red]"else red"',
],
]; ];