<?php
// src/Entity/StravaActivity.php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use App\Repository\StravaActivityRepository;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ORM\Entity(repositoryClass=StravaActivityRepository::class)
* @ORM\Table(name="strava_activity", uniqueConstraints={
* @ORM\UniqueConstraint(name="unique_strava_activity", columns={"strava_activity_id"})
* })
* @ApiResource(
* normalizationContext={"groups"={"strava_activity:read"}},
* denormalizationContext={"groups"={"strava_activity:write"}},
* itemOperations={
* "get"={
* "security"="is_granted('ROLE_ADMIN') or object.getStravaProfile().getUser() == user"
* }
* },
* collectionOperations={
* "get"={
* "security"="is_granted('ROLE_USER')"
* }
* }
* )
* @ApiFilter(SearchFilter::class, properties={"category": "exact", "stravaProfile.user.id": "exact"})
* @ApiFilter(OrderFilter::class, properties={"startDateLocal"})
* @ApiFilter(DateFilter::class, properties={"startDateLocal"})
*/
class StravaActivity
{
// Types Strava acceptés
const TYPE_RUN = 'Run';
const TYPE_RIDE = 'Ride';
const TYPE_VIRTUAL_RUN = 'VirtualRun';
const TYPE_VIRTUAL_RIDE = 'VirtualRide';
const TYPE_TRAIL_RUN = 'TrailRun';
const TYPE_GRAVEL_RIDE = 'GravelRide';
const TYPE_MOUNTAIN_BIKE_RIDE = 'MountainBikeRide';
const TYPE_E_BIKE_RIDE = 'EBikeRide';
const ALLOWED_TYPES = [
self::TYPE_RUN,
self::TYPE_RIDE,
self::TYPE_VIRTUAL_RUN,
self::TYPE_VIRTUAL_RIDE,
self::TYPE_TRAIL_RUN,
self::TYPE_GRAVEL_RIDE,
self::TYPE_MOUNTAIN_BIKE_RIDE,
self::TYPE_E_BIKE_RIDE,
];
// Catégories simplifiées
const CATEGORY_RUNNING = 'running';
const CATEGORY_CYCLING = 'cycling';
const TYPE_TO_CATEGORY = [
self::TYPE_RUN => self::CATEGORY_RUNNING,
self::TYPE_VIRTUAL_RUN => self::CATEGORY_RUNNING,
self::TYPE_TRAIL_RUN => self::CATEGORY_RUNNING,
self::TYPE_RIDE => self::CATEGORY_CYCLING,
self::TYPE_VIRTUAL_RIDE => self::CATEGORY_CYCLING,
self::TYPE_GRAVEL_RIDE => self::CATEGORY_CYCLING,
self::TYPE_MOUNTAIN_BIKE_RIDE => self::CATEGORY_CYCLING,
self::TYPE_E_BIKE_RIDE => self::CATEGORY_CYCLING,
];
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=StravaProfile::class, inversedBy="activities")
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
* @Groups({"strava_activity:read"})
*/
private $stravaProfile;
/**
* @ORM\Column(type="bigint", unique=true)
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $stravaActivityId;
/**
* Catégorie : "running" ou "cycling"
* @ORM\Column(type="string", length=20)
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $category;
/**
* Distance en mètres
* @ORM\Column(type="float")
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $distance;
/**
* Temps de déplacement en secondes
* @ORM\Column(type="integer")
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $movingTime;
/**
* Temps total écoulé en secondes
* @ORM\Column(type="integer")
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $elapsedTime;
/**
* Date/heure de début (UTC)
* @ORM\Column(type="datetime")
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $startDate;
/**
* Date/heure de début (locale à l'athlète)
* @ORM\Column(type="datetime")
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $startDateLocal;
/**
* Nombre de pas (course à pied uniquement, calculé via la cadence Strava)
* Strava ne fournit pas directement un champ "steps", on le calcule :
* steps = average_cadence * 2 * (moving_time / 60)
* (cadence Strava = pas par minute d'un seul pied, x2 pour les deux pieds)
*
* @ORM\Column(type="integer", nullable=true)
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
private $steps;
/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="create")
*/
private $createdAt;
/**
* @ORM\Column(type="datetime", nullable=true)
* @Gedmo\Timestampable(on="update")
*/
private $updatedAt;
// ─── Getters / Setters ───────────────────────────────────────────
public function getId(): ?int
{
return $this->id;
}
public function getStravaProfile(): ?StravaProfile
{
return $this->stravaProfile;
}
public function setStravaProfile(?StravaProfile $stravaProfile): self
{
$this->stravaProfile = $stravaProfile;
return $this;
}
public function getStravaActivityId(): ?int
{
return $this->stravaActivityId;
}
public function setStravaActivityId(int $stravaActivityId): self
{
$this->stravaActivityId = $stravaActivityId;
return $this;
}
public function getCategory(): ?string
{
return $this->category;
}
public function setCategory(string $category): self
{
$this->category = $category;
return $this;
}
/**
* Définit la catégorie à partir du type Strava brut
*/
public function setCategoryFromType(string $stravaType): self
{
$this->category = self::TYPE_TO_CATEGORY[$stravaType] ?? 'other';
return $this;
}
public function getDistance(): ?float
{
return $this->distance;
}
public function setDistance(float $distance): self
{
$this->distance = $distance;
return $this;
}
/**
* Distance en kilomètres
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
public function getDistanceKm(): ?float
{
return $this->distance !== null ? round($this->distance / 1000, 2) : null;
}
public function getMovingTime(): ?int
{
return $this->movingTime;
}
public function setMovingTime(int $movingTime): self
{
$this->movingTime = $movingTime;
return $this;
}
/**
* Temps de déplacement formaté HH:MM:SS
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
public function getMovingTimeFormatted(): ?string
{
if ($this->movingTime === null) {
return null;
}
$h = floor($this->movingTime / 3600);
$m = floor(($this->movingTime % 3600) / 60);
$s = $this->movingTime % 60;
return sprintf('%02d:%02d:%02d', $h, $m, $s);
}
public function getElapsedTime(): ?int
{
return $this->elapsedTime;
}
public function setElapsedTime(int $elapsedTime): self
{
$this->elapsedTime = $elapsedTime;
return $this;
}
/**
* Temps total formaté HH:MM:SS
* @Groups({"strava_activity:read", "strava_profile:read"})
*/
public function getElapsedTimeFormatted(): ?string
{
if ($this->elapsedTime === null) {
return null;
}
$h = floor($this->elapsedTime / 3600);
$m = floor(($this->elapsedTime % 3600) / 60);
$s = $this->elapsedTime % 60;
return sprintf('%02d:%02d:%02d', $h, $m, $s);
}
public function getStartDate(): ?\DateTimeInterface
{
return $this->startDate;
}
public function setStartDate(\DateTimeInterface $startDate): self
{
$this->startDate = $startDate;
return $this;
}
public function getStartDateLocal(): ?\DateTimeInterface
{
return $this->startDateLocal;
}
public function setStartDateLocal(\DateTimeInterface $startDateLocal): self
{
$this->startDateLocal = $startDateLocal;
return $this;
}
public function getSteps(): ?int
{
return $this->steps;
}
public function setSteps(?int $steps): self
{
$this->steps = $steps;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
public static function isAllowedType(string $type): bool
{
return in_array($type, self::ALLOWED_TYPES);
}
/**
* Calcule le nombre de pas à partir de la cadence Strava.
* Strava average_cadence pour la course = foulées par minute (un seul pied).
* Nombre total de pas = cadence * 2 * durée en minutes.
*/
public static function calculateSteps(?float $averageCadence, int $movingTimeSeconds): ?int
{
if ($averageCadence === null || $averageCadence <= 0) {
return null;
}
$movingTimeMinutes = $movingTimeSeconds / 60;
return (int) round($averageCadence * 2 * $movingTimeMinutes);
}
}