1: <?php
2: declare(strict_types=1);
3:
4: namespace om\ICal;
5:
6: use InvalidArgumentException;
7: use om\ICal\Value\PropertyFactory;
8:
9: /**
10: * VLOCATION (RFC 9073, section 7.2): rich information about a location of an event or task,
11: * e.g. the venue or the parking. Other properties, such as STRUCTURED-DATA, are available
12: * through property() and $component.
13: *
14: * @phpstan-import-type PropertyList from PropertyFactory
15: */
16: final class Location {
17: /**
18: * @internal use Item::locations() or Location::new()
19: */
20: public function __construct(
21: public readonly Component $component,
22: private readonly Calendar $calendar,
23: ) {
24: }
25:
26: /**
27: * A new VLOCATION for the locations of Event::new() and Todo::new().
28: *
29: * @param ?string $uid UID, a random UUID when null
30: * @param array{float|int, float|int}|null $geo latitude and longitude
31: * @param iterable<string> $types LOCATION-TYPE values of RFC 4589, e.g. "parking"
32: * @param PropertyList $properties other properties, e.g. STRUCTURED-DATA
33: * @throws InvalidArgumentException
34: */
35: public static function new(
36: ?string $uid = null,
37: ?string $name = null,
38: ?string $description = null,
39: ?array $geo = null,
40: iterable $types = [],
41: ?string $url = null,
42: array $properties = [],
43: ): self {
44: $builder = (new ComponentBuilder('VLOCATION'))
45: ->text('UID', ComponentBuilder::uid($uid))
46: ->text('NAME', $name)
47: ->text('DESCRIPTION', $description)
48: ->add($geo === null ? null : PropertyFactory::geo($geo), PropertyFactory::texts('LOCATION-TYPE', $types))
49: ->uri('URL', $url);
50: return new self($builder->build($properties), new Calendar());
51: }
52:
53: public function property(string $name): ?Property {
54: return $this->component->property($name);
55: }
56:
57: /**
58: * Typed value of the first property with the name, see ValueParser::value().
59: */
60: public function value(string $name): mixed {
61: $property = $this->property($name);
62: return $property === null ? null : $this->calendar->values()->value($property);
63: }
64:
65: public function uid(): ?string {
66: return $this->text('UID');
67: }
68:
69: /** NAME, e.g. "The venue". */
70: public function name(): ?string {
71: return $this->text('NAME');
72: }
73:
74: public function description(): ?string {
75: return $this->text('DESCRIPTION');
76: }
77:
78: /**
79: * LOCATION-TYPE values of RFC 4589, e.g. "hotel", "parking" or "restaurant".
80: *
81: * @return list<string>
82: */
83: public function types(): array {
84: $property = $this->property('LOCATION-TYPE');
85: return $property === null ? [] : $this->calendar->values()->texts($property);
86: }
87:
88: public function url(): ?string {
89: $property = $this->property('URL');
90: return $property === null ? null : $this->calendar->values()->uri($property);
91: }
92:
93: private function text(string $name): ?string {
94: $property = $this->property($name);
95: return $property === null ? null : $this->calendar->values()->text($property);
96: }
97: }
98: