diff --git a/docs/changes/1.0.0.md b/docs/changes/1.0.0.md index 621fc25c9..4b369161e 100644 --- a/docs/changes/1.0.0.md +++ b/docs/changes/1.0.0.md @@ -60,6 +60,8 @@ - ODPresentation Writer - PowerPoint2007 Reader - PowerPoint2007 Writer +- Support for custom document properties - @Progi1984 GH-313 + - PowerPoint2007 Writer ## Project Management - Migrated from Travis CI to Github Actions - @Progi1984 GH-635 diff --git a/src/PhpPresentation/DocumentProperties.php b/src/PhpPresentation/DocumentProperties.php index cc1e61f9d..59e3d28a8 100644 --- a/src/PhpPresentation/DocumentProperties.php +++ b/src/PhpPresentation/DocumentProperties.php @@ -23,6 +23,13 @@ */ class DocumentProperties { + public const PROPERTY_TYPE_BOOLEAN = 'b'; + public const PROPERTY_TYPE_INTEGER = 'i'; + public const PROPERTY_TYPE_FLOAT = 'f'; + public const PROPERTY_TYPE_DATE = 'd'; + public const PROPERTY_TYPE_STRING = 's'; + public const PROPERTY_TYPE_UNKNOWN = 'u'; + /** * Creator. * @@ -94,7 +101,14 @@ class DocumentProperties private $company; /** - * Create a new \PhpOffice\PhpPresentation\DocumentProperties. + * Custom Properties. + * + * @var array> + */ + private $customProperties = []; + + /** + * Create a new \PhpOffice\PhpPresentation\DocumentProperties */ public function __construct() { @@ -356,4 +370,99 @@ public function setCompany($pValue = '') return $this; } + + /** + * Get a List of Custom Property Names. + * + * @return array + */ + public function getCustomProperties(): array + { + return array_keys($this->customProperties); + } + + /** + * Check if a Custom Property is defined. + * + * @param string $propertyName + * + * @return bool + */ + public function isCustomPropertySet(string $propertyName): bool + { + return isset($this->customProperties[$propertyName]); + } + + /** + * Get a Custom Property Value. + * + * @param string $propertyName + * + * @return string|null + */ + public function getCustomPropertyValue(string $propertyName): ?string + { + if ($this->isCustomPropertySet($propertyName)) { + return $this->customProperties[$propertyName]['value']; + } + + return null; + } + + /** + * Get a Custom Property Type. + * + * @param string $propertyName + * + * @return string|null + */ + public function getCustomPropertyType(string $propertyName): ?string + { + if ($this->isCustomPropertySet($propertyName)) { + return $this->customProperties[$propertyName]['type']; + } + + return null; + } + + /** + * Set a Custom Property. + * + * @param string $propertyName + * @param mixed $propertyValue + * @param string|null $propertyType + * 'i' : Integer + * 'f' : Floating Point + * 's' : String + * 'd' : Date/Time + * 'b' : Boolean + * + * @return self + */ + public function setCustomProperty(string $propertyName, mixed $propertyValue = '', ?string $propertyType = null): self + { + if (!in_array($propertyType, [ + self::PROPERTY_TYPE_INTEGER, + self::PROPERTY_TYPE_FLOAT, + self::PROPERTY_TYPE_STRING, + self::PROPERTY_TYPE_DATE, + self::PROPERTY_TYPE_BOOLEAN, + ])) { + if (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; + } } diff --git a/src/PhpPresentation/Reader/ODPresentation.php b/src/PhpPresentation/Reader/ODPresentation.php index 646d1bf14..bc6ca4462 100644 --- a/src/PhpPresentation/Reader/ODPresentation.php +++ b/src/PhpPresentation/Reader/ODPresentation.php @@ -22,6 +22,7 @@ use DOMElement; use PhpOffice\Common\Drawing as CommonDrawing; use PhpOffice\Common\XMLReader; +use PhpOffice\PhpPresentation\DocumentProperties; use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\PresentationProperties; use PhpOffice\PhpPresentation\Shape\Drawing\Gd; @@ -169,7 +170,7 @@ protected function loadDocumentProperties(): void '/office:document-meta/office:meta/meta:creation-date' => 'setCreated', '/office:document-meta/office:meta/dc:date' => 'setModified', ]; - $oProperties = $this->oPhpPresentation->getDocumentProperties(); + $properties = $this->oPhpPresentation->getDocumentProperties(); foreach ($arrayProperties as $path => $property) { $oElement = $this->oXMLReader->getElement($path); if ($oElement instanceof DOMElement) { @@ -181,8 +182,36 @@ protected function loadDocumentProperties(): void } $value = $dateTime->getTimestamp(); } - $oProperties->{$property}($value); - } + $properties->{$property}($value); + } + } + + foreach ($this->oXMLReader->getElements('/office:document-meta/office:meta/meta:user-defined') as $element) { + if (!($element instanceof DOMElement) + || !$element->hasAttribute('meta:name')) { + continue; + } + $propertyName = $element->getAttribute('meta:name'); + $propertyValue = (string) $element->nodeValue; + $propertyType = $element->getAttribute('meta:value-type'); + switch ($propertyType) { + case 'boolean': + $propertyType = DocumentProperties::PROPERTY_TYPE_BOOLEAN; + break; + case 'float': + $propertyType = filter_var($variable, FILTER_VALIDATE_INT) === false + ? DocumentProperties::PROPERTY_TYPE_FLOAT + : DocumentProperties::PROPERTY_TYPE_INTEGER; + break; + case 'date': + $propertyType = DocumentProperties::PROPERTY_TYPE_DATE; + break; + case 'string': + default: + $propertyType = DocumentProperties::PROPERTY_TYPE_STRING; + break; + } + $properties->setCustomProperty($propertyName, $propertyValue, $propertyType); } } diff --git a/src/PhpPresentation/Reader/PowerPoint2007.php b/src/PhpPresentation/Reader/PowerPoint2007.php index b4ea147e7..0c3af9e69 100644 --- a/src/PhpPresentation/Reader/PowerPoint2007.php +++ b/src/PhpPresentation/Reader/PowerPoint2007.php @@ -244,10 +244,41 @@ protected function loadCustomProperties(string $sPart): void $sPart = str_replace(' xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"', '', $sPart); /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { - $pathMarkAsFinal = '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="_MarkAsFinal"]/vt:bool'; - if (is_object($oElement = $xmlReader->getElement($pathMarkAsFinal))) { - if ('true' == $oElement->nodeValue) { - $this->oPhpPresentation->getPresentationProperties()->markAsFinal(true); + foreach ($xmlReader->getElements('/Properties/property[@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"]') as $element) { + if (!$element->hasAttribute('name')) { + continue; + } + $propertyName = $element->getAttribute('name'); + if ($propertyName == '_MarkAsFinal') { + $attributeElement = $xmlReader->getElement('vt:bool', $element); + if ($attributeElement && 'true' == $attributeElement->nodeValue) { + $this->oPhpPresentation->getPresentationProperties()->markAsFinal(true); + } + } else { + $attributeTypeInt = $xmlReader->getElement('vt:i4', $element); + $attributeTypeFloat = $xmlReader->getElement('vt:r8', $element); + $attributeTypeBoolean = $xmlReader->getElement('vt:bool', $element); + $attributeTypeDate = $xmlReader->getElement('vt:filetime', $element); + $attributeTypeString = $xmlReader->getElement('vt:lpwstr', $element); + + if ($attributeTypeInt) { + $propertyType = DocumentProperties::PROPERTY_TYPE_INTEGER; + $propertyValue = (int) $attributeTypeInt->nodeValue; + } elseif ($attributeTypeFloat) { + $propertyType = DocumentProperties::PROPERTY_TYPE_FLOAT; + $propertyValue = (float) $attributeTypeInt->nodeValue; + } elseif ($attributeTypeBoolean) { + $propertyType = DocumentProperties::PROPERTY_TYPE_BOOLEAN; + $propertyValue = $attributeTypeInt->nodeValue == 'true' ? true : false; + } elseif ($attributeTypeDate) { + $propertyType = DocumentProperties::PROPERTY_TYPE_DATE; + $propertyValue = strtotime($attributeTypeInt->nodeValue); + } else { + $propertyType = DocumentProperties::PROPERTY_TYPE_STRING; + $propertyValue = $attributeTypeInt->nodeValue; + } + + $properties->setCustomProperty($propertyName, $propertyValue, $propertyType); } } } diff --git a/src/PhpPresentation/Writer/ODPresentation/Meta.php b/src/PhpPresentation/Writer/ODPresentation/Meta.php index 2c742ce61..95b2d41ae 100644 --- a/src/PhpPresentation/Writer/ODPresentation/Meta.php +++ b/src/PhpPresentation/Writer/ODPresentation/Meta.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpPresentation\Writer\ODPresentation; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpPresentation\DocumentProperties; class Meta extends AbstractDecoratorWriter { @@ -52,6 +53,38 @@ public function render() // meta:keyword $objWriter->writeElement('meta:keyword', $this->getPresentation()->getDocumentProperties()->getKeywords()); + // meta:user-defined + $oDocumentProperties = $this->oPresentation->getDocumentProperties(); + foreach ($oDocumentProperties->getCustomProperties() as $customProperty) { + $propertyValue = $oDocumentProperties->getCustomPropertyValue($customProperty); + $propertyType = $oDocumentProperties->getCustomPropertyType($customProperty); + + $objWriter->startElement('meta:user-defined'); + $objWriter->writeAttribute('meta:name', $customProperty); + switch ($propertyType) { + case DocumentProperties::PROPERTY_TYPE_INTEGER: + case DocumentProperties::PROPERTY_TYPE_FLOAT: + $objWriter->writeAttribute('meta:value-type', 'float'); + $objWriter->writeRaw($propertyValue); + break; + case DocumentProperties::PROPERTY_TYPE_BOOLEAN: + $objWriter->writeAttribute('meta:value-type', 'boolean'); + $objWriter->writeRaw($propertyValue ? 'true' : 'false'); + break; + case DocumentProperties::PROPERTY_TYPE_DATE: + $objWriter->writeAttribute('meta:value-type', 'date'); + $objWriter->writeRaw(date(DATE_W3C, strtotime($propertyValue))); + break; + case DocumentProperties::PROPERTY_TYPE_STRING: + case DocumentProperties::PROPERTY_TYPE_UNKNOWN: + default: + $objWriter->writeAttribute('meta:value-type', 'string'); + $objWriter->writeRaw($propertyValue); + break; + } + $objWriter->endElement(); + } + // @todo : Where these properties are written ? // $this->getPresentation()->getDocumentProperties()->getCategory() // $this->getPresentation()->getDocumentProperties()->getCompany() diff --git a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCustom.php b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCustom.php index 94981aa54..bc6e7b83f 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCustom.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCustom.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpPresentation\DocumentProperties; class DocPropsCustom extends AbstractDecoratorWriter { @@ -13,6 +14,9 @@ class DocPropsCustom extends AbstractDecoratorWriter */ public function render() { + // Variables + $pId = 0; + // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -28,7 +32,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 @@ -38,6 +42,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, strtotime($propertyValue))); + $objWriter->endElement(); + break; + default: + $objWriter->writeElement('vt:lpwstr', $propertyValue); + break; + } + $objWriter->endElement(); + } + // > Properties $objWriter->endElement(); diff --git a/tests/PhpPresentation/Tests/DocumentPropertiesTest.php b/tests/PhpPresentation/Tests/DocumentPropertiesTest.php index c89d745b1..273428fa1 100644 --- a/tests/PhpPresentation/Tests/DocumentPropertiesTest.php +++ b/tests/PhpPresentation/Tests/DocumentPropertiesTest.php @@ -74,4 +74,58 @@ public function testGetSetNull(): void $this->assertEquals($time, $object->$get()); } } + + public function testCustomProperties(): void + { + $valueTime = time(); + + $object = new DocumentProperties(); + $this->assertIsArray($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')); + } } diff --git a/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php b/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php index 02eadf4d5..904cd1e8f 100644 --- a/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php +++ b/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php @@ -96,6 +96,9 @@ public function testLoadFile01(): void $this->assertEquals('Sample 02 Subject', $oPhpPresentation->getDocumentProperties()->getSubject()); $this->assertEquals('Sample 02 Description', $oPhpPresentation->getDocumentProperties()->getDescription()); $this->assertEquals('office 2007 openxml libreoffice odt php', $oPhpPresentation->getDocumentProperties()->getKeywords()); + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); + // Presentation Properties $this->assertEquals(PresentationProperties::SLIDESHOW_TYPE_PRESENT, $oPhpPresentation->getPresentationProperties()->getSlideshowType()); @@ -559,6 +562,8 @@ public function testSlideName(): void $object = new ODPresentation(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); $this->assertEquals('MaDiapo', $oPhpPresentation->getSlide(0)->getName()); } @@ -569,6 +574,8 @@ public function testIssue00141(): void $object = new ODPresentation(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); $this->assertCount(3, $oPhpPresentation->getAllSlides()); diff --git a/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php b/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php index 2d2aa1f3a..08a5c1489 100644 --- a/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php +++ b/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php @@ -95,6 +95,9 @@ public function testLoadFile01(): void $this->assertEquals('Sample 02 Description', $oPhpPresentation->getDocumentProperties()->getDescription()); $this->assertEquals('office 2007 openxml libreoffice odt php', $oPhpPresentation->getDocumentProperties()->getKeywords()); $this->assertEquals('Sample Category', $oPhpPresentation->getDocumentProperties()->getCategory()); + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); + // Presentation Properties $this->assertEquals(PresentationProperties::SLIDESHOW_TYPE_PRESENT, $oPhpPresentation->getPresentationProperties()->getSlideshowType()); // Document Layout diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaTest.php new file mode 100644 index 000000000..54e3f412b --- /dev/null +++ b/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaTest.php @@ -0,0 +1,72 @@ +oPresentation->getDocumentProperties()->setCustomProperty('pName', $propertyValue, $propertyType); + + $this->assertZipXmlElementExists('meta.xml', '/office:document-meta'); + $this->assertZipXmlElementExists('meta.xml', '/office:document-meta/office:meta'); + $this->assertZipXmlElementExists('meta.xml', '/office:document-meta/office:meta/meta:user-defined'); + $this->assertZipXmlElementEquals('meta.xml', '/office:document-meta/office:meta/meta:user-defined', $expectedValue); + $this->assertZipXmlAttributeExists('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:name'); + $this->assertZipXmlAttributeEquals('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:name', 'pName'); + $this->assertZipXmlAttributeExists('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:value-type'); + $this->assertZipXmlAttributeEquals('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:value-type', $expectedValueType); + } + + public function dataProviderCustomProperties(): array + { + $valueTime = time(); + + return [ + [ + false, + null, + 'false', + 'boolean', + ], + [ + $valueTime, + DocumentProperties::PROPERTY_TYPE_DATE, + date(DATE_W3C, strtotime($valueTime)), + 'date', + ], + [ + 2.1, + null, + '2.1', + 'float', + ], + [ + 2, + null, + '2', + 'float', + ], + [ + null, + null, + '', + 'string', + ], + [ + (string) $valueTime, + DocumentProperties::PROPERTY_TYPE_UNKNOWN, + (string) $valueTime, + 'string', + ], + ]; + } +} diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php index dba9c54b0..d3200e13d 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php @@ -2,6 +2,7 @@ namespace PhpPresentation\Tests\Writer\PowerPoint2007; +use PhpOffice\PhpPresentation\DocumentProperties; use PhpOffice\PhpPresentation\Tests\PhpPresentationTestCase; class DocPropsCustomTest extends PhpPresentationTestCase @@ -33,4 +34,83 @@ public function testMarkAsFinalFalse(): void $this->assertZipXmlElementNotExists('docProps/custom.xml', '/Properties/property[@name="_MarkAsFinal"]'); $this->assertIsSchemaECMA376Valid(); } + + public function testCustomPropertiesBoolean(): void + { + $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(): void + { + $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, strtotime($value))); + } + + public function testCustomPropertiesFloat(): void + { + $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(): void + { + $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(): void + { + $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(): void + { + $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(): void + { + $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); + } }