PhpWord输出在LibreOffice中不起作用,但在MSWord中工作正常
这与 GitHub 页面 [链接]上列出的一个半已知问题有关,其中 PhpWord 生成表格的方式导致它将单元格宽度设置为“”,这在 LibreOffice 中无效,但在 Word 中很好。
GitHub 上的问题专门列出了 html-to-word 转换,但我在使用常规的面向对象界面时也遇到了这个问题。
我试过手动设置单元格宽度,但它似乎没有做任何事情。
我在这里询问是否有人对此问题有任何解决方法,因为它几乎不可能在不访问 MS Word 的情况下在 Linux 机器上调试我的输出。我需要为客户导出 .docx。
为什么不直接导出到 .odt 来测试它呢?如果我这样做,它也不会呈现我在页面上的列表......
这是我正在处理的文档的粗略概述(由于保密协议,我不能随意分享确切的代码):
$document = new PhpWordPhpWord();
$section = $document->addSection();
// This list doesn't get rendered in the ODT file
$section->addListItem('Employee ID: 98765');
$section->addListItem('First Name: John');
$section->addListItem('Last Name: Doe');
$section->addListItem('SSN: 12345');
// This table has errors in LibreOffice when exported to .docx
if ($show_adv_details) {
$table = $section->addTable();
$table->addRow();
$table->addCell()->addText('SSN');
$table->addCell()->addText('Email');
$table->addCell()->addText('Phone No');
$table->addRow();
$table->addCell()->addText('12345');
$table->addCell()->addText('jd@example.com');
$table->addCell()->addText('999 1234');
// repeat ad nauseam
}
$section->addTitle('Comment');
$section->addTitle('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.');
我在 Ubuntu 上使用 PHP 7.0(古老的遗留系统,对此无能为力)。
所以最后在这里重申一下这个问题:
我可以做些什么来使该文档在所有不同的输出上正确呈现?该文档似乎没有多大帮助。
回答
好吧,我不是 PHPOffice 包的维护者,但这里有一个解决方法,我在包代码中挖掘并解决了您的两个问题:
- ODT 列表不起作用;
- Word2007 Writer 上的表格在使用 LibreOffice 打开时不起作用。
我意识到ODText 编写器上不存在ListItem.php类,我想这是因为您无法将列表添加到 .odt 文件中。
您需要手动为列添加宽度以使其在 LibreOffice 上工作(正如Nigel所说,您可以通过每次addCell()调用并添加一些数字,甚至“1”也可以)。
如何解决这两个问题
我们将“覆盖”原始文件,并提供一些解决问题的更新。为了使其工作,您应该使用 Composer安装PHPWord。
(这是安装指南中唯一可用的选项,但还有其他方法可以做到这一点)。
如果没有 Composer,在 PHPWord require 之后需要自定义文件(我认为它有效)。或者直接更改其位置上的文件(一个坏主意)。
文件
创建一个这样的结构:
Custom
??? Element
? ??? Table.php
??? Writer
??? ODText
??? Element
??? ListItem.php
Custom
??? Element
? ??? Table.php
??? Writer
??? ODText
??? Element
??? ListItem.php
当然,你可以使用任何其他的,但我们将“覆盖”包的原始文件,所以我保留了它的结构。
我们将使用自动加载文件来获取这些文件:
作曲家.json:
如果您的composer.json上没有“自动加载”键,您必须添加它,“文件”键也是如此。
运行composer dump-autoload以更新更改。
自定义类
现在,我们必须将代码添加到我们的自定义文件中。
自定义/Writer/ODText/Element/ ListItem.php :
...
"autoload": {
"files": [
"Custom/Element/Table.php",
"Custom/Writer/ODText/Element/ListItem.php"
]
},
...
该文件已改编自 Word2007 版本并修复了您的第一个问题。现在列表将适用于 ODText。
自定义/元素/ Table.php :
<?php
namespace PhpOfficePhpWordWriterODTextElement;
/**
* ListItem element writer
*/
class ListItem extends AbstractElement
{
/**
* Write list item element.
*/
public function write()
{
$xmlWriter = $this->getXmlWriter();
$element = $this->getElement();
if (!$element instanceof PhpOfficePhpWordElementListItem) {
return;
}
$textObject = $element->getTextObject();
$xmlWriter->startElement('text:list');
$xmlWriter->writeAttribute('text:style-name', 'L1');
$xmlWriter->startElement('text:list-item');
$xmlWriter->startElement('text:p');
$xmlWriter->writeAttribute('text:style-name', 'P1');
$elementWriter = new Text($xmlWriter, $textObject, true);
$elementWriter->write();
$xmlWriter->endElement(); // text:list
$xmlWriter->endElement(); // text:p
$xmlWriter->endElement(); // text:list-item
}
}
当我们“覆盖”文件时,我们不能重用扩展它的原始文件(至少我不知道如何)。这里唯一的变化是public function addCell($width = 1, $style = null)始终将“1”作为函数的默认值。这解决了您的第二个问题,现在您可以在$table->addCell()没有值的情况下调用。
演示
<?php
namespace PhpOfficePhpWordElement;
use PhpOfficePhpWordStyleTable as TableStyle;
/**
* Table element writer
*/
class Table extends AbstractElement
{
/**
* Table style
*
* @var PhpOfficePhpWordStyleTable
*/
private $style;
/**
* Table rows
*
* @var PhpOfficePhpWordElementRow[]
*/
private $rows = array();
/**
* Table width
*
* @var int
*/
private $width = null;
/**
* Create a new table
*
* @param mixed $style
*/
public function __construct($style = null)
{
$this->style = $this->setNewStyle(new TableStyle(), $style);
}
/**
* Add a row
*
* @param int $height
* @param mixed $style
* @return PhpOfficePhpWordElementRow
*/
public function addRow($height = null, $style = null)
{
$row = new Row($height, $style);
$row->setParentContainer($this);
$this->rows[] = $row;
return $row;
}
/**
* Add a cell
*
* @param int $width
* @param mixed $style
* @return PhpOfficePhpWordElementCell
*/
public function addCell($width = 1, $style = null)
{
$index = count($this->rows) - 1;
$row = $this->rows[$index];
$cell = $row->addCell($width, $style);
return $cell;
}
/**
* Get all rows
*
* @return PhpOfficePhpWordElementRow[]
*/
public function getRows()
{
return $this->rows;
}
/**
* Get table style
*
* @return PhpOfficePhpWordStyleTable
*/
public function getStyle()
{
return $this->style;
}
/**
* Get table width
*
* @return int
*/
public function getWidth()
{
return $this->width;
}
/**
* Set table width.
*
* @param int $width
*/
public function setWidth($width)
{
$this->width = $width;
}
/**
* Get column count
*
* @return int
*/
public function countColumns()
{
$columnCount = 0;
$rowCount = count($this->rows);
for ($i = 0; $i < $rowCount; $i++) {
/** @var PhpOfficePhpWordElementRow $row Type hint */
$row = $this->rows[$i];
$cellCount = count($row->getCells());
if ($columnCount < $cellCount) {
$columnCount = $cellCount;
}
}
return $columnCount;
}
/**
* The first declared cell width for each column
*
* @return int[]
*/
public function findFirstDefinedCellWidths()
{
$cellWidths = array();
foreach ($this->rows as $row) {
$cells = $row->getCells();
if (count($cells) <= count($cellWidths)) {
continue;
}
$cellWidths = array();
foreach ($cells as $cell) {
$cellWidths[] = $cell->getWidth();
}
}
return $cellWidths;
}
}