Lines
100.00%
1 / 1
Functions and Methods
100.00%
1 / 1
Classes and Traits
100.00%
1 / 1
| Name | Lines | Functions and Methods | CRAP | Classes and Traits | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| TimelineEvent | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | 100.00% | 1 / 1 | |||
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| 1 | <?php | |
| 2 | ||
| 3 | declare(strict_types=1); | |
| 4 | ||
| 5 | namespace App\Entity; | |
| 6 | ||
| 7 | use ApiPlatform\Metadata\ApiResource; | |
| 8 | use ApiPlatform\Metadata\Delete; | |
| 9 | use ApiPlatform\Metadata\Get; | |
| 10 | use ApiPlatform\Metadata\GetCollection; | |
| 11 | use ApiPlatform\Metadata\Patch; | |
| 12 | use ApiPlatform\Metadata\Post; | |
| 13 | use App\Repository\TimelineEventRepository; | |
| 14 | use App\Security\Voter\TimelineEventVoter; | |
| 15 | use App\State\TimelineEventProcessor; | |
| 16 | use App\Validator\NoOverlappingTravel; | |
| 17 | use Doctrine\DBAL\Types\Types; | |
| 18 | use Doctrine\ORM\Mapping\Column; | |
| 19 | use Doctrine\ORM\Mapping\Entity; | |
| 20 | use Doctrine\ORM\Mapping\GeneratedValue; | |
| 21 | use Doctrine\ORM\Mapping\Id; | |
| 22 | use Doctrine\ORM\Mapping\JoinColumn; | |
| 23 | use Doctrine\ORM\Mapping\ManyToOne; | |
| 24 | use Symfony\Component\Serializer\Attribute\Context; | |
| 25 | use Symfony\Component\Serializer\Attribute\Groups; | |
| 26 | use Symfony\Component\Serializer\Attribute\Ignore; | |
| 27 | use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; | |
| 28 | use Symfony\Component\Validator\Constraints as Assert; | |
| 29 | ||
| 30 | /** | |
| 31 | * A custom event on the user's timeline (e.g. an anomaly or a mission day), with the stats | |
| 32 | * uploads; with an end date it lasts from [date] to [endDate] (e.g. a travel; travels cannot overlap). Others see the events with the stats history (ProfilePart::STATS_HISTORY). | |
| 33 | * | |
| 34 | * API: the user's own events, newest first (OwnerExtension); the owner adds, changes and deletes them. | |
| 35 | */ | |
| 36 | #[Entity(repositoryClass: TimelineEventRepository::class)] | |
| 37 | #[ApiResource( | |
| 38 | description: 'Custom events on your timeline: a date, an optional end date (an event over several days, e.g. a travel; travels cannot overlap: 422) and a text. Lists only your own, newest first; other agents see them with your stats history (GET /api/agents/{agentName} events).', | |
| 39 | operations: [ | |
| 40 | new GetCollection(paginationEnabled: false, security: "is_granted('ROLE_USER')"), | |
| 41 | new Get(security: "is_granted('".TimelineEventVoter::EDIT."', object)"), | |
| 42 | new Post(security: "is_granted('ROLE_USER')", processor: TimelineEventProcessor::class), | |
| 43 | new Patch(security: "is_granted('".TimelineEventVoter::EDIT."', object)"), | |
| 44 | new Delete(security: "is_granted('".TimelineEventVoter::EDIT."', object)"), | |
| 45 | ], | |
| 46 | normalizationContext: ['groups' => [self::READ]], | |
| 47 | denormalizationContext: ['groups' => [self::WRITE]], | |
| 48 | order: ['date' => 'DESC', 'id' => 'DESC'], | |
| 49 | )] | |
| 50 | #[NoOverlappingTravel] | |
| 51 | class TimelineEvent | |
| 52 | { | |
| 53 | public const string READ = 'timeline_event:read'; | |
| 54 | ||
| 55 | public const string WRITE = 'timeline_event:write'; | |
| 56 | ||
| 57 | public const string DATE_FORMAT = 'Y-m-d'; | |
| 58 | ||
| 59 | #[Column, Id, GeneratedValue] | |
| 60 | #[Groups([self::READ])] | |
| 61 | public ?int $id = null; | |
| 62 | ||
| 63 | /** Set on creation: by the form's controller, or TimelineEventProcessor for the API. */ | |
| 64 | #[ManyToOne, JoinColumn(nullable: false, onDelete: 'CASCADE'), Ignore] | |
| 65 | public ?User $owner = null; | |
| 66 | ||
| 67 | #[Column(type: Types::DATE_IMMUTABLE)] | |
| 68 | #[Context([DateTimeNormalizer::FORMAT_KEY => self::DATE_FORMAT])] | |
| 69 | #[Groups([self::READ, self::WRITE])] | |
| 70 | #[Assert\NotNull] | |
| 71 | public ?\DateTimeImmutable $date = null; | |
| 72 | ||
| 73 | /** The last day of an event over several days; null for a single day. */ | |
| 74 | #[Column(type: Types::DATE_IMMUTABLE, nullable: true)] | |
| 75 | #[Context([DateTimeNormalizer::FORMAT_KEY => self::DATE_FORMAT])] | |
| 76 | #[Groups([self::READ, self::WRITE])] | |
| 77 | #[Assert\GreaterThanOrEqual(propertyPath: 'date', message: 'The end date must not be before the date.')] | |
| 78 | public ?\DateTimeImmutable $endDate = null; | |
| 79 | ||
| 80 | #[Column(length: 500)] | |
| 81 | #[Groups([self::READ, self::WRITE])] | |
| 82 | #[Assert\NotBlank(normalizer: 'trim'), Assert\Length(max: 500)] | |
| 83 | public string $text = ''; | |
| 84 | ||
| 85 | #[Column(type: Types::DATETIME_IMMUTABLE)] | |
| 86 | #[Ignore] | |
| 87 | public private(set) \DateTimeImmutable $createdAt; | |
| 88 | ||
| 89 | public function __construct() | |
| 90 | { | |
| 91 | $this->createdAt = new \DateTimeImmutable(); | |
| 92 | } | |
| 93 | } |