Skip to content

Commit

Permalink
#313 : PowerPoint2007 Writer : Support for custom document properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Progi1984 committed Oct 14, 2017
1 parent ee77db7 commit f9ed39f
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- PowerPoint2007 Reader : Support for fill for image - @Progi1984 GH-370
- ODPresentation Writer : Support for fill for transparent image - @Progi1984 GH-370
- PowerPoint2007 Writer : Support for fill for transparent image - @JewrassicPark GH-370
- PowerPoint2007 Writer : Support for custom document properties - @Progi1984 GH-313

## 0.9.0 - 2017-07-05

Expand Down
110 changes: 110 additions & 0 deletions src/PhpPresentation/DocumentProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
*/
class DocumentProperties
{
/** Constants */
const PROPERTY_TYPE_BOOLEAN = 'b';
const PROPERTY_TYPE_INTEGER = 'i';
const PROPERTY_TYPE_FLOAT = 'f';
const PROPERTY_TYPE_DATE = 'd';
const PROPERTY_TYPE_STRING = 's';
const PROPERTY_TYPE_UNKNOWN = 'u';

/**
* Creator
*
Expand Down Expand Up @@ -92,6 +100,13 @@ class DocumentProperties
*/
private $company;

/**
* Custom Properties.
*
* @var string[]
*/
private $customProperties = array();

/**
* Create a new \PhpOffice\PhpPresentation\DocumentProperties
*/
Expand Down Expand Up @@ -345,4 +360,99 @@ public function setCompany($pValue = '')

return $this;
}

/**
* Get a List of Custom Property Names.
*
* @return array of string
*/
public function getCustomProperties()
{
return array_keys($this->customProperties);
}

/**
* Check if a Custom Property is defined.
*
* @param string $propertyName
*
* @return bool
*/
public function isCustomPropertySet($propertyName)
{
return isset($this->customProperties[$propertyName]);
}

/**
* Get a Custom Property Value.
*
* @param string $propertyName
*
* @return string
*/
public function getCustomPropertyValue($propertyName)
{
if (isset($this->customProperties[$propertyName])) {
return $this->customProperties[$propertyName]['value'];
}
return null;
}

/**
* Get a Custom Property Type.
*
* @param string $propertyName
*
* @return string
*/
public function getCustomPropertyType($propertyName)
{
if (isset($this->customProperties[$propertyName])) {
return $this->customProperties[$propertyName]['type'];
}
return null;
}

/**
* Set a Custom Property.
*
* @param string $propertyName
* @param mixed $propertyValue
* @param string $propertyType
* 'i' : Integer
* 'f' : Floating Point
* 's' : String
* 'd' : Date/Time
* 'b' : Boolean
*
* @return $this
*/
public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
{
if (($propertyType === null)
|| (!in_array($propertyType, array(
self::PROPERTY_TYPE_INTEGER,
self::PROPERTY_TYPE_FLOAT,
self::PROPERTY_TYPE_STRING,
self::PROPERTY_TYPE_DATE,
self::PROPERTY_TYPE_BOOLEAN,
)))) {
if ($propertyValue === null) {
$propertyType = self::PROPERTY_TYPE_STRING;
} elseif (is_float($propertyValue)) {
$propertyType = self::PROPERTY_TYPE_FLOAT;
} elseif (is_int($propertyValue)) {
$propertyType = self::PROPERTY_TYPE_INTEGER;
} elseif (is_bool($propertyValue)) {
$propertyType = self::PROPERTY_TYPE_BOOLEAN;
} else {
$propertyType = self::PROPERTY_TYPE_STRING;
}
}
$this->customProperties[$propertyName] = [
'value' => $propertyValue,
'type' => $propertyType,
];
return $this;
}
}
37 changes: 36 additions & 1 deletion src/PhpPresentation/Writer/PowerPoint2007/DocPropsCustom.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;

use PhpOffice\Common\XMLWriter;
use PhpOffice\PhpPresentation\DocumentProperties;

class DocPropsCustom extends AbstractDecoratorWriter
{
Expand All @@ -11,6 +12,9 @@ class DocPropsCustom extends AbstractDecoratorWriter
*/
public function render()
{
// Variables
$pId = 0;

// Create XML writer
$objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);

Expand All @@ -26,7 +30,7 @@ public function render()
// property
$objWriter->startElement('property');
$objWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}');
$objWriter->writeAttribute('pid', 2);
$objWriter->writeAttribute('pid', (++$pId) * 2);
$objWriter->writeAttribute('name', '_MarkAsFinal');

// property > vt:bool
Expand All @@ -36,6 +40,37 @@ public function render()
$objWriter->endElement();
}

$oDocumentProperties = $this->oPresentation->getDocumentProperties();
foreach ($oDocumentProperties->getCustomProperties() as $customProperty) {
$propertyValue = $oDocumentProperties->getCustomPropertyValue($customProperty);
$propertyType = $oDocumentProperties->getCustomPropertyType($customProperty);

$objWriter->startElement('property');
$objWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}');
$objWriter->writeAttribute('pid', (++$pId) * 2);
$objWriter->writeAttribute('name', $customProperty);
switch ($propertyType) {
case DocumentProperties::PROPERTY_TYPE_INTEGER:
$objWriter->writeElement('vt:i4', $propertyValue);
break;
case DocumentProperties::PROPERTY_TYPE_FLOAT:
$objWriter->writeElement('vt:r8', $propertyValue);
break;
case DocumentProperties::PROPERTY_TYPE_BOOLEAN:
$objWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false');
break;
case DocumentProperties::PROPERTY_TYPE_DATE:
$objWriter->startElement('vt:filetime');
$objWriter->writeRaw(date(DATE_W3C, $propertyValue));
$objWriter->endElement();
break;
default:
$objWriter->writeElement('vt:lpwstr', $propertyValue);
break;
}
$objWriter->endElement();
}

