From 43b0cb19ca17100ef7f314336825a0404e91826c Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Sat, 2 Mar 2019 22:13:32 +0100 Subject: [PATCH 1/5] Fix --- src/Parser/VcfParser.php | 26 +++++++++++++++++++++++--- tests/VCardTest.php | 28 +++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/Parser/VcfParser.php b/src/Parser/VcfParser.php index ec1b4b9..0db4837 100644 --- a/src/Parser/VcfParser.php +++ b/src/Parser/VcfParser.php @@ -9,6 +9,7 @@ use JeroenDesloovere\VCard\Parser\Property\NodeParserInterface; use JeroenDesloovere\VCard\Property\NodeInterface; use JeroenDesloovere\VCard\VCard; +use JeroenDesloovere\VCard\Property\Parameter\Version; final class VcfParser implements ParserInterface { @@ -67,16 +68,35 @@ private function parseParameters(?string $parameters): array private function parseVCard(string $content): VCard { - $vCard = new VCard(); + $vCard = $this->createVcardWithGeneralProperties($content); + $lines = explode("\n", $content); foreach ($lines as $line) { - $this->parseVCardLine($line, $vCard); + $this->parseVCardContentLine($line, $vCard); } return $vCard; } - private function parseVCardLine(string $line, VCard &$vCard): void + private function createVcardWithGeneralProperties(string $content): VCard + { + $kind = null; + $version = null; + $lines = explode("\n", $content); + foreach ($lines as $line) { + /** + * @var string $node + * @var string $value + */ + @list($node, $value) = explode(':', $line, 2); + echo "\r\nNode: " . $node; + echo "\r\nValue: " . $value; + } + + return new VCard(null, Version::version3()); + } + + private function parseVCardContentLine(string $line, VCard &$vCard): void { // Strip grouping information. We don't use the group names. We // simply use a list for entries that have multiple values. diff --git a/tests/VCardTest.php b/tests/VCardTest.php index 73e6396..c9ae90c 100644 --- a/tests/VCardTest.php +++ b/tests/VCardTest.php @@ -20,6 +20,7 @@ use JeroenDesloovere\VCard\Property\Parameter\Kind; use JeroenDesloovere\VCard\Property\Parameter\Revision; use JeroenDesloovere\VCard\Property\Parameter\Type; +use JeroenDesloovere\VCard\Property\Parameter\Version; use JeroenDesloovere\VCard\Property\Photo; use JeroenDesloovere\VCard\Property\Telephone; use JeroenDesloovere\VCard\Property\Title; @@ -164,14 +165,35 @@ public function testTelephoneParser(): void { // Given $vcard = (new Vcard())->add(new Telephone('+33-01-23-45-67')); + $content = "BEGIN:VCARD\r\nVERSION:4.0\r\nTEL;VALUE=uri;TYPE=home:tel:+33-01-23-45-67\r\nEND:VCARD"; // When - $parser = new Parser(new VcfParser(), "BEGIN:VCARD\r\nTEL;VALUE=uri;TYPE=home:tel:+33-01-23-45-67\r\nEND:VCARD"); + $parser = new Parser(new VcfParser(), $content); // Then $this->assertEquals($vcard->getProperties(Telephone::class), $parser->getVCards()[0]->getProperties(Telephone::class)); } + + /** + * Test the Version parameter parser independent + */ + public function testVersionParameterParser(): void + { + // Given + // Version 4 + $vcard = new Vcard(null, Version::version4()); + // Version 3 + $content = "BEGIN:VCARD\r\nVERSION:3.0\r\nEND:VCARD"; + + // When + $parser = new Parser(new VcfParser(), $content); + + // Then + $this->assertEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); + // THIS SHOULD FAIL! 4 != 3 + } + public function testParserMultipleVCardsFromVcfFile(): void { $parser = new Parser(new VcfParser(), Parser::getFileContents(__DIR__ . '/assets/vcards.vcf')); @@ -188,6 +210,7 @@ public function testParserOneVCardFromVcfFile(): void } /** + * Integration test: * Validate the number of properties from the created vCards in the Setup. */ public function testVCardGetProperties(): void @@ -222,6 +245,7 @@ public function testTelephonePropertyContent(): void { // Given $expectedContent = "BEGIN:VCARD\r\n" . + "VERSION:4.0\r\n" . "KIND:Individual\r\n" . "TEL;TYPE=home;VALUE=uri:tel:+33-01-23-45-67\r\n" . "TEL;TYPE=work;VALUE=uri:tel:+33-05-42-41-96\r\n" . @@ -246,6 +270,7 @@ public function testNamePropertyContent(): void { // Given $expectedContent = "BEGIN:VCARD\r\n" . + "VERSION:4.0\r\n" . "KIND:Individual\r\n" . "N:Berg;Melroy;van den;Mr.;\r\n" . "END:VCARD\r\n"; @@ -268,6 +293,7 @@ public function testAddressPropertyContentWithLineBreak() : void { // Given $expectedContent = "BEGIN:VCARD\r\n" . + "VERSION:4.0\r\n" . "KIND:Individual\r\n" . "ADR;TYPE=home:42;Villa;Main Street 500;London;Barnet;EN4 0AG;United Kingd\r\n" . // Line break because of 75 octets width limit, immediately followed by a single white space. From 4da443a095774d021bceea343f01beace44ab086 Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Sat, 2 Mar 2019 22:55:00 +0100 Subject: [PATCH 2/5] Parse version & kind, and use these properties to create a new vcard object --- src/Parser/VcfParser.php | 23 +++++++++++++-------- tests/VCardTest.php | 43 +++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/Parser/VcfParser.php b/src/Parser/VcfParser.php index 0db4837..7480107 100644 --- a/src/Parser/VcfParser.php +++ b/src/Parser/VcfParser.php @@ -10,6 +10,7 @@ use JeroenDesloovere\VCard\Property\NodeInterface; use JeroenDesloovere\VCard\VCard; use JeroenDesloovere\VCard\Property\Parameter\Version; +use JeroenDesloovere\VCard\Property\Parameter\Kind; final class VcfParser implements ParserInterface { @@ -68,7 +69,7 @@ private function parseParameters(?string $parameters): array private function parseVCard(string $content): VCard { - $vCard = $this->createVcardWithGeneralProperties($content); + $vCard = $this->createVcardObjectWithProperties($content); $lines = explode("\n", $content); foreach ($lines as $line) { @@ -78,10 +79,12 @@ private function parseVCard(string $content): VCard return $vCard; } - private function createVcardWithGeneralProperties(string $content): VCard - { - $kind = null; - $version = null; + private function createVcardObjectWithProperties(string $content): VCard + { + $vcardProperties = array( + Kind::getNode() => null, + Version::getNode() => null); + $lines = explode("\n", $content); foreach ($lines as $line) { /** @@ -89,11 +92,15 @@ private function createVcardWithGeneralProperties(string $content): VCard * @var string $value */ @list($node, $value) = explode(':', $line, 2); - echo "\r\nNode: " . $node; - echo "\r\nValue: " . $value; + if (array_key_exists($node, $this->parsers)) { + // Only check on either Kind or Version node + if ($node == Kind::getNode() || $node == Version::getNode()) { + $vcardProperties[$node] = $this->parsers[$node]->parseVcfString($value); + } + } } - return new VCard(null, Version::version3()); + return new VCard($vcardProperties[Kind::getNode()], $vcardProperties[Version::getNode()]); } private function parseVCardContentLine(string $line, VCard &$vCard): void diff --git a/tests/VCardTest.php b/tests/VCardTest.php index c9ae90c..af314b2 100644 --- a/tests/VCardTest.php +++ b/tests/VCardTest.php @@ -174,11 +174,11 @@ public function testTelephoneParser(): void $this->assertEquals($vcard->getProperties(Telephone::class), $parser->getVCards()[0]->getProperties(Telephone::class)); } - /** - * Test the Version parameter parser independent + * Test the Version parameter parser independent. + * With version 4 and version 3, should result in not equal (bad weather) */ - public function testVersionParameterParser(): void + public function testVersionParameterParserBadWeather(): void { // Given // Version 4 @@ -189,9 +189,42 @@ public function testVersionParameterParser(): void // When $parser = new Parser(new VcfParser(), $content); + // Then + $this->assertNotEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); + } + + /** + * Test the Version parameter parser independent. + * Both version 4 (good weather) + */ + public function testVersionParameterParserGoodWeather(): void + { + // Given + $vcard = new Vcard(null, Version::version4()); + $content = "BEGIN:VCARD\r\nVERSION:4.0\r\nEND:VCARD"; + + // When + $parser = new Parser(new VcfParser(), $content); + + // Then + $this->assertEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); + } + + /** + * Test the Version parameter parser independent. + * Without any version specified, should use the default Version value (4.0) + */ + public function testVersionParameterParserWithoutVersion(): void + { + // Given + $vcard = new Vcard(); + $content = "BEGIN:VCARD\r\nEND:VCARD"; + + // When + $parser = new Parser(new VcfParser(), $content); + // Then $this->assertEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); - // THIS SHOULD FAIL! 4 != 3 } public function testParserMultipleVCardsFromVcfFile(): void @@ -210,7 +243,7 @@ public function testParserOneVCardFromVcfFile(): void } /** - * Integration test: + * Integration test: * Validate the number of properties from the created vCards in the Setup. */ public function testVCardGetProperties(): void From cd827a3ac053bea21501a5b178c003cb6a0ae863 Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Sat, 2 Mar 2019 23:07:05 +0100 Subject: [PATCH 3/5] Fix indent --- src/Parser/VcfParser.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Parser/VcfParser.php b/src/Parser/VcfParser.php index 7480107..4dce037 100644 --- a/src/Parser/VcfParser.php +++ b/src/Parser/VcfParser.php @@ -93,10 +93,10 @@ private function createVcardObjectWithProperties(string $content): VCard */ @list($node, $value) = explode(':', $line, 2); if (array_key_exists($node, $this->parsers)) { - // Only check on either Kind or Version node - if ($node == Kind::getNode() || $node == Version::getNode()) { - $vcardProperties[$node] = $this->parsers[$node]->parseVcfString($value); - } + // Only check on either Kind or Version node + if ($node == Kind::getNode() || $node == Version::getNode()) { + $vcardProperties[$node] = $this->parsers[$node]->parseVcfString($value); + } } } From 709f29e71e4082e1a9c3119eb5ad0102398ed1e4 Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Sun, 3 Mar 2019 01:33:03 +0100 Subject: [PATCH 4/5] Version is required --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e5eadcb..883fd91 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ $formatter->download(); * [x] [ADDRESS](./src/Property/Address.php) - The address of the object represented in structured parts ### Communications Properties: -* [x] [TEL](./src/Property/Telephone.php) - The telephone number as a tel URI -* [x] [EMAIL](./src/Property/Email.php) - The email address as a mailto URI +* [x] [TEL](./src/Property/Telephone.php) - The telephone number(s) as a tel URI +* [x] [EMAIL](./src/Property/Email.php) - The email address(es) as a mailto URI * [ ] IMPP - The IMPP instant messaging contact information * [ ] LANG - The language of the object @@ -87,7 +87,7 @@ $formatter->download(); * [ ] UID - A unique identifier for the object * [ ] CLIENTPIDMAP - Not required * [ ] URL - Any URL related to the object -* [X] [VERSION](./src/Property/Parameter/Version.php) - Not required (namespace will capture this) +* [X] [VERSION](./src/Property/Parameter/Version.php) - Is mandatory for 4.0 ### Security Properties: * [ ] KEY - The security key of the object From a65a72aaae91a3cb19b95440c700b47381a167f9 Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Sun, 3 Mar 2019 02:10:22 +0100 Subject: [PATCH 5/5] Kind should be lower case. Add even more Uts --- src/Property/Parameter/Kind.php | 21 ++++++----- tests/VCardTest.php | 65 +++++++++++++++++++++++++++++---- tests/assets/vcard.vcf | 2 +- tests/assets/vcards.vcf | 6 +-- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/Property/Parameter/Kind.php b/src/Property/Parameter/Kind.php index 616ec1b..422222b 100644 --- a/src/Property/Parameter/Kind.php +++ b/src/Property/Parameter/Kind.php @@ -16,17 +16,17 @@ */ final class Kind implements PropertyParameterInterface, SimpleNodeInterface { - // Group - To represent groups of vCard objects - protected const GROUP = 'Group'; + // group - To represent groups of vCard objects + protected const GROUP = 'group'; - // Individual - To represent people - protected const INDIVIDUAL = 'Individual'; + // individual - To represent people + protected const INDIVIDUAL = 'individual'; - // Location - To represent location objects - protected const LOCATION = 'Location'; + // location - To represent location objects + protected const LOCATION = 'location'; - // Organization - To represent organisations - protected const ORGANIZATION = 'Organization'; + // org - To represent organisations + protected const ORGANIZATION = 'org'; public const POSSIBLE_VALUES = [ self::GROUP, @@ -43,8 +43,11 @@ final class Kind implements PropertyParameterInterface, SimpleNodeInterface */ public function __construct(string $value) { + $value = strtolower($value); if (!in_array($value, self::POSSIBLE_VALUES, true)) { - throw PropertyParameterException::forWrongValue($value, self::POSSIBLE_VALUES); + // If value is absent or not understood 'individual' must be used, + // as stated in RFC 6350 + $this->value = self::INDIVIDUAL; } $this->value = $value; diff --git a/tests/VCardTest.php b/tests/VCardTest.php index af314b2..686e6eb 100644 --- a/tests/VCardTest.php +++ b/tests/VCardTest.php @@ -159,7 +159,7 @@ public function testParserGetFileContentsException(): void } /** - * Test the Telephone parser independent + * Test the Telephone parser independently. */ public function testTelephoneParser(): void { @@ -175,7 +175,7 @@ public function testTelephoneParser(): void } /** - * Test the Version parameter parser independent. + * Test the Version parameter parser independently. * With version 4 and version 3, should result in not equal (bad weather) */ public function testVersionParameterParserBadWeather(): void @@ -194,7 +194,7 @@ public function testVersionParameterParserBadWeather(): void } /** - * Test the Version parameter parser independent. + * Test the Version parameter parser independently. * Both version 4 (good weather) */ public function testVersionParameterParserGoodWeather(): void @@ -211,7 +211,7 @@ public function testVersionParameterParserGoodWeather(): void } /** - * Test the Version parameter parser independent. + * Test the Version parameter parser independently. * Without any version specified, should use the default Version value (4.0) */ public function testVersionParameterParserWithoutVersion(): void @@ -227,6 +227,57 @@ public function testVersionParameterParserWithoutVersion(): void $this->assertEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); } + /** + * Test the Kind parameter parser independently. + * Test vcard with individual person (is default kind) + */ + public function testKindIndividual(): void + { + // Given + $vcard = new Vcard(); + $content = "BEGIN:VCARD\r\nVERSION:4.0\r\nKIND:individual\r\nEND:VCARD"; + + // When + $parser = new Parser(new VcfParser(), $content); + + // Then + $this->assertEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); + } + + /** + * Test the Kind parameter parser independently. + * Test vcard with department/organization + */ + public function testKindOrganization(): void + { + // Given + $vcard = new Vcard(Kind::organization()); + $content = "BEGIN:VCARD\r\nVERSION:4.0\r\nKIND:org\r\nEND:VCARD"; + + // When + $parser = new Parser(new VcfParser(), $content); + + // Then + $this->assertEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); + } + + /** + * Test the Kind parameter parser independently. + * Test vcard with group + */ + public function testKindGroup(): void + { + // Given + $vcard = new Vcard(Kind::group()); + $content = "BEGIN:VCARD\r\nVERSION:4.0\r\nKIND:group\r\nEND:VCARD"; + + // When + $parser = new Parser(new VcfParser(), $content); + + // Then + $this->assertEquals($vcard->getParameters(), $parser->getVCards()[0]->getParameters()); + } + public function testParserMultipleVCardsFromVcfFile(): void { $parser = new Parser(new VcfParser(), Parser::getFileContents(__DIR__ . '/assets/vcards.vcf')); @@ -279,7 +330,7 @@ public function testTelephonePropertyContent(): void // Given $expectedContent = "BEGIN:VCARD\r\n" . "VERSION:4.0\r\n" . - "KIND:Individual\r\n" . + "KIND:individual\r\n" . "TEL;TYPE=home;VALUE=uri:tel:+33-01-23-45-67\r\n" . "TEL;TYPE=work;VALUE=uri:tel:+33-05-42-41-96\r\n" . "END:VCARD\r\n"; @@ -304,7 +355,7 @@ public function testNamePropertyContent(): void // Given $expectedContent = "BEGIN:VCARD\r\n" . "VERSION:4.0\r\n" . - "KIND:Individual\r\n" . + "KIND:individual\r\n" . "N:Berg;Melroy;van den;Mr.;\r\n" . "END:VCARD\r\n"; @@ -327,7 +378,7 @@ public function testAddressPropertyContentWithLineBreak() : void // Given $expectedContent = "BEGIN:VCARD\r\n" . "VERSION:4.0\r\n" . - "KIND:Individual\r\n" . + "KIND:individual\r\n" . "ADR;TYPE=home:42;Villa;Main Street 500;London;Barnet;EN4 0AG;United Kingd\r\n" . // Line break because of 75 octets width limit, immediately followed by a single white space. " om\r\n" . diff --git a/tests/assets/vcard.vcf b/tests/assets/vcard.vcf index ce376bf..4b53d00 100644 --- a/tests/assets/vcard.vcf +++ b/tests/assets/vcard.vcf @@ -1,5 +1,5 @@ BEGIN:VCARD -KIND:Individual +KIND:individual VERSION:4.0 REV:2017-12-15T10:24:32Z GENDER:M;Dude diff --git a/tests/assets/vcards.vcf b/tests/assets/vcards.vcf index db93245..713f203 100644 --- a/tests/assets/vcards.vcf +++ b/tests/assets/vcards.vcf @@ -1,5 +1,5 @@ BEGIN:VCARD -KIND:Individual +KIND:individual VERSION:4.0 REV:2017-12-15T10:24:32Z GENDER:M;Dude @@ -16,14 +16,14 @@ TEL;VALUE=uri;TYPE=home:tel:+33-01-23-45-67 TEL;VALUE=uri;TYPE=work:tel:+33-05-42-41-96 END:VCARD BEGIN:VCARD -KIND:Individual +KIND:individual VERSION:4.0 REV:2017-12-15T10:24:32Z N:John;;Doe;; ADR;TYPE=work:;Penthouse;Korenmarkt 1;Gent;Oost-Vlaanderen;9000;Belgiƫ END:VCARD BEGIN:VCARD -KIND:Organization +KIND:org VERSION:4.0 REV:2017-12-15T10:24:32Z TITLE:Apple