Skip to content
This repository was archived by the owner on Apr 3, 2023. It is now read-only.

Commit 4152512

Browse files
author
Teddy Roncin
committed
✨ (Routes /ues) Added routes for UEs
Added route GET /ues/search : it can search UEs by their code and the type of ECTS they give. Added route GET /ues/{code} that returns informations about the UE with the provided code. Added a new search filter for ApiPlatform which allows to change the name of the parameters in the URL. Fixed a small bug in the UpdateAtSubscriber class that could make the server produce an error
1 parent 4fa0088 commit 4152512

13 files changed

+233
-8
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace App\ApiPlatform;
4+
5+
use ApiPlatform\Api\IdentifiersExtractorInterface;
6+
use ApiPlatform\Api\IriConverterInterface;
7+
use ApiPlatform\Doctrine\Common\Filter\SearchFilterInterface;
8+
use ApiPlatform\Doctrine\Common\Filter\SearchFilterTrait;
9+
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
10+
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
11+
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
12+
use ApiPlatform\Metadata\Operation;
13+
use Doctrine\DBAL\Types\Types;
14+
use Doctrine\ORM\QueryBuilder;
15+
use Doctrine\Persistence\ManagerRegistry;
16+
use Psr\Log\LoggerInterface;
17+
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
18+
19+
final class SearchWithCustomParametersNamesFilter extends AbstractFilter implements SearchFilterInterface
20+
{
21+
use SearchFilterTrait;
22+
23+
protected array $aliasMap;
24+
private SearchFilter $searchFilter;
25+
26+
public function __construct(ManagerRegistry $managerRegistry, IriConverterInterface $iriConverter, PropertyAccessorInterface $propertyAccessor = null, LoggerInterface $logger = null, array $properties = null, IdentifiersExtractorInterface $identifiersExtractor = null, array $aliasMap = null)
27+
{
28+
parent::__construct($managerRegistry, $logger, $properties);
29+
$this->aliasMap = $aliasMap;
30+
$this->searchFilter = new SearchFilter($managerRegistry, $iriConverter, $propertyAccessor, $logger, $properties, $identifiersExtractor);
31+
}
32+
33+
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void
34+
{
35+
$this->searchFilter->filterProperty($property, $value, $queryBuilder, $queryNameGenerator, $resourceClass, $operation, $context);
36+
}
37+
38+
protected function denormalizePropertyName(int|string $property): string
39+
{
40+
return array_search($property, $this->aliasMap, strict: true) ?: $property;
41+
}
42+
43+
protected function normalizePropertyName(int|string $property): string
44+
{
45+
return $this->aliasMap[$property] ?? $property;
46+
}
47+
48+
protected function getType(string $doctrineType): string
49+
{
50+
return match ($doctrineType) {
51+
Types::ARRAY => 'array',
52+
Types::BIGINT, Types::INTEGER, Types::SMALLINT => 'int',
53+
Types::BOOLEAN => 'bool',
54+
Types::DATE_MUTABLE, Types::TIME_MUTABLE, Types::DATETIME_MUTABLE, Types::DATETIMETZ_MUTABLE, Types::DATE_IMMUTABLE, Types::TIME_IMMUTABLE, Types::DATETIME_IMMUTABLE, Types::DATETIMETZ_IMMUTABLE => \DateTimeInterface::class,
55+
Types::FLOAT => 'float',
56+
default => 'string',
57+
};
58+
}
59+
60+
protected function getIriConverter(): IriConverterInterface
61+
{
62+
return $this->iriConverter;
63+
}
64+
65+
protected function getPropertyAccessor(): PropertyAccessorInterface
66+
{
67+
return $this->propertyAccessor;
68+
}
69+
}

src/Entity/UE.php

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use ApiPlatform\Metadata\GetCollection;
1111
use ApiPlatform\Metadata\Patch;
1212
use App\Controller\SoftDeleteController;
13+
use ApiPlatform\Metadata\ApiProperty;
14+
use App\ApiPlatform\SearchWithCustomParametersNamesFilter;
1315
use App\Repository\UERepository;
1416
use Doctrine\Common\Collections\ArrayCollection;
1517
use Doctrine\Common\Collections\Collection;
@@ -55,7 +57,11 @@
5557
)
5658
]
5759
#[
58-
ApiFilter(SearchFilter::class, properties : ['code' => 'partial'])
60+
ApiFilter(
61+
SearchWithCustomParametersNamesFilter::class,
62+
properties: ['code' => 'partial', 'credits.category.code' => 'exact'],
63+
arguments: ['aliasMap' => ['credits.category.code' => 'category']],
64+
),
5965
]
6066
class UE
6167
{
@@ -67,24 +73,27 @@ class UE
6773
* @Assert\Uuid
6874
*/
6975
#[Groups([
70-
'ue:read:one',
7176
'ue:read:some',
77+
'ue:read:one',
7278
])]
79+
#[ApiProperty(identifier: false)]
7380
private $id;
7481