// > Properties
$objWriter->endElement();

Expand Down
54 changes: 54 additions & 0 deletions tests/PhpPresentation/Tests/DocumentPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,58 @@ public function testGetSetNull()
$this->assertEquals($time, $object->$get());
}
}

public function testCustomProperties()
{
$valueTime = time();

$object = new DocumentProperties();
$this->assertInternalType('array', $object->getCustomProperties());
$this->assertCount(0, $object->getCustomProperties());
$this->assertFalse($object->isCustomPropertySet('pName'));
$this->assertNull($object->getCustomPropertyType('pName'));
$this->assertNull($object->getCustomPropertyValue('pName'));

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', 'pValue', null));
$this->assertCount(1, $object->getCustomProperties());
$this->assertTrue($object->isCustomPropertySet('pName'));
$this->assertEquals(DocumentProperties::PROPERTY_TYPE_STRING , $object->getCustomPropertyType('pName'));
$this->assertEquals('pValue' , $object->getCustomPropertyValue('pName'));

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', 2, null));
$this->assertCount(1, $object->getCustomProperties());
$this->assertTrue($object->isCustomPropertySet('pName'));
$this->assertEquals(DocumentProperties::PROPERTY_TYPE_INTEGER , $object->getCustomPropertyType('pName'));
$this->assertEquals(2 , $object->getCustomPropertyValue('pName'));

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', 2.1, null));
$this->assertCount(1, $object->getCustomProperties());
$this->assertTrue($object->isCustomPropertySet('pName'));
$this->assertEquals(DocumentProperties::PROPERTY_TYPE_FLOAT , $object->getCustomPropertyType('pName'));
$this->assertEquals(2.1 , $object->getCustomPropertyValue('pName'));

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', true, null));
$this->assertCount(1, $object->getCustomProperties());
$this->assertTrue($object->isCustomPropertySet('pName'));
$this->assertEquals(DocumentProperties::PROPERTY_TYPE_BOOLEAN , $object->getCustomPropertyType('pName'));
$this->assertEquals(true , $object->getCustomPropertyValue('pName'));

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', null, null));
$this->assertCount(1, $object->getCustomProperties());
$this->assertTrue($object->isCustomPropertySet('pName'));
$this->assertEquals(DocumentProperties::PROPERTY_TYPE_STRING , $object->getCustomPropertyType('pName'));
$this->assertEquals(null , $object->getCustomPropertyValue('pName'));

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', $valueTime, DocumentProperties::PROPERTY_TYPE_DATE));
$this->assertCount(1, $object->getCustomProperties());
$this->assertTrue($object->isCustomPropertySet('pName'));
$this->assertEquals(DocumentProperties::PROPERTY_TYPE_DATE , $object->getCustomPropertyType('pName'));
$this->assertEquals($valueTime , $object->getCustomPropertyValue('pName'));

$this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', (string)$valueTime, DocumentProperties::PROPERTY_TYPE_UNKNOWN));
$this->assertCount(1, $object->getCustomProperties());
$this->assertTrue($object->isCustomPropertySet('pName'));
$this->assertEquals(DocumentProperties::PROPERTY_TYPE_STRING, $object->getCustomPropertyType('pName'));
$this->assertEquals($valueTime , $object->getCustomPropertyValue('pName'));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PhpPresentation\Tests\Writer\PowerPoint2007;

use PhpOffice\PhpPresentation\DocumentProperties;
use PhpOffice\PhpPresentation\Tests\PhpPresentationTestCase;

class DocPropsCustomTest extends PhpPresentationTestCase
Expand Down Expand Up @@ -30,4 +31,83 @@ public function testMarkAsFinalFalse()

$this->assertZipXmlElementNotExists('docProps/custom.xml', '/Properties/property[@name="_MarkAsFinal"]');
}

public function testCustomPropertiesBoolean()
{
$this->oPresentation->getDocumentProperties()->setCustomProperty('pName', false, null);

$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:bool');
$this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:bool', 'false');
}

public function testCustomPropertiesDate()
{
$value = time();
$this->oPresentation->getDocumentProperties()->setCustomProperty('pName', $value, DocumentProperties::PROPERTY_TYPE_DATE);

$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:filetime');
$this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:filetime', date(DATE_W3C, $value));
}

public function testCustomPropertiesFloat()
{
$this->oPresentation->getDocumentProperties()->setCustomProperty('pName', 2.1, null);

$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:r8');
$this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:r8', 2.1);
}

public function testCustomPropertiesInteger()
{
$this->oPresentation->getDocumentProperties()->setCustomProperty('pName', 2, null);

$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:i4');
$this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:i4', 2);
}

public function testCustomPropertiesNull()
{
$this->oPresentation->getDocumentProperties()->setCustomProperty('pName', null, null);

$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr');
$this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr', '');
}

public function testCustomPropertiesString()
{
$this->oPresentation->getDocumentProperties()->setCustomProperty('pName', 'pValue', null);

$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr');
$this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr', 'pValue');
}

public function testCustomPropertiesUnknown()
{
$value = time();
$this->oPresentation->getDocumentProperties()->setCustomProperty('pName', (string)$value, DocumentProperties::PROPERTY_TYPE_UNKNOWN);

$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]');
$this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr');
$this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr', $value);
}
}

0 comments on commit f9ed39f

Please sign in to comment.