Adding more functionalities to containers:

- Table: Ability to add footnote in table cell
- Footnote: Ability to add image in footnote
- ListItem: Ability to add list item in header/footer
- CheckBox: Ability to add checkbox in header/footer
- Link: Ability to add link in header/footer
This commit is contained in:
Ivan Lanin 2014-04-01 15:01:30 +07:00
parent faba46cc05
commit 07be5eaea3
24 changed files with 419 additions and 302 deletions

View File

@ -14,6 +14,11 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
- Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan GH-168
- Element: New `CheckBox` element for sections and table cells - @ozilion GH-156
- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185
- Table: Ability to add footnote in table cell - @ivanlanin GH-187
- Footnote: Ability to add image in footnote - @ivanlanin GH-187
- ListItem: Ability to add list item in header/footer - @ivanlanin GH-187
- CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187
- Link: Ability to add link in header/footer - @ivanlanin GH-187
### Bugfixes
@ -24,8 +29,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
- Documentation: Simplify page level docblock - @ivanlanin GH-179
- Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160
- Reader: Rename AbstractReader > Reader - @ivanlanin
- General: Refactor folders: Element, Container, and Exception - @ivanlanin
- Container: Create new Container abstract class - @ivanlanin
- General: Refactor folders: Element, Container, and Exception - @ivanlanin GH-187
- Container: Create new Container abstract class - @ivanlanin GH-187
## 0.9.1 - 27 Mar 2014

View File

@ -28,7 +28,7 @@ $textrun->addText(' All elements are placed inside a paragraph with the optional
$textrun->addText(' Sample Link: ');
$textrun->addLink('http://www.google.com', null, 'NLink');
$textrun->addText(' Sample Image: ');
$textrun->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18));
$textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18));
$textrun->addText(' Here is some more text. ');
// Save file

View File

@ -4,6 +4,7 @@ include_once 'Sample_Header.php';
// New Word Document
echo date('H:i:s') , " Create new PhpWord object" , \EOL;
$phpWord = new \PhpOffice\PhpWord\PhpWord();
\PhpOffice\PhpWord\Settings::setCompatibility(false);
// New portrait section
$section = $phpWord->createSection();
@ -19,16 +20,16 @@ $textrun = $section->createTextRun('pStyle');
$textrun->addText('This is some lead text in a paragraph with a following footnote. ','pStyle');
$footnote = $textrun->createFootnote();
$footnote->addText('Just like a textrun a footnote can contain native text and link elements.');
$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('Just like a textrun, a footnote can contain native texts. ');
$footnote->addText('No break is placed after adding an element. ', 'BoldText');
$footnote->addText('All elements are placed inside a paragraph. ', 'ColoredText');
$footnote->addTextBreak();
$footnote->addLink('http://www.bing.com', null, 'NLink');
$textrun->addText('The trailing text in the paragraph.');
$footnote->addText('But you can insert a manual text break like above, ');
$footnote->addText('links like ');
$footnote->addLink('http://www.google.com', null, 'NLink');
$footnote->addText(', or image like ');
$footnote->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18));
$footnote->addText('But you can only put footnote in section, not in header or footer.');
$section->addText('You can also create the footnote directly from the section making it wrap in a paragraph like the footnote below this paragraph. But is is best used from within a textrun.');
$footnote = $section->createFootnote();

View File

@ -63,10 +63,21 @@ $cellVCentered = array('valign' => 'center');
$phpWord->addTableStyle('Colspan Rowspan', $styleTable);
$table = $section->addTable('Colspan Rowspan');
$table->addRow();
$table->addCell(2000, $cellRowSpan)->addText('A', null, $cellHCentered);
$table->addCell(4000, $cellColSpan)->addText('B', null, $cellHCentered);
$cell1 = $table->addCell(2000, $cellRowSpan);
$textrun1 = $cell1->addTextRun($cellHCentered);
$textrun1->addText('A');
$textrun1->addFootnote()->addText('Row span');
$cell2 = $table->addCell(4000, $cellColSpan);
$textrun2 = $cell2->addTextRun($cellHCentered);
$textrun2->addText('B');
$textrun2->addFootnote()->addText('Colspan span');
$table->addCell(2000, $cellRowSpan)->addText('E', null, $cellHCentered);
$table->addRow();
$table->addCell(null, $cellRowContinue);
$table->addCell(2000, $cellVCentered)->addText('C', null, $cellHCentered);

View File

