Passed
Pull Request — master (#6810)
by
unknown
10:30
created

ConferenceActivity::getActivityData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Entity;
8
9
use ApiPlatform\Metadata\ApiResource;
10
use ApiPlatform\Metadata\Post;
11
use Chamilo\CoreBundle\Controller\Api\VideoConferenceCallbackController;
12
use Chamilo\CoreBundle\Repository\ConferenceActivityRepository;
13
use DateTime;
14
use Doctrine\ORM\Mapping as ORM;
15
16
/**
17
 * Conference Activity entity.
18
 */
19
#[ApiResource(
20
    operations: [
21
        new Post(
22
            uriTemplate: '/videoconference/callback',
23
            controller: VideoConferenceCallbackController::class,
24
            read: false,
25
            deserialize: false,
26
            validate: false
27
        ),
28
    ]
29
)]
30
#[ORM\Entity(repositoryClass: ConferenceActivityRepository::class)]
31
#[ORM\Table(name: 'conference_activity')]
32
class ConferenceActivity
33
{
34
    #[ORM\Id]
35
    #[ORM\GeneratedValue]
36
    #[ORM\Column(type: 'integer')]
37
    protected int $id;
38
39
    #[ORM\ManyToOne(targetEntity: ConferenceMeeting::class)]
40
    #[ORM\JoinColumn(name: 'meeting_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
41
    protected ?ConferenceMeeting $meeting = null;
42
43
    #[ORM\ManyToOne(targetEntity: User::class)]
44
    #[ORM\JoinColumn(name: 'participant_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
45
    protected ?User $participant = null;
46
47
    #[ORM\Column(name: 'in_at', type: 'datetime', nullable: true)]
48
    protected ?DateTime $inAt = null;
49
50
    #[ORM\Column(name: 'out_at', type: 'datetime', nullable: true)]
51
    protected ?DateTime $outAt = null;
52
53
    #[ORM\Column(name: 'close', type: 'boolean')]
54
    protected bool $close = false;
55
56
    #[ORM\Column(name: 'type', type: 'string', length: 50)]
57
    protected string $type = '';
58
59
    #[ORM\Column(name: 'event', type: 'string', length: 255)]
60
    protected string $event = '';
61
62
    #[ORM\Column(name: 'activity_data', type: 'text', nullable: true)]
63
    protected ?string $activityData = null;
64
65
    #[ORM\Column(name: 'signature_file', type: 'string', length: 255, nullable: true)]
66
    protected ?string $signatureFile = null;
67
68
    #[ORM\Column(name: 'signed_at', type: 'datetime', nullable: true)]
69
    protected ?DateTime $signedAt = null;
70
71
    /** Stores per-user analytics for the meeting (dashboard metrics). */
72
    #[ORM\Column(name: 'metrics', type: 'json', nullable: true)]
73
    protected ?array $metrics = null;
74
75
    public function __construct()
76
    {
77
        $this->close = false;
78
        $this->type = '';
79
        $this->event = '';
80
        $this->activityData = null;
81
        $this->signatureFile = null;
82
        $this->inAt = new DateTime();
83
        $this->outAt = null;
84
        $this->signedAt = null;
85
        $this->metrics = null;
86
    }
87
88
    public function getId(): int
89
    {
90
        return $this->id;
91
    }
92
93
    public function getMeeting(): ?ConferenceMeeting
94
    {
95
        return $this->meeting;
96
    }
97
98
    public function setMeeting(?ConferenceMeeting $meeting): self
99
    {
100
        $this->meeting = $meeting;
101
102
        return $this;
103
    }
104
105
    public function getParticipant(): ?User
106
    {
107
        return $this->participant;
108
    }
109
110
    public function setParticipant(?User $participant): self
111
    {
112
        $this->participant = $participant;
113
114
        return $this;
115
    }
116
117
    public function getInAt(): ?DateTime
118
    {
119
        return $this->inAt;
120
    }
121
122
    public function setInAt(?DateTime $inAt): self
123
    {
124
        $this->inAt = $inAt;
125
126
        return $this;
127
    }
128
129
    public function getOutAt(): ?DateTime
130
    {
131
        return $this->outAt;
132
    }
133
134
    public function setOutAt(?DateTime $outAt): self
135
    {
136
        $this->outAt = $outAt;
137
138
        return $this;
139
    }
140
141
    public function isClose(): bool
142
    {
143
        return $this->close;
144
    }
145
146
    public function setClose(bool $close): self
147
    {
148
        $this->close = $close;
149
150
        return $this;
151
    }
152
153
    public function getType(): string
154
    {
155
        return $this->type;
156
    }
157
158
    public function setType(string $type): self
159
    {
160
        $this->type = $type;
161
162
        return $this;
163
    }
164
165
    public function getEvent(): string
166
    {
167
        return $this->event;
168
    }
169
170
    public function setEvent(string $event): self
171
    {
172
        $this->event = $event;
173
174
        return $this;
175
    }
176
177
    public function getActivityData(): ?string
178
    {
179
        return $this->activityData;
180
    }
181
182
    public function setActivityData(?string $activityData): self
183
    {
184
        $this->activityData = $activityData;
185
186
        return $this;
187
    }
188
189
    public function getSignatureFile(): ?string
190
    {
191
        return $this->signatureFile;
192
    }
193
194
    public function setSignatureFile(?string $signatureFile): self
195
    {
196
        $this->signatureFile = $signatureFile;
197
198
        return $this;
199
    }
200
201
    public function getSignedAt(): ?DateTime
202
    {
203
        return $this->signedAt;
204
    }
205
206
    public function setSignedAt(?DateTime $signedAt): self
207
    {
208
        $this->signedAt = $signedAt;
209
210
        return $this;
211
    }
212
213
    /**
214
     * Returns the full metrics array (never null to simplify callers).
215
     * Keep in mind: this method does NOT create defaults; it just returns stored data.
216
     */
217
    public function getMetrics(): array
218
    {
219
        return $this->metrics ?? [];
220
    }
221
222
    /**
223
     * Replaces the entire metrics array. Null or empty arrays will store NULL to keep DB small.
224
     */
225
    public function setMetrics(?array $metrics): self
226
    {
227
        $this->metrics = $metrics ? $this->pruneEmpty($metrics) : null;
228
229
        return $this;
230
    }
231
232
    /** Read a value from metrics by dot path, with a default if missing. */
233
    public function getMetric(string $path, mixed $default = null): mixed
234
    {
235
        $data = $this->getMetrics();
236
        foreach (explode('.', $path) as $seg) {
237
            if (!is_array($data) || !array_key_exists($seg, $data)) {
238
                return $default;
239
            }
240
            $data = $data[$seg];
241
        }
242
243
        return $data;
244
    }
245
246
    /** Set a value into metrics by dot path, creating nested arrays as needed. */
247
    public function setMetric(string $path, mixed $value): self
248
    {
249
        $metrics = $this->getMetrics();
250
        $ref =& $metrics;
251
252
        $parts = $path === '' ? [] : explode('.', $path);
253
        foreach ($parts as $seg) {
254
            if (!isset($ref[$seg]) || !is_array($ref[$seg])) {
255
                $ref[$seg] = [];
256
            }
257
            $ref =& $ref[$seg];
258
        }
259
260
        $ref = $value;
261
262
        return $this->setMetrics($metrics);
263
    }
264
265
    /** Increment an integer metric by dot path (initializes to 0 if missing). */
266
    public function incMetric(string $path, int $by = 1): self
267
    {
268
        $current = (int) $this->getMetric($path, 0);
269
270
        return $this->setMetric($path, $current + $by);
271
    }
272
273
    /**
274
     * Start a named timer: stores ISO timestamp under "timers.{key}.on_at".
275
     * Timer is idempotent (won't overwrite if already running).
276
     */
277
    public function startTimer(string $key, ?\DateTimeInterface $now = null): self
278
    {
279
        $now ??= new \DateTimeImmutable();
280
281
        if (!$this->getMetric("timers.$key.on_at")) {
282
            $this->setMetric("timers.$key.on_at", $now->format(DATE_ATOM));
283
        }
284
285
        return $this;
286
    }
287
288
    /**
289
     * Stop a named timer and add elapsed seconds to "totals.{key}_seconds".
290
     * If the timer is not running, this is a no-op.
291
     */
292
    public function stopTimer(string $key, ?\DateTimeInterface $now = null): self
293
    {
294
        $now ??= new \DateTimeImmutable();
295
        $onAt = $this->getMetric("timers.$key.on_at");
296
297
        if ($onAt) {
298
            $started = \DateTimeImmutable::createFromFormat(DATE_ATOM, $onAt) ?: new \DateTimeImmutable($onAt);
299
            $elapsed = max(0, $now->getTimestamp() - $started->getTimestamp());
300
301
            $this->incMetric("totals.{$key}_seconds", $elapsed);
302
            $this->setMetric("timers.$key.on_at", null);
303
        }
304
305
        return $this;
306
    }
307
308
    /**
309
     * Internal helper to remove null/empty leaves so JSON column stays lean.
310
     * This is called from setMetrics().
311
     */
312
    private function pruneEmpty(array $data): array
313
    {
314
        foreach ($data as $k => $v) {
315
            if (is_array($v)) {
316
                $v = $this->pruneEmpty($v);
317
                if ($v === []) {
318
                    unset($data[$k]);
319
                    continue;
320
                }
321
                $data[$k] = $v;
322
            } elseif ($v === null || $v === '') {
323
                unset($data[$k]);
324
            }
325
        }
326
327
        return $data;
328
    }
329
}
330