Refactor Media, addObject to header and footer

This commit is contained in:
Ivan Lanin 2014-04-04 00:29:57 +07:00
parent 0fc1a06267
commit b75403f9a1
15 changed files with 381 additions and 545 deletions

View File

@ -20,7 +20,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
- 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
- Object: Ability to add object in textrun and footnote - @ivanlanin GH-187
- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187
### Bugfixes
@ -35,6 +35,9 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
- `createSection` replaced by `addSection`
- `Element\Footnote::getReferenceId` replaced by `Container\Container::getRelationId`
- `Element\Footnote::setReferenceId` replaced by `Container\Container::setRelationId`
- `Footnote::addFootnoteLinkElement` replaced by `Media::addMediaElement`
- `Footnote::getFootnoteLinkElements` replaced by `Media::getMediaElements`
- All current methods on `Media`
### Miscellaneous
@ -45,6 +48,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
- General: Remove legacy HashTable and ZipStreamWrapper and all related properties/methods - @ivanlanin GH-187
- Container: Create new Container abstract class - @ivanlanin GH-187
- Element: Create new Element abstract class - @ivanlanin GH-187
- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187
## 0.9.1 - 27 Mar 2014

View File

@ -31,7 +31,7 @@ the containers while the rows lists the elements.
+-----+---------------+---------+--------+--------+------+----------+----------+
| 11 | Watermark | \- | v | \- | \- | \- | \- |
+-----+---------------+---------+--------+--------+------+----------+----------+
| 12 | Object | v | ? | ? | v | v | v |
| 12 | Object | v | v | v | v | v | v |
+-----+---------------+---------+--------+--------+------+----------+----------+
| 13 | TOC | v | \- | \- | \- | \- | \- |
+-----+---------------+---------+--------+--------+------+----------+----------+

View File

@ -3,7 +3,7 @@ include_once 'Sample_Header.php';
if (!CLI) {
?>
<div class="jumbotron">
<p>Welcome to PHPWord, a library written in pure PHP that provides a set of classes to write to and read from different document file formats, i.e. Word (.docx), WordPad (.rtf), and Libre/OpenOffice Writer (.odt).</p>
<p>Welcome to PHPWord, a pure PHP library for reading and writing word processing documents, i.e. Word (.docx), WordPad (.rtf), and Libre/OpenOffice Writer (.odt).</p>
<p>Please use the menu above to browse PHPWord samples.</p>
<p>
<a class="btn btn-lg btn-primary" href="https://github.com/PHPOffice/PHPWord" role="button">Fork us on Github!</a>

View File

@ -143,30 +143,12 @@ abstract class Container extends Element
public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null)
{
$this->checkValidity('link');
$inSection = true;
if (!is_null($this->docPart)) {
$container = $this->docPart;
$containerId = $this->docPartId;
} else {
$container = $this->container;
$containerId = $this->containerId;
}
if ($container == 'header' || $container == 'footer') {
$container .= $containerId;
$inSection = false;
} elseif ($container == 'footnote') {
$inSection = false;
}
$elementDocPart = $this->checkElementDocPart();
$linkSrc = String::toUTF8($linkSrc);
$linkName = String::toUTF8($linkName);
$link = new Link($linkSrc, $linkName, $fontStyle, $paragraphStyle);
if ($inSection) {
$rID = Media::addSectionLinkElement($linkSrc);
} else {
$rID = Media::addMediaElement($container, 'hyperlink', $linkSrc);
}
$rID = Media::addMediaElement($elementDocPart, 'link', $linkSrc);
$link->setRelationId($rID);
$this->elements[] = $link;
@ -286,32 +268,11 @@ abstract class Container extends Element
public function addImage($src, $style = null, $isWatermark = false)
{
$this->checkValidity('image');
if ($this->container == 'cell' || $this->container == 'textrun') {
$container = $this->docPart;
$containerId = $this->docPartId;
} else {
$container = $this->container;
$containerId = $this->containerId;
}
$elementDocPart = $this->checkElementDocPart();
$image = new Image($src, $style, $isWatermark);
if (!is_null($image->getSource())) {
$rID = null;
switch ($container) {
case 'textrun':
case 'section':
$rID = Media::addSectionMediaElement($src, 'image', $image);
break;
case 'header':
$rID = Media::addHeaderMediaElement($containerId, $src, $image);
break;
case 'footer':
$rID = Media::addFooterMediaElement($containerId, $src, $image);
break;
case 'footnote':
$rID = Media::addMediaElement('footnote', 'image', $src, $image);
break;
}
$rID = Media::addMediaElement($elementDocPart, 'image', $src, $image);
if (is_int($rID)) {
$image->setRelationId($rID);
}
@ -334,20 +295,8 @@ abstract class Container extends Element
*/
public function addObject($src, $style = null)
{
$inSection = true;
if (!is_null($this->docPart)) {
$container = $this->docPart;
$containerId = $this->docPartId;
} else {
$container = $this->container;
$containerId = $this->containerId;
}
if ($container == 'header' || $container == 'footer') {
$container .= $containerId;
$inSection = false;
} elseif ($container == 'footnote') {
$inSection = false;
}
$this->checkValidity('object');
$elementDocPart = $this->checkElementDocPart();
$object = new Object($src, $style);
if (!is_null($object->getSource())) {
@ -357,13 +306,8 @@ abstract class Container extends Element
$ext = substr($ext, 0, -1);
}
$icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png");
if ($inSection) {
$rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon));
$data = Media::addSectionMediaElement($src, 'oleObject');
} else {
$rIDimg = Media::addMediaElement($container, 'image', $icon, new Image($icon));
$data = Media::addMediaElement($container, 'embeddings', $src);
}
$rIDimg = Media::addMediaElement($elementDocPart, 'image', $icon, new Image($icon));
$data = Media::addMediaElement($elementDocPart, 'object', $src);
$rID = $data[0];
$objectId = $data[1];
$object->setRelationId($rID);
@ -509,11 +453,11 @@ abstract class Container extends Element
'link' => array(),
'textbreak' => array(),
'image' => array(),
'object' => array(),
'textrun' => array('section', 'header', 'footer', 'cell'),
'listitem' => array('section', 'header', 'footer', 'cell'),
'checkbox' => array('section', 'header', 'footer', 'cell'),
'table' => array('section', 'header', 'footer'),
'object' => array('section', 'textrun', 'cell', 'footnote'),
'footnote' => array('section', 'textrun', 'cell'),
'preservetext' => array('header', 'footer', 'cell'),
'relationid' => array('header', 'footer', 'footnote'),
@ -523,7 +467,6 @@ abstract class Container extends Element
// the cell is located in header or footer
$validContainerInContainers = array(
'preservetext' => array(array('cell'), array('header', 'footer')),
'object' => array(array('cell', 'textrun'), array('section')),
'footnote' => array(array('cell', 'textrun'), array('section')),
);
@ -549,4 +492,17 @@ abstract class Container extends Element
return true;
}
/**
* Return element location in document: section, headerx, or footerx
*/
private function checkElementDocPart()
{
$isCellTextrun = in_array($this->container, array('cell', 'textrun'));
$docPart = $isCellTextrun ? $this->docPart : $this->container;
$docPartId = $isCellTextrun ? $this->docPartId : $this->containerId;
$inHeaderFooter = ($docPart == 'header' || $docPart == 'footer');
return $inHeaderFooter ? $docPart . $docPartId : $docPart;
}
}

