From 42721e95726559b4a601240bb5b0fe4e5d755b2a Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Wed, 27 Nov 2019 23:43:21 +0100 Subject: Added Schedule parsing and replaced old Fahrplan importer Resolves #553 (Change Frab Import from xCal to XML) Resolves #538 (Feature Request: Multi Frab Import) --- src/Helpers/Schedule/CalculatesTime.php | 24 +++ src/Helpers/Schedule/Conference.php | 129 ++++++++++++ src/Helpers/Schedule/Day.php | 88 +++++++++ src/Helpers/Schedule/Event.php | 337 ++++++++++++++++++++++++++++++++ src/Helpers/Schedule/Room.php | 52 +++++ src/Helpers/Schedule/Schedule.php | 111 +++++++++++ src/Helpers/Schedule/XmlParser.php | 172 ++++++++++++++++ 7 files changed, 913 insertions(+) create mode 100644 src/Helpers/Schedule/CalculatesTime.php create mode 100644 src/Helpers/Schedule/Conference.php create mode 100644 src/Helpers/Schedule/Day.php create mode 100644 src/Helpers/Schedule/Event.php create mode 100644 src/Helpers/Schedule/Room.php create mode 100644 src/Helpers/Schedule/Schedule.php create mode 100644 src/Helpers/Schedule/XmlParser.php (limited to 'src/Helpers') diff --git a/src/Helpers/Schedule/CalculatesTime.php b/src/Helpers/Schedule/CalculatesTime.php new file mode 100644 index 00000000..c9dbeea1 --- /dev/null +++ b/src/Helpers/Schedule/CalculatesTime.php @@ -0,0 +1,24 @@ + $times) { + $seconds += [60 * 60, 60][$key] * $times; + } + + return $seconds; + } +} diff --git a/src/Helpers/Schedule/Conference.php b/src/Helpers/Schedule/Conference.php new file mode 100644 index 00000000..0819d059 --- /dev/null +++ b/src/Helpers/Schedule/Conference.php @@ -0,0 +1,129 @@ +title = $title; + $this->acronym = $acronym; + $this->start = $start; + $this->end = $end; + $this->days = $days; + $this->timeslotDuration = $timeslotDuration; + $this->baseUrl = $baseUrl; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getAcronym(): string + { + return $this->acronym; + } + + /** + * @return string|null + */ + public function getStart(): ?string + { + return $this->start; + } + + /** + * @return string|null + */ + public function getEnd(): ?string + { + return $this->end; + } + + /** + * @return int|null + */ + public function getDays(): ?int + { + return $this->days; + } + + /** + * @return string|null + */ + public function getTimeslotDuration(): ?string + { + return $this->timeslotDuration; + } + + /** + * @return int|null + */ + public function getTimeslotDurationSeconds(): ?int + { + $duration = $this->getTimeslotDuration(); + if (!$duration) { + return null; + } + + return $this->secondsFromTime($duration); + } + + /** + * @return string|null + */ + public function getBaseUrl(): ?string + { + return $this->baseUrl; + } +} diff --git a/src/Helpers/Schedule/Day.php b/src/Helpers/Schedule/Day.php new file mode 100644 index 00000000..03106e8f --- /dev/null +++ b/src/Helpers/Schedule/Day.php @@ -0,0 +1,88 @@ +date = $date; + $this->start = $start; + $this->end = $end; + $this->index = $index; + $this->room = $rooms; + } + + /** + * @return string + */ + public function getDate(): string + { + return $this->date; + } + + /** + * @return Carbon + */ + public function getStart(): Carbon + { + return $this->start; + } + + /** + * @return Carbon + */ + public function getEnd(): Carbon + { + return $this->end; + } + + /** + * @return int + */ + public function getIndex(): int + { + return $this->index; + } + + /** + * @return Room[] + */ + public function getRoom(): array + { + return $this->room; + } +} diff --git a/src/Helpers/Schedule/Event.php b/src/Helpers/Schedule/Event.php new file mode 100644 index 00000000..46970e7b --- /dev/null +++ b/src/Helpers/Schedule/Event.php @@ -0,0 +1,337 @@ + name */ + protected $persons; + + /** @var string|null two letter code */ + protected $language; + + /** @var string|null */ + protected $description; + + /** @var string|null license (and opt out in XML, null if not recorded, empty if no license defined) */ + protected $recording; + + /** @var array href => title */ + protected $links; + + /** @var array href => name */ + protected $attachments; + + /** @var string|null */ + protected $url; + + /** @var string|null */ + protected $videoDownloadUrl; + + /** @var Carbon Calculated */ + protected $endDate; + + /** + * Event constructor. + * + * @param string $guid + * @param int $id + * @param Room $room + * @param string $title + * @param string $subtitle + * @param string $type + * @param Carbon $date + * @param string $start + * @param string $duration + * @param string $abstract + * @param string $slug + * @param string $track + * @param string|null $logo + * @param string[] $persons + * @param string|null $language + * @param string|null $description + * @param string|null $recording license + * @param array $links + * @param array $attachments + * @param string|null $url + * @param string|null $videoDownloadUrl + */ + public function __construct( + string $guid, + int $id, + Room $room, + string $title, + string $subtitle, + string $type, + Carbon $date, + string $start, + string $duration, + string $abstract, + string $slug, + string $track, + ?string $logo = null, + array $persons = [], + ?string $language = null, + ?string $description = null, + string $recording = '', + array $links = [], + array $attachments = [], + ?string $url = null, + ?string $videoDownloadUrl = null + ) { + $this->guid = $guid; + $this->id = $id; + $this->room = $room; + $this->title = $title; + $this->subtitle = $subtitle; + $this->type = $type; + $this->date = $date; + $this->start = $start; + $this->duration = $duration; + $this->abstract = $abstract; + $this->slug = $slug; + $this->track = $track; + $this->logo = $logo; + $this->persons = $persons; + $this->language = $language; + $this->description = $description; + $this->recording = $recording; + $this->links = $links; + $this->attachments = $attachments; + $this->url = $url; + $this->videoDownloadUrl = $videoDownloadUrl; + + $this->endDate = $this->date + ->copy() + ->addSeconds($this->getDurationSeconds()); + } + + /** + * @return string + */ + public function getGuid(): string + { + return $this->guid; + } + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return Room + */ + public function getRoom(): Room + { + return $this->room; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getSubtitle(): string + { + return $this->subtitle; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return Carbon + */ + public function getDate(): Carbon + { + return $this->date; + } + + /** + * @return string + */ + public function getStart(): string + { + return $this->start; + } + + /** + * @return string + */ + public function getDuration(): string + { + return $this->duration; + } + + /** + * @return int + */ + public function getDurationSeconds(): int + { + return $this->secondsFromTime($this->duration); + } + + /** + * @return string + */ + public function getAbstract(): string + { + return $this->abstract; + } + + /** + * @return string + */ + public function getSlug(): string + { + return $this->slug; + } + + /** + * @return string + */ + public function getTrack(): string + { + return $this->track; + } + + /** + * @return string|null + */ + public function getLogo(): ?string + { + return $this->logo; + } + + /** + * @return string[] + */ + public function getPersons(): array + { + return $this->persons; + } + + /** + * @return string|null + */ + public function getLanguage(): ?string + { + return $this->language; + } + + /** + * @return string|null + */ + public function getDescription(): ?string + { + return $this->description; + } + + /** + * @return string|null + */ + public function getRecording(): ?string + { + return $this->recording; + } + + /** + * @return array + */ + public function getLinks(): array + { + return $this->links; + } + + /** + * @return array + */ + public function getAttachments(): array + { + return $this->attachments; + } + + /** + * @return string|null + */ + public function getUrl(): ?string + { + return $this->url; + } + + /** + * @return string|null + */ + public function getVideoDownloadUrl(): ?string + { + return $this->videoDownloadUrl; + } + + /** + * @return Carbon + */ + public function getEndDate(): Carbon + { + return $this->endDate; + } +} diff --git a/src/Helpers/Schedule/Room.php b/src/Helpers/Schedule/Room.php new file mode 100644 index 00000000..45a09f5f --- /dev/null +++ b/src/Helpers/Schedule/Room.php @@ -0,0 +1,52 @@ +name = $name; + $this->event = $events; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return Event[] + */ + public function getEvent(): array + { + return $this->event; + } + + /** + * @param Event[] $event + */ + public function setEvent(array $event): void + { + $this->event = $event; + } +} diff --git a/src/Helpers/Schedule/Schedule.php b/src/Helpers/Schedule/Schedule.php new file mode 100644 index 00000000..7150480c --- /dev/null +++ b/src/Helpers/Schedule/Schedule.php @@ -0,0 +1,111 @@ +version = $version; + $this->conference = $conference; + $this->day = $days; + } + + /** + * @return string + */ + public function getVersion(): string + { + return $this->version; + } + + /** + * @return Conference + */ + public function getConference(): Conference + { + return $this->conference; + } + + /** + * @return Day[] + */ + public function getDay(): array + { + return $this->day; + } + + /** + * @return Room[] + */ + public function getRooms(): array + { + $rooms = []; + foreach ($this->day as $day) { + foreach ($day->getRoom() as $room) { + $name = $room->getName(); + $rooms[$name] = $room; + } + } + + return $rooms; + } + + + /** + * @return Carbon|null + */ + public function getStartDateTime(): ?Carbon + { + $start = null; + foreach ($this->day as $day) { + $time = $day->getStart(); + if ($time > $start && $start) { + continue; + } + + $start = $time; + } + + return $start; + } + + /** + * @return Carbon|null + */ + public function getEndDateTime(): ?Carbon + { + $end = null; + foreach ($this->day as $day) { + $time = $day->getEnd(); + if ($time < $end && $end) { + continue; + } + + $end = $time; + } + + return $end; + } +} diff --git a/src/Helpers/Schedule/XmlParser.php b/src/Helpers/Schedule/XmlParser.php new file mode 100644 index 00000000..1492aaca --- /dev/null +++ b/src/Helpers/Schedule/XmlParser.php @@ -0,0 +1,172 @@ +scheduleXML = simplexml_load_string($xml); + + if (!$this->scheduleXML) { + return false; + } + + $this->parseXml(); + + return true; + } + + /** + * Parse the predefined XML content + */ + protected function parseXml(): void + { + $version = $this->getFirstXpathContent('version'); + $conference = new Conference( + $this->getFirstXpathContent('conference/title'), + $this->getFirstXpathContent('conference/acronym'), + $this->getFirstXpathContent('conference/start'), + $this->getFirstXpathContent('conference/end'), + (int)$this->getFirstXpathContent('conference/days'), + $this->getFirstXpathContent('conference/timeslot_duration'), + $this->getFirstXpathContent('conference/base_url') + ); + $days = []; + + foreach ($this->scheduleXML->xpath('day') as $day) { + $rooms = []; + + foreach ($day->xpath('room') as $roomElement) { + $room = new Room( + (string)$roomElement->attributes()['name'] + ); + + $events = $this->parseEvents($roomElement->xpath('event'), $room); + $room->setEvent($events); + $rooms[] = $room; + } + + $days[] = new Day( + (string)$day->attributes()['date'], + new Carbon($day->attributes()['start']), + new Carbon($day->attributes()['end']), + (int)$day->attributes()['index'], + $rooms + ); + } + + $this->schedule = new Schedule( + $version, + $conference, + $days + ); + } + + /** + * @param SimpleXMLElement[] $eventElements + * @param Room $room + * @return array + */ + protected function parseEvents(array $eventElements, Room $room): array + { + $events = []; + + foreach ($eventElements as $event) { + $persons = $this->getListFromSequence($event, 'persons', 'person', 'id'); + $links = $this->getListFromSequence($event, 'links', 'link', 'href'); + $attachments = $this->getListFromSequence($event, 'attachments', 'attachment', 'href'); + + $recording = ''; + $recordingElement = $event->xpath('recording')[0]; + if ($this->getFirstXpathContent('optout', $recordingElement) == 'false') { + $recording = $this->getFirstXpathContent('license', $recordingElement); + } + + $events[] = new Event( + (string)$event->attributes()['guid'], + (int)$event->attributes()['id'], + $room, + $this->getFirstXpathContent('title', $event), + $this->getFirstXpathContent('subtitle', $event), + $this->getFirstXpathContent('type', $event), + new Carbon($this->getFirstXpathContent('date', $event)), + $this->getFirstXpathContent('start', $event), + $this->getFirstXpathContent('duration', $event), + $this->getFirstXpathContent('abstract', $event), + $this->getFirstXpathContent('slug', $event), + $this->getFirstXpathContent('track', $event), + $this->getFirstXpathContent('logo', $event) ?: null, + $persons, + $this->getFirstXpathContent('language', $event) ?: null, + $this->getFirstXpathContent('description', $event) ?: null, + $recording, + $links, + $attachments, + $this->getFirstXpathContent('url', $event) ?: null, + $this->getFirstXpathContent('video_download_url', $event) ?: null + ); + } + + return $events; + } + + /** + * @param string $path + * @param SimpleXMLElement|null $xml + * @return string + */ + protected function getFirstXpathContent(string $path, ?SimpleXMLElement $xml = null): string + { + $element = ($xml ?: $this->scheduleXML)->xpath($path); + + return $element ? (string)$element[0] : ''; + } + + /** + * Resolves a list from a sequence of elements + * + * @param SimpleXMLElement $element + * @param string $firstElement + * @param string $secondElement + * @param string $idAttribute + * @return array + */ + protected function getListFromSequence( + SimpleXMLElement $element, + string $firstElement, + string $secondElement, + string $idAttribute + ): array { + $items = []; + + foreach ($element->xpath($firstElement)[0]->xpath($secondElement) as $item) { + $items[(string)$item->attributes()[$idAttribute]] = (string)$item; + } + + return $items; + } + + /** + * @return Schedule + */ + public function getSchedule(): Schedule + { + return $this->schedule; + } +} -- cgit v1.2.3-54-g00ecf