Completed
Push — master ( 69bbac...c6a45b )
by Dragos
03:11
created

TCX::dumpToString()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 17
nc 1
nop 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace SportTrackerConnector\Core\Workout\Dumper;
6
7
use DateTime;
8
use DateTimeZone;
9
use InvalidArgumentException;
10
use SportTrackerConnector\Core\Workout\Extension\ExtensionInterface;
11
use SportTrackerConnector\Core\Workout\Extension\HR;
12
use SportTrackerConnector\Core\Workout\Track;
13
use SportTrackerConnector\Core\Workout\TrackPoint;
14
use SportTrackerConnector\Core\Workout\Workout;
15
use XMLWriter;
16
17
/**
18
 * Dump a workout to TCX format.
19
 */
20
class TCX extends AbstractDumper
21
{
22
    /**
23
     * {@inheritdoc}
24
     */
25
    public function toString(Workout $workout) : string
26
    {
27
        $xmlWriter = new XMLWriter();
28
        $xmlWriter->openMemory();
29
        $xmlWriter->setIndent(true);
30
        $xmlWriter->startDocument('1.0', 'UTF-8');
31
        $xmlWriter->startElement('TrainingCenterDatabase');
32
33
        $xmlWriter->writeAttributeNs(
34
            'xsi',
35
            'schemaLocation',
36
            null,
37
            'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd'
38
        );
39
        $xmlWriter->writeAttribute('xmlns', 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2');
40
        $xmlWriter->writeAttributeNs('xmlns', 'xsi', null, 'http://www.w3.org/2001/XMLSchema-instance');
41
42
        $this->writeTracks($xmlWriter, $workout);
43
44
        $xmlWriter->endElement();
45
        $xmlWriter->endDocument();
46
47
        return $xmlWriter->outputMemory(true);
48
    }
49
50
    /**
51
     * Write the tracks to the TCX.
52
     *
53
     * @param XMLWriter $xmlWriter The XML writer.
54
     * @param Workout $workout The workout.
55
     */
56
    private function writeTracks(XMLWriter $xmlWriter, Workout $workout)
57
    {
58
        $xmlWriter->startElement('Activities');
59
        foreach ($workout->tracks() as $track) {
60
            $xmlWriter->startElement('Activity');
61
            $xmlWriter->writeAttribute('Sport', ucfirst($track->sport()));
62
            // Use the start date time as the ID. This could be anything.
63
            $xmlWriter->writeElement('Id', $this->formatDateTime($track->startDateTime()));
64
65
            $xmlWriter->startElement('Lap');
66
67
            $xmlWriter->writeAttribute('StartTime', $this->formatDateTime($track->startDateTime()));
68
            $xmlWriter->writeElement('TotalTimeSeconds', (string)$track->duration()->totalSeconds());
69
            $xmlWriter->writeElement('DistanceMeters', (string)$track->length());
70
71
            $this->writeLapHeartRateDate($xmlWriter, $track);
72
73
            $xmlWriter->startElement('Track');
74
            $this->writeTrackPoints($xmlWriter, $track->trackPoints());
75
            $xmlWriter->endElement();
76
77
            $xmlWriter->endElement();
78
79
            $xmlWriter->endElement();
80
        }
81
        $xmlWriter->endElement();
82
    }
83
84
    /**
85
     * Write the track points to the TCX.
86
     *
87
     * @param XMLWriter $xmlWriter The XML writer.
88
     * @param TrackPoint[] $trackPoints The track points to write.
89
     */
90
    private function writeTrackPoints(XMLWriter $xmlWriter, array $trackPoints)
91
    {
92
        foreach ($trackPoints as $trackPoint) {
93
            $xmlWriter->startElement('Trackpoint');
94
95
            // Time of position
96
            $dateTime = clone $trackPoint->dateTime();
97
            $dateTime->setTimezone(new DateTimeZone('UTC'));
98
            $xmlWriter->writeElement('Time', $this->formatDateTime($dateTime));
99
100
            // Position.
101
            $xmlWriter->startElement('Position');
102
            $xmlWriter->writeElement('LatitudeDegrees', (string)$trackPoint->latitude());
103
            $xmlWriter->writeElement('LongitudeDegrees', (string)$trackPoint->longitude());
104
            $xmlWriter->endElement();
105
106
            // Elevation.
107
            $xmlWriter->writeElement('AltitudeMeters', (string)$trackPoint->getElevation());
108
109
            // Distance.
110
            if ($trackPoint->hasDistance() === true) {
111
                $xmlWriter->writeElement('DistanceMeters', (string)$trackPoint->getDistance());
112
            }
113
114
            // Extensions.
115
            $this->writeExtensions($xmlWriter, $trackPoint->extensions());
116
117
            $xmlWriter->endElement();
118
        }
119
    }
120
121
    /**
122
     * Write the heart rate data for a lap.
123
     *
124
     * @param XMLWriter $xmlWriter The XML writer.
125
     * @param Track $track The track to write.
126
     */
127
    protected function writeLapHeartRateDate(XMLWriter $xmlWriter, Track $track)
128
    {
129
        $averageHeartRate = array();
130
        $maxHearRate = null;
131
        foreach ($track->trackPoints() as $trackPoint) {
132
            if ($trackPoint->hasExtension(HR::ID()) === true) {
133
                $pointHearRate = $trackPoint->extension(HR::ID())->value();
134
135
                $maxHearRate = max($maxHearRate, $pointHearRate);
136
                $averageHeartRate[] = $pointHearRate;
137
            }
138
        }
139
140
        if ($averageHeartRate !== array()) {
141
            $xmlWriter->startElement('AverageHeartRateBpm');
142
            $xmlWriter->writeAttributeNs('xsi', 'type', null, 'HeartRateInBeatsPerMinute_t');
143
            $hearRateValue = array_sum($averageHeartRate) / count($averageHeartRate);
144
            $xmlWriter->writeElement('Value', (string)$hearRateValue);
145
            $xmlWriter->endElement();
146
        }
147
148
        if ($maxHearRate !== null) {
149
            $xmlWriter->startElement('MaximumHeartRateBpm');
150
            $xmlWriter->writeAttributeNs('xsi', 'type', null, 'HeartRateInBeatsPerMinute_t');
151
            $xmlWriter->writeElement('Value', (string)$maxHearRate);
152
            $xmlWriter->endElement();
153
        }
154
    }
155
156
    /**
157
     * Write the extensions into the TCX.
158
     *
159
     * @param XMLWriter $xmlWriter The XMLWriter.
160
     * @param ExtensionInterface[] $extensions The extensions to write.
161
     * @throws InvalidArgumentException If an extension is not known.
162
     */
163
    protected function writeExtensions(XMLWriter $xmlWriter, array $extensions)
164
    {
165
        foreach ($extensions as $extension) {
166
            switch ($extension::ID()) {
167
                case HR::ID():
168
                    $xmlWriter->startElement('HeartRateBpm');
169
                    $xmlWriter->writeElement('Value', (string)$extension->value());
170
                    $xmlWriter->endElement();
171
                    break;
172
            }
173
        }
174
    }
175
176
    /**
177
     * Format a DateTime object for TCX format.
178
     *
179
     * @param DateTime $dateTime The date time to format.
180
     * @return string
181
     */
182
    protected function formatDateTime(DateTime $dateTime)
183
    {
184
        return $dateTime->format('Y-m-d\TH:i:s\Z');
185
    }
186
}
187