Skip to content

Commit 200067d

Browse files
committed
Add lazy connection to connect in the background
1 parent 3879082 commit 200067d

File tree

9 files changed

+649
-50
lines changed

9 files changed

+649
-50
lines changed

README.md

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ It is written in pure PHP and does not require any extensions.
1515
* [Usage](#usage)
1616
* [Factory](#factory)
1717
* [createConnection()](#createconnection)
18+
* [createLazyConnection()](#createlazyconnection)
1819
* [ConnectionInterface](#connectioninterface)
1920
* [query()](#query)
2021
* [queryStream()](#querystream)
@@ -35,20 +36,20 @@ $loop = React\EventLoop\Factory::create();
3536
$factory = new Factory($loop);
3637

3738
$uri = 'test:test@localhost/test';
38-
$factory->createConnection($uri)->then(function (ConnectionInterface $connection) {
39-
$connection->query('SELECT * FROM book')->then(
40-
function (QueryResult $command) {
41-
print_r($command->resultFields);
42-
print_r($command->resultRows);
43-
echo count($command->resultRows) . ' row(s) in set' . PHP_EOL;
44-
},
45-
function (Exception $error) {
46-
echo 'Error: ' . $error->getMessage() . PHP_EOL;
47-
}
48-
);
49-
50-
$connection->quit();
51-
});
39+
$connection = $factory->createLazyConnection($uri);
40+
41+
$connection->query('SELECT * FROM book')->then(
42+
function (QueryResult $command) {
43+
print_r($command->resultFields);
44+
print_r($command->resultRows);
45+
echo count($command->resultRows) . ' row(s) in set' . PHP_EOL;
46+
},
47+
function (Exception $error) {
48+
echo 'Error: ' . $error->getMessage() . PHP_EOL;
49+
}
50+
);
51+
52+
$connection->quit();
5253

5354
$loop->run();
5455
```
@@ -154,6 +155,69 @@ authentication. You can explicitly pass a custom timeout value in seconds
154155
$factory->createConnection('localhost?timeout=0.5');
155156
```
156157

158+
#### createLazyConnection()
159+
160+
Creates a new connection.
161+
162+
It helps with establishing a TCP/IP connection to your MySQL database
163+
and issuing the initial authentication handshake.
164+
165+
```php
166+
$connection = $factory->createLazyConnection($url);
167+
168+
$connection->query(…);
169+
```
170+
171+
This method immediately returns a "virtual" connection implementing the
172+
[`ConnectionInterface`](#connectioninterface) that can be used to
173+
interface with your MySQL database. Internally, it lazily creates the
174+
underlying database connection (which may take some time) and will
175+
queue all outstanding requests until the underlying connection is ready.
176+
177+
From a consumer side this means that you can start sending queries to the
178+
database right away while the connection may still be pending. It will
179+
ensure that all commands will be executed in the order they are enqueued
180+
once the connection is ready. If the database connection fails, it will
181+
emit an `error` event, reject all outstanding commands and `close` the
182+
connection as described in the `ConnectionInterface`. In other words, it
183+
behaves just like a real connection and frees you from having to deal
184+
with its async resolution.
185+
186+
Depending on your particular use case, you may prefer this method or the
187+
underlying `createConnection()` which resolves with a promise. For many
188+
simple use cases it may be easier to create a lazy connection.
189+
190+
The `$url` parameter must contain the database host, optional
191+
authentication, port and database to connect to:
192+
193+
```php
194+
$factory->createLazyConnection('user:secret@localhost:3306/database');
195+
```
196+
197+
You can omit the port if you're connecting to default port `3306`:
198+
199+
```php
200+
$factory->createLazyConnection('user:secret@localhost/database');
201+
```
202+
203+
If you do not include authentication and/or database, then this method
204+
will default to trying to connect as user `root` with an empty password
205+
and no database selected. This may be useful when initially setting up a
206+
database, but likely to yield an authentication error in a production system:
207+
208+
```php
209+
$factory->createLazyConnection('localhost');
210+
```
211+
212+
This method respects PHP's `default_socket_timeout` setting (default 60s)
213+
as a timeout for establishing the connection and waiting for successful
214+
authentication. You can explicitly pass a custom timeout value in seconds
215+
(or use a negative number to not apply a timeout) like this:
216+
217+
```php
218+
$factory->createLazyConnection('localhost?timeout=0.5');
219+
```
220+
157221
### ConnectionInterface
158222

159223
The `ConnectionInterface` represents a connection that is responsible for

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"evenement/evenement": "^3.0 || ^2.1 || ^1.1",
99
"react/event-loop": "^1.0 || ^0.5 || ^0.4",
1010
"react/promise": "^2.7",
11+
"react/promise-stream": "^1.1",
1112
"react/promise-timer": "^1.5",
1213
"react/socket": "^1.1"
1314
},

examples/01-query.php

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php
22

3-
use React\MySQL\ConnectionInterface;
43
use React\MySQL\Factory;
54
use React\MySQL\QueryResult;
65

@@ -12,27 +11,27 @@
1211
$uri = 'test:test@localhost/test';
1312
$query = isset($argv[1]) ? $argv[1] : 'select * from book';
1413

15-
//create a mysql connection for executing query
16-
$factory->createConnection($uri)->then(function (ConnectionInterface $connection) use ($query) {
17-
$connection->query($query)->then(function (QueryResult $command) {
18-
if (isset($command->resultRows)) {
19-
// this is a response to a SELECT etc. with some rows (0+)
20-
print_r($command->resultFields);
21-
print_r($command->resultRows);
22-
echo count($command->resultRows) . ' row(s) in set' . PHP_EOL;
23-
} else {
24-
// this is an OK message in response to an UPDATE etc.
25-
if ($command->insertId !== 0) {
26-
var_dump('last insert ID', $command->insertId);
27-
}
28-
echo 'Query OK, ' . $command->affectedRows . ' row(s) affected' . PHP_EOL;
14+
//create a lazy mysql connection for executing query
15+
$connection = $factory->createLazyConnection($uri);
16+
17+
$connection->query($query)->then(function (QueryResult $command) {
18+
if (isset($command->resultRows)) {
19+
// this is a response to a SELECT etc. with some rows (0+)
20+
print_r($command->resultFields);
21+
print_r($command->resultRows);
22+
echo count($command->resultRows) . ' row(s) in set' . PHP_EOL;
23+
} else {
24+
// this is an OK message in response to an UPDATE etc.
25+
if ($command->insertId !== 0) {
26+
var_dump('last insert ID', $command->insertId);
2927
}
30-
}, function (Exception $error) {
31-
// the query was not executed successfully
32-
echo 'Error: ' . $error->getMessage() . PHP_EOL;
33-
});
28+
echo 'Query OK, ' . $command->affectedRows . ' row(s) affected' . PHP_EOL;
29+
}
30+
}, function (Exception $error) {
31+
// the query was not executed successfully
32+
echo 'Error: ' . $error->getMessage() . PHP_EOL;
33+
});
3434

35-
$connection->quit();
36-
}, 'printf');
35+
$connection->quit();
3736

3837
$loop->run();

examples/02-query-stream.php

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
// $ php examples/02-query-stream.php "SHOW VARIABLES"
44

5-
use React\MySQL\ConnectionInterface;
65
use React\MySQL\Factory;
76

87
require __DIR__ . '/../vendor/autoload.php';
@@ -13,23 +12,23 @@
1312
$uri = 'test:test@localhost/test';
1413
$query = isset($argv[1]) ? $argv[1] : 'select * from book';
1514

16-
//create a mysql connection for executing query
17-
$factory->createConnection($uri)->then(function (ConnectionInterface $connection) use ($query) {
18-
$stream = $connection->queryStream($query);
15+
//create a lazy mysql connection for executing query
16+
$connection = $factory->createLazyConnection($uri);
1917

20-
$stream->on('data', function ($row) {
21-
echo json_encode($row, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
22-
});
18+
$stream = $connection->queryStream($query);
2319

24-
$stream->on('error', function (Exception $e) {
25-
echo 'Error: ' . $e->getMessage() . PHP_EOL;
26-
});
20+
$stream->on('data', function ($row) {
21+
echo json_encode($row, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
22+
});
2723

28-
$stream->on('close', function () {
29-
echo 'CLOSED' . PHP_EOL;
30-
});
24+
$stream->on('error', function (Exception $e) {
25+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
26+
});
3127

32-
$connection->quit();
33-
}, 'printf');
28+
$stream->on('close', function () {
29+
echo 'CLOSED' . PHP_EOL;
30+
});
31+
32+
$connection->quit();
3433

3534
$loop->run();

src/Factory.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use React\Socket\Connector;
1414
use React\Socket\ConnectorInterface;
1515
use React\Socket\ConnectionInterface;
16+
use React\MySQL\Io\LazyConnection;
1617

1718
class Factory
1819
{
@@ -194,4 +195,74 @@ public function createConnection($uri)
194195
throw $e;
195196
});
196197
}
198+
199+
/**
200+
* Creates a new connection.
201+
*
202+
* It helps with establishing a TCP/IP connection to your MySQL database
203+
* and issuing the initial authentication handshake.
204+
*
205+
* ```php
206+
* $connection = $factory->createLazyConnection($url);
207+
*
208+
* $connection->query(…);
209+
* ```
210+
*
211+
* This method immediately returns a "virtual" connection implementing the
212+
* [`ConnectionInterface`](#connectioninterface) that can be used to
213+
* interface with your MySQL database. Internally, it lazily creates the
214+
* underlying database connection (which may take some time) and will
215+
* queue all outstanding requests until the underlying connection is ready.
216+
*
217+
* From a consumer side this means that you can start sending queries to the
218+
* database right away while the connection may still be pending. It will
219+
* ensure that all commands will be executed in the order they are enqueued
220+
* once the connection is ready. If the database connection fails, it will
221+
* emit an `error` event, reject all outstanding commands and `close` the
222+
* connection as described in the `ConnectionInterface`. In other words, it
223+
* behaves just like a real connection and frees you from having to deal
224+
* with its async resolution.
225+
*
226+
* Depending on your particular use case, you may prefer this method or the
227+
* underlying `createConnection()` which resolves with a promise. For many
228+
* simple use cases it may be easier to create a lazy connection.
229+
*
230+
* The `$url` parameter must contain the database host, optional
231+
* authentication, port and database to connect to:
232+
*
233+
* ```php
234+
* $factory->createLazyConnection('user:secret@localhost:3306/database');
235+
* ```
236+
*
237+
* You can omit the port if you're connecting to default port `3306`:
238+
*
239+
* ```php
240+
* $factory->createLazyConnection('user:secret@localhost/database');
241+
* ```
242+
*
243+
* If you do not include authentication and/or database, then this method
244+
* will default to trying to connect as user `root` with an empty password
245+
* and no database selected. This may be useful when initially setting up a
246+
* database, but likely to yield an authentication error in a production system:
247+
*
248+
* ```php
249+
* $factory->createLazyConnection('localhost');
250+
* ```
251+
*
252+
* This method respects PHP's `default_socket_timeout` setting (default 60s)
253+
* as a timeout for establishing the connection and waiting for successful
254+
* authentication. You can explicitly pass a custom timeout value in seconds
255+
* (or use a negative number to not apply a timeout) like this:
256+
*
257+
* ```php
258+
* $factory->createLazyConnection('localhost?timeout=0.5');
259+
* ```
260+
*
261+
* @param string $uri
262+
* @return ConnectionInterface
263+
*/
264+
public function createLazyConnection($uri)
265+
{
266+
return new LazyConnection($this->createConnection($uri));
267+
}
197268
}

0 commit comments

Comments
 (0)