View File

@ -51,7 +51,6 @@ class Object extends Element
*/
private $objectId;
/**
* Create a new Ole-Object Element
*

View File

@ -16,31 +16,6 @@ use PhpOffice\PhpWord\Element\Image;
*/
class Media
{
/**
* Section Media Elements
*
* @var array
*/
private static $sectionMedia = array(
'images' => array(),
'embeddings' => array(),
'links' => array()
);
/**
* Header Media Elements
*
* @var array
*/
private static $headerMedia = array();
/**
* Footer Media Elements
*
* @var array
*/
private static $footerMedia = array();
/**
* Media elements
*
@ -51,213 +26,23 @@ class Media
/**
* ObjectID Counter
*
* @var int
* @var integer
*/
private static $objectId = 1325353440;
/**
* Add new Section Media Element
*
* @param string $src
* @param string $type
* @param Image $image
* @return integer|array
*/
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])) {
$cImg = self::countSectionMediaElements('images');
$cObj = self::countSectionMediaElements('embeddings');
$rID = self::countSectionMediaElements() + 7;
$media = array();
$folder = null;
$file = null;
if ($type === 'image') {
$cImg++;
$isMemImage = false;
if (!is_null($image)) {
$isMemImage = $image->getIsMemImage();
$ext = $image->getImageExtension();
}
if ($isMemImage) {
$media['isMemImage'] = true;
$media['createfunction'] = $image->getImageCreateFunction();
$media['imagefunction'] = $image->getImageFunction();
}
$folder = 'media';
$file = $type . $cImg . '.' . strtolower($ext);
} elseif ($type === 'oleObject') {
$cObj++;
$folder = 'embeddings';
$file = $type . $cObj . '.bin';
}
$media['source'] = $src;
$media['target'] = "$folder/section_$file";
$media['type'] = $type;
$media['rID'] = $rID;
self::$sectionMedia[$key][$mediaId] = $media;
if ($type === 'oleObject') {
return array($rID, ++self::$objectId);
}
return $rID;
} else {
if ($type === 'oleObject') {
$rID = self::$sectionMedia[$key][$mediaId]['rID'];
return array($rID, ++self::$objectId);
}
return self::$sectionMedia[$key][$mediaId]['rID'];
}
}
/**
* Add new Section Link Element
*
* @param string $linkSrc
* @return integer
*/
public static function addSectionLinkElement($linkSrc)
{
$rID = self::countSectionMediaElements() + 7;
$link = array();
$link['target'] = $linkSrc;
$link['rID'] = $rID;
$link['type'] = 'hyperlink';
self::$sectionMedia['links'][] = $link;
return $rID;
}
/**
* Get Section Media Elements
*
* @param string $key
* @return array
*/
public static function getSectionMediaElements($key = null)
{
if (!is_null($key)) {
return self::$sectionMedia[$key];
}
$arrImages = self::$sectionMedia['images'];
$arrObjects = self::$sectionMedia['embeddings'];
$arrLinks = self::$sectionMedia['links'];
return array_merge($arrImages, $arrObjects, $arrLinks);
}
/**
* Get Section Media Elements Count
*
* @param string $key
* @return int
*/
public static function countSectionMediaElements($key = null)
{
if (!is_null($key)) {
return count(self::$sectionMedia[$key]);
}
$cImages = count(self::$sectionMedia['images']);
$cObjects = count(self::$sectionMedia['embeddings']);
$cLinks = count(self::$sectionMedia['links']);
return ($cImages + $cObjects + $cLinks);
}
/**
* Add new Header Media Element
*
* @param int $headerCount
* @param string $src
* @param Image $image
* @return int
*/
public static function addHeaderMediaElement($headerCount, $src, Image $image = null)
{
return self::addMediaElement("header{$headerCount}", 'image', $src, $image);
}
/**
* Get Header Media Elements Count
*
* @param string $key
* @return int
*/
public static function countHeaderMediaElements($key)
{
return self::countMediaElements($key);
}
/**
* Get Header Media Elements
*
* @param string $prefix header|footer
* @return array
*/
public static function getHeaderMediaElements($prefix = 'header')
{
$mediaCollection = array();
if (!empty(self::$media)) {
foreach (self::$media as $key => $val) {
if (substr($key, 0, 6) == $prefix) {
$mediaCollection[$key] = $val;
}
}
}
return $mediaCollection;
}
/**
* Add new Footer Media Element
*
* @param int $footerCount
* @param string $src
* @param Image $image
* @return int
*/
public static function addFooterMediaElement($footerCount, $src, Image $image = null)
{
return self::addMediaElement("footer{$footerCount}", 'image', $src, $image);
}
/**
* Get Footer Media Elements Count
*
* @param string $key
* @return int
*/
public static function countFooterMediaElements($key)
{
return self::countMediaElements($key);
}
/**
* Get Footer Media Elements
*
* @return array
*/
public static function getFooterMediaElements()
{
return self::getHeaderMediaElements('footer');
}
/**
* Add new media element
*
* @param string $container section|headerx|footerx|footnote
* @param string $mediaType image|embeddings|hyperlink
* @param string $mediaType image|object|link
* @param string $source
* @param Image $image
* @return int
* @return integer|array
*/
public static function addMediaElement($container, $mediaType, $source, Image $image = null)
{
// Assign media Id and initiate media container if none exists
$mediaId = md5($source);
// Assign unique media Id and initiate media container if none exists
$mediaId = md5($container . $source);
if (!array_key_exists($container, self::$media)) {
self::$media[$container]= array();
}
@ -267,7 +52,7 @@ class Media
$mediaCount = self::countMediaElements($container);
$mediaTypeCount = self::countMediaElements($container, $mediaType);
$mediaData = array();
$relId = $mediaCount + 1;
$relId = ++$mediaCount;
$target = null;
$mediaTypeCount++;
@ -286,11 +71,11 @@ class Media
}
$target = "media/{$container}_image{$mediaTypeCount}.{$ext}";
// Objects
} elseif ($mediaType == 'embeddings') {
} elseif ($mediaType == 'object') {
$file = "oleObject{$mediaTypeCount}.bin";
$target = "embeddings/{$container}_oleObject{$mediaTypeCount}.bin";
// Links
} elseif ($mediaType == 'hyperlink') {
} elseif ($mediaType == 'link') {
$target = $source;
}
@ -299,13 +84,13 @@ class Media
$mediaData['type'] = $mediaType;
$mediaData['rID'] = $relId;
self::$media[$container][$mediaId] = $mediaData;
if ($mediaType === 'embeddings') {
if ($mediaType === 'object') {
return array($relId, ++self::$objectId);
} else {
return $relId;
}
} else {
if ($mediaType === 'embeddings') {
if ($mediaType === 'object') {
$relId = self::$media[$container][$mediaId]['rID'];
return array($relId, ++self::$objectId);
} else {
@ -317,20 +102,23 @@ class Media
/**
* Get media elements count
*
* @param string $container
* @param string $mediaType
* @return int
* @param string $container section|headerx|footerx|footnote
* @param string $mediaType image|object|link
* @return integer
*/
public static function countMediaElements($container, $mediaType = null)
{
$mediaCount = 0;
foreach (self::$media[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
if (array_key_exists($container, self::$media)) {
foreach (self::$media[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
$mediaCount++;
}
} else {
$mediaCount++;
}
} else {
$mediaCount++;
}
}
@ -340,27 +128,171 @@ class Media
/**
* Get media elements
*
* @param string $container
* @param string $mediaType
* @return int
* @param string $container section|headerx|footerx|footnote
* @param string $mediaType image|object|link
* @return array
*/
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']) {
// If header/footer, search for headerx and footerx where x is number
if ($container == 'header' || $container == 'footer') {
foreach (self::$media as $key => $val) {
if (substr($key, 0, 6) == $container) {
$mediaElements[$key] = $val;
}
}
} else {
if (!array_key_exists($container, self::$media)) {
return $mediaElements;
}
foreach (self::$media[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
$mediaElements[$mediaKey] = $mediaData;
}
} else {
$mediaElements[$mediaKey] = $mediaData;
}
} else {
$mediaElements[$mediaKey] = $mediaData;
}
}
return $mediaElements;
}
/**
* Add new Section Media Element
*
* @param string $src
* @param string $type
* @param Image $image
* @return integer|array
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function addSectionMediaElement($src, $type, Image $image = null)
{
return self::addMediaElement("section", $type, $src, $image);
}
/**
* Add new Section Link Element
*
* @param string $linkSrc
* @return integer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function addSectionLinkElement($linkSrc)
{
return self::addMediaElement('section', 'link', $linkSrc);
}
/**
* Get Section Media Elements
*
* @param string $key
* @return array
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function getSectionMediaElements($key = null)
{
return self::getMediaElements('section', $key);
}
/**
* Get Section Media Elements Count
*
* @param string $key
* @return integer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function countSectionMediaElements($key = null)
{
return self::countMediaElements('section', $key);
}
/**
* Add new Header Media Element
*
* @param integer $headerCount
* @param string $src
* @param Image $image
* @return integer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function addHeaderMediaElement($headerCount, $src, Image $image = null)
{
return self::addMediaElement("header{$headerCount}", 'image', $src, $image);
}
/**
* Get Header Media Elements Count
*
* @param string $key
* @return integer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function countHeaderMediaElements($key)
{
return self::countMediaElements($key);
}
/**
* Get Header Media Elements
*
* @param string $prefix header|footer
* @return array
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function getHeaderMediaElements()
{
return self::getMediaElements('header');
}
/**
* Add new Footer Media Element
*
* @param integer $footerCount
* @param string $src
* @param Image $image
* @return integer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function addFooterMediaElement($footerCount, $src, Image $image = null)
{
return self::addMediaElement("footer{$footerCount}", 'image', $src, $image);
}
/**
* Get Footer Media Elements Count
*
* @param string $key
* @return integer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function countFooterMediaElements($key)
{
return self::countMediaElements($key);
}
/**
* Get Footer Media Elements
*
* @return array
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function getFooterMediaElements()
{
return self::getMediaElements('footer');
}
}

View File

@ -17,8 +17,8 @@ class Drawing
/**
* Convert pixels to EMU
*
* @param int $pValue Value in pixels
* @return int Value in EMU
* @param integer $pValue Value in pixels
* @return double Value in EMU
*/
public static function pixelsToEMU($pValue = 0)
{
@ -28,8 +28,8 @@ class Drawing
/**
* Convert EMU to pixels
*
* @param int $pValue Value in EMU
* @return int Value in pixels
* @param integer $pValue Value in EMU
* @return integer Value in pixels
*/
public static function EMUToPixels($pValue = 0)
{
@ -43,8 +43,8 @@ class Drawing
/**
* Convert pixels to points
*
* @param int $pValue Value in pixels
* @return int Value in points
* @param integer $pValue Value in pixels
* @return double Value in points
*/
public static function pixelsToPoints($pValue = 0)
{
@ -54,8 +54,8 @@ class Drawing
/**
* Convert points width to pixels
*
* @param int $pValue Value in points
* @return int Value in pixels
* @param integer $pValue Value in points
* @return integer Value in pixels
*/
public static function pointsToPixels($pValue = 0)
{
@ -69,19 +69,19 @@ class Drawing
/**
* Convert degrees to angle
*
* @param int $pValue Degrees
* @return int Angle
* @param integer $pValue Degrees
* @return integer Angle
*/
public static function degreesToAngle($pValue = 0)
{
return (int)round($pValue * 60000);
return (integer)round($pValue * 60000);
}
/**
* Convert angle to degrees
*
* @param int $pValue Angle
* @return int Degrees
* @param integer $pValue Angle
* @return integer Degrees
*/
public static function angleToDegrees($pValue = 0)
{
@ -95,8 +95,8 @@ class Drawing
/**
* Convert pixels to centimeters
*
* @param int $pValue Value in pixels
* @return int Value in centimeters
* @param integer $pValue Value in pixels
* @return double Value in centimeters
*/
public static function pixelsToCentimeters($pValue = 0)
{
@ -106,8 +106,8 @@ class Drawing
/**
* Convert centimeters width to pixels
*
* @param int $pValue Value in centimeters
* @return int Value in pixels
* @param integer $pValue Value in centimeters
* @return integer Value in pixels
*/
public static function centimetersToPixels($pValue = 0)
{
@ -121,8 +121,8 @@ class Drawing
/**
* Convert HTML hexadecimal to RGB
*
* @param str $pValue HTML Color in hexadecimal
* @return array Value in RGB
* @param string $pValue HTML Color in hexadecimal
* @return array Value in RGB
*/
public static function htmlToRGB($pValue)
{

View File

@ -19,66 +19,36 @@ class String
*
* @var string[]
*/
private static $_controlCharacters = array();
/**
* Build control characters array
*/
private static function _buildControlCharacters()
{
for ($i = 0; $i <= 19; ++$i) {
if ($i != 9 && $i != 10 && $i != 13) {
$find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';
$replace = chr($i);
self::$_controlCharacters[$find] = $replace;
}
}
}
private static $controlCharacters = array();
/**
* Convert from OpenXML escaped control character to PHP control character
*
* Excel 2007 team:
* ----------------
* That's correct, control characters are stored directly in the shared-strings table.
* We do encode characters that cannot be represented in XML using the following escape sequence:
* _xHHHH_ where H represents a hexadecimal character in the character's value...
* So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
* element or in the shared string <t> element.
*
* @param string $value Value to unescape
* @return string
* @param string $value Value to unescape
* @return string
*/
public static function controlCharacterOOXML2PHP($value = '')
{
if (empty(self::$_controlCharacters)) {
self::_buildControlCharacters();
if (empty(self::$controlCharacters)) {
self::buildControlCharacters();
}
return str_replace(array_keys(self::$_controlCharacters), array_values(self::$_controlCharacters), $value);
return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);
}
/**
* Convert from PHP control character to OpenXML escaped control character
*
* Excel 2007 team:
* ----------------
* That's correct, control characters are stored directly in the shared-strings table.
* We do encode characters that cannot be represented in XML using the following escape sequence:
* _xHHHH_ where H represents a hexadecimal character in the character's value...
* So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
* element or in the shared string <t> element.
*
* @param string $value Value to escape
* @return string
* @param string $value Value to escape
* @return string
*/
public static function controlCharacterPHP2OOXML($value = '')
{
if (empty(self::$_controlCharacters)) {
self::_buildControlCharacters();
if (empty(self::$controlCharacters)) {
self::buildControlCharacters();
}
return str_replace(array_values(self::$_controlCharacters), array_keys(self::$_controlCharacters), $value);
return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value);
}
/**
@ -106,4 +76,18 @@ class String
return $value;
}
/**
* Build control characters array
*/
private static function buildControlCharacters()
{
for ($i = 0; $i <= 19; ++$i) {
if ($i != 9 && $i != 10 && $i != 13) {
$find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';
$replace = chr($i);
self::$controlCharacters[$find] = $replace;
}
}
}
}

View File

@ -38,14 +38,14 @@ class XMLWriter
*
* @var \XMLWriter
*/
private $_xmlWriter;
private $xmlWriter;
/**
* Temporary filename
*
* @var string
*/
private $_tempFileName = '';
private $tempFile = '';
/**
* Create new XMLWriter
@ -56,30 +56,30 @@ class XMLWriter
public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = './')
{
// Create internal XMLWriter
$this->_xmlWriter = new \XMLWriter();
$this->xmlWriter = new \XMLWriter();
// Open temporary storage
if ($pTemporaryStorage == self::STORAGE_MEMORY) {
$this->_xmlWriter->openMemory();
$this->xmlWriter->openMemory();
} else {
// Create temporary filename
$this->_tempFileName = @tempnam($pTemporaryStorageFolder, 'xml');
$this->tempFile = @tempnam($pTemporaryStorageFolder, 'xml');
// Open storage
if ($this->_xmlWriter->openUri($this->_tempFileName) === false) {
if ($this->xmlWriter->openUri($this->tempFile) === false) {
// Fallback to memory...
$this->_xmlWriter->openMemory();
$this->xmlWriter->openMemory();
}
}
// Set xml Compatibility
$compatibility = Settings::getCompatibility();
if ($compatibility) {
$this->_xmlWriter->setIndent(false);
$this->_xmlWriter->setIndentString('');
$this->xmlWriter->setIndent(false);
$this->xmlWriter->setIndentString('');
} else {
$this->_xmlWriter->setIndent(true);
$this->_xmlWriter->setIndentString(' ');
$this->xmlWriter->setIndent(true);
$this->xmlWriter->setIndentString(' ');
}
}
@ -89,26 +89,11 @@ class XMLWriter
public function __destruct()
{
// Desctruct XMLWriter
unset($this->_xmlWriter);
unset($this->xmlWriter);
// Unlink temporary files
if ($this->_tempFileName != '') {
@unlink($this->_tempFileName);
}
}
/**
* Get written data
*
* @return string XML data
*/
public function getData()
{
if ($this->_tempFileName == '') {
return $this->_xmlWriter->outputMemory(true);
} else {
$this->_xmlWriter->flush();
return file_get_contents($this->_tempFileName);
if ($this->tempFile != '') {
@unlink($this->tempFile);
}
}
@ -121,22 +106,37 @@ class XMLWriter
public function __call($function, $args)
{
try {
@call_user_func_array(array($this->_xmlWriter, $function), $args);
@call_user_func_array(array($this->xmlWriter, $function), $args);
} catch (\Exception $ex) {
// Do nothing!
}
}
/**
* Get written data
*
* @return string XML data
*/
public function getData()
{
if ($this->tempFile == '') {
return $this->xmlWriter->outputMemory(true);
} else {
$this->xmlWriter->flush();
return file_get_contents($this->tempFile);
}
}
/**
* Fallback method for writeRaw, introduced in PHP 5.2
*
* @param string $text
* @return string
* @return bool
*/
public function writeRaw($text)
{
if (isset($this->_xmlWriter) && is_object($this->_xmlWriter) && (method_exists($this->_xmlWriter, 'writeRaw'))) {
return $this->_xmlWriter->writeRaw($text);
if (isset($this->xmlWriter) && is_object($this->xmlWriter) && (method_exists($this->xmlWriter, 'writeRaw'))) {
return $this->xmlWriter->writeRaw($text);
}
return $this->text($text);

View File

@ -10,7 +10,6 @@
namespace PhpOffice\PhpWord\Writer\ODText;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Container\Section;
use PhpOffice\PhpWord\Element\Image;
use PhpOffice\PhpWord\Element\Link;
use PhpOffice\PhpWord\Element\ListItem;

View File

@ -24,7 +24,6 @@ use PhpOffice\PhpWord\Element\Title;
use PhpOffice\PhpWord\Shared\Drawing;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\TOC;
/**

View File

@ -98,65 +98,40 @@ class Word2007 extends Writer implements IWriter
}
}
// Add section elements
// Add section media files
$sectionElements = array();
$secElements = Media::getSectionMediaElements();
foreach ($secElements as $element) { // loop through section media elements
if ($element['type'] != 'hyperlink') {
$this->addFileToPackage($objZip, $element);
}
$sectionElements[] = $element;
}
// 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('rels')->writeMediaRels($hdrMedia)
);
foreach ($hdrMedia as $element) {
if ($element['type'] != 'hyperlink') {
$this->addFileToPackage($objZip, $element);
}
}
$secElements = Media::getMediaElements('section');
if (!empty($secElements)) {
$this->addFilesToPackage($objZip, $secElements);
foreach ($secElements as $element) {
$sectionElements[] = $element;
}
}
// 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('rels')->writeMediaRels($ftrMedia)
);
foreach ($ftrMedia as $element) {
if ($element['type'] != 'hyperlink') {
$this->addFileToPackage($objZip, $element);
}
}
}
}
// Add header/footer media files & relations
$this->addHeaderFooterMedia($objZip, 'header');
$this->addHeaderFooterMedia($objZip, 'footer');
// Process header/footer xml files
// Add header/footer contents
$cHdrs = 0;
$cFtrs = 0;
$rID = Media::countSectionMediaElements() + 6;
$rID = Media::countMediaElements('section') + 6; // @see Rels::writeDocRels for 6 first elements
$sections = $this->phpWord->getSections();
$footers = array();
foreach ($sections as $section) {
$headers = $section->getHeaders();
foreach ($headers as $index => &$header) {
$cHdrs++;
$header->setRelationId(++$rID);
$hdrFile = "header{$cHdrs}.xml";
$sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID);
$objZip->addFromString(
"word/{$hdrFile}",
$this->getWriterPart('header')->writeHeader($header)
);
if (!empty($headers)) {
foreach ($headers as $index => &$header) {
$cHdrs++;
$header->setRelationId(++$rID);
$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;
@ -172,34 +147,23 @@ class Word2007 extends Writer implements IWriter
}
}
// Process footnotes
// Add footnotes media files, relations, and contents
if (Footnote::countFootnoteElements() > 0) {
// Push to document.xml.rels
$sectionElements[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID);
// Add footnote media to package
$footnoteMedia = Media::getMediaElements('footnote');
if (!empty($footnoteMedia)) {
foreach ($footnoteMedia as $media) {
if ($media['type'] != 'hyperlink') {
$this->addFileToPackage($objZip, $media);
}
}
}
// Write footnotes.xml
$objZip->addFromString(
'word/footnotes.xml',
$this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements())
);
// Write footnotes.xml.rels
$this->addFilesToPackage($objZip, $footnoteMedia);
if (!empty($footnoteMedia)) {
$objZip->addFromString(
'word/_rels/footnotes.xml.rels',
$this->getWriterPart('rels')->writeMediaRels($footnoteMedia)
);
}
$objZip->addFromString(
'word/footnotes.xml',
$this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements())
);
}
// build docx file
// Write dynamic files
$objZip->addFromString(
'[Content_Types].xml',
@ -288,21 +252,47 @@ class Word2007 extends Writer implements IWriter
* @param mixed $objZip
* @param mixed $element
*/
private function addFileToPackage($objZip, $element)
private function addFilesToPackage($objZip, $elements)
{
if (isset($element['isMemImage']) && $element['isMemImage']) {
$image = call_user_func($element['createfunction'], $element['source']);
ob_start();
call_user_func($element['imagefunction'], $image);
$imageContents = ob_get_contents();
ob_end_clean();
$objZip->addFromString('word/' . $element['target'], $imageContents);
imagedestroy($image);
foreach ($elements as $element) {
if ($element['type'] == 'link') {
continue;
}
if (isset($element['isMemImage']) && $element['isMemImage']) {
$image = call_user_func($element['createfunction'], $element['source']);
ob_start();
call_user_func($element['imagefunction'], $image);
$imageContents = ob_get_contents();
ob_end_clean();
$objZip->addFromString('word/' . $element['target'], $imageContents);
imagedestroy($image);
$this->checkContentTypes($element['source']);
} else {
$objZip->addFile($element['source'], 'word/' . $element['target']);
$this->checkContentTypes($element['source']);
$this->checkContentTypes($element['source']);
} else {
$objZip->addFile($element['source'], 'word/' . $element['target']);
$this->checkContentTypes($element['source']);
}
}
}
/**
* Add header/footer media elements
*/
private function addHeaderFooterMedia($objZip, $docPart)
{
$elements = Media::getMediaElements($docPart);
if (!empty($elements)) {
foreach ($elements as $file => $media) {
if (count($media) > 0) {
$objZip->addFromString(
'word/_rels/' . $file . '.xml.rels',
$this->getWriterPart('rels')->writeMediaRels($media)
);
if (!empty($media)) {
$this->addFilesToPackage($objZip, $media);
}
}
}
}
}
}

View File

@ -1126,15 +1126,15 @@ class Base extends WriterPart
protected function writeContainerElements(XMLWriter $xmlWriter, Container $container)
{
// Check allowed elements
$elmCommon = array('Text', 'Link', 'TextBreak', 'Image');
$elmCommon = array('Text', 'Link', 'TextBreak', 'Image', 'Object');
$elmMainCell = array_merge($elmCommon, array('TextRun', 'ListItem', 'CheckBox'));
$allowedElements = array(
'Section' => array_merge($elmMainCell, array('Table', 'Footnote', 'Object', 'Title', 'PageBreak', 'TOC')),
'Section' => array_merge($elmMainCell, array('Table', 'Footnote', 'Title', 'PageBreak', 'TOC')),
'Header' => array_merge($elmMainCell, array('Table', 'PreserveText')),
'Footer' => array_merge($elmMainCell, array('Table', 'PreserveText')),
'Cell' => array_merge($elmMainCell, array('Object', 'PreserveText', 'Footnote')),
'TextRun' => array_merge($elmCommon, array('Object', 'Footnote')),
'Footnote' => array_merge($elmCommon, array('Object')),
'Cell' => array_merge($elmMainCell, array('PreserveText', 'Footnote')),
'TextRun' => array_merge($elmCommon, array('Footnote')),
'Footnote' => $elmCommon,
);
$containerName = get_class($container);
$containerName = substr($containerName, strrpos($containerName, '\\') + 1);

View File

@ -26,8 +26,6 @@ class Rels extends WriterPart
/**
* Write _rels/.rels
*
* @param PhpWord $phpWord
*/
public function writeMainRels()
{
@ -95,15 +93,14 @@ class Rels extends WriterPart
$this->writeRel($xmlWriter, $id++, $type, $target);
}
}
if (is_array($mediaRels)) {
$typePrefix = 'officeDocument/2006/relationships/';
if (!is_null($mediaRels) && is_array($mediaRels)) {
$mapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink');
foreach ($mediaRels as $mediaRel) {
$id = $mediaRel['rID'];
$type = $mediaRel['type'];
$target = $mediaRel['target']; // file name
$type = array_key_exists($type, $mapping) ? $mapping[$type] : $type;
$target = $mediaRel['target'];
$targetMode = ($type == 'hyperlink') ? 'External' : '';
$type = $typePrefix . ($type == 'embeddings' ? 'oleObject' : $type);
$this->writeRel($xmlWriter, $id, $type, $target, $targetMode);
$this->writeRel($xmlWriter, $id++, "officeDocument/2006/relationships/{$type}", $target, $targetMode);
}
}
$xmlWriter->endElement();

View File

@ -25,7 +25,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase
*/
public function testGetSectionMediaElementsWithNull()
{
$this->assertEquals(Media::getSectionMediaElements(), array());
$this->assertEquals(Media::getMediaElements('section'), array());
}
/**
@ -33,31 +33,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase
*/
public function testCountSectionMediaElementsWithNull()
{
$this->assertEquals(Media::countSectionMediaElements(), 0);
}
/**
* Get header media elements
*/
public function testGetHeaderMediaElements()
{
$this->assertAttributeEquals(
Media::getHeaderMediaElements(),
'headerMedia',
'PhpOffice\\PhpWord\\Media'
);
}
/**
* Get footer media elements
*/
public function testGetFooterMediaElements()
{
$this->assertAttributeEquals(
Media::getFooterMediaElements(),
'footerMedia',
'PhpOffice\\PhpWord\\Media'
);
$this->assertEquals(Media::countMediaElements('section'), 0);
}
/**
@ -68,13 +44,13 @@ class MediaTest extends \PHPUnit_Framework_TestCase
$local = __DIR__ . "/_files/images/mars.jpg";
$object = __DIR__ . "/_files/documents/sheet.xls";
$remote = 'http://php.net/images/logos/php-med-trans-light.gif';
Media::addSectionMediaElement($local, 'image', new Image($local));
Media::addSectionMediaElement($local, 'image', new Image($local));
Media::addSectionMediaElement($remote, 'image', new Image($remote));
Media::addSectionMediaElement($object, 'oleObject');
Media::addSectionMediaElement($object, 'oleObject');
Media::addMediaElement('section', 'image', $local, new Image($local));
Media::addMediaElement('section', 'image', $local, new Image($local));
Media::addMediaElement('section', 'image', $remote, new Image($local));
Media::addMediaElement('section', 'object', $object);
Media::addMediaElement('section', 'object', $object);
$this->assertEquals(3, Media::countSectionMediaElements());
$this->assertEquals(3, Media::countMediaElements('section'));
}
/**
@ -82,12 +58,12 @@ class MediaTest extends \PHPUnit_Framework_TestCase
*/
public function testAddSectionLinkElement()
{
$expected = Media::countSectionMediaElements() + 7;
$actual = Media::addSectionLinkElement('http://test.com');
$expected = Media::countMediaElements('section') + 1;
$actual = Media::addMediaElement('section', 'link', 'http://test.com');
$this->assertEquals($expected, $actual);
$this->assertEquals(1, Media::countSectionMediaElements('links'));
$this->assertEquals(1, count(Media::getSectionMediaElements('links')));
$this->assertEquals(1, Media::countMediaElements('section', 'link'));
$this->assertEquals(1, count(Media::getMediaElements('section', 'link')));
}
/**
@ -97,13 +73,13 @@ class MediaTest extends \PHPUnit_Framework_TestCase
{
$local = __DIR__ . "/_files/images/mars.jpg";
$remote = 'http://php.net/images/logos/php-med-trans-light.gif';
Media::addHeaderMediaElement(1, $local, new Image($local));
Media::addHeaderMediaElement(1, $local, new Image($local));
Media::addHeaderMediaElement(1, $remote, new Image($remote));
Media::addMediaElement('header1', 'image', $local, new Image($local));
Media::addMediaElement('header1', 'image', $local, new Image($local));
Media::addMediaElement('header1', 'image', $remote, new Image($remote));
$this->assertEquals(2, Media::countHeaderMediaElements('header1'));
$this->assertEquals(2, Media::countMediaElements('header1'));
$this->assertEquals(2, count(Media::getMediaElements('header1')));
$this->assertFalse(Media::getMediaElements('header2'));
$this->assertEmpty(Media::getMediaElements('header2'));
}
/**
@ -113,10 +89,10 @@ class MediaTest extends \PHPUnit_Framework_TestCase
{
$local = __DIR__ . "/_files/images/mars.jpg";
$remote = 'http://php.net/images/logos/php-med-trans-light.gif';
Media::addFooterMediaElement(1, $local, new Image($local));
Media::addFooterMediaElement(1, $local, new Image($local));
Media::addFooterMediaElement(1, $remote, new Image($remote));
Media::addMediaElement('footer1', 'image', $local, new Image($local));
Media::addMediaElement('footer1', 'image', $local, new Image($local));
Media::addMediaElement('footer1', 'image', $remote, new Image($remote));
$this->assertEquals(2, Media::countFooterMediaElements('footer1'));
$this->assertEquals(2, Media::countMediaElements('footer1'));
}
}