Bugfix for footnote reference number and additional feature to insert text break and style the reference number

This commit is contained in:
Ivan Lanin 2014-03-29 00:57:23 +07:00
parent 92588ccfd9
commit 255af437f2
10 changed files with 235 additions and 109 deletions

View File

@ -8,10 +8,12 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
- Image: Get image dimensions without EXIF extension - @andrew-kzoo GH-184
- Table: Add tblGrid element for Libre/Open Office table sizing - @gianis6 GH-183
- Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin
- Footnote: Ability to style footnote reference mark by using `FootnoteReference` style - @ivanlanin
### Bugfixes
-
- Footnote: Footnote content doesn't show footnote reference number - @ivanlanin GH-170
### Miscellaneous

View File

@ -326,7 +326,8 @@ Footnotes
---------
You can create footnotes in texts or textruns, but it's recommended to
use textrun to have better layout.
use textrun to have better layout. You can use ``addText``, ``addLink``,
and ``addTextBreak`` on a footnote.
On textrun:
@ -335,7 +336,11 @@ On textrun:
$textrun = $section->createTextRun();
$textrun->addText('Lead text.');
$footnote = $textrun->createFootnote();
$footnote->addText('Footnote text.');
$footnote->addText('Footnote text can have ');
$footnote->addLink('http://test.com', 'links');
$footnote->addText('.');
$footnote->addTextBreak();
$footnote->addText('And text break.');
$textrun->addText('Trailing text.');
On text:
@ -345,3 +350,8 @@ On text:
$section->addText('Lead text.');
$footnote = $section->createFootnote();
$footnote->addText('Footnote text.');
The footnote reference number will be displayed with decimal number starting
from 1. This number use ``FooterReference`` style which you can redefine by
``addFontStyle`` method. Default value for this style is
``array('superScript' => true)``;

View File

@ -24,7 +24,8 @@ $footnote->addText(' No break is placed after adding an element.', 'BoldText');
$footnote->addText(' All elements are placed inside a paragraph.', 'ColoredText');
$footnote->addText(' The best search engine: ');
$footnote->addLink('http://www.google.com', null, 'NLink');
$footnote->addText('. Also not bad: ');
$footnote->addText('. Also not bad:');
$footnote->addTextBreak();
$footnote->addLink('http://www.bing.com', null, 'NLink');
$textrun->addText('The trailing text in the paragraph.');

View File

@ -77,6 +77,20 @@ class Footnote
return $text;
}
/**
* Add TextBreak
*
* @param int $count
* @param mixed $fontStyle
* @param mixed $paragraphStyle
*/
public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null)
{
for ($i = 1; $i <= $count; $i++) {
$this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle);
}
}
/**
* Add a Link Element
*

View File

@ -125,7 +125,7 @@ class Base extends WriterPart
} elseif ($element instanceof Image) {
$this->_writeImage($xmlWriter, $element, true);
} elseif ($element instanceof Footnote) {
$this->_writeFootnoteReference($xmlWriter, $element, true);
$this->_writeFootnote($xmlWriter, $element, true);
} elseif ($element instanceof TextBreak) {
$xmlWriter->writeElement('w:br');
}
@ -1172,61 +1172,24 @@ class Base extends WriterPart
}
/**
* Write footnote element
*
* @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param PhpOffice\PhpWord\Section\Footnote $footnote
*/
protected function _writeFootnote(XMLWriter $xmlWriter, Footnote $footnote)
{
$xmlWriter->startElement('w:footnote');
$xmlWriter->writeAttribute('w:id', $footnote->getReferenceId());
$styleParagraph = $footnote->getParagraphStyle();
$SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false;
$xmlWriter->startElement('w:p');
if ($SpIsObject) {
$this->_writeParagraphStyle($xmlWriter, $styleParagraph);
} elseif (!$SpIsObject && !is_null($styleParagraph)) {
$xmlWriter->startElement('w:pPr');
$xmlWriter->startElement('w:pStyle');
$xmlWriter->writeAttribute('w:val', $styleParagraph);
$xmlWriter->endElement();
$xmlWriter->endElement();
}
$elements = $footnote->getElements();
if (count($elements) > 0) {
foreach ($elements as $element) {
if ($element instanceof Text) {
$this->_writeText($xmlWriter, $element, true);
} elseif ($element instanceof Link) {
$this->_writeLink($xmlWriter, $element, true);
}
}
}
$xmlWriter->endElement(); // w:p
$xmlWriter->endElement(); // w:footnote
}
/**
* Write footnote reference element
* Write footnote element which links to the actual content in footnotes.xml
*
* @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param PhpOffice\PhpWord\Section\Footnote $footnote
* @param boolean $withoutP
*/
protected function _writeFootnoteReference(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false)
protected function _writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false)
{
if (!$withoutP) {
$xmlWriter->startElement('w:p');
}
$xmlWriter->startElement('w:r');
$xmlWriter->startElement('w:rPr');
$xmlWriter->startElement('w:rStyle');
$xmlWriter->writeAttribute('w:val', 'FootnoteReference');
$xmlWriter->endElement(); // w:rStyle
$xmlWriter->endElement(); // w:rPr
$xmlWriter->startElement('w:footnoteReference');
$xmlWriter->writeAttribute('w:id', $footnote->getReferenceId());
$xmlWriter->endElement(); // w:footnoteReference

View File

@ -98,7 +98,7 @@ class Document extends Base
} elseif ($element instanceof TOC) {
$this->_writeTOC($xmlWriter);
} elseif ($element instanceof Footnote) {
$this->_writeFootnoteReference($xmlWriter, $element);
$this->_writeFootnote($xmlWriter, $element);
}
}

