66
77use App \Entity \HintOpenEvent ;
88use App \Entity \Question ;
9+ use App \Entity \SolutionEventStatus ;
910use App \Entity \User ;
1011use App \Repository \SolutionEventRepository ;
12+ use App \Service \DbRunnerComparer ;
1113use App \Service \DbRunnerService ;
1214use App \Service \PointCalculationService ;
1315use App \Service \PromptService ;
1416use Doctrine \ORM \EntityManagerInterface ;
1517use Symfony \Component \DependencyInjection \ParameterBag \ParameterBagInterface ;
1618use Symfony \Component \HttpKernel \Exception \BadRequestHttpException ;
17- use Symfony \Component \Serializer \ SerializerInterface ;
19+ use Symfony \Component \Translation \ TranslatableMessage ;
1820use Symfony \Contracts \Translation \TranslatorInterface ;
1921use Symfony \UX \LiveComponent \Attribute \AsLiveComponent ;
2022use Symfony \UX \LiveComponent \Attribute \LiveAction ;
2123use Symfony \UX \LiveComponent \Attribute \LiveProp ;
2224use Symfony \UX \LiveComponent \ComponentToolsTrait ;
2325use Symfony \UX \LiveComponent \DefaultActionTrait ;
2426
27+ use function Symfony \Component \Translation \t ;
28+
2529#[AsLiveComponent]
2630final class Modal
2731{
2832 use ComponentToolsTrait;
2933 use DefaultActionTrait;
3034
35+ public function __construct (
36+ private readonly TranslatorInterface $ translator ,
37+ ) {
38+ }
39+
3140 #[LiveProp]
3241 public User $ currentUser ;
3342
@@ -50,7 +59,6 @@ public function instruct(
5059 DbRunnerService $ dbRunnerService ,
5160 PromptService $ promptService ,
5261 TranslatorInterface $ translator ,
53- SerializerInterface $ serializer ,
5462 EntityManagerInterface $ entityManager ,
5563 ParameterBagInterface $ parameterBag ,
5664 ): void {
@@ -63,49 +71,77 @@ public function instruct(
6371
6472 $ query = $ solutionEventRepository ->getLatestQuery ($ this ->question , $ this ->currentUser );
6573 if (null === $ query ) {
74+ $ this ->flushHint ('informative ' , t ('instruction.hint.not_submitted ' ));
75+
6676 return ;
6777 }
78+ if (SolutionEventStatus::Passed === $ query ->getStatus ()) {
79+ $ this ->flushHint ('informative ' , t ('instruction.hint.solved ' ));
6880
69- $ schema = $ this -> question -> getSchema ()-> getSchema () ;
70- $ answer = $ this -> question -> getAnswer ();
81+ return ;
82+ }
7183
72- $ hintOpenEvent = (new HintOpenEvent ())
73- ->setOpener ($ this ->currentUser )
74- ->setQuestion ($ this ->question )
75- ->setQuery ($ query ->getQuery ());
84+ $ schema = $ query ->getQuestion ()->getSchema ();
7685
77- // run answer. if it failed, we should consider it an error
7886 try {
79- $ answerResult = $ dbRunnerService ->runQuery ($ schema , $ answer );
87+ $ answer = $ query ->getQuestion ()->getAnswer ();
88+ $ answerResult = $ dbRunnerService ->runQuery ($ schema ->getSchema (), $ answer );
8089 } catch (\Throwable $ e ) {
81- $ this ->emit ( ' app:challenge- hint ' , [
82- 'hint ' => $ serializer -> serialize (HintPayload:: fromError ( $ e ->getMessage ()), ' json ' ),
83- ]);
90+ $ this ->flushHint ( ' informative ' , t ( ' instruction. hint.error ' , [
91+ '%error% ' => $ e ->getMessage (),
92+ ])) ;
8493
8594 return ;
8695 }
8796
97+ $ hintOpenEvent = (new HintOpenEvent ())
98+ ->setOpener ($ this ->currentUser )
99+ ->setQuestion ($ this ->question )
100+ ->setQuery ($ query ->getQuery ());
101+
88102 try {
89- // run query to get the error message (or compare the result)
90- $ result = $ dbRunnerService ->runQuery ($ schema , $ query ->getQuery ());
91- } catch (\Throwable $ e ) {
92- $ hint = $ promptService ->hint ($ query ->getQuery (), $ e ->getMessage (), $ answer );
93- }
103+ try {
104+ $ userResult = $ dbRunnerService ->runQuery ($ schema-> getSchema () , $ query ->getQuery ());
105+ } catch (\Throwable $ e ) {
106+ $ hint = $ promptService ->hint ($ query ->getQuery (), $ e ->getMessage (), $ answer );
107+ $ hintOpenEvent -> setResponse ( $ hint );
94108
95- if (isset ($ result ) && $ result !== $ answerResult ) {
96- $ hint = $ promptService ->hint ($ query ->getQuery (), 'Different output ' , $ answer );
97- }
109+ $ this ->flushHint ('hint ' , $ hint );
110+
111+ return ;
112+ }
113+
114+ $ compareResult = DbRunnerComparer::compare ($ answerResult , $ userResult );
115+ if ($ compareResult ->correct ()) {
116+ $ this ->flushHint ('informative ' , t ('instruction.hint.solved ' ));
117+
118+ return ;
119+ }
98120
99- if (!isset ($ hint )) {
100- $ hint = $ translator ->trans ('instruction.hint.no_hint ' );
121+ $ compareReason = $ compareResult ->reason ()->trans ($ translator , 'en_US ' );
122+ $ hint = $ promptService ->hint ($ query ->getQuery (), "Different result: {$ compareReason }" , $ answer );
123+ $ hintOpenEvent ->setResponse ($ hint );
124+
125+ $ this ->flushHint ('hint ' , $ hint );
126+ } finally {
127+ $ entityManager ->persist ($ hintOpenEvent );
128+ $ entityManager ->flush ();
101129 }
130+ }
102131
132+ /**
133+ * Flush the hint to the client.
134+ *
135+ * @param string $type the type of the hint (informative or hint)
136+ * @param string|TranslatableMessage $hint the hint to flush
137+ */
138+ private function flushHint (string $ type , string |TranslatableMessage $ hint ): void
139+ {
103140 $ this ->emit ('app:challenge-hint ' , [
104- 'hint ' => $ serializer ->serialize (HintPayload::fromHint ($ hint ), 'json ' ),
141+ 'type ' => $ type ,
142+ 'hint ' => $ hint instanceof TranslatableMessage
143+ ? $ hint ->trans ($ this ->translator )
144+ : $ hint ,
105145 ]);
106-
107- $ hintOpenEvent = $ hintOpenEvent ->setResponse ($ hint );
108- $ entityManager ->persist ($ hintOpenEvent );
109- $ entityManager ->flush ();
110146 }
111147}
0 commit comments