7582
/**
7683
* The code of the UE (e.g. "MATH01").
7784
*
78-
* @ORM\Column(type="string", length=10)
85+
* @ORM\Column(type="string", length=10, unique=true)
86+
*
7987
* @Assert\Type("string")
8088
* @Assert\Length(min=1, max=10)
8189
* @Assert\Regex("/^[a-zA-Z]{1,5}[0-9]{1,2}$/")
8290
*/
8391
#[Groups([
84-
'ue:read:one',
8592
'ue:read:some',
93+
'ue:read:one',
8694
'user-edt:read:one',
8795
])]
96+
#[ApiProperty(identifier: true)]
8897
private $code;
8998

9099
/**
@@ -95,8 +104,8 @@ class UE
95104
* @Assert\Length(min=1, max=255)
96105
*/
97106
#[Groups([
98-
'ue:read:one',
99107
'ue:read:some',
108+
'ue:read:one',
100109
])]
101110
private $name;
102111

@@ -138,13 +147,20 @@ class UE
138147
* @ORM\ManyToOne(targetEntity=UTTFiliere::class, inversedBy="UEs")
139148
* @ORM\JoinColumn(name="filiere_code", referencedColumnName="code")
140149
*/
150+
#[Groups([
151+
'ue:read:one',
152+
])]
141153
private $filiere;
142154

143155
/**
144156
* The amount of UECredits of this UE. A UECredit object is a number of credit in a UECreditCategory.
145157
*
146158
* @ORM\OneToMany(targetEntity=UECredit::class, mappedBy="UE", orphanRemoval=true)
147159
*/
160+
#[Groups([
161+
'ue:read:one',
162+
'ue:read:some',
163+
])]
148164
private $credits;
149165

150166
/**
@@ -164,41 +180,72 @@ class UE
164180
* inverseJoinColumns={@ORM\JoinColumn(name="semester_code", referencedColumnName="code")}
165181
* )
166182
*/
183+
#[Groups([
184+
'ue:read:one',
185+
])]
167186
private $openSemester;
168187

188+
/**
189+
* Whether this UE is closed. A UE can still be opened, but not available at a given semester
190+
* (it could for example only be available in spring). When it is marked as closed, it should never be available again.
191+
*
192+
* @ORM\Column(type="boolean", options={"default": false})
193+
* @Assert\Type("boolean")
194+
*/
195+
#[Groups([
196+
'ue:read:some',
197+
'ue:read:one',
198+
])]
199+
private $isClosed = false;
200+
169201
/**
170202
* The relation to the entity that store the work time of this UE.
171203
*
172204
* @ORM\OneToOne(targetEntity=UEWorkTime::class, mappedBy="UE", cascade={"persist", "remove"})
173205
*/
206+
#[Groups([
207+
'ue:read:one',
208+
])]
174209
private $workTime;
175210

176211
/**
177212
* The relation to the entity that store the info of this UE given by UTT.
178213
*
179214
* @ORM\OneToOne(targetEntity=UEInfo::class, mappedBy="UE", cascade={"persist", "remove"})
180215
*/
216+
#[Groups([
217+
'ue:read:one',
218+
])]
181219
private $info;
182220

183221
/**
184222
* The relation to all UEAnnals related to this UE.
185223
*
186224
* @ORM\OneToMany(targetEntity=UEAnnal::class, mappedBy="UE", orphanRemoval=true)
187225
*/
226+
#[Groups([
227+
'ue:read:one',
228+
])]
188229
private $annals;
189230

190231
/**
191232
* The relation to all UEComments related to this UE.
192233
*
193234
* @ORM\OneToMany(targetEntity=UEComment::class, mappedBy="UE", orphanRemoval=true)
194235
*/
236+
#[Groups([
237+
'ue:read:one',
238+
])]
195239
private $comments;
196240

197241
/**
198242
* The relation to all UECourses of this UE.
199243
*
200244
* @ORM\OneToMany(targetEntity=UECourse::class, mappedBy="UE")
201245
*/
246+
#[Groups([
247+
'ue:read:one',
248+
])]
202249
private $courses;
203250