View File

@ -10,6 +10,10 @@
namespace PhpOffice\PhpWord\Writer\Word2007;
use PhpOffice\PhpWord\Section\Footnote;
use PhpOffice\PhpWord\Section\Text;
use PhpOffice\PhpWord\Section\Link;
use PhpOffice\PhpWord\Section\TextBreak;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\Shared\XMLWriter;
/**
@ -27,19 +31,25 @@ class Footnotes extends Base
// Create XML writer
$xmlWriter = null;
if ($this->getParentWriter()->getUseDiskCaching()) {
$xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
$xmlWriter = new XMLWriter(
XMLWriter::STORAGE_DISK,
$this->getParentWriter()->getDiskCachingDirectory()
);
} else {
$xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
}
// XML header
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('w:footnotes');
$xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
// write separator and continuation separator
$xmlWriter->writeAttribute(
'xmlns:r',
'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
);
$xmlWriter->writeAttribute(
'xmlns:w',
'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
);
// Separator and continuation separator
$xmlWriter->startElement('w:footnote');
$xmlWriter->writeAttribute('w:id', 0);
$xmlWriter->writeAttribute('w:type', 'separator');
@ -50,7 +60,7 @@ class Footnotes extends Base
$xmlWriter->endElement(); // w:r
$xmlWriter->endElement(); // w:p
$xmlWriter->endElement(); // w:footnote
// Content
$xmlWriter->startElement('w:footnote');
$xmlWriter->writeAttribute('w:id', 1);
$xmlWriter->writeAttribute('w:type', 'continuationSeparator');
@ -61,16 +71,69 @@ class Footnotes extends Base
$xmlWriter->endElement(); // w:r
$xmlWriter->endElement(); // w:p
$xmlWriter->endElement(); // w:footnote
foreach ($allFootnotesCollection as $footnote) {
if ($footnote instanceof Footnote) {
$this->_writeFootnote($xmlWriter, $footnote);
$this->writeFootnote($xmlWriter, $footnote);
}
}
$xmlWriter->endElement();
// Return
return $xmlWriter->getData();
}
/**
* Write footnote content, overrides method in parent class
*
* @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param PhpOffice\PhpWord\Section\Footnote $footnote
*/
private function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote)
{
$xmlWriter->startElement('w:footnote');
$xmlWriter->writeAttribute('w:id', $footnote->getReferenceId());
$xmlWriter->startElement('w:p');
// Paragraph style
$paragraphStyle = $footnote->getParagraphStyle();
$spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false;
if ($spIsObject) {
$this->_writeParagraphStyle($xmlWriter, $paragraphStyle);
} elseif (!$spIsObject && !is_null($paragraphStyle)) {
$xmlWriter->startElement('w:pPr');
$xmlWriter->startElement('w:pStyle');
$xmlWriter->writeAttribute('w:val', $paragraphStyle);
$xmlWriter->endElement();
$xmlWriter->endElement();
}
// Reference symbol
$xmlWriter->startElement('w:r');
$xmlWriter->startElement('w:rPr');
$xmlWriter->startElement('w:rStyle');
$xmlWriter->writeAttribute('w:val', 'FootnoteReference');
$xmlWriter->endElement(); // w:rStyle
$xmlWriter->endElement(); // w:rPr
$xmlWriter->writeElement('w:footnoteRef');
$xmlWriter->endElement(); // w:r
// Empty space after refence symbol
$xmlWriter->startElement('w:r');
$xmlWriter->startElement('w:t');
$xmlWriter->writeAttribute('xml:space', 'preserve');
$xmlWriter->writeRaw(' ');
$xmlWriter->endElement(); // w:t
$xmlWriter->endElement(); // w:r
// Actual footnote contents
$elements = $footnote->getElements();
if (count($elements) > 0) {
foreach ($elements as $element) {
if ($element instanceof Text) {
$this->_writeText($xmlWriter, $element, true);
} elseif ($element instanceof Link) {
$this->_writeLink($xmlWriter, $element, true);
} elseif ($element instanceof TextBreak) {
$xmlWriter->writeElement('w:br');
}
}
}
$xmlWriter->endElement(); // w:p
$xmlWriter->endElement(); // w:footnote
}
}