@ -13,7 +13,10 @@ $header = $section->createHeader();
$header->firstPage();
$table = $header->addTable();
$table->addRow();
$table->addCell(4500)->addText('This is the header.');
$cell = $table->addCell(4500);
$textrun = $cell->addTextRun();
$textrun->addText('This is the header with ');
$textrun->addLink('http://google.com', 'link to Google');
$table->addCell(4500)->addImage(
'resources/PhpWord.png',
array('width' => 80, 'height' => 80, 'align' => 'right')
@ -26,6 +29,7 @@ $subsequent->addText("Subsequent pages in Section 1 will Have this!");
// Add footer
$footer = $section->createFooter();
$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', array('align' => 'center'));
$footer->addLink('http://google.com', 'Direct Google');
// Write some text
$section->addTextBreak();

View File

@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Exception\InvalidObjectException;
use PhpOffice\PhpWord\Media;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\TOC;
use PhpOffice\PhpWord\Footnote;
use PhpOffice\PhpWord\Footnote as FootnoteCollection;
use PhpOffice\PhpWord\Shared\String;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextRun;
@ -58,18 +58,22 @@ abstract class Container
protected $elements = array();
/**
* Parent container type: section|header|footer
* Document part type: section|header|footer
*
* Used by textrun and cell to determine where the element is located
* because it will affect the availability of other element, e.g. footnote
* will not be available when $docPartType is header or footer.
*
* @var string
*/
protected $parentContainer = null;
protected $docPartType = null;
/**
* Parent container Id
* Document part Id
*
* @var int
*/
protected $parentContainerId;
protected $docPartId;
/**
* Relation Id
@ -91,9 +95,7 @@ abstract class Container
if (in_array($this->containerType, array('footnote', 'textrun'))) {
$paragraphStyle = null;
}
if (!String::isUTF8($text)) {
$text = utf8_encode($text);
}
$text = String::toUTF8($text);
$element = new Text($text, $fontStyle, $paragraphStyle);
$this->elements[] = $element;
@ -125,8 +127,15 @@ abstract class Container
if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) {
throw new \BadMethodCallException();
}
if ($this->containerType == 'cell') {
$docPartType = $this->docPartType;
$docPartId = $this->docPartId;
} else {
$docPartType = $this->containerType;
$docPartId = $this->sectionId;
}
$textRun = new TextRun($paragraphStyle);
$textRun = new TextRun($paragraphStyle, $docPartType, $docPartId);
$this->elements[] = $textRun;
return $textRun;
@ -140,30 +149,27 @@ abstract class Container
* @param mixed $fontStyle
* @param mixed $paragraphStyle
* @return Link
* @todo Enable link element in header and footer
*/
public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null)
{
if (!in_array($this->containerType, array('section', 'footnote', 'textrun', 'cell'))) {
throw new \BadMethodCallException();
if (!is_null($this->docPartType)) {
$linkContainer = $this->docPartType;
$linkContainerId = $this->docPartId;
} else {
$linkContainer = $this->containerType;
$linkContainerId = $this->sectionId;
}
if ($this->containerType == 'cell' && $this->parentContainer != 'section') {
throw new \BadMethodCallException();
if ($linkContainer == 'header' || $linkContainer == 'footer') {
$linkContainer .= $linkContainerId;
}
if (!String::isUTF8($linkSrc)) {
$linkSrc = utf8_encode($linkSrc);
}
if (!is_null($linkName)) {
if (!String::isUTF8($linkName)) {
$linkName = utf8_encode($linkName);
}
}
$linkSrc = String::toUTF8($linkSrc);
$linkName = String::toUTF8($linkName);
$link = new Link($linkSrc, $linkName, $fontStyle, $paragraphStyle);
if ($this->containerType == 'footnote') {
$rID = Footnote::addFootnoteLinkElement($linkSrc);
} else {
if ($linkContainer == 'section') {
$rID = Media::addSectionLinkElement($linkSrc);
} else {
$rID = Media::addMediaElement($linkContainer, 'hyperlink', $linkSrc);
}
$link->setRelationId($rID);
$this->elements[] = $link;
@ -181,13 +187,11 @@ abstract class Container
*/
public function addTitle($text, $depth = 1)
{
if ($this->containerType != 'section') {
if (!in_array($this->containerType, array('section'))) {
throw new \BadMethodCallException();
}
if (!String::isUTF8($text)) {
$text = utf8_encode($text);
}
$text = String::toUTF8($text);
$styles = Style::getStyles();
if (array_key_exists('Heading_' . $depth, $styles)) {
$style = 'Heading' . $depth;
@ -218,13 +222,11 @@ abstract class Container
if (!in_array($this->containerType, array('header', 'footer', 'cell'))) {
throw new \BadMethodCallException();
}
if ($this->containerType == 'cell' && $this->parentContainer == 'section') {
if ($this->containerType == 'cell' && $this->docPartType == 'section') {
throw new \BadMethodCallException();
}
if (!String::isUTF8($text)) {
$text = utf8_encode($text);
}
$text = String::toUTF8($text);
$ptext = new PreserveText($text, $fontStyle, $paragraphStyle);
$this->elements[] = $ptext;
@ -244,16 +246,11 @@ abstract class Container
*/
public function addListItem($text, $depth = 0, $fontStyle = null, $styleList = null, $paragraphStyle = null)
{
if (!in_array($this->containerType, array('section', 'cell'))) {
throw new \BadMethodCallException();
}
if ($this->containerType == 'cell' && $this->parentContainer != 'section') {
if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) {
throw new \BadMethodCallException();
}
if (!String::isUTF8($text)) {
$text = utf8_encode($text);
}
$text = String::toUTF8($text);
$listItem = new ListItem($text, $depth, $fontStyle, $styleList, $paragraphStyle);
$this->elements[] = $listItem;
@ -288,12 +285,9 @@ abstract class Container
*/
public function addImage($src, $style = null, $isWatermark = false)
{
if ($this->containerType == 'footnote') {
throw new \BadMethodCallException();
}
if (!is_null($this->parentContainer)) {
$imageContainerType = $this->parentContainer;
$imageContainerId = $this->parentContainerId;
if ($this->containerType == 'cell') {
$imageContainerType = $this->docPartType;
$imageContainerId = $this->docPartId;
} else {
$imageContainerType = $this->containerType;
$imageContainerId = $this->sectionId;
@ -301,6 +295,7 @@ abstract class Container
$image = new Image($src, $style, $isWatermark);
if (!is_null($image->getSource())) {
$rID = null;
switch ($imageContainerType) {
case 'textrun':
case 'section':
@ -312,6 +307,9 @@ abstract class Container
case 'footer':
$rID = Media::addFooterMediaElement($imageContainerId, $src, $image);
break;
case 'footnote':
$rID = Media::addMediaElement('footnotes', 'image', $src, $image);
break;
}
$image->setRelationId($rID);
$this->elements[] = $image;
@ -336,7 +334,7 @@ abstract class Container
if (!in_array($this->containerType, array('section', 'cell'))) {
throw new \BadMethodCallException();
}
if ($this->containerType == 'cell' && $this->parentContainer != 'section') {
if ($this->containerType == 'cell' && $this->docPartType != 'section') {
throw new \BadMethodCallException();
}
@ -367,18 +365,21 @@ abstract class Container
*
* @param mixed $paragraphStyle
* @return FootnoteElement
* @todo Enable footnote element in header and footer
*/
public function addFootnote($paragraphStyle = null)
{
if (!in_array($this->containerType, array('section', 'textrun'))) {
if (!in_array($this->containerType, array('section', 'textrun', 'cell'))) {
throw new \BadMethodCallException();
}
if (!is_null($this->docPartType) && $this->docPartType != 'section') {
throw new \BadMethodCallException();
}
$footnote = new FootnoteElement($paragraphStyle);
$refID = Footnote::addFootnoteElement($footnote);
$refID = FootnoteCollection::addFootnoteElement($footnote);
$footnote->setReferenceId($refID);
$this->elements[] = $footnote;
return $footnote;
}
@ -394,19 +395,15 @@ abstract class Container
*/
public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null)
{
if (!in_array($this->containerType, array('section', 'cell'))) {
if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) {
throw new \BadMethodCallException();
}
if ($this->containerType == 'cell' && $this->parentContainer != 'section') {
if ($this->containerType == 'cell' && $this->docPartType != 'section') {
throw new \BadMethodCallException();
}
if (!String::isUTF8($name)) {
$name = utf8_encode($name);
}
if (!String::isUTF8($text)) {
$text = utf8_encode($text);
}
$name = String::toUTF8($name);
$text = String::toUTF8($text);
$element = new CheckBox($name, $text, $fontStyle, $paragraphStyle);
$this->elements[] = $element;

View File

@ -39,7 +39,6 @@ class Footnote extends Container
public function __construct($paragraphStyle = null)
{
$this->containerType = 'footnote';
// Set paragraph style
if (is_array($paragraphStyle)) {
$this->paragraphStyle = new Paragraph();

View File

@ -34,17 +34,16 @@ class Cell extends Container
/**
* Create new instance
*
* @param string $parentType section|header|footer
* @param int $parentId
* @param string $docPartType section|header|footer
* @param int $docPartId
* @param int $width
* @param array|CellStyle $style
*/
public function __construct($parentType, $parentId, $width = null, $style = null)
public function __construct($docPartType, $docPartId, $width = null, $style = null)
{
$this->containerType = 'cell';
$this->parentContainer = $parentType;
$this->parentContainerId = $parentId;
$this->docPartType = $docPartType;
$this->docPartId = $docPartId;
$this->width = $width;
$this->cellStyle = new CellStyle();

View File

@ -28,11 +28,14 @@ class TextRun extends Container
* Create new instance
*
* @param string|array|Paragraph $paragraphStyle
* @param string $docPartType section|header|footer
* @param int $docPartId
*/
public function __construct($paragraphStyle = null)
public function __construct($paragraphStyle = null, $docPartType = 'section', $docPartId = 1)
{
$this->containerType = 'textrun';
$this->docPartType = $docPartType;
$this->docPartId = $docPartId;
// Set paragraph style
if (is_array($paragraphStyle)) {
$this->paragraphStyle = new Paragraph();

View File

@ -9,35 +9,32 @@
namespace PhpOffice\PhpWord;
use PhpOffice\PhpWord\Media;
use PhpOffice\PhpWord\Element\Footnote as FootnoteElement;
/**
* Footnote
*/
class Footnote
{
/**
* Footnote Elements
* Footnote elements
*
* @var array
*/
private static $_footnoteCollection = array();
private static $elements = array();
/**
* Footnote Link Elements
*
* @var array
*/
private static $_footnoteLink = array();
/**
* Add new Footnote Element
* Add new footnote
*
* @param FootnoteElement $footnote
* @return int Reference ID
*/
public static function addFootnoteElement(\PhpOffice\PhpWord\Element\Footnote $footnote)
public static function addFootnoteElement(FootnoteElement $footnote)
{
$refID = self::countFootnoteElements() + 2;
$refID = self::countFootnoteElements() + 1;
self::$_footnoteCollection[] = $footnote;
self::$elements[] = $footnote;
return $refID;
}
@ -49,7 +46,7 @@ class Footnote
*/
public static function getFootnoteElements()
{
return self::$_footnoteCollection;
return self::$elements;
}
/**
@ -59,47 +56,29 @@ class Footnote
*/
public static function countFootnoteElements()
{
return count(self::$_footnoteCollection);
return count(self::$elements);
}
/**
* Add new Footnote Link Element
*
* @param string $linkSrc
*
* @return int Reference ID
* @deprecated 0.9.2
*/
public static function addFootnoteLinkElement($linkSrc)
{
$rID = self::countFootnoteLinkElements() + 1;
$link = array();
$link['target'] = $linkSrc;
$link['rID'] = $rID;
$link['type'] = 'hyperlink';
self::$_footnoteLink[] = $link;
return $rID;
return Media::addMediaElement('footnotes', 'hyperlink', $linkSrc);
}
/**
* Get Footnote Link Elements
*
* @return array
* @deprecated 0.9.2
*/
public static function getFootnoteLinkElements()
{
return self::$_footnoteLink;
}
/**
* Get Footnote Link Elements Count
*
* @return int
*/
public static function countFootnoteLinkElements()
{
return count(self::$_footnoteLink);
return Media::getMediaElements('footnotes', 'hyperlink');
}
}

View File

@ -21,7 +21,7 @@ class Media
*
* @var array
*/
private static $_sectionMedia = array(
private static $sectionMedia = array(
'images' => array(),
'embeddings' => array(),
'links' => array()
@ -32,35 +32,42 @@ class Media
*
* @var array
*/
private static $_headerMedia = array();
private static $headerMedia = array();
/**
* Footer Media Elements
*
* @var array
*/
private static $_footerMedia = array();
private static $footerMedia = array();
/**
* Media elements
*
* @var array
*/
private static $media = array();
/**
* ObjectID Counter
*
* @var int
*/
private static $_objectId = 1325353440;
private static $objectId = 1325353440;
/**
* Add new Section Media Element
*
* @param string $src
* @param string $type
* @param \PhpOffice\PhpWord\Element\Image $image
* @param Image $image
* @return mixed
*/
public static function addSectionMediaElement($src, $type, Image $image = null)
{
$mediaId = md5($src);
$key = ($type === 'image') ? 'images' : 'embeddings';
if (!array_key_exists($mediaId, self::$_sectionMedia[$key])) {
if (!array_key_exists($mediaId, self::$sectionMedia[$key])) {
$cImg = self::countSectionMediaElements('images');
$cObj = self::countSectionMediaElements('embeddings');
$rID = self::countSectionMediaElements() + 7;
@ -90,17 +97,17 @@ class Media
$media['target'] = "$folder/section_$file";
$media['type'] = $type;
$media['rID'] = $rID;
self::$_sectionMedia[$key][$mediaId] = $media;
self::$sectionMedia[$key][$mediaId] = $media;
if ($type === 'oleObject') {
return array($rID, ++self::$_objectId);
return array($rID, ++self::$objectId);
}
return $rID;
} else {
if ($type === 'oleObject') {
$rID = self::$_sectionMedia[$key][$mediaId]['rID'];
return array($rID, ++self::$_objectId);
$rID = self::$sectionMedia[$key][$mediaId]['rID'];
return array($rID, ++self::$objectId);
}
return self::$_sectionMedia[$key][$mediaId]['rID'];
return self::$sectionMedia[$key][$mediaId]['rID'];
}
}
@ -119,7 +126,7 @@ class Media
$link['rID'] = $rID;
$link['type'] = 'hyperlink';
self::$_sectionMedia['links'][] = $link;
self::$sectionMedia['links'][] = $link;
return $rID;
}
@ -133,12 +140,12 @@ class Media
public static function getSectionMediaElements($key = null)
{
if (!is_null($key)) {
return self::$_sectionMedia[$key];
return self::$sectionMedia[$key];
}
$arrImages = self::$_sectionMedia['images'];
$arrObjects = self::$_sectionMedia['embeddings'];
$arrLinks = self::$_sectionMedia['links'];
$arrImages = self::$sectionMedia['images'];
$arrObjects = self::$sectionMedia['embeddings'];
$arrLinks = self::$sectionMedia['links'];
return array_merge($arrImages, $arrObjects, $arrLinks);
}
@ -151,12 +158,12 @@ class Media
public static function countSectionMediaElements($key = null)
{
if (!is_null($key)) {
return count(self::$_sectionMedia[$key]);
return count(self::$sectionMedia[$key]);
}
$cImages = count(self::$_sectionMedia['images']);
$cObjects = count(self::$_sectionMedia['embeddings']);
$cLinks = count(self::$_sectionMedia['links']);
$cImages = count(self::$sectionMedia['images']);
$cObjects = count(self::$sectionMedia['embeddings']);
$cLinks = count(self::$sectionMedia['links']);
return ($cImages + $cObjects + $cLinks);
}
@ -165,41 +172,12 @@ class Media
*
* @param int $headerCount
* @param string $src
* @param \PhpOffice\PhpWord\Element\Image $image
* @param Image $image
* @return int
*/
public static function addHeaderMediaElement($headerCount, $src, Image $image = null)
{
$mediaId = md5($src);
$key = 'header' . $headerCount;
if (!array_key_exists($key, self::$_headerMedia)) {
self::$_headerMedia[$key] = array();
}
if (!array_key_exists($mediaId, self::$_headerMedia[$key])) {
$cImg = self::countHeaderMediaElements($key);
$rID = $cImg + 1;
$cImg++;
$media = array();
$isMemImage = false;
if (!is_null($image)) {
$isMemImage = $image->getIsMemImage();
$extension = $image->getImageExtension();
}
if ($isMemImage) {
$media['isMemImage'] = true;
$media['createfunction'] = $image->getImageCreateFunction();
$media['imagefunction'] = $image->getImageFunction();
}
$file = 'image' . $cImg . '.' . strtolower($extension);
$media['source'] = $src;
$media['target'] = 'media/' . $key . '_' . $file;
$media['type'] = 'image';
$media['rID'] = $rID;
self::$_headerMedia[$key][$mediaId] = $media;
return $rID;
} else {
return self::$_headerMedia[$key][$mediaId]['rID'];
}
return self::addMediaElement("header{$headerCount}", 'image', $src, $image);
}
/**
@ -210,17 +188,26 @@ class Media
*/
public static function countHeaderMediaElements($key)
{
return count(self::$_headerMedia[$key]);
return self::countMediaElements($key);
}
/**
* Get Header Media Elements
*
* @return int
* @return array
*/
public static function getHeaderMediaElements()
public static function getHeaderMediaElements($prefix = 'header')
{
return self::$_headerMedia;
$mediaCollection = array();
if (!empty(self::$media)) {
foreach (self::$media as $key => $val) {
if (substr($key, 0, 6) == $prefix) {
$mediaCollection[$key] = $val;
}
}
}
return $mediaCollection;
}
/**
@ -228,41 +215,12 @@ class Media
*
* @param int $footerCount
* @param string $src
* @param \PhpOffice\PhpWord\Element\Image $image
* @param Image $image
* @return int
*/
public static function addFooterMediaElement($footerCount, $src, Image $image = null)
{
$mediaId = md5($src);
$key = 'footer' . $footerCount;
if (!array_key_exists($key, self::$_footerMedia)) {
self::$_footerMedia[$key] = array();
}
if (!array_key_exists($mediaId, self::$_footerMedia[$key])) {
$cImg = self::countFooterMediaElements($key);
$rID = $cImg + 1;
$cImg++;
$media = array();
$isMemImage = false;
if (!is_null($image)) {
$isMemImage = $image->getIsMemImage();
$extension = $image->getImageExtension();
}
if ($isMemImage) {
$media['isMemImage'] = true;
$media['createfunction'] = $image->getImageCreateFunction();
$media['imagefunction'] = $image->getImageFunction();
}
$file = 'image' . $cImg . '.' . strtolower($extension);
$media['source'] = $src;
$media['target'] = 'media/' . $key . '_' . $file;
$media['type'] = 'image';
$media['rID'] = $rID;
self::$_footerMedia[$key][$mediaId] = $media;
return $rID;
} else {
return self::$_footerMedia[$key][$mediaId]['rID'];
}
return self::addMediaElement("footer{$footerCount}", 'image', $src, $image);
}
/**
@ -273,16 +231,120 @@ class Media
*/
public static function countFooterMediaElements($key)
{
return count(self::$_footerMedia[$key]);
return self::countMediaElements($key);
}
/**
* Get Footer Media Elements
*
* @return int
* @return array
*/
public static function getFooterMediaElements()
{
return self::$_footerMedia;
return self::getHeaderMediaElements('footer');
}
/**
* Add new media element
*
* @param string $container section|header|footer|footnotes
* @param string $mediaType image|embedding|hyperlink
* @param string $source
* @param Image $image
* @return int
*/
public static function addMediaElement($container, $mediaType, $source, Image $image = null)
{
// Assign media Id and initiate media container if none exists
$mediaId = md5($source);
if (!array_key_exists($container, self::$media)) {
self::$media[$container]= array();
}
// Add media if not exists or point to existing media
if (!array_key_exists($mediaId, self::$media[$container])) {
$mediaCount = self::countMediaElements($container);
$mediaTypeCount = self::countMediaElements($container, $mediaType);
$mediaData = array();
$relId = $mediaCount + 1;
$mediaTypeCount++;
if ($mediaType == 'image') {
$isMemImage = false;
if (!is_null($image)) {
$isMemImage = $image->getIsMemImage();
$extension = $image->getImageExtension();
}
if ($isMemImage) {
$mediaData['isMemImage'] = true;
$mediaData['createfunction'] = $image->getImageCreateFunction();
$mediaData['imagefunction'] = $image->getImageFunction();
}
$file = 'image' . $mediaTypeCount . '.' . strtolower($extension);
if ($container != 'footnotes') {
$file = $container . '_' . $file;
}
$target = 'media/' . $file;
} elseif ($mediaType == 'hyperlink') {
$target = $source;
}
$mediaData['source'] = $source;
$mediaData['target'] = $target;
$mediaData['type'] = $mediaType;
$mediaData['rID'] = $relId;
self::$media[$container][$mediaId] = $mediaData;
return $relId;
} else {
return self::$media[$container][$mediaId]['rID'];
}
}
/**
* Get media elements count
*
* @param string $container
* @param string $mediaType
* @return int
*/
public static function countMediaElements($container, $mediaType = null)
{
$mediaCount = 0;
foreach (self::$media[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
$mediaCount++;
}
} else {
$mediaCount++;
}
}
return $mediaCount;
}
/**
* Get media elements
*
* @param string $container
* @return int
*/
public static function getMediaElements($container, $mediaType = null)
{
if (!array_key_exists($container, self::$media)) {
return false;
}
$mediaElements = array();
foreach (self::$media[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
$mediaElements[$mediaKey] = $mediaData;
}
} else {
$mediaElements[$mediaKey] = $mediaData;
}
}
return $mediaElements;
}
}

View File

@ -194,7 +194,7 @@ class Word2007 extends Reader implements IReader
);
// w:r more than 1? It's a textrun
} else {
$textRun = $section->createTextRun();
$textRun = $section->addTextRun();
foreach ($elm->r as $r) {
$textRun->addText(
$r->t,

View File

@ -91,4 +91,19 @@ class String
{
return $value === '' || preg_match('/^./su', $value) === 1;
}
/**
* Return UTF8 encoded value
*
* @param string $value
* @return string
*/
public static function toUTF8($value = '')
{
if (!is_null($value) && !self::isUTF8($value)) {
$value = utf8_encode($value);
}
return $value;
}
}

View File

@ -24,6 +24,8 @@ if (!defined('DATE_W3C')) {
* @method bool startElement(string $name)
* @method bool writeAttribute(string $name, string $value)
* @method bool endElement()
* @method bool startDocument(string $version = 1.0, string $encoding = null, string $standalone = null)
* @method bool text(string $content)
*/
class XMLWriter
{

View File

@ -102,6 +102,7 @@ class Word2007 extends Writer implements IWriter
}
}
// Add section elements
$sectionElements = array();
$_secElements = Media::getSectionMediaElements();
foreach ($_secElements as $element) { // loop through section media elements
@ -111,67 +112,94 @@ class Word2007 extends Writer implements IWriter
$sectionElements[] = $element;
}
$_hdrElements = Media::getHeaderMediaElements();
foreach ($_hdrElements as $_headerFile => $_hdrMedia) { // loop through headers
if (count($_hdrMedia) > 0) {
$objZip->addFromString('word/_rels/' . $_headerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_hdrMedia));
foreach ($_hdrMedia as $element) { // loop through header media elements
// Add header relations & elements
$hdrElements = Media::getHeaderMediaElements();
foreach ($hdrElements as $hdrFile => $hdrMedia) {
if (count($hdrMedia) > 0) {
$objZip->addFromString(
'word/_rels/' . $hdrFile . '.xml.rels',
$this->getWriterPart('documentrels')->writeHeaderFooterRels($hdrMedia)
);
foreach ($hdrMedia as $element) {
if ($element['type'] == 'image') {
$this->addFileToPackage($objZip, $element);
}
}
}
}
$_ftrElements = Media::getFooterMediaElements();
foreach ($_ftrElements as $_footerFile => $_ftrMedia) { // loop through footers
if (count($_ftrMedia) > 0) {
$objZip->addFromString('word/_rels/' . $_footerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_ftrMedia));
foreach ($_ftrMedia as $element) { // loop through footers media elements
// Add footer relations & elements
$ftrElements = Media::getFooterMediaElements();
foreach ($ftrElements as $ftrFile => $ftrMedia) {
if (count($ftrMedia) > 0) {
$objZip->addFromString(
'word/_rels/' . $ftrFile . '.xml.rels',
$this->getWriterPart('documentrels')->writeHeaderFooterRels($ftrMedia)
);
foreach ($ftrMedia as $element) {
if ($element['type'] == 'image') {
$this->addFileToPackage($objZip, $element);
}
}
}
$footnoteLinks = array();
$_footnoteElements = Footnote::getFootnoteLinkElements();
// loop through footnote link elements
foreach ($_footnoteElements as $element) {
$footnoteLinks[] = $element;
}
// Process header/footer xml files
$_cHdrs = 0;
$_cFtrs = 0;
$rID = Media::countSectionMediaElements() + 6;
$_sections = $this->phpWord->getSections();
$footers = array();
foreach ($_sections as $section) {
$_headers = $section->getHeaders();
foreach ($_headers as $index => &$_header) {
$_cHdrs++;
$_header->setRelationId(++$rID);
$_headerFile = 'header' . $_cHdrs . '.xml';
$sectionElements[] = array('target' => $_headerFile, 'type' => 'header', 'rID' => $rID);
$objZip->addFromString('word/' . $_headerFile, $this->getWriterPart('header')->writeHeader($_header));
$hdrFile = 'header' . $_cHdrs . '.xml';
$sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID);
$objZip->addFromString(
'word/' . $hdrFile,
$this->getWriterPart('header')->writeHeader($_header)
);
}
$_footer = $section->getFooter();
$footers[++$_cFtrs] = $_footer;
if (!is_null($_footer)) {
$_footer->setRelationId(++$rID);
$_footerCount = $_footer->getSectionId();
$_footerFile = 'footer' . $_footerCount . '.xml';
$sectionElements[] = array('target' => $_footerFile, 'type' => 'footer', 'rID' => $rID);
$objZip->addFromString('word/' . $_footerFile, $this->getWriterPart('footer')->writeFooter($_footer));
$ftrFile = 'footer' . $_footerCount . '.xml';
$sectionElements[] = array('target' => $ftrFile, 'type' => 'footer', 'rID' => $rID);
$objZip->addFromString(
'word/' . $ftrFile,
$this->getWriterPart('footer')->writeFooter($_footer)
);
}
}
// Process footnotes
if (Footnote::countFootnoteElements() > 0) {
$_allFootnotesCollection = Footnote::getFootnoteElements();
$_footnoteFile = 'footnotes.xml';
$sectionElements[] = array('target'=>$_footnoteFile, 'type'=>'footnotes', 'rID'=>++$rID);
$objZip->addFromString('word/'.$_footnoteFile, $this->getWriterPart('footnotes')->writeFootnotes($_allFootnotesCollection));
if (count($footnoteLinks) > 0) {
$objZip->addFromString('word/_rels/footnotes.xml.rels', $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnoteLinks));
// Push to document.xml.rels
$sectionElements[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID);
// Add footnote media to package
$footnotesMedia = Media::getMediaElements('footnotes');
if (!empty($footnotesMedia)) {
foreach ($footnotesMedia as $media) {
if ($media['type'] == 'image') {
$this->addFileToPackage($objZip, $media);
}
}
}
// Write footnotes.xml
$objZip->addFromString(
"word/footnotes.xml",
$this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements())
);
// Write footnotes.xml.rels
if (!empty($footnotesMedia)) {
$objZip->addFromString(
'word/_rels/footnotes.xml.rels',
$this->getWriterPart('footnotesrels')->writeFootnotesRels($footnotesMedia)
);
}
}

View File

@ -90,12 +90,12 @@ class Base extends WriterPart
$this->writeText($xmlWriter, $element, true);
} elseif ($element instanceof Link) {
$this->writeLink($xmlWriter, $element, true);
} elseif ($element instanceof TextBreak) {
$xmlWriter->writeElement('w:br');
} elseif ($element instanceof Image) {
$this->writeImage($xmlWriter, $element, true);
} elseif ($element instanceof Footnote) {
$this->writeFootnote($xmlWriter, $element, true);
} elseif ($element instanceof TextBreak) {
$xmlWriter->writeElement('w:br');
}
}
}
@ -434,6 +434,8 @@ class Base extends WriterPart
$this->writeTextRun($xmlWriter, $element);
} elseif ($element instanceof Link) {
$this->writeLink($xmlWriter, $element);
} elseif ($element instanceof PreserveText) {
$this->writePreserveText($xmlWriter, $element);
} elseif ($element instanceof TextBreak) {
$this->writeTextBreak($xmlWriter, $element);
} elseif ($element instanceof ListItem) {
@ -442,8 +444,6 @@ class Base extends WriterPart
$this->writeImage($xmlWriter, $element);
} elseif ($element instanceof Object) {
$this->writeObject($xmlWriter, $element);
} elseif ($element instanceof PreserveText) {
$this->writePreserveText($xmlWriter, $element);
} elseif ($element instanceof CheckBox) {
$this->writeCheckBox($xmlWriter, $element);
}
@ -493,7 +493,6 @@ class Base extends WriterPart
$xmlWriter->endElement();
}
}
$xmlWriter->startElement('w:r');
$xmlWriter->startElement('w:pict');
@ -995,7 +994,6 @@ class Base extends WriterPart
if ($margins) {
$xmlWriter->startElement('w:tblCellMar');
if ($mTop) {
echo $margins[0];
$xmlWriter->startElement('w:top');
$xmlWriter->writeAttribute('w:w', $cellMargin[0]);
$xmlWriter->writeAttribute('w:type', 'dxa');

View File

@ -10,23 +10,23 @@
namespace PhpOffice\PhpWord\Writer\Word2007;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\TOC;
use PhpOffice\PhpWord\Container\Section;
use PhpOffice\PhpWord\Element\Footnote;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\Link;
use PhpOffice\PhpWord\Element\ListItem;
use PhpOffice\PhpWord\Element\Object;
use PhpOffice\PhpWord\Element\PageBreak;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Element\Link;
use PhpOffice\PhpWord\Element\Title;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Element\PageBreak;
use PhpOffice\PhpWord\Element\ListItem;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\Object;
use PhpOffice\PhpWord\Element\Footnote;
use PhpOffice\PhpWord\Element\CheckBox;
use PhpOffice\PhpWord\Shared\XMLWriter;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\TOC;
/**
* Word2007 document part writer
@ -83,10 +83,10 @@ class Document extends Base
$this->writeTextBreak($xmlWriter, $element);
} elseif ($element instanceof PageBreak) {
$this->writePageBreak($xmlWriter);
} elseif ($element instanceof Table) {
$this->writeTable($xmlWriter, $element);
} elseif ($element instanceof ListItem) {
$this->writeListItem($xmlWriter, $element);
} elseif ($element instanceof Table) {
$this->writeTable($xmlWriter, $element);
} elseif ($element instanceof Image) {
$this->writeImage($xmlWriter, $element);
} elseif ($element instanceof Object) {

View File

@ -127,12 +127,14 @@ class DocumentRels extends Base
$relationType = $relation['type'];
$relationName = $relation['target'];
$relationId = $relation['rID'];
$targetMode = ($relationType == 'hyperlink') ? 'External' : '';
$this->writeRelationship(
$xmlWriter,
$relationId,
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType,
$relationName
$relationName,
$targetMode
);
}

View File

@ -9,13 +9,16 @@
namespace PhpOffice\PhpWord\Writer\Word2007;
use PhpOffice\PhpWord\Element\PreserveText;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Container\Footer as FooterElement;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Element\Link;
use PhpOffice\PhpWord\Element\PreserveText;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Element\ListItem;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\CheckBox;
use PhpOffice\PhpWord\Shared\XMLWriter;
/**
@ -54,14 +57,20 @@ class Footer extends Base
$this->writeText($xmlWriter, $element);
} elseif ($element instanceof TextRun) {
$this->writeTextRun($xmlWriter, $element);
} elseif ($element instanceof Link) {
$this->writeLink($xmlWriter, $element);
} elseif ($element instanceof PreserveText) {
$this->writePreserveText($xmlWriter, $element);
} elseif ($element instanceof TextBreak) {
$this->writeTextBreak($xmlWriter, $element);
} elseif ($element instanceof ListItem) {
$this->writeListItem($xmlWriter, $element);
} elseif ($element instanceof Table) {
$this->writeTable($xmlWriter, $element);
} elseif ($element instanceof Image) {
$this->writeImage($xmlWriter, $element);
} elseif ($element instanceof PreserveText) {
$this->writePreserveText($xmlWriter, $element);
} elseif ($element instanceof CheckBox) {
$this->writeCheckBox($xmlWriter, $element);
}
}

View File

@ -12,6 +12,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007;
use PhpOffice\PhpWord\Element\Footnote;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\Link;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\Shared\XMLWriter;
@ -34,17 +35,20 @@ class Footnotes extends Base
// 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'
);
$xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006');
$xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');
$xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');
$xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');
$xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing');
$xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word');
$xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
$xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml');
// Separator and continuation separator
$xmlWriter->startElement('w:footnote');
$xmlWriter->writeAttribute('w:id', 0);
$xmlWriter->writeAttribute('w:id', -1);
$xmlWriter->writeAttribute('w:type', 'separator');
$xmlWriter->startElement('w:p');
$xmlWriter->startElement('w:r');
@ -53,9 +57,8 @@ 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:id', 0);
$xmlWriter->writeAttribute('w:type', 'continuationSeparator');
$xmlWriter->startElement('w:p');
$xmlWriter->startElement('w:r');
@ -64,6 +67,7 @@ class Footnotes extends Base
$xmlWriter->endElement(); // w:r
$xmlWriter->endElement(); // w:p
$xmlWriter->endElement(); // w:footnote
// Content
foreach ($allFootnotesCollection as $footnote) {
if ($footnote instanceof Footnote) {
$this->writeFootnote($xmlWriter, $footnote);
@ -113,6 +117,8 @@ class Footnotes extends Base
$this->writeText($xmlWriter, $element, true);
} elseif ($element instanceof Link) {
$this->writeLink($xmlWriter, $element, true);
} elseif ($element instanceof Image) {
$this->writeImage($xmlWriter, $element, true);
} elseif ($element instanceof TextBreak) {
$xmlWriter->writeElement('w:br');
}

View File

@ -9,13 +9,16 @@
namespace PhpOffice\PhpWord\Writer\Word2007;
use PhpOffice\PhpWord\Element\PreserveText;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Container\Header as HeaderElement;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Element\Link;
use PhpOffice\PhpWord\Element\PreserveText;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Element\ListItem;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\CheckBox;
use PhpOffice\PhpWord\Shared\XMLWriter;
/**
@ -47,7 +50,6 @@ class Header extends Base
$xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
$xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml');
$_elements = $header->getElements();
foreach ($_elements as $element) {
@ -55,8 +57,14 @@ class Header extends Base
$this->writeText($xmlWriter, $element);
} elseif ($element instanceof TextRun) {
$this->writeTextRun($xmlWriter, $element);
} elseif ($element instanceof Link) {
$this->writeLink($xmlWriter, $element);
} elseif ($element instanceof PreserveText) {
$this->writePreserveText($xmlWriter, $element);
} elseif ($element instanceof TextBreak) {
$this->writeTextBreak($xmlWriter, $element);
} elseif ($element instanceof ListItem) {
$this->writeListItem($xmlWriter, $element);
} elseif ($element instanceof Table) {
$this->writeTable($xmlWriter, $element);
} elseif ($element instanceof Image) {
@ -65,8 +73,8 @@ class Header extends Base
} else {
$this->writeWatermark($xmlWriter, $element);
}
} elseif ($element instanceof PreserveText) {
$this->writePreserveText($xmlWriter, $element);
} elseif ($element instanceof CheckBox) {
$this->writeCheckBox($xmlWriter, $element);
}
}

View File

@ -90,16 +90,6 @@ class CellTest extends \PHPUnit_Framework_TestCase
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
}
/**
* Add link exception
* @expectedException \BadMethodCallException
*/
public function testAddLinkException()
{
$oCell = new Cell('header', 1);
$element = $oCell->addLink('http://google.com', 'Google');
}
/**
* Add text break
*/

View File

@ -27,9 +27,8 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase
$rIdFootnote = Footnote::addFootnoteElement($footnoteElement);
$rIdLink = Footnote::addFootnoteLinkElement('http://test.com');
$this->assertEquals(2, $rIdFootnote);
$this->assertEquals(1, $rIdFootnote);
$this->assertEquals(1, $rIdLink);
$this->assertEquals(1, count(Footnote::getFootnoteElements()));
$this->assertEquals(1, count(Footnote::getFootnoteLinkElements()));
}
}

View File

@ -43,7 +43,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase
{
$this->assertAttributeEquals(
Media::getHeaderMediaElements(),
'_headerMedia',
'headerMedia',
'PhpOffice\\PhpWord\\Media'
);
}
@ -55,7 +55,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase
{
$this->assertAttributeEquals(
Media::getFooterMediaElements(),
'_footerMedia',
'footerMedia',
'PhpOffice\\PhpWord\\Media'
);
}