204251
public function __construct()
@@ -406,6 +453,17 @@ public function removeOpenSemester(Semester $openSemester): self
406453
return $this;
407454
}
408455

456+
public function getIsClosed(): bool
457+
{
458+
return $this->isClosed;
459+
}
460+
461+
public function close(): self
462+
{
463+
$this->isClosed = false;
464+
return $this;
465+
}
466+
409467
public function getWorkTime(): ?UEWorkTime
410468
{
411469
return $this->workTime;

src/Entity/UEAnnal.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\Common\Collections\Collection;
88
use Doctrine\ORM\Mapping as ORM;
99
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
10+
use Symfony\Component\Serializer\Annotation\Groups;
1011
use Symfony\Component\Uid\Uuid;
1112
use Symfony\Component\Validator\Constraints as Assert;
1213

@@ -39,6 +40,9 @@ class UEAnnal
3940
* @ORM\ManyToOne(targetEntity=User::class)
4041
* @ORM\JoinColumn(nullable=false)
4142
*/
43+
#[Groups([
44+
'ue:read:one',
45+
])]
4246
private $sender;
4347

4448
/**
@@ -47,6 +51,9 @@ class UEAnnal
4751
* @ORM\ManyToOne(targetEntity=Semester::class)
4852
* @ORM\JoinColumn(name="semester_code", referencedColumnName="code")
4953
*/
54+
#[Groups([
55+
'ue:read:one',
56+
])]
5057
private $semester;
5158

5259
/**
@@ -55,6 +62,9 @@ class UEAnnal
5562
* @ORM\ManyToOne(targetEntity=UEAnnalType::class)
5663
* @ORM\JoinColumn(name="type_name", referencedColumnName="name")
5764
*/
65+
#[Groups([
66+
'ue:read:one',
67+
])]
5868
private $type;
5969

6070
/**
@@ -64,6 +74,9 @@ class UEAnnal
6474
* @Assert\Type("string")
6575
* @Assert\Length(min=1, max=255)
6676
*/
77+
#[Groups([
78+
'ue:read:one',
79+
])]
6780
private $filename;
6881

6982
/**

src/Entity/UEComment.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\Common\Collections\Collection;
88
use Doctrine\ORM\Mapping as ORM;
99
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
10+
use Symfony\Component\Serializer\Annotation\Groups;
1011
use Symfony\Component\Uid\Uuid;
1112
use Symfony\Component\Validator\Constraints as Assert;
1213

@@ -41,6 +42,9 @@ class UEComment
4142
* @ORM\ManyToOne(targetEntity=User::class)
4243
* @ORM\JoinColumn(nullable=false)
4344
*/
45+
#[Groups([
46+
'ue:read:one',
47+
])]
4448
private $author;
4549

4650
/**
@@ -49,6 +53,9 @@ class UEComment
4953
* @ORM\Column(type="text")
5054
* @Assert\Type("string")
5155
*/
56+
#[Groups([
57+
'ue:read:one',
58+
])]
5259
private $body;
5360

5461
/**
@@ -65,13 +72,19 @@ class UEComment
6572
* @ORM\ManyToOne(targetEntity=Semester::class)
6673
* @ORM\JoinColumn(name="semester_code", referencedColumnName="code")
6774
*/
75+
#[Groups([
76+
'ue:read:one',
77+
])]
6878
private $semester;
6979

7080
/**
7181
* The relation to all UECommentReply that are answering to this Comment.
7282
*
7383
* @ORM\OneToMany(targetEntity=UECommentReply::class, mappedBy="comment")
7484
*/
85+
#[Groups([
86+
'ue:read:one',
87+
])]
7588
private $answers;
7689

7790
/**

src/Entity/UECommentReply.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Repository\UECommentReplyRepository;
66
use Doctrine\ORM\Mapping as ORM;
77
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
8+
use Symfony\Component\Serializer\Annotation\Groups;
89
use Symfony\Component\Uid\Uuid;
910
use Symfony\Component\Validator\Constraints as Assert;
1011

@@ -39,6 +40,9 @@ class UECommentReply
3940
* @ORM\ManyToOne(targetEntity=User::class)
4041
* @ORM\JoinColumn(nullable=false)
4142
*/
43+
#[Groups([
44+
'ue:read:one',
45+
])]
4246
private $author;
4347

4448
/**
@@ -47,6 +51,9 @@ class UECommentReply
4751
* @ORM\Column(type="text")
4852
* @Assert\Type("string")
4953
*/
54+
#[Groups([
55+
'ue:read:one',
56+
])]
5057
private $body;
5158

5259
/**

0 commit comments

Comments
 (0)