View File

@ -21,11 +21,11 @@ use PhpOffice\PhpWord\Style\Paragraph;
class Styles extends Base
{
/**
* PHPWord object
* PhpWord object
*
* @var PhpWord
*/
private $_document;
private $phpWord;
/**
* Write word/styles.xml
@ -37,44 +37,28 @@ class Styles extends Base
// Create XML writer
$xmlWriter = null;
if ($this->getParentWriter()->getUseDiskCaching()) {
$xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
$xmlWriter = new XMLWriter(
XMLWriter::STORAGE_DISK,
$this->getParentWriter()->getDiskCachingDirectory()
);
} else {
$xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
}
$this->_document = $phpWord;
$this->phpWord = $phpWord;
// XML header
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('w:styles');
$xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
// Write DocDefaults
$this->_writeDocDefaults($xmlWriter);
// Write Style Definitions
$xmlWriter->writeAttribute(
'xmlns:r',
'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
);
$xmlWriter->writeAttribute(
'xmlns:w',
'http://schemas.openxmlformats.org/wordprocessingml/2006/main'
);
// Write default styles
$styles = Style::getStyles();
// Write normal paragraph style
$normalStyle = null;
if (array_key_exists('Normal', $styles)) {
$normalStyle = $styles['Normal'];
}
$xmlWriter->startElement('w:style');
$xmlWriter->writeAttribute('w:type', 'paragraph');
$xmlWriter->writeAttribute('w:default', '1');
$xmlWriter->writeAttribute('w:styleId', 'Normal');
$xmlWriter->startElement('w:name');
$xmlWriter->writeAttribute('w:val', 'Normal');
$xmlWriter->endElement();
if (!is_null($normalStyle)) {
$this->_writeParagraphStyle($xmlWriter, $normalStyle);
}
$xmlWriter->endElement();
$this->writeDefaultStyles($xmlWriter, $styles);
// Write other styles
if (count($styles) > 0) {
foreach ($styles as $styleName => $style) {
@ -180,36 +164,65 @@ class Styles extends Base
}
/**
* Write document defaults
* Write default font and other default styles
*
* @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param array $styles
*/
private function _writeDocDefaults(XMLWriter $xmlWriter)
private function writeDefaultStyles(XMLWriter $xmlWriter, $styles)
{
$fontName = $this->_document->getDefaultFontName();
$fontSize = $this->_document->getDefaultFontSize();
$fontName = $this->phpWord->getDefaultFontName();
$fontSize = $this->phpWord->getDefaultFontSize();
// Default font
$xmlWriter->startElement('w:docDefaults');
$xmlWriter->startElement('w:rPrDefault');
$xmlWriter->startElement('w:rPr');
$xmlWriter->startElement('w:rFonts');
$xmlWriter->writeAttribute('w:ascii', $fontName);
$xmlWriter->writeAttribute('w:hAnsi', $fontName);
$xmlWriter->writeAttribute('w:eastAsia', $fontName);
$xmlWriter->writeAttribute('w:cs', $fontName);
$xmlWriter->endElement();
$xmlWriter->endElement(); // w:rFonts
$xmlWriter->startElement('w:sz');
$xmlWriter->writeAttribute('w:val', $fontSize * 2);
$xmlWriter->endElement();
$xmlWriter->endElement(); // w:sz
$xmlWriter->startElement('w:szCs');
$xmlWriter->writeAttribute('w:val', $fontSize * 2);
$xmlWriter->endElement();
$xmlWriter->endElement(); // w:szCs
$xmlWriter->endElement(); // w:rPr
$xmlWriter->endElement(); // w:rPrDefault
$xmlWriter->endElement(); // w:docDefaults
$xmlWriter->endElement();
$xmlWriter->endElement();
$xmlWriter->endElement();
// Normal style
$xmlWriter->startElement('w:style');
$xmlWriter->writeAttribute('w:type', 'paragraph');
$xmlWriter->writeAttribute('w:default', '1');
$xmlWriter->writeAttribute('w:styleId', 'Normal');
$xmlWriter->startElement('w:name');
$xmlWriter->writeAttribute('w:val', 'Normal');
$xmlWriter->endElement(); // w:name
if (array_key_exists('Normal', $styles)) {
$this->_writeParagraphStyle($xmlWriter, $styles['Normal']);
}
$xmlWriter->endElement(); // w:style
// FootnoteReference style
if (!array_key_exists('FootnoteReference', $styles)) {
$xmlWriter->startElement('w:style');
$xmlWriter->writeAttribute('w:type', 'character');
$xmlWriter->writeAttribute('w:styleId', 'FootnoteReference');
$xmlWriter->startElement('w:name');
$xmlWriter->writeAttribute('w:val', 'Footnote Reference');
$xmlWriter->endElement(); // w:name
$xmlWriter->writeElement('w:semiHidden');
$xmlWriter->writeElement('w:unhideWhenUsed');
$xmlWriter->startElement('w:rPr');
$xmlWriter->startElement('w:vertAlign');
$xmlWriter->writeAttribute('w:val', 'superscript');
$xmlWriter->endElement(); // w:vertAlign
$xmlWriter->endElement(); // w:rPr
$xmlWriter->endElement(); // w:style
}
}
}

