nfTlWNl rn Ѻq$³* hx!.p2L0f8wb6 iXi/. vu˼ƒPQ?ltjdK,sUܑ4YfKv5GC8ǙobG@+x,La)CHw) yuF +ӯyh+:UU'MD>~I" nve69:W86SGQt |>P듩k0ԋ7ü~<=A/lA2Hkogph)/Jx1hǡ,Umue &0xnr c—d#>jK䛰?tܬKufE _w) yGV-Ĺp Ձ@r $&Mɤ > *vc ZuJg{"f{Gqq I]V8Lo C69ј`г " x2,70pN|sw{\ؽ_Ee$ vsmW)nVƦH1`8J6!*J'!}C&!acP7jm;棭 i[+{,_vZ/TeL?9ޅAE0qH/rtOZhPllPQܥ%|t Ҭ2yKZb#Xeő(wBUDv,db@S=9vʳ+ Ҏ(CCb^BFwnUid/}*"[wn6T9\r?cb&І9?˜;u`&3Md2^ [zse&VV?)%m_$K^o\%d|߬W_ :T.aҊ BgJz+(fel&d:m}Ch\Ծ#ՈD ;3圹X ,_=T 2YəMC]9;C\/(|=LLc[s?R-.ވMX+cy#f "aH ߐVY}@T+S}ԸH!22Z?@~mx01y$/p0b=:v)(ȉٕR,..M2^pT"s~S3]"8-A4K;>TjN4ރ\lz~p4ZHa3T{ybbQ}hnj053lJ3dž;)[t,7a֐k]u?mnU_n RvIw"A h[P4u,_f S&|t{iqmhXWDM౸!nJ\] ز3 L;o`Y@%`|ɆeBѷFk^Jt h(;1'ZVeD K`Բ'uKpNCy~o'fޥ:rx/³N‘m ,Aε(JaXR tb/pb(PT&}5P7 =گ6 |NNTNн)ReyG|CKN1ui+)nfa^^gYQ%:+9Np ½,z.YmA'gV~kkz^Ar%)UȼY,ppu0ɶL7=8v?4nM*8?g ܶT72aIMf26/#뒽J1`me:xVGI)҇wk LHkz^Ar%T\?'* PPhJ1R X8j+yKInOz\Zw}𓼣X^ž?50)U18ٛ;ۆ{I{衑st܆[zdN(X5E ز3 L;o`Y@%`|Ɇ㾚*Z~%Knfa^^g 0ZF{/uW~ 4m˥ݩ: )(\KG%3`t^&!׊'Y&z7<[zsP^D5wr"B S&?qS?`^z[#n9[mҘEnuϐVvE67cGԒ$9^WmR 1If_ƎQ^;wPї~?7I 耀%D(3mҘEnuϐVvE67cGԒ$9^WmR 1If_ƎQfv́#,Fk#0ȴ},,kv{k^q OPV>*5h~% Ĺ<A>3,U)둤K'BW.t߹Jiw{j:mo#q2T3_6xE\Y)j[@o{ʯ%)±RzWR7sWmc*^E{]wص1Z];u)x83K ZDQq*7&\]8m ;̩}kT#L؀Ș;Lj|w#1Ŗ d9`9YK0R8o>8Kq sllOIA#:@S5)݇Ң'7qmP[H@:^,Ⱥoa)Q 66M"C VLX%8D1#OCc>UX,גA!s6CGB5OoMka<^cSƙTf1ZknBig~ӨpoQ%Gcv/whBe7x0_P}Qǐα.IN(˭^^kz"YXwgtCU1Y+@wsK }clum@߻(L{$pK.r^ * * @return float|int */ public function getModified() { return $this->modified; } /** * Set Modified. * * @param null|float|int|string $timestamp * * @return $this */ public function setModified($timestamp): self { $this->modified = self::intOrFloatTimestamp($timestamp); return $this; } /** * Get Title. */ public function getTitle(): string { return $this->title; } /** * Set Title. * * @return $this */ public function setTitle(string $title): self { $this->title = $title; return $this; } /** * Get Description. */ public function getDescription(): string { return $this->description; } /** * Set Description. * * @return $this */ public function setDescription(string $description): self { $this->description = $description; return $this; } /** * Get Subject. */ public function getSubject(): string { return $this->subject; } /** * Set Subject. * * @return $this */ public function setSubject(string $subject): self { $this->subject = $subject; return $this; } /** * Get Keywords. */ public function getKeywords(): string { return $this->keywords; } /** * Set Keywords. * * @return $this */ public function setKeywords(string $keywords): self { $this->keywords = $keywords; return $this; } /** * Get Category. */ public function getCategory(): string { return $this->category; } /** * Set Category. * * @return $this */ public function setCategory(string $category): self { $this->category = $category; return $this; } /** * Get Company. */ public function getCompany(): string { return $this->company; } /** * Set Company. * * @return $this */ public function setCompany(string $company): self { $this->company = $company; return $this; } /** * Get Manager. */ public function getManager(): string { return $this->manager; } /** * Set Manager. * * @return $this */ public function setManager(string $manager): self { $this->manager = $manager; return $this; } /** * Get a List of Custom Property Names. * * @return string[] */ public function getCustomProperties(): array { return array_keys($this->customProperties); } /** * Check if a Custom Property is defined. */ public function isCustomPropertySet(string $propertyName): bool { return array_key_exists($propertyName, $this->customProperties); } /** * Get a Custom Property Value. * * @return mixed */ public function getCustomPropertyValue(string $propertyName) { if (isset($this->customProperties[$propertyName])) { return $this->customProperties[$propertyName]['value']; } return null; } /** * Get a Custom Property Type. * * @return null|string */ public function getCustomPropertyType(string $propertyName) { return $this->customProperties[$propertyName]['type'] ?? null; } /** * @param mixed $propertyValue */ private function identifyPropertyType($propertyValue): string { if (is_float($propertyValue)) { return self::PROPERTY_TYPE_FLOAT; } if (is_int($propertyValue)) { return self::PROPERTY_TYPE_INTEGER; } if (is_bool($propertyValue)) { return self::PROPERTY_TYPE_BOOLEAN; } return self::PROPERTY_TYPE_STRING; } /** * Set a Custom Property. * * @param mixed $propertyValue * @param string $propertyType * 'i' : Integer * 'f' : Floating Point * 's' : String * 'd' : Date/Time * 'b' : Boolean * * @return $this */ public function setCustomProperty(string $propertyName, $propertyValue = '', $propertyType = null): self { if (($propertyType === null) || (!in_array($propertyType, self::VALID_PROPERTY_TYPE_LIST))) { $propertyType = $this->identifyPropertyType($propertyValue); } if (!is_object($propertyValue)) { $this->customProperties[$propertyName] = [ 'value' => self::convertProperty($propertyValue, $propertyType), 'type' => $propertyType, ]; } return $this; } private const PROPERTY_TYPE_ARRAY = [ 'i' => self::PROPERTY_TYPE_INTEGER, // Integer 'i1' => self::PROPERTY_TYPE_INTEGER, // 1-Byte Signed Integer 'i2' => self::PROPERTY_TYPE_INTEGER, // 2-Byte Signed Integer 'i4' => self::PROPERTY_TYPE_INTEGER, // 4-Byte Signed Integer 'i8' => self::PROPERTY_TYPE_INTEGER, // 8-Byte Signed Integer 'int' => self::PROPERTY_TYPE_INTEGER, // Integer 'ui1' => self::PROPERTY_TYPE_INTEGER, // 1-Byte Unsigned Integer 'ui2' => self::PROPERTY_TYPE_INTEGER, // 2-Byte Unsigned Integer 'ui4' => self::PROPERTY_TYPE_INTEGER, // 4-Byte Unsigned Integer 'ui8' => self::PROPERTY_TYPE_INTEGER, // 8-Byte Unsigned Integer 'uint' => self::PROPERTY_TYPE_INTEGER, // Unsigned Integer 'f' => self::PROPERTY_TYPE_FLOAT, // Real Number 'r4' => self::PROPERTY_TYPE_FLOAT, // 4-Byte Real Number 'r8' => self::PROPERTY_TYPE_FLOAT, // 8-Byte Real Number 'decimal' => self::PROPERTY_TYPE_FLOAT, // Decimal 's' => self::PROPERTY_TYPE_STRING, // String 'empty' => self::PROPERTY_TYPE_STRING, // Empty 'null' => self::PROPERTY_TYPE_STRING, // Null 'lpstr' => self::PROPERTY_TYPE_STRING, // LPSTR 'lpwstr' => self::PROPERTY_TYPE_STRING, // LPWSTR 'bstr' => self::PROPERTY_TYPE_STRING, // Basic String 'd' => self::PROPERTY_TYPE_DATE, // Date and Time 'date' => self::PROPERTY_TYPE_DATE, // Date and Time 'filetime' => self::PROPERTY_TYPE_DATE, // File Time 'b' => self::PROPERTY_TYPE_BOOLEAN, // Boolean 'bool' => self::PROPERTY_TYPE_BOOLEAN, // Boolean ]; private const SPECIAL_TYPES = [ 'empty' => '', 'null' => null, ]; /** * Convert property to form desired by Excel. * * @param mixed $propertyValue * * @return mixed */ public static function convertProperty($propertyValue, string $propertyType) { return self::SPECIAL_TYPES[$propertyType] ?? self::convertProperty2($propertyValue, $propertyType); } /** * Convert property to form desired by Excel. * * @param mixed $propertyValue * * @return mixed */ private static function convertProperty2($propertyValue, string $type) { $propertyType = self::convertPropertyType($type); switch ($propertyType) { case self::PROPERTY_TYPE_INTEGER: $intValue = (int) $propertyValue; return ($type[0] === 'u') ? abs($intValue) : $intValue; case self::PROPERTY_TYPE_FLOAT: return (float) $propertyValue; case self::PROPERTY_TYPE_DATE: return self::intOrFloatTimestamp($propertyValue); case self::PROPERTY_TYPE_BOOLEAN: return is_bool($propertyValue) ? $propertyValue : ($propertyValue === 'true'); default: // includes string return $propertyValue; } } public static function convertPropertyType(string $propertyType): string { return self::PROPERTY_TYPE_ARRAY[$propertyType] ?? self::PROPERTY_TYPE_UNKNOWN; } public function getHyperlinkBase(): string { return $this->hyperlinkBase; } public function setHyperlinkBase(string $hyperlinkBase): self { $this->hyperlinkBase = $hyperlinkBase; return $this; } }