From 4fe278adf2af96a5f71c15a59ea4b69cb2e6afec Mon Sep 17 00:00:00 2001 From: Wouter Admiraal Date: Mon, 4 Jul 2016 12:38:58 +0200 Subject: [PATCH] Issue #69: Handle grouped properties As per RFC, properties can be grouped together by prefixing them with an arbitrary, alphanumeric value, followed by a full stop (.). Add support for this in the VCardParser class, and add unit tests accordingly. --- src/VCardParser.php | 16 ++++++++++++++++ tests/VCardParserTest.php | 10 +++++++--- tests/example.vcf | 4 ++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/VCardParser.php b/src/VCardParser.php index 9a999e3..aff4b74 100644 --- a/src/VCardParser.php +++ b/src/VCardParser.php @@ -164,6 +164,12 @@ protected function parse() } elseif (strtoupper($line) == "END:VCARD") { $this->vcardObjects[] = $cardData; } elseif (!empty($line)) { + // Strip grouping information. We don't use the group names. We + // simply use a list for entries that have multiple values. + // As per RFC, group names are alphanumerical, and end with a + // period (.). + $line = preg_replace('/^\w+\./', '', $line); + $type = ''; $value = ''; @list($type, $value) = explode(':', $line, 2); @@ -172,6 +178,16 @@ protected function parse() $element = strtoupper($types[0]); array_shift($types); + + // Normalize types. A type can either be a type-param directly, + // or can be prefixed with "type=". E.g.: "INTERNET" or + // "type=INTERNET". + if (!empty($types)) { + $types = array_map(function($type) { + return preg_replace('/^type=/i', '', $type); + }, $types); + } + $i = 0; $rawValue = false; foreach ($types as $type) { diff --git a/tests/VCardParserTest.php b/tests/VCardParserTest.php index 43b79a2..510ad37 100644 --- a/tests/VCardParserTest.php +++ b/tests/VCardParserTest.php @@ -153,17 +153,17 @@ public function testUrl() $this->assertEquals($parser->getCardAtIndex(0)->url['PREF;WORK'][0], 'http://work1.example.com'); $this->assertEquals($parser->getCardAtIndex(0)->url['PREF;WORK'][1], 'http://work2.example.com'); } - + public function testNote() { $vcard = new VCard(); $vcard->addNote('This is a testnote'); $parser = new VCardParser($vcard->buildVCard()); - + $vcardMultiline = new VCard(); $vcardMultiline->addNote("This is a multiline note\nNew line content!\r\nLine 2"); $parserMultiline = new VCardParser($vcardMultiline->buildVCard()); - + $this->assertEquals($parser->getCardAtIndex(0)->note, 'This is a testnote'); $this->assertEquals(nl2br($parserMultiline->getCardAtIndex(0)->note), nl2br("This is a multiline note" . PHP_EOL . "New line content!" . PHP_EOL . "Line 2")); } @@ -239,6 +239,10 @@ public function testFromFile() $this->assertEquals($cards[0]->firstname, "Wouter"); $this->assertEquals($cards[0]->lastname, "Admiraal"); $this->assertEquals($cards[0]->fullname, "Wouter Admiraal"); + // Check the parsing of grouped items as well, which are present in the + // example file. + $this->assertEquals($cards[0]->url['default'][0], 'http://example.com'); + $this->assertEquals($cards[0]->email['INTERNET'][0], 'site@example.com'); } /** diff --git a/tests/example.vcf b/tests/example.vcf index d04a41d..5fb912e 100644 --- a/tests/example.vcf +++ b/tests/example.vcf @@ -3,4 +3,8 @@ VERSION:3.0 REV:2016-05-30T10:36:13Z N;CHARSET=utf-8:Admiraal;Wouter;;; FN;CHARSET=utf-8:Wouter Admiraal +item1.EMAIL;type=INTERNET:site@example.com +item1.X-ABLabel:$!!$ +item2.URL:http://example.com +item2.X-ABLabel:$!!$ END:VCARD