55namespace  PhpSchool \PhpWorkshop \Check ;
66
77use  PDO ;
8- use  PDOException ;
8+ use  PhpSchool \ PhpWorkshop \ Event \ CgiExerciseRunnerEvent ;
99use  PhpSchool \PhpWorkshop \Event \CliExecuteEvent ;
10+ use  PhpSchool \PhpWorkshop \Event \CliExerciseRunnerEvent ;
1011use  PhpSchool \PhpWorkshop \Event \Event ;
1112use  PhpSchool \PhpWorkshop \Event \EventDispatcher ;
12- use  PhpSchool \PhpWorkshop \Exercise \ TemporaryDirectoryTrait ;
13+ use  PhpSchool \PhpWorkshop \Event \ ExerciseRunnerEvent ;
1314use  PhpSchool \PhpWorkshop \ExerciseCheck \DatabaseExerciseCheck ;
1415use  PhpSchool \PhpWorkshop \Result \Failure ;
1516use  PhpSchool \PhpWorkshop \Result \Success ;
16- use  RuntimeException ;
17+ use  PhpSchool \PhpWorkshop \Utils \Path ;
18+ use  PhpSchool \PhpWorkshop \Utils \System ;
19+ use  Symfony \Component \Filesystem \Filesystem ;
1720
1821/** 
1922 * This check sets up a database and a `PDO` object. It prepends the database DSN as a CLI argument to the student's 
2326 */ 
2427class  DatabaseCheck implements  ListenableCheckInterface
2528{
26-     use  TemporaryDirectoryTrait;
29+     private  Filesystem $ filesystem
30+     private  ?string  $ dbContentnull ;
2731
28-     private  string  $ databaseDirectory
29-     private  string  $ userDatabasePath
30-     private  string  $ solutionDatabasePath
31-     private  string  $ userDsn
32-     private  string  $ solutionDsn
33- 
34-     /** 
35-      * Setup paths and DSN's. 
36-      */ 
37-     public  function  __construct ()
32+     public  function  __construct (Filesystem $ filesystemnull )
3833    {
39-         $ this databaseDirectory  = $ this getTemporaryPath ();
40-         $ this userDatabasePath  = sprintf ('%s/user-db.sqlite ' , $ this databaseDirectory );
41-         $ this solutionDatabasePath  = sprintf ('%s/solution-db.sqlite ' , $ this databaseDirectory );
42-         $ this solutionDsn  = sprintf ('sqlite:%s ' , $ this solutionDatabasePath );
43-         $ this userDsn  = sprintf ('sqlite:%s ' , $ this userDatabasePath );
34+         $ this filesystem  = $ filesystem$ filesystemnew  Filesystem ();
4435    }
4536
4637    /** 
@@ -64,78 +55,69 @@ public function getExerciseInterface(): string
6455     */ 
6556    public  function  attach (EventDispatcher $ eventDispatchervoid 
6657    {
67-         if  (file_exists ($ this databaseDirectory )) {
68-             throw  new  RuntimeException (
69-                 sprintf ('Database directory: "%s" already exists ' , $ this databaseDirectory ),
70-             );
71-         }
72- 
73-         mkdir ($ this databaseDirectory , 0777 , true );
74- 
75-         try  {
76-             $ dbnew  PDO ($ this userDsn );
77-             $ dbsetAttribute (PDO ::ATTR_ERRMODE , PDO ::ERRMODE_EXCEPTION );
78-         } catch  (PDOException $ e
79-             rmdir ($ this databaseDirectory );
80-             throw  $ e
81-         }
82- 
83-         $ eventDispatcherlisten ('verify.start ' , function  (Event $ euse  ($ db
84-             /** @var DatabaseExerciseCheck $exercise */ 
85-             $ exercise$ egetParameter ('exercise ' );
86-             $ exerciseseed ($ db
87-             //make a copy - so solution can modify without effecting database user has access to 
88-             copy ($ this userDatabasePath , $ this solutionDatabasePath );
89-         });
58+         $ eventDispatcherlisten (['verify.start ' , 'run.start ' ], function  (Event $ e
59+             $ pathrandomTempPath ('sqlite ' );
9060
91-         $ eventDispatcherlisten ('run.start ' , function  (Event $ euse  ($ db
92-             /** @var DatabaseExerciseCheck $exercise */ 
93-             $ exercise$ egetParameter ('exercise ' );
94-             $ exerciseseed ($ db
95-         });
61+             $ this filesystem ->touch ($ path
62+ 
63+             try  {
64+                 $ db$ this getPDO ($ path
65+ 
66+                 /** @var DatabaseExerciseCheck $exercise */ 
67+                 $ exercise$ egetParameter ('exercise ' );
68+                 $ exerciseseed ($ db
9669
97-         $ eventDispatcherlisten ('cli.verify.reference-execute.pre ' , function  (CliExecuteEvent $ e
98-             $ eprependArg ($ this solutionDsn );
70+                 $ this dbContent  = (string ) file_get_contents ($ path
71+             } finally  {
72+                 unset($ db
73+ 
74+                 $ this filesystem ->remove ($ path
75+             }
9976        });
10077
10178        $ eventDispatcherlisten (
102-             ['cli.verify.student-execute.pre ' , 'cli.run.student-execute.pre ' ],
103-             function  (CliExecuteEvent $ e
104-                 $ eprependArg ($ this userDsn );
79+             ['cli.verify.prepare ' , 'cgi.verify.prepare ' ],
80+             function  (CliExerciseRunnerEvent CgiExerciseRunnerEvent $ e
81+                 $ egetScenario ()->withFile ('db.sqlite ' , (string ) $ this dbContent );
82+ 
83+                 $ this dbContent  = null ;
10584            },
10685        );
10786
108-         $ eventDispatcherinsertVerifier ( ' verify.finish ' ,  function  ( Event   $ e )  use  ( $ db ) { 
109-             /** @var DatabaseExerciseCheck $exercise */ 
110-             $ exercise  =  $ egetParameter ( ' exercise ' ); 
111-              $ verifyResult  =  $ exercise -> verify ( $ db 
87+         $ eventDispatcherlisten ( 
88+             ' cli.verify.reference-execute.pre ' , 
89+             fn ( CliExecuteEvent   $ e ) =>  $ eprependArg ( ' sqlite:db.sqlite ' ), 
90+         );
11291
113-             if  (false  === $ verifyResult
114-                 return  Failure::fromNameAndReason ($ this getName (), 'Database verification failed ' );
115-             }
92+         $ eventDispatcherlisten (
93+             ['cli.verify.student-execute.pre ' , 'cli.run.student-execute.pre ' ],
94+             fn (CliExecuteEvent $ e$ eprependArg ('sqlite:db.sqlite ' ),
95+         );
11696
117-              return   new   Success ( ' Database Verification Check ' ); 
118-         } );
97+         $ eventDispatcher -> insertVerifier ( ' verify.finish ' ,  function  ( ExerciseRunnerEvent   $ e ) { 
98+              $ db  =  $ this -> getPDO (Path:: join ( $ e -> getContext ()-> getStudentExecutionDirectory (),  ' db.sqlite ' ) );
11999
120-         $ eventDispatcherlisten (
121-             [
122-                 'cli.verify.reference-execute.fail ' ,
123-                 'verify.finish ' ,
124-                 'run.finish ' ,
125-             ],
126-             function  () use  ($ db
100+             try  {
101+                 /** @var DatabaseExerciseCheck $exercise */ 
102+                 $ exercise$ egetParameter ('exercise ' );
103+                 $ verifyResult$ exerciseverify ($ db
104+ 
105+                 if  (false  === $ verifyResult
106+                     return  Failure::fromNameAndReason ($ this getName (), 'Database verification failed ' );
107+                 }
108+ 
109+                 return  new  Success ('Database Verification Check ' );
110+             } finally  {
127111                unset($ db
128-                 $ this unlink ($ this userDatabasePath );
129-                 $ this unlink ($ this solutionDatabasePath );
130-                 rmdir ($ this databaseDirectory );
131-             },
132-         );
112+             }
113+         });
133114    }
134115
135-     private  function  unlink (string  $ file void 
116+     private  function  getPDO (string  $ path PDO 
136117    {
137-         if  (file_exists ($ file
138-             unlink ($ file
139-         }
118+         $ dbnew  PDO ('sqlite: '  . $ path
119+         $ dbsetAttribute (PDO ::ATTR_ERRMODE , PDO ::ERRMODE_EXCEPTION );
120+ 
121+         return  $ db
140122    }
141123}
0 commit comments