Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).

### Fixed

- Writer Html/Pdf support RTL alignment of tables. [Issue #1104](https://github.com/PHPOffice/PhpSpreadsheet/issues/1104) [PR #4535](https://github.com/PHPOffice/PhpSpreadsheet/pull/4535)
- Xlsx Reader use dynamic arrays if spreadsheet did so. [PR #4533](https://github.com/PHPOffice/PhpSpreadsheet/pull/4533)
- Ods Reader Nested table-row. [Issue #4528](https://github.com/PHPOffice/PhpSpreadsheet/issues/4528) [Issue #2507](https://github.com/PHPOffice/PhpSpreadsheet/issues/2507) [PR #4531](https://github.com/PHPOffice/PhpSpreadsheet/pull/4531)
- Recognize application/x-empty mimetype. [Issue #4521](https://github.com/PHPOffice/PhpSpreadsheet/issues/4521) [PR #4524](https://github.com/PHPOffice/PhpSpreadsheet/pull/4524)
Expand Down
13 changes: 3 additions & 10 deletions samples/Pdf/21f_Drawing_mpdf.php → samples/Pdf/21f_Drawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;

require __DIR__ . '/../Header.php';
/** @var PhpOffice\PhpSpreadsheet\Helper\Sample $helper */
require_once __DIR__ . '/Mpdf2.php';

/** @var PhpOffice\PhpSpreadsheet\Helper\Sample $helper */
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

Expand Down Expand Up @@ -41,11 +39,6 @@
$spreadsheet->mergeDrawingCellsForPdf();

$helper->log('Write to Mpdf');
$writer = new Mpdf($spreadsheet);
$filename = $helper->getFileName(__FILE__, 'pdf');
$writer->save($filename);
$helper->log("Saved $filename");
if (PHP_SAPI !== 'cli') {
echo '<a href="/download.php?type=pdf&name=' . basename($filename) . '">Download ' . basename($filename) . '</a><br />';
}
$helper->write($spreadsheet, __FILE__, ['Mpdf']);

$spreadsheet->disconnectWorksheets();
28 changes: 28 additions & 0 deletions samples/Pdf/21g_Direction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use PhpOffice\PhpSpreadsheet\Spreadsheet;

require __DIR__ . '/../Header.php';

/** @var PhpOffice\PhpSpreadsheet\Helper\Sample $helper */
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

$sheet1 = $spreadsheet->getActiveSheet();
$sheet2 = $spreadsheet->createSheet();
$sheet3 = $spreadsheet->createSheet();
$cells = [
['a1', 'b1', 'c1'],
['a2', 'b2', 'c2'],
];
$sheet1->fromArray($cells);
$sheet1->setRightToLeft(true);
$sheet2->fromArray($cells);
$sheet3->fromArray($cells);
$sheet3->setRightToLeft(true);

$helper->log('Write to html, mpdf, tcpdf');
// Save
$helper->write($spreadsheet, __FILE__, ['Html', 'Mpdf', 'Tcpdf']);

$spreadsheet->disconnectWorksheets();
36 changes: 36 additions & 0 deletions samples/Pdf/21h_DirectionMultiple.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;

require __DIR__ . '/../Header.php';

/** @var PhpOffice\PhpSpreadsheet\Helper\Sample $helper */
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

$sheet1 = $spreadsheet->getActiveSheet();
$sheet2 = $spreadsheet->createSheet();
$sheet3 = $spreadsheet->createSheet();
$cells = [
['a1', 'b1', 'c1'],
['a2', 'b2', 'c2'],
];
$sheet1->fromArray($cells);
$sheet1->setRightToLeft(true);
$sheet2->fromArray($cells);
$sheet3->fromArray($cells);
$sheet3->setRightToLeft(true);

$helper->log('Write to html, mpdf');
// Save
$helper->write(
$spreadsheet,
__FILE__,
['Html', 'Mpdf'],
writerCallback: function (HtmlWriter $writer): void {
$writer->writeAllSheets();
}
);

$spreadsheet->disconnectWorksheets();
3 changes: 3 additions & 0 deletions src/PhpSpreadsheet/Reader/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,9 @@ private function processDomElementTable(Worksheet $sheet, int &$row, string &$co
$sheet->setShowGridlines(in_array('gridlines', $classes, true));
$sheet->setPrintGridlines(in_array('gridlinesp', $classes, true));
}
if ('rtl' === ($attributeArray['dir'] ?? '')) {
$sheet->setRightToLeft(true);
}
$this->currentColumn = 'A';
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);
$column = $this->setTableStartColumn($column);
Expand Down
81 changes: 72 additions & 9 deletions src/PhpSpreadsheet/Writer/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ class Html extends BaseWriter

private string $getFalse = 'FALSE';

protected bool $rtlSheets = false;

protected bool $ltrSheets = false;

/**
* Create a new HTML.
*/
Expand Down Expand Up @@ -186,11 +190,31 @@ public function save($filename, int $flags = 0): void
$this->maybeCloseFileHandle();
}

protected function checkRtlAndLtr(): void
{
$this->rtlSheets = false;
$this->ltrSheets = false;
if ($this->sheetIndex === null) {
foreach ($this->spreadsheet->getAllSheets() as $sheet) {
if ($sheet->getRightToLeft()) {
$this->rtlSheets = true;
} else {
$this->ltrSheets = true;
}
}
} else {
if ($this->spreadsheet->getSheet($this->sheetIndex)->getRightToLeft()) {
$this->rtlSheets = true;
}
}
}

/**
* Save Spreadsheet as html to variable.
*/
public function generateHtmlAll(): string
{
$this->checkRtlAndLtr();
$sheets = $this->generateSheetPrep();
foreach ($sheets as $sheet) {
$sheet->calculateArrays($this->preCalculateFormulas);
Expand Down Expand Up @@ -369,7 +393,8 @@ public function generateHTMLHeader(bool $includeStyles = false): string
// Construct HTML
$properties = $this->spreadsheet->getProperties();
$html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . PHP_EOL;
$html .= '<html xmlns="http://www.w3.org/1999/xhtml">' . PHP_EOL;
$rtl = ($this->rtlSheets && !$this->ltrSheets) ? " dir='rtl'" : '';
$html .= '<html xmlns="http://www.w3.org/1999/xhtml"' . $rtl . '>' . PHP_EOL;
$html .= ' <head>' . PHP_EOL;
$html .= ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . PHP_EOL;
$html .= ' <meta name="generator" content="PhpSpreadsheet, https://github.com/PHPOffice/PhpSpreadsheet" />' . PHP_EOL;
Expand Down Expand Up @@ -1013,6 +1038,9 @@ public function buildCSS(bool $generateSurroundingHTML = true): array
// .s {}
$css['.s']['text-align'] = 'left'; // STRING

$css['.floatright']['float'] = 'right';
$css['.floatleft']['float'] = 'left';

// Calculate cell style hashes
foreach ($this->spreadsheet->getCellXfCollection() as $index => $style) {
$css['td.style' . $index . ', th.style' . $index] = $this->createCSSStyle($style);
Expand Down Expand Up @@ -1221,21 +1249,52 @@ public function generateHTMLFooter(): string
return $html;
}

private function getDir(Worksheet $worksheet): string
{
if ($worksheet->getRightToLeft()) {
return " dir='rtl'";
}
if ($this->rtlSheets) {
return " dir='ltr'";
}

return '';
}

private function getFloat(Worksheet $worksheet): string
{
$float = '';
if ($worksheet->getRightToLeft()) {
if ($this->ltrSheets) {
$float = ' floatright';
}
} else {
if ($this->rtlSheets) {
$float = ' floatleft';
}
}

return $float;
}

private function generateTableTagInline(Worksheet $worksheet, string $id): string
{
$style = isset($this->cssStyles['table'])
? $this->assembleCSS($this->cssStyles['table']) : '';

$rtl = $this->getDir($worksheet);
$float = $this->getFloat($worksheet);
$prntgrid = $worksheet->getPrintGridlines();
$viewgrid = $this->isPdf ? $prntgrid : $worksheet->getShowGridlines();
if ($viewgrid && $prntgrid) {
$html = " <table border='1' cellpadding='1' $id cellspacing='1' style='$style' class='gridlines gridlinesp'>" . PHP_EOL;
$html = " <table border='1' cellpadding='1'$rtl $id cellspacing='1' style='$style' class='gridlines gridlinesp$float'>" . PHP_EOL;
} elseif ($viewgrid) {
$html = " <table border='0' cellpadding='0' $id cellspacing='0' style='$style' class='gridlines'>" . PHP_EOL;
$html = " <table border='0' cellpadding='0'$rtl $id cellspacing='0' style='$style' class='gridlines$float'>" . PHP_EOL;
} elseif ($prntgrid) {
$html = " <table border='0' cellpadding='0' $id cellspacing='0' style='$style' class='gridlinesp'>" . PHP_EOL;
$html = " <table border='0' cellpadding='0'$rtl $id cellspacing='0' style='$style' class='gridlinesp$float'>" . PHP_EOL;
} elseif ($float === '') {
$html = " <table border='0' cellpadding='1'$rtl $id cellspacing='0' style='$style'>" . PHP_EOL;
} else {
$html = " <table border='0' cellpadding='1' $id cellspacing='0' style='$style'>" . PHP_EOL;
$html = " <table border='0' cellpadding='1'$rtl $id cellspacing='0' style='$style' class='$float'>" . PHP_EOL;
}

return $html;
Expand All @@ -1244,9 +1303,11 @@ private function generateTableTagInline(Worksheet $worksheet, string $id): strin
private function generateTableTag(Worksheet $worksheet, string $id, string &$html, int $sheetIndex): void
{
if (!$this->useInlineCss) {
$rtl = $this->getDir($worksheet);
$float = $this->getFloat($worksheet);
$gridlines = $worksheet->getShowGridlines() ? ' gridlines' : '';
$gridlinesp = $worksheet->getPrintGridlines() ? ' gridlinesp' : '';
$html .= " <table border='0' cellpadding='0' cellspacing='0' $id class='sheet$sheetIndex$gridlines$gridlinesp'>" . PHP_EOL;
$html .= " <table border='0' cellpadding='0' cellspacing='0'$rtl $id class='sheet$sheetIndex$gridlines$gridlinesp$float'>" . PHP_EOL;
} else {
$html .= $this->generateTableTagInline($worksheet, $id);
}
Expand All @@ -1265,10 +1326,12 @@ private function generateTableHeader(Worksheet $worksheet, bool $showid = true):
// Construct HTML
$html = '';
$id = $showid ? "id='sheet$sheetIndex'" : '';
$clear = ($this->rtlSheets && $this->ltrSheets) ? '; clear:both' : '';

if ($showid) {
$html .= "<div style='page: page$sheetIndex'>" . PHP_EOL;
$html .= "<div style='page: page$sheetIndex$clear'>" . PHP_EOL;
} else {
$html .= "<div style='page: page$sheetIndex' class='scrpgbrk'>" . PHP_EOL;
$html .= "<div style='page: page$sheetIndex$clear' class='scrpgbrk'>" . PHP_EOL;
}

$this->generateTableTag($worksheet, $id, $html, $sheetIndex);
Expand Down
24 changes: 19 additions & 5 deletions src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,28 @@ public function save($filename, int $flags = 0): void

// Set the appropriate font
$pdf->SetFont($this->getFont());
$this->checkRtlAndLtr();
if ($this->rtlSheets && !$this->ltrSheets) {
$pdf->setRTL(true);
}
$pdf->writeHTML($this->generateHTMLAll());

// Document info
$pdf->SetTitle($this->spreadsheet->getProperties()->getTitle());
$pdf->SetAuthor($this->spreadsheet->getProperties()->getCreator());
$pdf->SetSubject($this->spreadsheet->getProperties()->getSubject());
$pdf->SetKeywords($this->spreadsheet->getProperties()->getKeywords());
$pdf->SetCreator($this->spreadsheet->getProperties()->getCreator());
$pdf->SetTitle(
$this->spreadsheet->getProperties()->getTitle()
);
$pdf->SetAuthor(
$this->spreadsheet->getProperties()->getCreator()
);
$pdf->SetSubject(
$this->spreadsheet->getProperties()->getSubject()
);
$pdf->SetKeywords(
$this->spreadsheet->getProperties()->getKeywords()
);
$pdf->SetCreator(
$this->spreadsheet->getProperties()->getCreator()
);

// Write to file
fwrite($fileHandle, $pdf->output('', 'S'));
Expand Down
92 changes: 92 additions & 0 deletions tests/PhpSpreadsheetTests/Reader/Html/DirectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;

use PhpOffice\PhpSpreadsheet\Reader\Html as HtmlReader;
use PHPUnit\Framework\TestCase;

class DirectionTest extends TestCase
{
public function testRtl(): void
{
$inlines = [
"<table border='0' cellpadding='0' cellspacing='0' dir='rtl' id='sheet0' class='sheet0 gridlines'>",
'<tbody>',
'<tr class="row0">',
'<td class="column0 style0 s">a1</td>',
'<td class="column1 style0 s">b1</td>',
'<td class="column2 style0 s">c1</td>',
'</tr>',
'<tr class="row1">',
'<td class="column0 style0 s">a2</td>',
'<td class="column1 style0 s">b2</td>',
'<td class="column2 style0 s">c2</td>',
'</tr>',
'</tbody></table>',
];
$html = implode("\n", $inlines);
$reader = new HtmlReader();
$spreadsheet = $reader->loadFromString($html);
$sheet = $spreadsheet->getActiveSheet();
self::assertTrue($sheet->getRightToLeft());
self::assertSame('a1', $sheet->getCell('A1')->getValue());
self::assertSame('c2', $sheet->getCell('C2')->getValue());
$spreadsheet->disconnectWorksheets();
}

public function testLtr(): void
{
$inlines = [
"<table border='0' cellpadding='0' cellspacing='0' dir='ltr' id='sheet0' class='sheet0 gridlines'>",
'<tbody>',
'<tr class="row0">',
'<td class="column0 style0 s">a1</td>',
'<td class="column1 style0 s">b1</td>',
'<td class="column2 style0 s">c1</td>',
'</tr>',
'<tr class="row1">',
'<td class="column0 style0 s">a2</td>',
'<td class="column1 style0 s">b2</td>',
'<td class="column2 style0 s">c2</td>',
'</tr>',
'</tbody></table>',
];
$html = implode("\n", $inlines);
$reader = new HtmlReader();
$spreadsheet = $reader->loadFromString($html);
$sheet = $spreadsheet->getActiveSheet();
self::assertFalse($sheet->getRightToLeft());
self::assertSame('a1', $sheet->getCell('A1')->getValue());
self::assertSame('c2', $sheet->getCell('C2')->getValue());
$spreadsheet->disconnectWorksheets();
}

public function testDefault(): void
{
$inlines = [
"<table border='0' cellpadding='0' cellspacing='0' id='sheet0' class='sheet0 gridlines'>",
'<tbody>',
'<tr class="row0">',
'<td class="column0 style0 s">a1</td>',
'<td class="column1 style0 s">b1</td>',
'<td class="column2 style0 s">c1</td>',
'</tr>',
'<tr class="row1">',
'<td class="column0 style0 s">a2</td>',
'<td class="column1 style0 s">b2</td>',
'<td class="column2 style0 s">c2</td>',
'</tr>',
'</tbody></table>',
];
$html = implode("\n", $inlines);
$reader = new HtmlReader();
$spreadsheet = $reader->loadFromString($html);
$sheet = $spreadsheet->getActiveSheet();
self::assertFalse($sheet->getRightToLeft());
self::assertSame('a1', $sheet->getCell('A1')->getValue());
self::assertSame('c2', $sheet->getCell('C2')->getValue());
$spreadsheet->disconnectWorksheets();
}
}
Loading