From edd590cde9b7c8f892f6bce095b8b5521d01c972 Mon Sep 17 00:00:00 2001 From: PierreLebedel Date: Thu, 31 Oct 2024 15:34:05 +0100 Subject: [PATCH] add documentation pages --- .gitignore | 2 +- README.md | 106 +++++++++++++---------- composer.json | 7 +- docs/agent.md | 35 ++++++++ docs/builder.md | 149 +++++++++++++++++++++++++++++++++ docs/collection.md | 98 ++++++++++++++++++++++ docs/index.md | 28 +++++++ docs/parsing.md | 30 +++++++ docs/vcard.md | 172 ++++++++++++++++++++++++++++++++++++++ src/Fields/AgentField.php | 2 +- src/VCardBuilder.php | 14 ++-- src/VCardsCollection.php | 2 +- 12 files changed, 588 insertions(+), 57 deletions(-) create mode 100644 docs/agent.md create mode 100644 docs/builder.md create mode 100644 docs/collection.md create mode 100644 docs/index.md create mode 100644 docs/parsing.md create mode 100644 docs/vcard.md diff --git a/.gitignore b/.gitignore index 81d7cc9..584869a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,5 +29,5 @@ phpunit.xml phpstan.neon psalm.xml testbench.yaml -/docs +#/docs /coverage diff --git a/README.md b/README.md index ff3f433..20cf42b 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,22 @@ It allows you to build vCard objects & export them to text or .vcf files. ## Installation -You can install the package via composer: +Via composer: ```bash composer require pleb/vcardio ``` +## Documentation + +- [Parsing data](docs/parsing.md) +- [vCards collection](docs/collection.md) +- [vCard builder](docs/builder.md) +- [vCard object](docs/vcard.md) + ## Usage -### Parse vCards +### Parsing data You can parse vCards objects from .vcf file or from raw data, and obtain an iterable collection of vCards. @@ -34,9 +41,13 @@ X-MAIN-HOBBY:Bowling END:VCARD'; $vCardsCollection = Pleb\VCardIO\VCardParser::parseRaw($vCardsRawData); +``` -// RESULT: +### The vCards collection +The result of parsing is a collection of vCards: + +```php Pleb\VCardIO\VCardsCollection { vCards: [ Pleb\VCardIO\Models\VCardV40 { @@ -76,7 +87,21 @@ Pleb\VCardIO\VCardsCollection { } ``` -You can retreive single vCard objects by iterating on VCardsCollection, or by getting them by index: +#### Manually build a vCards collection + +```php +$vCardsCollection = (new Pleb\VCardIO\VCardsCollection()) + ->addVCard($vCard1) + ->addVCard($vCard2); + +// OR + +$vCardsCollection = new Pleb\VCardIO\VCardsCollection([$vCard1, $vCard2]); +``` + +#### Manipulate collection + +The `VCardsCollection` object implements `ArrayAccess`, `Iterator` and `Countable` interfaces, so you can loop on it. ```php foreach($vCardsCollection as $vCard){ @@ -88,9 +113,32 @@ $vCard = $vCardsCollection->first(); $vCard = $vCardsCollection->getVCard(0); // 1,2,... ``` -#### Support of old school Agent property +### The vCard object + +A huge set of methods is implemented to read the vCard properties. You can see all available getters methods [on the vCard object documentation](docs/vcard.md). + +```php +$vCard->getFullName(); // :?string +$vCard->getLastName(); // :?string +$vCard->getFirstName(); // :?string +$vCard->getEmails(); // :array +$vCard->getPhones(); // :array +$vCard->getX('main-hobby', multiple:false); // :?string|array +$vCard->getX('main-hobby', multiple:true); // :array +// ... +``` + +#### Note on "Pseudo-singular" properties -The `AGENT` property is not longer supported by the vCard specification, but if you parse old data, you can see something like this, with imbricated vCards: +[RFC 6350](https://datatracker.ietf.org/doc/html/rfc6350) allows most of properties to be present multiple times in a vCard. For example the `FN` (fullName) property can be present 1 or multiple times, and accompagnied by attributes to distinct them. + +In this package, we assume that some of properties (like fullName) got a **unique main value**. The vCard's *`getProperty()`* methods will return this main value, as well as the sub-object `$vCard->relevantData`. + +The complete set of value is stil available in the root of `$vCard` object. + +#### Note on the old school `AGENT` property + +The `AGENT` property is not longer supported by the vCard specification, but if you parse old data, you can see something like this, with nested vCards: ```txt BEGIN:VCARD @@ -108,43 +156,23 @@ This package will parse it as a VCard's `agent` property: ```php Pleb\VCardIO\Models\VCardV30 { version: '3.0' - fn: [...], + // ..., agent: Pleb\VCardIO\Models\VCardV30 { version: "3.0" - fn: [...], - ... + // ... }, - ... + // ... } ``` -### Read vCard object - -A huge set of methods is implemented to read the vCard properties. - -```php -$vCard->getFullName(); // :string -$vCard->getLastName(); // :string -$vCard->getFirstName(); // :string -$vCard->getEmails(); // :array -$vCard->getPhones(); // :array -$vCard->getX('main-hobby'); // :string|array -// ... -``` - -> [!NOTE] -> **"Pseudo-singular" properties:** [RFC 6350](https://datatracker.ietf.org/doc/html/rfc6350) allows most of properties to be present multiple times in a vCard. For example the `FN` (fullName) property can be present 1 or multiple times, and accompagnied by attributes to distinct them. -> In this package, we assume that some of properties (like fullName) got a **unique main value**. The vCard's *`getProperty()`* methods will return this main value, as well as the sub-object `$vCard->relevantData`. -> The complete set of value is stil available in the root of `$vCard` object. - -### Build vCard +### The vCard builder -You can create your vCard objects from scratch fluently by using the large set of methods implemented on the vCard builder. +You can create your vCard objects from scratch fluently by using the large set of methods implemented on the vCard builder. You can see all available setters methods [on the vCard builder documentation](docs/builder.md). ```php $vCard = Pleb\VCardIO\VCardBuilder::make() ->fullName('Jeffrey Lebowski') - ->nickname('The Dude') + ->nickName('The Dude') ->birthday(new DateTime('1942-12-04')) ->x('main-hobby', 'Bowling') ->get(); @@ -154,19 +182,9 @@ Each method returns the builder instance, so you can chain them. Use the `get()` method to get your vCard. -#### Build vCards collection - -```php -$vCardsCollection = (new VCardsCollection()) - ->addVCard($vCard1) - ->addVCard($vCard2); - -// OR - -$vCardsCollection = new VCardsCollection([$vCard1, $vCard2]); -``` +### Print vCards -### Print vCard +#### Print a single vCard You can use `(string) $vCard` to display vCard contents: diff --git a/composer.json b/composer.json index 3ef37c6..97b5ea1 100644 --- a/composer.json +++ b/composer.json @@ -1,16 +1,17 @@ { "name": "pleb/vcardio", - "description": "Parse & write vCard (vcf) files", + "description": "Parse vCards from files (.vcf) or raw data. Build vCards from scratch. Export vCards as string or file.", "keywords": [ "vcard", "vcf" ], - "homepage": "https://github.com/pleb/vcardio", + "homepage": "https://github.com/PierreLebedel/vCardIO", "license": "MIT", "authors": [ { "name": "Pierre Lebedel", "email": "pierrelebedel@gmail.com", + "homepage": "https://www.pierrelebedel.fr", "role": "Developer" } ], @@ -45,6 +46,6 @@ "phpstan/extension-installer": true } }, - "minimum-stability": "dev", + "minimum-stability": "stable", "prefer-stable": true } diff --git a/docs/agent.md b/docs/agent.md new file mode 100644 index 0000000..0552be3 --- /dev/null +++ b/docs/agent.md @@ -0,0 +1,35 @@ +[Documentation homepage](index.md) + +# vCard's `AGENT` property + +The old school `AGENT` property is not longer supported by the vCard specification, but if you parse old data, you can see something like this, with imbricated vCards: + +```txt +BEGIN:VCARD +VERSION:3.0 +FN:Jeffrey Lebowski +AGENT:BEGIN:VCARD + VERSION:3.0 + FN:Walter Sobchak + END:VCARD +END:VCARD +``` + +This package will parse it as a VCard's `agent` property: + +```php +Pleb\VCardIO\Models\VCardV30 { + version: '3.0' + fn: [...], + agent: Pleb\VCardIO\Models\VCardV30 { + version: "3.0" + fn: [...], + ... + }, + ... +} +``` + +## The vCard object + +View the [vCard object documentation](vcard.md). diff --git a/docs/builder.md b/docs/builder.md new file mode 100644 index 0000000..4d0e2fd --- /dev/null +++ b/docs/builder.md @@ -0,0 +1,149 @@ +[Documentation homepage](index.md) + +# Builder + +## Build a vCard + +Each `VCardBuilder` setter returns the builder instance so you can chain them. + +```php +$vCard = Pleb\VCardIO\VCardBuilder::make() + ->fullName('Jeffrey Lebowski') + ->nickName('The Dude') + ->birthday(new DateTime('1942-12-04')) + ->x('main-hobby', 'Bowling') + ->get(); +``` + +## Available setters + + + +```php +$vCardBuilder->version(string|VCardVersionEnum $version); + +$vCardBuilder->agent(string|AbstractVCard $agent); + +$vCardBuilder->fullName(?string $fullName); + +$vCardBuilder->name( + ?string $lastName = null, + ?string $firstName = null, + ?string $middleName = null, + ?string $namePrefix = null, + ?string $nameSuffix = null +); + +$vCardBuilder->lastName(string $lastName); + +$vCardBuilder->firstName(string $firstName); + +$vCardBuilder->middleName(string $middleName); + +$vCardBuilder->namePrefix(string $namePrefix); + +$vCardBuilder->nameSuffix(string $nameSuffix); + +$vCardBuilder->email(string $email, array $types = []); + +$vCardBuilder->phone(string $number, array $types = ['voice']); + +$vCardBuilder->url(string $url); + +$vCardBuilder->photo(string $photo); + +$vCardBuilder->bday(DateTimeInterface $bday); +$vCardBuilder->birthday(DateTimeInterface $bday); + +$vCardBuilder->anniversary(DateTimeInterface $anniversary); + +$vCardBuilder->kind(string $kind); + +$vCardBuilder->gender(string $gender); + +$vCardBuilder->organization(string $company, ?string $unit1, ?string $unit2); + +$vCardBuilder->title(string $title); + +$vCardBuilder->role(string $role); + +$vCardBuilder->member(string $uid); + +$vCardBuilder->address( + ?string $postOfficeAddress, + ?string $extendedAddress, + ?string $street, + ?string $locality, + ?string $region, + ?string $postalCode, + ?string $country, + array $types = [] +); + +$vCardBuilder->geo(float $latitude, float $longitude); + +$vCardBuilder->categories(array $categories); + +$vCardBuilder->category(string $category); + +$vCardBuilder->nickNames(array $nickNames); + +$vCardBuilder->nickName(string $nickName); + +$vCardBuilder->timeZone(DateTimeZone $timeZone); + +$vCardBuilder->uid(string $uid); +$vCardBuilder->uuid(string $uuid); + +$vCardBuilder->calendarAddressUri(string $uri); + +$vCardBuilder->calendarUri(string $uri); + +$vCardBuilder->clientPidMap(int $pid, string $uri); + +$vCardBuilder->fbUrl(string $url); + +$vCardBuilder->impp(string $number, array $types = []); + +$vCardBuilder->key(string $key); + +$vCardBuilder->lang(string $lang, int $pref = 1); + +$vCardBuilder->langs(array $langs); + +$vCardBuilder->logo(string $logo); + +$vCardBuilder->note(string $note); + +$vCardBuilder->prodid(string $prodid); + +$vCardBuilder->related(string $related); + +$vCardBuilder->rev(DateTimeInterface $dateTime); +$vCardBuilder->revision(DateTimeInterface $dateTime); + +$vCardBuilder->sound(string $sound); + +$vCardBuilder->source(string $source); + +$vCardBuilder->xml(string $xml); + +$vCardBuilder->x(string $name, string $value); + +``` + +## Get the vCard object + +```php +$vCard = Pleb\VCardIO\VCardBuilder::make() + // ... + ->get(); +``` + +View the [vCard object documentation](vcard.md) for more information. diff --git a/docs/collection.md b/docs/collection.md new file mode 100644 index 0000000..5fd7c13 --- /dev/null +++ b/docs/collection.md @@ -0,0 +1,98 @@ +[Documentation homepage](index.md) + +# vCards collection + +## the VCardsCollection object + + + +```php +Pleb\VCardIO\VCardsCollection { + vCards: [ + Pleb\VCardIO\Models\VCardV40 { + version: "4.0", + relevantData: { + version: "4.0", + fn: "Jeffrey Lebowski", + bday: DateTimeImmutable @-854466859, + x: { + mainHobby: "Bowling" + } + }, + fn: [ + { + value: "Jeffrey Lebowski", + attributes: [] + } + ], + bday: { + dateTime: DateTimeImmutable @-854466859, + format: "Ymd", + formatted: "19421204", + extactYear: true, + attributes: [] + }, + x: [ + { + name: "main-hobby", + formattedName: "mainHobby", + value: "Bowling", + attributes: [] + } + ], + ... + }, + ], +} +``` + +## Build a vCards collection + +Pass the vCards array to the constructor: +```php +$vCardsCollection = new Pleb\VCardIO\VCardsCollection([$vCard1, $vCard2]); +``` + +Or add vCards fluently: +```php +$vCardsCollection = (new Pleb\VCardIO\VCardsCollection()) + ->addVCard($vCard1) + ->addVCard($vCard2); +``` + + + +## Retreive collection vCard objects + +The `VCardsCollection` object implements `ArrayAccess`, `Iterator` and `Countable` interfaces, so you can loop on it. + +```php +foreach($vCardsCollection as $vCard){ + // ... +} +// OR +$vCard = $vCardsCollection->first(); +// OR +$vCard = $vCardsCollection->getVCard(0); // 1,2,... +``` + +View the [vCard object documentation](vcard.md) for more information. + +## Render a collection + +You can use `(string) $vCard` to display vCard contents: + +```php +echo nl2br((string) $vCardsCollection); +``` +```txt +BEGIN:VCARD +VERSION:4.0 +FN:Jeffrey Lebowski +END:VCARD +BEGIN:VCARD +VERSION:3.0 +FN:Walter Sobchak +END:VCARD +... +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..441bcb8 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,28 @@ +# vCardIO + +## [Parsing data](parsing.md) + +- Parse data form .vcf file. +- Parse data from string. +- Return format. + +## [vCards collection](collection.md) + +- VCardsCollection object description. +- Build a collection manually. +- Retreive collection vCard objects +- Render the collection as a string. + +## [vCard builder](builder.md) + +- How to create a vCard object using the builder. +- The complete list of setters methods. + +## [vCards object](vcard.md) + +- The distinct models relative to vCard's version. +- vCard object description. +- A note on "pseudo-singular" properties. +- The complete list of getters methods. +- Render the vCard as a string. +- A note about the [vCard `agent` property](docs/agent.md). diff --git a/docs/parsing.md b/docs/parsing.md new file mode 100644 index 0000000..db767a1 --- /dev/null +++ b/docs/parsing.md @@ -0,0 +1,30 @@ +[Documentation homepage](index.md) + +# Parsing data + +## Parse .vcf file + +```php +$vCardsCollection = Pleb\VCardIO\VCardParser::parseFile('./contacts.vcf'); +``` + +## Parse raw data + +Give a string to the parser to obtain same result. + +```php +$vCardsRawData = 'BEGIN:VCARD +VERSION:4.0 +FN:Jeffrey Lebowski +BDAY:19421204 +X-MAIN-HOBBY:Bowling +END:VCARD'; + +$vCardsCollection = Pleb\VCardIO\VCardParser::parseRaw($vCardsRawData); +``` + +## Return format + +The result of parsing is a VCardsCollection object. + +View the [collection documentation](collection.md) for more information. diff --git a/docs/vcard.md b/docs/vcard.md new file mode 100644 index 0000000..0bc8dad --- /dev/null +++ b/docs/vcard.md @@ -0,0 +1,172 @@ +[Documentation homepage](index.md) + +# vCard + +## Model classes + +Each vCard standard version got its model class, which extends the AbstractVCard: + +Version | Class +--- | --- +2.1 | VCardV21 +3.0 | VCardV30 +4.0 | VCardV40 + +## vCard object description + +```php +Pleb\VCardIO\Models\VCardV40 { + version: "4.0", + relevantData: { + version: "4.0", + fn: "Jeffrey Lebowski", + bday: DateTimeImmutable @-854466859, + x: { + mainHobby: "Bowling" + } + }, + fn: [ + { + value: "Jeffrey Lebowski", + attributes: [] + } + ], + bday: { + dateTime: DateTimeImmutable @-854466859, + format: "Ymd", + formatted: "19421204", + extactYear: true, + attributes: [] + }, + x: [ + { + name: "main-hobby", + formattedName: "mainHobby", + value: "Bowling", + attributes: [] + } + ], + ... +}, +``` + +## Available getters methods + +> [!NOTE] +> **"Pseudo-singular" properties:** [RFC 6350](https://datatracker.ietf.org/doc/html/rfc6350) allows most of properties to be present multiple times in a vCard. For example the `FN` (fullName) property can be present 1 or multiple times, and accompagnied by attributes to distinct them. +> In this package, we assume that some of properties (like fullName) got a **unique main value**. The vCard's *`getProperty()`* methods will return this main value, as well as the sub-object `$vCard->relevantData`. +> The complete set of value is stil available in the root of `$vCard` object. + +```php +$vCard->getFullName(): ?string; + +$vCard->getName(): ?stdClass; + +$vCard->getLastName(): ?string; + +$vCard->getFirstName(): ?string; + +$vCard->getMiddleName(): ?string; + +$vCard->getNamePrefix(): ?string; + +$vCard->getNameSuffix(): ?string; + +$vCard->getEmails(): array; + +$vCard->getPhones(): array; + +$vCard->getUrls(): array; + +$vCard->getPhoto(): ?string; + +$vCard->getBirthday(): ?DateTimeImmutable; + +$vCard->getAnniversary(): ?DateTimeImmutable; + +$vCard->getKind(): ?string; + +$vCard->getGender(): ?string; + +$vCard->getOrganization(): ?stdClass; + +$vCard->getOrganizationName(): ?string; + +$vCard->getTitle(): ?string; + +$vCard->getRole(): ?string; + +$vCard->getMember(): ?string; + +$vCard->getAddresses(): array; + +$vCard->getGeo(): ?stdClass; + +$vCard->getCategories(): array; + +$vCard->getNicknames(): array; + +$vCard->getTimeZone(): ?DateTimeZone; + +$vCard->getUid(): ?string; +$vCard->getUuid(): ?string; + +$vCard->getCalendarAddressUri(): ?string; + +$vCard->getCalendarUri(): ?string; + +$vCard->getClientPidMap(): array; + +$vCard->getFbUrl(): ?string; + +$vCard->getImpps(): array; + +$vCard->getKey(): ?string; + +$vCard->getLangs(): array; + +$vCard->getLang(): ?string; + +$vCard->getLogo(): ?string; + +$vCard->getNote(): ?string; + +$vCard->getProdid(): ?string; + +$vCard->getRelated(): ?string; + +$vCard->getRev(): ?DateTimeImmutable; +$vCard->getRevision(): ?DateTimeImmutable; + +$vCard->getSound(): ?string; + +$vCard->getSource(): ?string; + +$vCard->getXml(): ?string; + +$vCard->getX(string $name, multiple:false): ?string; +$vCard->getX(string $name, multiple:true): array; +``` + +## Render a vCard + +```php +echo nl2br((string) $vCard); +``` +```txt +BEGIN:VCARD +VERSION:4.0 +FN:Jeffrey Lebowski +NICKNAME:The Dude +BDAY:19421204 +X-HOBBY:Bowling +REV:20241029 +PRODID:-//Pleb//Pleb vCardIO 1.1.0 //EN +END:VCARD +``` + +## Note on the Agent property + +The `AGENT` property is not longer supported by the vCard specification, but you can use it as a child vCard object. + +View the [agent property documentation](agent.md) for more information. diff --git a/src/Fields/AgentField.php b/src/Fields/AgentField.php index 21693d2..2f9c27b 100644 --- a/src/Fields/AgentField.php +++ b/src/Fields/AgentField.php @@ -30,7 +30,7 @@ public function render(): mixed public function relevantRender(): mixed { - return $this->render(); + return $this->render()->relevantData; } public function __toString(): string diff --git a/src/VCardBuilder.php b/src/VCardBuilder.php index 17c4116..5f82e8e 100644 --- a/src/VCardBuilder.php +++ b/src/VCardBuilder.php @@ -98,7 +98,7 @@ public function agent(string|AbstractVCard $agent): self return $this; } - public function fullName(?string $fullName): self + public function fullName(string $fullName): self { $property = $this->getProperty('fn'); if ($property) { @@ -147,27 +147,27 @@ protected function namePart(int $index, string $namePart): self return $this; } - public function lastName(?string $lastName): self + public function lastName(string $lastName): self { return $this->namePart(0, $lastName); } - public function firstName(?string $firstName): self + public function firstName(string $firstName): self { return $this->namePart(1, $firstName); } - public function middleName(?string $middleName): self + public function middleName(string $middleName): self { return $this->namePart(2, $middleName); } - public function namePrefix(?string $namePrefix): self + public function namePrefix(string $namePrefix): self { return $this->namePart(3, $namePrefix); } - public function nameSuffix(?string $nameSuffix): self + public function nameSuffix(string $nameSuffix): self { return $this->namePart(4, $nameSuffix); } @@ -261,7 +261,7 @@ public function gender(string $gender): self return $this; } - public function organization(?string $company = null, ?string $unit1 = null, ?string $unit2 = null): self + public function organization(string $company, ?string $unit1 = null, ?string $unit2 = null): self { $property = $this->getProperty('org'); if ($property) { diff --git a/src/VCardsCollection.php b/src/VCardsCollection.php index 0556cd3..17cc537 100644 --- a/src/VCardsCollection.php +++ b/src/VCardsCollection.php @@ -124,7 +124,7 @@ public function offsetSet(mixed $offset, mixed $value): void if (! is_int($offset)) { throw VCardCollectionException::invalidIndex('Invalid integer index'); } - if (! $value instanceof VCard) { + if (! $value instanceof AbstractVCard) { throw VCardCollectionException::invalidValue('Invalid VCard value'); }