Refactor header/footer and media model

This commit is contained in:
Ivan Lanin 2014-04-05 19:02:49 +07:00
parent 6aa73544a6
commit 03934af334
17 changed files with 356 additions and 361 deletions

View File

@ -39,8 +39,8 @@ 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`
- `Footnote::addFootnoteLinkElement` replaced by `Media::addElement`
- `Footnote::getFootnoteLinkElements` replaced by `Media::getElements`
- All current methods on `Media`
### Miscellaneous

View File

@ -49,7 +49,7 @@ abstract class Container extends Element
*
* @var int
*/
protected $containerId;
protected $sectionId;
/**
* Elements collection
@ -123,7 +123,7 @@ abstract class Container extends Element
$link = new Link(String::toUTF8($linkSrc), String::toUTF8($linkName), $fontStyle, $paragraphStyle);
$link->setDocPart($this->getDocPart(), $this->getDocPartId());
$rID = Media::addMediaElement($elementDocPart, 'link', $linkSrc);
$rID = Media::addElement($elementDocPart, 'link', $linkSrc);
$link->setRelationId($rID);
$this->elements[] = $link;
@ -250,14 +250,10 @@ abstract class Container extends Element
$image = new Image($src, $style, $isWatermark);
$image->setDocPart($this->getDocPart(), $this->getDocPartId());
if (!is_null($image->getSource())) {
$rID = Media::addMediaElement($elementDocPart, 'image', $src, $image);
$image->setRelationId($rID);
$this->elements[] = $image;
return $image;
} else {
throw new InvalidImageException;
}
$rID = Media::addElement($elementDocPart, 'image', $src, $image);
$image->setRelationId($rID);
$this->elements[] = $image;
return $image;
}
/**
@ -284,9 +280,9 @@ abstract class Container extends Element
$ext = substr($ext, 0, -1);
}
$icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png");
$rID = Media::addMediaElement($elementDocPart, 'object', $src);
$rID = Media::addElement($elementDocPart, 'object', $src);
$object->setRelationId($rID);
$rIDimg = Media::addMediaElement($elementDocPart, 'image', $icon, new Image($icon));
$rIDimg = Media::addElement($elementDocPart, 'image', $icon, new Image($icon));
$object->setImageRelationId($rIDimg);
$this->elements[] = $object;
return $object;
@ -307,7 +303,7 @@ abstract class Container extends Element
$footnote = new FootnoteElement($paragraphStyle);
$refID = FootnoteCollection::addFootnoteElement($footnote);
$footnote->setDocPart($this->getDocPart(), $this->getDocPartId());
$footnote->setDocPart('footnote', $this->getDocPartId());
$footnote->setRelationId($refID);
$this->elements[] = $footnote;
@ -337,11 +333,11 @@ abstract class Container extends Element
/**
* Get section number
*
* @return array
* @return integer
*/
public function getSectionId()
{
return $this->containerId;
return $this->sectionId;
}
/**
@ -474,7 +470,7 @@ abstract class Container extends Element
{
$isCellTextrun = in_array($this->container, array('cell', 'textrun'));
$docPart = $isCellTextrun ? $this->getDocPart() : $this->container;
$docPartId = $isCellTextrun ? $this->getDocPartId() : $this->containerId;
$docPartId = $isCellTextrun ? $this->getDocPartId() : $this->sectionId;
$inHeaderFooter = ($docPart == 'header' || $docPart == 'footer');
return $inHeaderFooter ? $docPart . $docPartId : $docPart;

View File

@ -14,15 +14,51 @@ namespace PhpOffice\PhpWord\Container;
*/
class Footer extends Container
{
const AUTO = 'default'; // default and odd pages
const FIRST = 'first';
const EVEN = 'even';
/**
* Header type
*
* @var string
*/
private $type = self::AUTO;
/**
* Create new instance
*
* @param int $sectionId
* @param int $footerId
* @param string $type
*/
public function __construct($sectionId)
public function __construct($sectionId, $footerId = 1, $type = self::AUTO)
{
$this->container = 'footer';
$this->containerId = $sectionId;
$this->setDocPart($this->container, $this->containerId);
$this->sectionId = $sectionId;
$this->setType($type);
$this->setDocPart($this->container, ($sectionId - 1) * 3 + $footerId);
}
/**
* Set type
*
* @param string $value
* @since 0.9.2
*/
public function setType($value = self::AUTO)
{
$this->type = $value;
}
/**
* Get type
*
* @return string
* @since 0.9.2
*/
public function getType()
{
return $this->type;
}
}

View File

@ -20,29 +20,32 @@ class Header extends Container
* Header types constants
*
* @var string
* @link http://www.schemacentral.com/sc/ooxml/a-wheaderType-4.html Header or Footer Type
* @link http://www.schemacentral.com/sc/ooxml/a-wtype-4.html Header or Footer Type
*/
const AUTO = 'default'; // Did not use DEFAULT because it is a PHP keyword
const EVEN = 'even';
const AUTO = 'default'; // default and odd pages
const FIRST = 'first';
const EVEN = 'even';
/**
* Header type
*
* @var string
*/
private $headerType = self::AUTO;
private $type = self::AUTO;
/**
* Create new instance
*
* @param int $sectionId
* @param int $headerId
* @param string $type
*/
public function __construct($sectionId)
public function __construct($sectionId, $headerId = 1, $type = self::AUTO)
{
$this->container = 'header';
$this->containerId = $sectionId;
$this->setDocPart($this->container, $this->containerId);
$this->sectionId = $sectionId;
$this->setType($type);
$this->setDocPart($this->container, ($sectionId - 1) * 3 + $headerId);
}
/**
@ -57,35 +60,57 @@ class Header extends Container
return $this->addImage($src, $style, true);
}
/**
* Set header type
*
* @param string $value
* @since 0.9.2
*/
public function setType($value = self::AUTO)
{
if (!in_array($value, array(self::AUTO, self::FIRST, self::EVEN))) {
$value = self::AUTO;
}
$this->type = $value;
}
/**
* Get header type
*
* @return string
*/
public function getType()
{
return $this->headerType;
return $this->type;
}
/**
* Reset type to default
*
* @return string
*/
public function resetType()
{
return $this->headerType = self::AUTO;
return $this->type = self::AUTO;
}
/**
* First page only header
*
* @return string
*/
public function firstPage()
{
return $this->headerType = self::FIRST;
return $this->type = self::FIRST;
}
/**
* Even numbered pages only
*
* @return string
*/
public function evenPage()
{
return $this->headerType = self::EVEN;
return $this->type = self::EVEN;
}
}

View File

@ -9,6 +9,7 @@
namespace PhpOffice\PhpWord\Container;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\TOC;
use PhpOffice\PhpWord\Container\Footer;
use PhpOffice\PhpWord\Container\Header;
@ -28,19 +29,18 @@ class Section extends Container
private $settings;
/**
* Section headers
* Section headers, indexed from 1, not zero
*
* @var Header[]
*/
private $headers = array();
/**
* Section footer
* Section footers, indexed from 1, not zero
*
* @var Footer
* @var Footer[]
*/
private $footer = null;
private $footers = array();
/**
* Create new instance
@ -51,8 +51,8 @@ class Section extends Container
public function __construct($sectionCount, $settings = null)
{
$this->container = 'section';
$this->containerId = $sectionCount;
$this->setDocPart($this->container, $this->containerId);
$this->sectionId = $sectionCount;
$this->setDocPart($this->container, $this->sectionId);
$this->settings = new Settings();
$this->setSettings($settings);
}
@ -109,29 +109,29 @@ class Section extends Container
/**
* Add header
*
* @param string $type
* @return Header
* @since 0.9.2
*/
public function addHeader()
public function addHeader($type = Header::AUTO)
{
$header = new Header($this->containerId);
$this->headers[] = $header;
return $header;
return $this->addHeaderFooter($type, true);
}
/**
* Add footer
*
* @param string $type
* @return Footer
* @since 0.9.2
*/
public function addFooter()
public function addFooter($type = Header::AUTO)
{
$footer = new Footer($this->containerId);
$this->footer = $footer;
return $footer;
return $this->addHeaderFooter($type, false);
}
/**
* Get Headers
* Get header elements
*
* @return Header[]
*/
@ -141,13 +141,13 @@ class Section extends Container
}
/**
* Get footer element
* Get footer elements
*
* @return Footer
* @return Footer[]
*/
public function getFooter()
public function getFooters()
{
return $this->footer;
return $this->footers;
}
/**
@ -160,10 +160,38 @@ class Section extends Container
*/
public function hasDifferentFirstPage()
{
$value = array_filter($this->headers, function (Header &$header) {
return $header->getType() == Header::FIRST;
});
return count($value) > 0;
foreach ($this->headers as $header) {
if ($header->getType() == Header::FIRST) {
return true;
}
}
return false;
}
/**
* Add header/footer
*
* @param string $type
* @param string $header
* @return Header|Footer
* @since 0.9.2
*/
private function addHeaderFooter($type = Header::AUTO, $header = true)
{
$collectionArray = $header ? 'headers' : 'footers';
$containerClass = 'PhpOffice\\PhpWord\\Container\\';
$containerClass .= ($header ? 'Header' : 'Footer');
$collection = &$this->$collectionArray;
if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) {
$index = count($collection);
$container = new $containerClass($this->sectionId, ++$index, $type);
$collection[$index] = $container;
return $container;
} else {
throw new Exception('Invalid header/footer type.');
}
}
/**
@ -189,4 +217,20 @@ class Section extends Container
{
return $this->addFooter();
}
/**
* Get footer
*
* @return Footer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public function getFooter()
{
if (empty($this->footers)) {
return null;
} else {
return $this->footers[1];
}
}
}

View File

@ -30,6 +30,10 @@ abstract class Element
/**
* Document part Id
*
* For header and footer, this will be = ($sectionId - 1) * 3 + $index
* because the max number of header/footer in every page is 3, i.e.
* AUTO, FIRST, and EVEN (AUTO = ODD)
*
* @var integer
*/
private $docPartId = 1;

View File

@ -28,8 +28,6 @@ class TextRun extends Container
* Create new instance
*
* @param string|array|Paragraph $paragraphStyle
* @param string $docPart section|header|footer
* @param int $docPartId
*/
public function __construct($paragraphStyle = null)
{

View File

@ -77,7 +77,7 @@ class Footnote
*/
public static function addFootnoteLinkElement($linkSrc)
{
return Media::addMediaElement('footnotes', 'hyperlink', $linkSrc);
return Media::addElement('footnotes', 'link', $linkSrc);
}
/**
@ -89,6 +89,6 @@ class Footnote
*/
public static function getFootnoteLinkElements()
{
return Media::getMediaElements('footnotes', 'hyperlink');
return Media::getElements('footnotes', 'link');
}
}

View File

@ -9,6 +9,7 @@
namespace PhpOffice\PhpWord;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\Element\Image;
/**
@ -21,7 +22,7 @@ class Media
*
* @var array
*/
private static $media = array();
private static $elements = array();
/**
* Add new media element
@ -31,19 +32,20 @@ class Media
* @param string $source
* @param Image $image
* @return integer
* @since 0.9.2
*/
public static function addMediaElement($container, $mediaType, $source, Image $image = null)
public static function addElement($container, $mediaType, $source, Image $image = null)
{
// 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();
if (!array_key_exists($container, self::$elements)) {
self::$elements[$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);
if (!array_key_exists($mediaId, self::$elements[$container])) {
$mediaCount = self::countElements($container);
$mediaTypeCount = self::countElements($container, $mediaType);
$mediaData = array();
$relId = ++$mediaCount;
$target = null;
@ -51,16 +53,17 @@ class Media
// Images
if ($mediaType == 'image') {
$isMemImage = false;
if (!is_null($image)) {
$isMemImage = $image->getIsMemImage();
$ext = $image->getImageExtension();
$ext = strtolower($ext);
if (is_null($image)) {
throw new Exception('Image object not assigned.');
}
$isMemImage = $image->getIsMemImage();
$ext = $image->getImageExtension();
$mediaData['imageExtension'] = $ext;
$mediaData['imageType'] = $image->getImageType();
if ($isMemImage) {
$mediaData['isMemImage'] = true;
$mediaData['createfunction'] = $image->getImageCreateFunction();
$mediaData['imagefunction'] = $image->getImageFunction();
$mediaData['createFunction'] = $image->getImageCreateFunction();
$mediaData['imageFunction'] = $image->getImageFunction();
}
$target = "media/{$container}_image{$mediaTypeCount}.{$ext}";
// Objects
@ -76,10 +79,10 @@ class Media
$mediaData['target'] = $target;
$mediaData['type'] = $mediaType;
$mediaData['rID'] = $relId;
self::$media[$container][$mediaId] = $mediaData;
self::$elements[$container][$mediaId] = $mediaData;
return $relId;
} else {
return self::$media[$container][$mediaId]['rID'];
return self::$elements[$container][$mediaId]['rID'];
}
}
@ -89,13 +92,14 @@ class Media
* @param string $container section|headerx|footerx|footnote
* @param string $mediaType image|object|link
* @return integer
* @since 0.9.2
*/
public static function countMediaElements($container, $mediaType = null)
public static function countElements($container, $mediaType = null)
{
$mediaCount = 0;
if (array_key_exists($container, self::$media)) {
foreach (self::$media[$container] as $mediaKey => $mediaData) {
if (array_key_exists($container, self::$elements)) {
foreach (self::$elements[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
$mediaCount++;
@ -115,23 +119,24 @@ class Media
* @param string $container section|headerx|footerx|footnote
* @param string $mediaType image|object|link
* @return array
* @since 0.9.2
*/
public static function getMediaElements($container, $mediaType = null)
public static function getElements($container, $mediaType = null)
{
$mediaElements = array();
// If header/footer, search for headerx and footerx where x is number
if ($container == 'header' || $container == 'footer') {
foreach (self::$media as $key => $val) {
foreach (self::$elements as $key => $val) {
if (substr($key, 0, 6) == $container) {
$mediaElements[$key] = $val;
}
}
} else {
if (!array_key_exists($container, self::$media)) {
if (!array_key_exists($container, self::$elements)) {
return $mediaElements;
}
foreach (self::$media[$container] as $mediaKey => $mediaData) {
foreach (self::$elements[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
$mediaElements[$mediaKey] = $mediaData;
@ -150,7 +155,7 @@ class Media
*/
public static function reset()
{
self::$media = array();
self::$elements = array();
}
/**
@ -159,13 +164,13 @@ class Media
* @param string $src
* @param string $type
* @param Image $image
* @return integer|array
* @return integer
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
public static function addSectionMediaElement($src, $type, Image $image = null)
{
return self::addMediaElement("section", $type, $src, $image);
return self::addElement('section', $type, $src, $image);
}
/**
@ -178,7 +183,7 @@ class Media
*/
public static function addSectionLinkElement($linkSrc)
{
return self::addMediaElement('section', 'link', $linkSrc);
return self::addElement('section', 'link', $linkSrc);
}
/**
@ -191,7 +196,7 @@ class Media
*/
public static function getSectionMediaElements($key = null)
{
return self::getMediaElements('section', $key);
return self::getElements('section', $key);
}
/**
@ -204,7 +209,7 @@ class Media
*/
public static function countSectionMediaElements($key = null)
{
return self::countMediaElements('section', $key);
return self::countElements('section', $key);
}
/**
@ -219,7 +224,7 @@ class Media
*/
public static function addHeaderMediaElement($headerCount, $src, Image $image = null)
{
return self::addMediaElement("header{$headerCount}", 'image', $src, $image);
return self::addElement("header{$headerCount}", 'image', $src, $image);
}
/**
@ -232,7 +237,7 @@ class Media
*/
public static function countHeaderMediaElements($key)
{
return self::countMediaElements($key);
return self::countElements($key);
}
/**
@ -244,7 +249,7 @@ class Media
*/
public static function getHeaderMediaElements()
{
return self::getMediaElements('header');
return self::getElements('header');
}
/**
@ -259,7 +264,7 @@ class Media
*/
public static function addFooterMediaElement($footerCount, $src, Image $image = null)
{
return self::addMediaElement("footer{$footerCount}", 'image', $src, $image);
return self::addElement("footer{$footerCount}", 'image', $src, $image);
}
/**
@ -272,7 +277,7 @@ class Media
*/
public static function countFooterMediaElements($key)
{
return self::countMediaElements($key);
return self::countElements($key);
}
/**
@ -284,6 +289,6 @@ class Media
*/
public static function getFooterMediaElements()
{
return self::getMediaElements('footer');
return self::getElements('footer');
}
}

View File

@ -63,22 +63,4 @@ class Manifest extends WriterPart
// Return
return $xmlWriter->getData();
}
/**
* Get image mime type
*
* @param string $pFile Filename
* @return string Mime Type
* @throws Exception
*/
private function getImageMimeType($pFile = '')
{
if (file_exists($pFile)) {
$image = getimagesize($pFile);
return image_type_to_mime_type($image[2]);
} else {
throw new Exception("File $pFile does not exist");
}
}
}

View File

@ -29,18 +29,18 @@ use PhpOffice\PhpWord\Writer\Word2007\Styles;
class Word2007 extends Writer implements IWriter
{
/**
* Types of images
* Content types values
*
* @var array
*/
private $imageTypes = array();
private $cTypes = array('default' => array(), 'override' => array());
/**
* Types of objects
* Document relationship
*
* @var array
*/
private $objectTypes = array();
private $docRels = array();
/**
* Create new Word2007 writer
@ -98,14 +98,18 @@ class Word2007 extends Writer implements IWriter
}
}
// Add section media files
$sectionElements = array();
// Content types
$this->cTypes['default'] = array(
'rels' => 'application/vnd.openxmlformats-package.relationships+xml',
'xml' => 'application/xml',
);
$secElements = Media::getMediaElements('section');
if (!empty($secElements)) {
$this->addFilesToPackage($objZip, $secElements);
foreach ($secElements as $element) {
$sectionElements[] = $element;
// Add section media files
$sectionMedia = Media::getElements('section');
if (!empty($sectionMedia)) {
$this->addFilesToPackage($objZip, $sectionMedia);
foreach ($sectionMedia as $element) {
$this->docRels[] = $element;
}
}
@ -114,70 +118,32 @@ class Word2007 extends Writer implements IWriter
$this->addHeaderFooterMedia($objZip, 'footer');
// Add header/footer contents
$cHdrs = 0;
$cFtrs = 0;
$rID = Media::countMediaElements('section') + 6; // @see Rels::writeDocRels for 6 first elements
$overrides = array();
$rID = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements
$sections = $this->phpWord->getSections();
$footers = array();
foreach ($sections as $section) {
$headers = $section->getHeaders();
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;
if (!is_null($footer)) {
$footer->setRelationId(++$rID);
$footerCount = $footer->getSectionId();
$ftrFile = "footer{$footerCount}.xml";
$sectionElements[] = array('target' => $ftrFile, 'type' => 'footer', 'rID' => $rID);
$objZip->addFromString(
"word/{$ftrFile}",
$this->getWriterPart('footer')->writeFooter($footer)
);
}
$this->addHeaderFooterContent($section, $objZip, 'header', $rID);
$this->addHeaderFooterContent($section, $objZip, 'footer', $rID);
}
// Add footnotes media files, relations, and contents
if (Footnote::countFootnoteElements() > 0) {
$sectionElements[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID);
$footnoteMedia = Media::getMediaElements('footnote');
$footnoteMedia = Media::getElements('footnote');
$this->addFilesToPackage($objZip, $footnoteMedia);
if (!empty($footnoteMedia)) {
$objZip->addFromString(
'word/_rels/footnotes.xml.rels',
$this->getWriterPart('rels')->writeMediaRels($footnoteMedia)
);
$objZip->addFromString('word/_rels/footnotes.xml.rels', $this->getWriterPart('rels')->writeMediaRels($footnoteMedia));
}
$objZip->addFromString(
'word/footnotes.xml',
$this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements())
);
$objZip->addFromString('word/footnotes.xml', $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements()));
$this->cTypes['override']["/word/footnotes.xml"] = 'footnotes';
$this->docRels[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID);
}
// Write dynamic files
$objZip->addFromString(
'[Content_Types].xml',
$this->getWriterPart('contenttypes')->writeContentTypes(
$this->imageTypes,
$this->objectTypes,
$cHdrs,
$footers
)
);
$objZip->addFromString('[Content_Types].xml', $this->getWriterPart('contenttypes')->writeContentTypes($this->cTypes));
$objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeMainRels());
$objZip->addFromString('docProps/app.xml', $this->getWriterPart('docprops')->writeDocPropsApp($this->phpWord));
$objZip->addFromString('docProps/core.xml', $this->getWriterPart('docprops')->writeDocPropsCore($this->phpWord));
$objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('rels')->writeDocRels($sectionElements));
$objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('rels')->writeDocRels($this->docRels));
$objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->phpWord));
$objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord));
@ -200,54 +166,7 @@ class Word2007 extends Writer implements IWriter
}
/**
* Check content types
*
* @param string $src
*/
private function checkContentTypes($src)
{
$extension = null;
if (stripos(strrev($src), strrev('.php')) === 0) {
$extension = 'php';
} else {
if (function_exists('exif_imagetype')) {
$imageType = exif_imagetype($src);
} else {
$tmp = getimagesize($src);
$imageType = $tmp[2];
}
if ($imageType === \IMAGETYPE_JPEG) {
$extension = 'jpg';
} elseif ($imageType === \IMAGETYPE_GIF) {
$extension = 'gif';
} elseif ($imageType === \IMAGETYPE_PNG) {
$extension = 'png';
} elseif ($imageType === \IMAGETYPE_BMP) {
$extension = 'bmp';
} elseif ($imageType === \IMAGETYPE_TIFF_II || $imageType === \IMAGETYPE_TIFF_MM) {
$extension = 'tif';
}
}
if (isset($extension)) {
$imageData = getimagesize($src);
$imageType = image_type_to_mime_type($imageData[2]);
$imageExtension = str_replace('.', '', image_type_to_extension($imageData[2]));
if ($imageExtension === 'jpeg') {
$imageExtension = 'jpg';
}
if (!in_array($imageType, $this->imageTypes)) {
$this->imageTypes[$imageExtension] = $imageType;
}
} else {
if (!in_array($extension, $this->objectTypes)) {
$this->objectTypes[] = $extension;
}
}
}
/**
* Check content types
* Add section files to package
*
* @param mixed $objZip
* @param mixed $elements
@ -255,47 +174,78 @@ class Word2007 extends Writer implements IWriter
private function addFilesToPackage($objZip, $elements)
{
foreach ($elements as $element) {
// Do not add link
if ($element['type'] == 'link') {
continue;
}
// Retrieve remote image
if (isset($element['isMemImage']) && $element['isMemImage']) {
$image = call_user_func($element['createfunction'], $element['source']);
$image = call_user_func($element['createFunction'], $element['source']);
ob_start();
call_user_func($element['imagefunction'], $image);
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']);
}
// Register content types
if ($element['type'] == 'image') {
$imageExtension = $element['imageExtension'];
$imageType = $element['imageType'];
if (!array_key_exists($imageExtension, $this->cTypes['default'])) {
$this->cTypes['default'][$imageExtension] = $imageType;
}
} else {
if (!array_key_exists('bin', $this->cTypes['default'])) {
$this->cTypes['default']['bin'] = 'application/vnd.openxmlformats-officedocument.oleObject';
}
}
}
}
/**
* Add header/footer media elements
* Add header/footer media files
*
* @param mixed $objZip
* @param string $docPart
*/
private function addHeaderFooterMedia($objZip, $docPart)
{
$elements = Media::getMediaElements($docPart);
$elements = Media::getElements($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);
}
$objZip->addFromString("word/_rels/{$file}.xml.rels", $this->getWriterPart('rels')->writeMediaRels($media));
}
}
}
}
/**
* Add header/footer content
*
* @param Section $section
* @param string $elmType
* @param integer $rID
*/
private function addHeaderFooterContent(&$section, $objZip, $elmType, &$rID)
{
$getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters';
$writeFunction = $elmType == 'header' ? 'writeHeader' : 'writeFooter';
$elmCount = ($section->getSectionId() - 1) * 3;
$elmObjects = $section->$getFunction();
foreach ($elmObjects as $index => &$elmObject) {
$elmCount++;
$elmObject->setRelationId(++$rID);
$elmFile = "{$elmType}{$elmCount}.xml";
$objZip->addFromString("word/$elmFile", $this->getWriterPart($elmType)->$writeFunction($elmObject));
$this->cTypes['override']["/word/$elmFile"] = $elmType;
$this->docRels[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rID);
}
}
}

View File

@ -19,28 +19,13 @@ class ContentTypes extends WriterPart
{
/**
* Write [Content_Types].xml
* @param array $imageTypes
* @param array $objectTypes
* @param int $cHdrs
* @param array $footers
*
* @param array $contentTypes
*/
public function writeContentTypes($imageTypes, $objectTypes, $cHdrs, $footers)
public function writeContentTypes($contentTypes)
{
$OpenXMLPrefix = 'application/vnd.openxmlformats-';
$WordMLPrefix = $OpenXMLPrefix . 'officedocument.wordprocessingml.';
$defaults = array(
'rels' => $OpenXMLPrefix . 'package.relationships+xml',
'xml' => 'application/xml',
);
if (is_array($imageTypes)) {
$defaults = array_merge($defaults, $imageTypes);
}
if (count($objectTypes) > 0) {
$defaults['bin'] = $OpenXMLPrefix . 'officedocument.oleObject';
}
$WordMLPrefix = $OpenXMLPrefix . 'officedocument.wordprocessingml.';
$overrides = array(
'/docProps/core.xml' => $OpenXMLPrefix . 'package.core-properties+xml',
'/docProps/app.xml' => $OpenXMLPrefix . 'officedocument.extended-properties+xml',
@ -51,14 +36,12 @@ class ContentTypes extends WriterPart
'/word/theme/theme1.xml' => $OpenXMLPrefix . 'officedocument.theme+xml',
'/word/webSettings.xml' => $WordMLPrefix . 'webSettings+xml',
'/word/fontTable.xml' => $WordMLPrefix . 'fontTable+xml',
'/word/footnotes.xml' => $WordMLPrefix . 'footnotes+xml',
);
for ($i = 1; $i <= $cHdrs; $i++) {
$overrides["/word/header{$i}.xml"] = $WordMLPrefix . 'header+xml';
}
for ($i = 1; $i <= count($footers); $i++) {
if (!is_null($footers[$i])) {
$overrides["/word/footer{$i}.xml"] = $WordMLPrefix . 'footer+xml';
$defaults = $contentTypes['default'];
if (!empty($contentTypes['override'])) {
foreach ($contentTypes['override'] as $key => $val) {
$overrides[$key] = $WordMLPrefix . $val . '+xml';
}
}
@ -66,12 +49,8 @@ class ContentTypes extends WriterPart
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('Types');
$xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types');
foreach ($defaults as $key => $value) {
$this->writeContentType($xmlWriter, true, $key, $value);
}
foreach ($overrides as $key => $value) {
$this->writeContentType($xmlWriter, false, $key, $value);
}
$this->writeContentType($xmlWriter, $defaults, true);
$this->writeContentType($xmlWriter, $overrides, false);
$xmlWriter->endElement();
return $xmlWriter->getData();
@ -86,62 +65,19 @@ class ContentTypes extends WriterPart
* @param string $contentType Content type
* @throws Exception
*/
private function writeContentType(XMLWriter $xmlWriter, $isDefault, $partName = '', $contentType = '')
private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault)
{
if ($partName != '' && $contentType != '') {
$element = $isDefault ? 'Default' : 'Override';
$partAttribute = $isDefault ? 'Extension' : 'PartName';
$xmlWriter->startElement($element);
$xmlWriter->writeAttribute($partAttribute, $partName);
$xmlWriter->writeAttribute('ContentType', $contentType);
$xmlWriter->endElement();
} else {
throw new Exception("Invalid parameters passed.");
foreach ($parts as $partName => $contentType) {
if ($partName != '' && $contentType != '') {
$partType = $isDefault ? 'Default' : 'Override';
$partAttribute = $isDefault ? 'Extension' : 'PartName';
$xmlWriter->startElement($partType);
$xmlWriter->writeAttribute($partAttribute, $partName);
$xmlWriter->writeAttribute('ContentType', $contentType);
$xmlWriter->endElement();
} else {
throw new Exception("Invalid parameters passed.");
}
}
}
/**
* Get image mime type
*
* @param string $pFile Filename
* @return string Mime Type
* @throws Exception
*/
private function getImageMimeType($pFile = '')
{
if (file_exists($pFile)) {
$image = getimagesize($pFile);
return image_type_to_mime_type($image[2]);
} else {
throw new Exception("File $pFile does not exist");
}
}
/**
* Write Default XML element
*
* @param XMLWriter $xmlWriter
* @param string $partName Part name
* @param string $contentType Content type
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
private function writeDefaultContentType(XMLWriter $xmlWriter, $partName = '', $contentType = '')
{
$this->writeContentType($xmlWriter, true, $partName, $contentType);
}
/**
* Write Override XML element
*
* @param XMLWriter $xmlWriter
* @param string $partName Part name
* @param string $contentType Content type
* @deprecated 0.9.2
* @codeCoverageIgnore
*/
private function writeOverrideContentType(XMLWriter $xmlWriter, $partName = '', $contentType = '')
{
$this->writeContentType($xmlWriter, false, $partName, $contentType);
}
}

View File

@ -103,7 +103,7 @@ class Document extends Base
{
$settings = $section->getSettings();
$headers = $section->getHeaders();
$footer = $section->getFooter();
$footers = $section->getFooters();
$pgSzW = $settings->getPageSizeW();
$pgSzH = $settings->getPageSizeH();
$orientation = $settings->getOrientation();
@ -139,19 +139,19 @@ class Document extends Base
$xmlWriter->writeAttribute('r:id', 'rId' . $rId);
$xmlWriter->endElement();
}
if ($section->hasDifferentFirstPage()) {
$xmlWriter->startElement('w:titlePg');
$xmlWriter->endElement();
}
// Footer reference
if (!is_null($footer)) {
foreach ($footers as &$footer) {
$rId = $footer->getRelationId();
$xmlWriter->startElement('w:footerReference');
$xmlWriter->writeAttribute('w:type', 'default');
$xmlWriter->writeAttribute('w:type', $footer->getType());
$xmlWriter->writeAttribute('r:id', 'rId' . $rId);
$xmlWriter->endElement();
}
// Different first page
if ($section->hasDifferentFirstPage()) {
$xmlWriter->startElement('w:titlePg');
$xmlWriter->endElement();
}
// Page size & orientation
$xmlWriter->startElement('w:pgSz');

View File

@ -29,13 +29,13 @@ class Rels extends WriterPart
*/
public function writeMainRels()
{
$rels = array(
'word/document.xml' => 'officeDocument/2006/relationships/officeDocument',
$xmlRels = array(
'docProps/core.xml' => 'package/2006/relationships/metadata/core-properties',
'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties',
'word/document.xml' => 'officeDocument/2006/relationships/officeDocument',
);
$xmlWriter = $this->getXmlWriter();
$this->writeRels($xmlWriter, $rels);
$this->writeRels($xmlWriter, $xmlRels);
return $xmlWriter->getData();
}
@ -47,7 +47,7 @@ class Rels extends WriterPart
*/
public function writeDocRels($mediaRels)
{
$rels = array(
$xmlRels = array(
'styles.xml' => 'officeDocument/2006/relationships/styles',
'numbering.xml' => 'officeDocument/2006/relationships/numbering',
'settings.xml' => 'officeDocument/2006/relationships/settings',
@ -56,7 +56,7 @@ class Rels extends WriterPart
'fontTable.xml' => 'officeDocument/2006/relationships/fontTable',
);
$xmlWriter = $this->getXmlWriter();
$this->writeRels($xmlWriter, $rels, $mediaRels);
$this->writeRels($xmlWriter, $xmlRels, $mediaRels);
return $xmlWriter->getData();
}
@ -79,20 +79,24 @@ class Rels extends WriterPart
* Write relationships
*
* @param XMLWriter $xmlWriter
* @param null|array $rels
* @param null|array $xmlRels
* @param null|array $mediaRels
* @param integer $id
*/
private function writeRels(XMLWriter $xmlWriter, $rels = null, $mediaRels = null, $id = 1)
private function writeRels(XMLWriter $xmlWriter, $xmlRels = null, $mediaRels = null, $id = 1)
{
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('Relationships');
$xmlWriter->writeAttribute('xmlns', self::RELS_BASE . 'package/2006/relationships');
if (is_array($rels)) {
foreach ($rels as $target => $type) {
// XML files relationships
if (is_array($xmlRels)) {
foreach ($xmlRels as $target => $type) {
$this->writeRel($xmlWriter, $id++, $type, $target);
}
}
// Media relationships
if (!is_null($mediaRels) && is_array($mediaRels)) {
$mapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink');
foreach ($mediaRels as $mediaRel) {

View File

@ -28,6 +28,10 @@ class Styles extends Base
*/
public function writeStyles(PhpWord $phpWord = null)
{
if (is_null($phpWord)) {
throw new Exception("No PhpWord assigned.");
}
// Create XML writer
$xmlWriter = $this->getXmlWriter();

View File

@ -40,10 +40,10 @@ class SectionTest extends \PHPUnit_Framework_TestCase
/**
* Get footer
*/
public function testGetFooter()
public function testGetFooters()
{
$oSection = new Section(0);
$this->assertAttributeEquals($oSection->getFooter(), 'footer', new Section(0));
$this->assertAttributeEquals($oSection->getFooters(), 'footers', new Section(0));
}
/**

View File

@ -25,7 +25,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase
*/
public function testGetSectionMediaElementsWithNull()
{
$this->assertEquals(Media::getMediaElements('section'), array());
$this->assertEquals(Media::getElements('section'), array());
}
/**
@ -33,7 +33,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase
*/
public function testCountSectionMediaElementsWithNull()
{
$this->assertEquals(Media::countMediaElements('section'), 0);
$this->assertEquals(Media::countElements('section'), 0);
}
/**
@ -44,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::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);
Media::addElement('section', 'image', $local, new Image($local));
Media::addElement('section', 'image', $local, new Image($local));
Media::addElement('section', 'image', $remote, new Image($local));
Media::addElement('section', 'object', $object);
Media::addElement('section', 'object', $object);
$this->assertEquals(3, Media::countMediaElements('section'));
$this->assertEquals(3, Media::countElements('section'));
}
/**
@ -58,12 +58,12 @@ class MediaTest extends \PHPUnit_Framework_TestCase
*/
public function testAddSectionLinkElement()
{
$expected = Media::countMediaElements('section') + 1;
$actual = Media::addMediaElement('section', 'link', 'http://test.com');
$expected = Media::countElements('section') + 1;
$actual = Media::addElement('section', 'link', 'http://test.com');
$this->assertEquals($expected, $actual);
$this->assertEquals(1, Media::countMediaElements('section', 'link'));
$this->assertEquals(1, count(Media::getMediaElements('section', 'link')));
$this->assertEquals(1, Media::countElements('section', 'link'));
$this->assertEquals(1, count(Media::getElements('section', 'link')));
}
/**
@ -73,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::addMediaElement('header1', 'image', $local, new Image($local));
Media::addMediaElement('header1', 'image', $local, new Image($local));
Media::addMediaElement('header1', 'image', $remote, new Image($remote));
Media::addElement('header1', 'image', $local, new Image($local));
Media::addElement('header1', 'image', $local, new Image($local));
Media::addElement('header1', 'image', $remote, new Image($remote));
$this->assertEquals(2, Media::countMediaElements('header1'));
$this->assertEquals(2, count(Media::getMediaElements('header1')));
$this->assertEmpty(Media::getMediaElements('header2'));
$this->assertEquals(2, Media::countElements('header1'));
$this->assertEquals(2, count(Media::getElements('header1')));
$this->assertEmpty(Media::getElements('header2'));
}
/**
@ -89,13 +89,24 @@ class MediaTest extends \PHPUnit_Framework_TestCase
{
$local = __DIR__ . "/_files/images/mars.jpg";
$remote = 'http://php.net/images/logos/php-med-trans-light.gif';
Media::addMediaElement('footer1', 'image', $local, new Image($local));
Media::addMediaElement('footer1', 'image', $local, new Image($local));
Media::addMediaElement('footer1', 'image', $remote, new Image($remote));
Media::addElement('footer1', 'image', $local, new Image($local));
Media::addElement('footer1', 'image', $local, new Image($local));
Media::addElement('footer1', 'image', $remote, new Image($remote));
$this->assertEquals(2, Media::countMediaElements('footer1'));
$this->assertEquals(2, Media::countElements('footer1'));
Media::reset();
$this->assertEquals(0, Media::countMediaElements('footer1'));
$this->assertEquals(0, Media::countElements('footer1'));
}
/**
* Add image element exception
*
* @expectedException Exception
* @expectedExceptionMessage Image object not assigned.
*/
public function testAddElementImageException()
{
Media::addElement('section', 'image', __DIR__ . "/_files/images/mars.jpg");
}
}