View File

@ -19,6 +19,11 @@ use PhpOffice\PhpWord\Section\Footnote;
*/
class FootnoteTest extends \PHPUnit_Framework_TestCase
{
/**
* New instance without parameter
*
* @covers ::__construct
*/
public function testConstruct()
{
$oFootnote = new Footnote();
@ -28,6 +33,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($oFootnote->getParagraphStyle(), null);
}
/**
* New instance with string parameter
*
* @covers ::__construct
*/
public function testConstructString()
{
$oFootnote = new Footnote('pStyle');
@ -35,6 +45,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($oFootnote->getParagraphStyle(), 'pStyle');
}
/**
* New instance with array parameter
*
* @covers ::__construct
*/
public function testConstructArray()
{
$oFootnote = new Footnote(array('spacing' => 100));
@ -45,6 +60,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase
);
}
/**
* Add text element
*
* @covers ::addText
*/
public function testAddText()
{
$oFootnote = new Footnote();
@ -54,6 +74,24 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase
$this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element);
}
/**
* Add text break element
*
* @covers ::addTextBreak
*/
public function testAddTextBreak()
{
$oFootnote = new Footnote();
$oFootnote->addTextBreak(2);
$this->assertCount(2, $oFootnote->getElements());
}
/**
* Add link element
*
* @covers ::addLink
*/
public function testAddLink()
{
$oFootnote = new Footnote();
@ -63,6 +101,12 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase
$this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element);
}
/**
* Set/get reference Id
*
* @covers ::setReferenceId
* @covers ::getReferenceId
*/
public function testReferenceId()
{
$oFootnote = new Footnote();
@ -72,6 +116,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($oFootnote->getReferenceId(), $iVal);
}
/**
* Get elements
*
* @covers ::getElements
*/
public function testGetElements()
{
$oFootnote = new Footnote();

View File

@ -79,9 +79,13 @@ class BaseTest extends \PHPUnit_Framework_TestCase
{
$phpWord = new PhpWord();
$section = $phpWord->createSection();
$fontStyleArray = array('bold' => true);
$fontStyleName = 'Test';
$expected = 'PhpWord';
$section->addLink('http://github.com/phpoffice/phpword', $expected);
$section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleArray);
$section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleName);
$doc = TestHelperDOCX::getDocument($phpWord);
$element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t');
@ -97,8 +101,14 @@ class BaseTest extends \PHPUnit_Framework_TestCase
$phpWord = new PhpWord();
$section = $phpWord->createSection();
$footer = $section->createFooter();
$fontStyleArray = array('bold' => true);
$fontStyleName = 'Font';
$paragraphStyleArray = array('align' => 'right');
$paragraphStyleName = 'Paragraph';
$footer->addPreserveText('{PAGE}');
$footer->addPreserveText('Page {PAGE}');
$footer->addPreserveText('{PAGE}', $fontStyleArray, $paragraphStyleArray);
$footer->addPreserveText('{PAGE}', $fontStyleName, $paragraphStyleName);
$doc = TestHelperDOCX::getDocument($phpWord);
$preserve = $doc->getElement("w:p/w:r[2]/w:instrText", 'word/footer1.xml');
@ -193,6 +203,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase
$styles['superScript'] = true;
$styles['color'] = 'FF0000';
$styles['fgColor'] = 'yellow';
$styles['hint'] = 'eastAsia';
$section = $phpWord->createSection();
$section->addText('Test', $styles);