8
8
use ApiPlatform \Metadata \Operation ;
9
9
use ApiPlatform \State \ProcessorInterface ;
10
10
use App \Dto \ScreenInput ;
11
- use App \Entity \Tenant \Playlist ;
12
11
use App \Entity \Tenant \PlaylistScreenRegion ;
13
12
use App \Entity \Tenant \Screen ;
14
13
use App \Repository \PlaylistRepository ;
@@ -32,7 +31,7 @@ public function __construct(
32
31
EntityManagerInterface $ entityManager ,
33
32
ProcessorInterface $ persistProcessor ,
34
33
ProcessorInterface $ removeProcessor ,
35
- ScreenProvider $ provider
34
+ ScreenProvider $ provider,
36
35
) {
37
36
parent ::__construct ($ entityManager , $ persistProcessor , $ removeProcessor , $ provider );
38
37
}
@@ -42,6 +41,10 @@ protected function fromInput(mixed $object, Operation $operation, array $uriVari
42
41
// FIXME Do we really have to do (something like) this to load an existing object into the entity manager?
43
42
$ screen = $ this ->loadPrevious (new Screen (), $ context );
44
43
44
+ if (!$ screen instanceof Screen) {
45
+ throw new InvalidArgumentException ('object must be of type Screen ' );
46
+ }
47
+
45
48
assert ($ object instanceof ScreenInput);
46
49
empty ($ object ->title ) ?: $ screen ->setTitle ($ object ->title );
47
50
empty ($ object ->description ) ?: $ screen ->setDescription ($ object ->description );
@@ -56,57 +59,67 @@ protected function fromInput(mixed $object, Operation $operation, array $uriVari
56
59
$ screen ->setEnableColorSchemeChange ($ object ->enableColorSchemeChange );
57
60
}
58
61
59
- // Adding relations for playlist/screen/region
60
- if (isset ($ object ->regions ) && isset ($ screen )) {
62
+ // Adding relations for playlist/screen/region if object has region property.
63
+ if (isset ($ object ->regions )) {
64
+ // Ensure regions object has valid structure
65
+ $ this ->validateRegionsAndPlaylists ($ object ->regions );
66
+
67
+ $ existingPlaylistScreenRegions = $ screen ->getPlaylistScreenRegions ();
68
+
61
69
foreach ($ object ->regions as $ regionAndPlaylists ) {
62
- // Relevant region
63
- $ region = $ this ->screenLayoutRegionsRepository ->findOneBy (['id ' => $ regionAndPlaylists ['regionId ' ]]);
70
+ $ regionId = $ regionAndPlaylists ['regionId ' ];
71
+
72
+ $ region = $ this ->screenLayoutRegionsRepository ->findOneBy (['id ' => $ regionId ]);
64
73
65
74
if (is_null ($ region )) {
66
- throw new InvalidArgumentException ('Unknown region resource ' );
75
+ throw new InvalidArgumentException (sprintf ( 'Unknown region resource (id: %s) ' , $ regionId ) );
67
76
}
68
77
69
- // Collection to be saved.
70
- $ playlistScreenRegionCollection = new ArrayCollection ();
78
+ $ existingPlaylistScreenRegionsInRegion = $ existingPlaylistScreenRegions ->filter (
79
+ fn (PlaylistScreenRegion $ psr ) => $ psr ->getRegion ()?->getId() == $ regionId
80
+ );
81
+
82
+ $ inputPlaylists = $ regionAndPlaylists ['playlists ' ];
83
+ $ inputPlaylistIds = array_map (fn (array $ entry ): string => $ entry ['id ' ], $ inputPlaylists );
84
+
85
+ // Remove playlist screen regions that should not exist in region.
86
+ /** @var PlaylistScreenRegion $existingPSR */
87
+ foreach ($ existingPlaylistScreenRegionsInRegion as $ existingPSR ) {
88
+ if (!in_array ($ existingPSR ->getPlaylist ()?->getId(), $ inputPlaylistIds )) {
89
+ $ screen ->removePlaylistScreenRegion ($ existingPSR );
90
+ }
91
+ }
71
92
72
- // Looping through playlists connected to region
73
- foreach ($ regionAndPlaylists ['playlists ' ] as $ inputPlaylist ) {
74
- // Checking if playlists exists
93
+ // Add or update the input playlists.
94
+ foreach ($ inputPlaylists as $ inputPlaylist ) {
75
95
$ playlist = $ this ->playlistRepository ->findOneBy (['id ' => $ inputPlaylist ['id ' ]]);
76
96
77
97
if (is_null ($ playlist )) {
78
- throw new InvalidArgumentException ('Unknown playlist resource ' );
98
+ throw new InvalidArgumentException (sprintf ( 'Unknown playlist resource (id: %s) ' , $ inputPlaylist [ ' id ' ]) );
79
99
}
80
100
81
- // See if relation already exists
82
- $ existingPlaylistScreenRegion = $ this ->playlistScreenRegionRepository ->findOneBy ([
83
- 'screen ' => $ screen ,
84
- 'region ' => $ region ,
101
+ $ existingPlaylistScreenRegionRelation = $ this ->playlistScreenRegionRepository ->findOneBy ([
85
102
'playlist ' => $ playlist ,
103
+ 'region ' => $ region ,
104
+ 'screen ' => $ screen ,
86
105
]);
87
106
88
- if (is_null ($ existingPlaylistScreenRegion )) {
89
- // If relation does not exist, create new PlaylistScreenRegion
107
+ if (!is_null ($ existingPlaylistScreenRegionRelation )) {
108
+ $ existingPlaylistScreenRegionRelation ->setWeight ($ inputPlaylist ['weight ' ] ?? 0 );
109
+ } else {
90
110
$ newPlaylistScreenRegionRelation = new PlaylistScreenRegion ();
91
111
$ newPlaylistScreenRegionRelation ->setPlaylist ($ playlist );
92
112
$ newPlaylistScreenRegionRelation ->setRegion ($ region );
93
113
$ newPlaylistScreenRegionRelation ->setScreen ($ screen );
94
114
$ newPlaylistScreenRegionRelation ->setWeight ($ inputPlaylist ['weight ' ] ?? 0 );
95
- /** @psalm-suppress InvalidArgument */
96
- $ playlistScreenRegionCollection ->add ($ newPlaylistScreenRegionRelation );
97
- } else {
98
- // Update weight, add existing relation
99
- $ existingPlaylistScreenRegion ->setWeight ($ inputPlaylist ['weight ' ] ?? 0 );
100
- /** @psalm-suppress InvalidArgument */
101
- $ playlistScreenRegionCollection ->add ($ existingPlaylistScreenRegion );
115
+ $ screen ->addPlaylistScreenRegion ($ newPlaylistScreenRegionRelation );
102
116
}
103
117
}
104
- $ region ->setPlaylistScreenRegions ($ playlistScreenRegionCollection );
105
118
}
106
119
}
107
120
108
121
// Maps ids of existing groups
109
- if (isset ($ object ->groups ) && isset ( $ screen ) ) {
122
+ if (isset ($ object ->groups )) {
110
123
$ groupCollection = new ArrayCollection ();
111
124
foreach ($ object ->groups as $ group ) {
112
125
$ groupToSave = $ this ->groupRepository ->findOneBy (['id ' => $ group ]);
@@ -134,4 +147,38 @@ protected function fromInput(mixed $object, Operation $operation, array $uriVari
134
147
135
148
return $ screen ;
136
149
}
150
+
151
+ private function validateRegionsAndPlaylists (array $ regions ): void
152
+ {
153
+ foreach ($ regions as $ region ) {
154
+ $ this ->validateRegion ($ region );
155
+
156
+ foreach ($ region ['playlists ' ] as $ playlist ) {
157
+ $ this ->validatePlaylist ($ playlist );
158
+ }
159
+ }
160
+ }
161
+
162
+ private function validateRegion (array $ region ): void
163
+ {
164
+ if (!isset ($ region ['regionId ' ]) || !is_string ($ region ['regionId ' ])) {
165
+ throw new InvalidArgumentException ('All regions must specify a valid Ulid ' );
166
+ }
167
+
168
+ if (!isset ($ region ['playlists ' ]) || !is_array ($ region ['playlists ' ])) {
169
+ throw new InvalidArgumentException ('All regions must specify a list of playlists ' );
170
+ }
171
+ }
172
+
173
+ private function validatePlaylist (array $ playlist ): void
174
+ {
175
+ if (!isset ($ playlist ['id ' ]) || !is_string ($ playlist ['id ' ])) {
176
+ throw new InvalidArgumentException ('All playlists must specify a valid Ulid ' );
177
+
178
+ }
179
+
180
+ if (isset ($ playlist ['weight ' ]) && !is_integer ($ playlist ['weight ' ])) {
181
+ throw new InvalidArgumentException ('Playlists weight must be an integer ' );
182
+ }
183
+ }
137
184
}
0 commit comments