@@ -90,17 +90,6 @@ class Problem extends BaseApiEntity
90
90
#[Serializer \Exclude]
91
91
private bool $ combined_run_compare = false ;
92
92
93
- /**
94
- * @var resource|string|null
95
- */
96
- #[ORM \Column(
97
- type: 'blob ' ,
98
- nullable: true ,
99
- options: ['comment ' => 'Problem text in HTML/PDF/ASCII ' ]
100
- )]
101
- #[Serializer \Exclude]
102
- private mixed $ problemtext = null ;
103
-
104
93
#[Assert \File]
105
94
#[Serializer \Exclude]
106
95
private ?UploadedFile $ problemtextFile = null ;
@@ -155,6 +144,22 @@ class Problem extends BaseApiEntity
155
144
#[Serializer \Exclude]
156
145
private Collection $ testcases ;
157
146
147
+ /**
148
+ * @var Collection<int, ProblemTextContent>
149
+ *
150
+ * We use a OneToMany instead of a OneToOne here, because otherwise this
151
+ * relation will always be loaded. See the commit message of commit
152
+ * 9e421f96691ec67ed62767fe465a6d8751edd884 for a more elaborate explanation
153
+ */
154
+ #[ORM \OneToMany(
155
+ mappedBy: 'problem ' ,
156
+ targetEntity: ProblemTextContent::class,
157
+ cascade: ['persist ' ],
158
+ orphanRemoval: true
159
+ )]
160
+ #[Serializer \Exclude]
161
+ private Collection $ problemTextContent ;
162
+
158
163
/**
159
164
* @var Collection<int, ProblemAttachment>
160
165
*/
@@ -259,39 +264,27 @@ public function getCombinedRunCompare(): bool
259
264
return $ this ->combined_run_compare ;
260
265
}
261
266
262
- /**
263
- * @param resource|string|null $problemtext
264
- */
265
- public function setProblemtext ($ problemtext ): Problem
266
- {
267
- $ this ->problemtext = $ problemtext ;
268
- return $ this ;
269
- }
270
-
271
267
public function setProblemtextFile (?UploadedFile $ problemtextFile ): Problem
272
268
{
273
269
$ this ->problemtextFile = $ problemtextFile ;
274
270
275
271
// Clear the problem text to make sure the entity is modified.
276
- $ this ->problemtext = '' ;
272
+ $ this ->setProblemTextContent ( null ) ;
277
273
278
274
return $ this ;
279
275
}
280
276
281
277
public function setClearProblemtext (bool $ clearProblemtext ): Problem
282
278
{
283
279
$ this ->clearProblemtext = $ clearProblemtext ;
284
- $ this ->problemtext = null ;
280
+ $ this ->setProblemTextContent ( null ) ;
285
281
286
282
return $ this ;
287
283
}
288
284
289
- /**
290
- * @return resource|string
291
- */
292
- public function getProblemtext ()
285
+ public function getProblemtext (): ?string
293
286
{
294
- return $ this ->problemtext ;
287
+ return $ this ->getProblemTextContent ()?->getContent() ;
295
288
}
296
289
297
290
public function getProblemtextFile (): ?UploadedFile
@@ -339,11 +332,12 @@ public function getRunExecutable(): ?Executable
339
332
340
333
public function __construct ()
341
334
{
342
- $ this ->testcases = new ArrayCollection ();
343
- $ this ->submissions = new ArrayCollection ();
344
- $ this ->clarifications = new ArrayCollection ();
345
- $ this ->contest_problems = new ArrayCollection ();
346
- $ this ->attachments = new ArrayCollection ();
335
+ $ this ->testcases = new ArrayCollection ();
336
+ $ this ->submissions = new ArrayCollection ();
337
+ $ this ->clarifications = new ArrayCollection ();
338
+ $ this ->contest_problems = new ArrayCollection ();
339
+ $ this ->attachments = new ArrayCollection ();
340
+ $ this ->problemTextContent = new ArrayCollection ();
347
341
}
348
342
349
343
public function addTestcase (Testcase $ testcase ): Problem
@@ -433,13 +427,29 @@ public function getAttachments(): Collection
433
427
return $ this ->attachments ;
434
428
}
435
429
430
+ public function setProblemTextContent (?ProblemTextContent $ content ): self
431
+ {
432
+ $ this ->problemTextContent ->clear ();
433
+ if ($ content ) {
434
+ $ this ->problemTextContent ->add ($ content );
435
+ $ content ->setProblem ($ this );
436
+ }
437
+
438
+ return $ this ;
439
+ }
440
+
441
+ public function getProblemTextContent (): ?ProblemTextContent
442
+ {
443
+ return $ this ->problemTextContent ->first () ?: null ;
444
+ }
445
+
436
446
#[ORM \PrePersist]
437
447
#[ORM \PreUpdate]
438
448
public function processProblemText (): void
439
449
{
440
450
if ($ this ->isClearProblemtext ()) {
441
451
$ this
442
- ->setProblemtext (null )
452
+ ->setProblemTextContent (null )
443
453
->setProblemtextType (null );
444
454
} elseif ($ this ->getProblemtextFile ()) {
445
455
$ content = file_get_contents ($ this ->getProblemtextFile ()->getRealPath ());
@@ -476,8 +486,10 @@ public function processProblemText(): void
476
486
throw new Exception ('Problem statement has unknown file type. ' );
477
487
}
478
488
489
+ $ problemTextContent = (new ProblemTextContent ())
490
+ ->setContent ($ content );
479
491
$ this
480
- ->setProblemtext ( $ content )
492
+ ->setProblemTextContent ( $ problemTextContent )
481
493
->setProblemtextType ($ problemTextType );
482
494
}
483
495
}
@@ -492,7 +504,7 @@ public function getProblemTextStreamedResponse(): StreamedResponse
492
504
};
493
505
494
506
$ filename = sprintf ('prob-%s.%s ' , $ this ->getName (), $ this ->getProblemtextType ());
495
- $ problemText = stream_get_contents ( $ this ->getProblemtext () );
507
+ $ problemText = $ this ->getProblemtext ();
496
508
497
509
$ response = new StreamedResponse ();
498
510
$ response ->setCallback (function () use ($ problemText ) {
0 commit comments