1
1
<?php
2
+
3
+ use Psr \Http \Message \ResponseInterface ;
2
4
use Psr \Http \Message \ServerRequestInterface as Request ;
5
+ use React \EventLoop \Loop ;
6
+ use React \MySQL \ConnectionInterface as DbConnection ;
7
+ use React \MySQL \Factory as DbFactory ;
3
8
use React \Http \Message \Response ;
9
+ use React \MySQL \QueryResult ;
10
+ use React \Promise \PromiseInterface ;
4
11
5
- function init ()
6
- {
7
- global $ world , $ fortune , $ update ;
8
- $ pdo = new PDO (
9
- 'mysql:host=tfb-database;dbname=hello_world ' ,
10
- 'benchmarkdbuser ' ,
11
- 'benchmarkdbpass ' ,
12
- [
13
- PDO ::ATTR_DEFAULT_FETCH_MODE => PDO ::FETCH_ASSOC ,
14
- PDO ::ATTR_EMULATE_PREPARES => false
15
- ]
16
- );
17
- $ world = $ pdo ->prepare ('SELECT id,randomNumber FROM World WHERE id=? ' );
18
- $ update = $ pdo ->prepare ('UPDATE World SET randomNumber=? WHERE id=? ' );
19
- $ fortune = $ pdo ->prepare ('SELECT id,message FROM Fortune ' );
20
- $ fortune ->setFetchMode (PDO ::FETCH_KEY_PAIR );
21
- }
12
+ use function React \Promise \all ;
22
13
23
- function router (Request $ request )
14
+ /** @return Closure(Request):ResponseInterface */
15
+ function requestHandler (): Closure
24
16
{
25
- return match ($ request ->getUri ()->getPath ()) {
26
- '/plaintext ' => text (),
27
- '/json ' => json (),
28
- '/db ' => db (),
29
- '/fortunes ' => fortune (),
30
- '/query ' => query ($ request ),
31
- '/update ' => updateraw ($ request ),
32
- // '/info' => info(),
33
- default => new Response (404 , [], 'Error 404 ' ),
17
+ $ connection = establishDbConnection ('benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world?idle=0.5 ' );
18
+
19
+ $ world = static function (int $ id ) use ($ connection ): PromiseInterface {
20
+ return $ connection ->query ('SELECT id,randomNumber FROM World WHERE id=? ' , [$ id ]);
34
21
};
35
- }
36
22
37
- function text ()
38
- {
39
- return new Response (200 , [
40
- 'Content-Type ' => 'text/plain '
41
- ], 'Hello, World! ' );
42
- }
23
+ $ fortune = static function () use ($ connection ): PromiseInterface {
24
+ return $ connection ->query ('SELECT id,message FROM Fortune ' );
25
+ };
43
26
44
- function json ()
45
- {
46
- return new Response (200 , [
47
- 'Content-Type ' => 'application/json '
48
- ], json_encode (['message ' => 'Hello, World! ' ]));
27
+ $ update = static function (int $ id , int $ randomNumber ) use ($ connection ): PromiseInterface {
28
+ return $ connection ->query ('UPDATE World SET randomNumber=? WHERE id=? ' , [$ randomNumber , $ id ]);
29
+ };
30
+
31
+ return static function (Request $ request ) use ($ world , $ fortune , $ update ): ResponseInterface | PromiseInterface {
32
+ return match ($ request ->getUri ()->getPath ()) {
33
+ '/plaintext ' => Response::plaintext ('Hello, World! ' ),
34
+ '/json ' => Response::json (['message ' => 'Hello, World! ' ]),
35
+ '/db ' => db ($ world ),
36
+ '/fortunes ' => fortune ($ fortune ),
37
+ '/query ' => query (queryCount ($ request ), $ world ),
38
+ '/update ' => updateraw (queryCount ($ request ), $ world , $ update ),
39
+ // '/info' => info(),
40
+ default => new Response (404 , [], 'Error 404 ' ),
41
+ };
42
+ };
49
43
}
50
44
51
- function db ()
52
- {
53
- global $ world ;
45
+ function establishDbConnection (
46
+ #[SensitiveParameter]
47
+ string $ uri ,
48
+ ): DbConnection {
49
+ $ connection = (new DbFactory ())->createLazyConnection ($ uri );
50
+
51
+ $ interrupt = $ connection ->quit (...);
54
52
55
- $ world ->execute ([mt_rand (1 , 10000 )]);
53
+ $ connection ->on ('close ' , static function () use (&$ interrupt ) {
54
+ Loop::removeSignal (SIGINT , $ interrupt );
55
+ Loop::removeSignal (SIGTERM , $ interrupt );
56
+ });
56
57
57
- return new Response (200 , [
58
- 'Content-Type ' => 'application/json '
59
- ], json_encode ($ world ->fetch ()));
58
+ Loop::addSignal (SIGINT , $ interrupt );
59
+ Loop::addSignal (SIGTERM , $ interrupt );
60
+
61
+ return $ connection ;
60
62
}
61
63
62
- function query ($ request )
64
+ /** @param Closure(int):PromiseInterface $world */
65
+ function db (Closure $ world ): PromiseInterface
63
66
{
64
- global $ world ;
67
+ $ id = mt_rand ( 1 , 10000 ) ;
65
68
66
- $ query_count = 1 ;
67
- $ q = (int ) $ request ->getQueryParams ()['q ' ];
68
- if ($ q > 1 ) {
69
- $ query_count = min ($ q , 500 );
70
- }
69
+ return $ world ($ id )->then (
70
+ static fn (QueryResult $ result ): ResponseInterface => Response::json ($ result ->resultRows [0 ]),
71
+ );
72
+ }
71
73
72
- while ($ query_count --) {
73
- $ world ->execute ([mt_rand (1 , 10000 )]);
74
- $ arr [] = $ world ->fetch ();
74
+ function queryCount (Request $ request ): int
75
+ {
76
+ $ count = (int ) ($ request ->getQueryParams ()['q ' ] ?? 1 );
77
+
78
+ if ($ count > 1 ) {
79
+ return min ($ count , 500 );
75
80
}
76
81
77
- return new Response (200 , [
78
- 'Content-Type ' => 'application/json '
79
- ], json_encode ($ arr ));
82
+ return 1 ;
80
83
}
81
84
82
- function updateraw ($ request )
85
+ /** @param Closure(int):PromiseInterface $world */
86
+ function query (int $ queryCount , Closure $ world ): PromiseInterface
83
87
{
84
- global $ world , $ update ;
88
+ $ processQueries = static function (int $ count ) use ($ world ): iterable {
89
+ while ($ count --) {
90
+ $ id = mt_rand (1 , 10000 );
85
91
86
- $ query_count = 1 ;
87
- $ q = (int ) $ request ->getQueryParams ()['q ' ];
88
- if ($ q > 1 ) {
89
- $ query_count = min ($ q , 500 );
90
- }
92
+ yield $ world ($ id )->then (static fn (QueryResult $ result ): array => $ result ->resultRows [0 ]);
93
+ }
94
+ };
91
95
92
- while ($ query_count --) {
93
- $ id = mt_rand (1 , 10000 );
94
- $ world ->execute ([$ id ]);
95
- $ item = $ world ->fetch ();
96
- $ update ->execute (
97
- [$ item ['randomNumber ' ] = mt_rand (1 , 10000 ), $ id ]
98
- );
96
+ return all ($ processQueries ($ queryCount ))
97
+ ->then (static fn (array $ result ): ResponseInterface => Response::json ($ result ));
98
+ }
99
99
100
- $ arr [] = $ item ;
101
- }
100
+ /**
101
+ * @param Closure(int):PromiseInterface $world
102
+ * @param Closure(int, int):PromiseInterface $update
103
+ */
104
+ function updateraw (int $ queryCount , Closure $ world , Closure $ update ): PromiseInterface
105
+ {
106
+ $ processQueries = static function (int $ count ) use ($ world , $ update ): iterable {
107
+ while ($ count --) {
108
+ $ id = mt_rand (1 , 10000 );
109
+
110
+ yield $ world ($ id )->then (
111
+ static function (QueryResult $ result ) use ($ update ): PromiseInterface {
112
+ $ updated = $ result ->resultRows [0 ];
113
+ $ updated ['randomNumber ' ] = mt_rand (1 , 10000 );
114
+
115
+ return $ update ($ updated ['id ' ], $ updated ['randomNumber ' ])
116
+ ->then (static fn (): array => $ updated );
117
+ }
118
+ );
119
+ }
120
+ };
102
121
103
- // $pdo->beginTransaction();
104
- // foreach($arr as $world) {
105
- // $update->execute([$world['randomNumber'], $world['id']]);
106
- // }
107
- // $pdo->commit();
108
- return new Response (200 , [
109
- 'Content-Type ' => 'application/json '
110
- ], json_encode ($ arr ));
122
+ return all ($ processQueries ($ queryCount ))
123
+ ->then (static fn (array $ result ): ResponseInterface => Response::json ($ result ));
111
124
}
112
125
113
- function fortune ()
126
+ function fortune (Closure $ fortune ): PromiseInterface
114
127
{
115
- global $ fortune ;
128
+ $ formatResult = static function (array $ rows ): string {
129
+ $ rows [] = ['id ' => 0 , 'message ' => 'Additional fortune added at request time. ' ];
130
+ usort ($ rows , static fn (array $ one , array $ other ) => $ one ['message ' ] <=> $ other ['message ' ]);
116
131
117
- $ fortune -> execute () ;
132
+ $ html = '' ;
118
133
119
- $ arr = $ fortune ->fetchAll ();
120
- $ arr [0 ] = 'Additional fortune added at request time. ' ;
121
- asort ($ arr );
134
+ foreach ($ rows as $ row ) {
135
+ $ message = htmlspecialchars ($ row ['message ' ], ENT_QUOTES , 'UTF-8 ' );
122
136
123
- $ html = '' ;
124
- foreach ( $ arr as $ id => $ message ) {
125
- $ message = htmlspecialchars ( $ message , ENT_QUOTES , ' UTF-8 ' );
126
- $ html .= " < tr><td> $ id</td><td> $ message</td ></tr> " ;
127
- }
137
+ $ html .= " <tr><td> $ {row[ ' id ' ]} </td><td> $ {message} </td></tr> " ;
138
+ }
139
+
140
+ return " <!DOCTYPE html><html><head><title>Fortunes</title></head><body><table>< tr><th> id</th><th> message</th ></tr> $ html </table></body></html > " ;
141
+ };
128
142
129
- return new Response (200 , [
130
- 'Content-Type ' => 'text/html; charset=UTF-8 ' ,
131
- ], "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr> $ html</table></body></html> "
143
+ return $ fortune ()->then (
144
+ static fn (QueryResult $ result ): ResponseInterface => Response::html ($ formatResult ($ result ->resultRows )),
132
145
);
133
146
}
134
147
@@ -138,4 +151,4 @@ function fortune()
138
151
phpinfo();
139
152
return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean());
140
153
}
141
- */
154
+ */
0 commit comments