Skip to content

Commit d0b0c0b

Browse files
authored
Merge pull request #87 from clue-labs/lazy-connection
Add new createLazyConnection() method to only connect only on demand (on first command)
2 parents f235ab8 + 83ac29b commit d0b0c0b

File tree

9 files changed

+782
-50
lines changed

9 files changed

+782
-50
lines changed

README.md

Lines changed: 85 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,76 @@ 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) only once the
175+
first request is invoked on this instance and will queue all outstanding
176+
requests until the underlying connection is ready.
177+
178+
From a consumer side this means that you can start sending queries to the
179+
database right away while the actual connection may still be outstanding.
180+
It will ensure that all commands will be executed in the order they are
181+
enqueued once the connection is ready. If the database connection fails,
182+
it will emit an `error` event, reject all outstanding commands and `close`
183+
the connection as described in the `ConnectionInterface`. In other words,
184+
it behaves just like a real connection and frees you from having to deal
185+
with its async resolution.
186+
187+
Note that creating the underlying connection will be deferred until the
188+
first request is invoked. Accordingly, any eventual connection issues
189+
will be detected once this instance is first used. Similarly, calling
190+
`quit()` on this instance before invoking any requests will succeed
191+
immediately and will not wait for an actual underlying connection.
192+
193+
Depending on your particular use case, you may prefer this method or the
194+
underlying `createConnection()` which resolves with a promise. For many
195+
simple use cases it may be easier to create a lazy connection.
196+
197+
The `$url` parameter must contain the database host, optional
198+
authentication, port and database to connect to:
199+
200+
```php
201+
$factory->createLazyConnection('user:secret@localhost:3306/database');
202+
```
203+
204+
You can omit the port if you're connecting to default port `3306`:
205+
206+
```php
207+
$factory->createLazyConnection('user:secret@localhost/database');
208+
```
209+
210+
If you do not include authentication and/or database, then this method
211+
will default to trying to connect as user `root` with an empty password
212+
and no database selected. This may be useful when initially setting up a
213+
database, but likely to yield an authentication error in a production system:
214+
215+
```php
216+
$factory->createLazyConnection('localhost');
217+
```
218+
219+
This method respects PHP's `default_socket_timeout` setting (default 60s)
220+
as a timeout for establishing the underlying connection and waiting for
221+
successful authentication. You can explicitly pass a custom timeout value
222+
in seconds (or use a negative number to not apply a timeout) like this:
223+
224+
```php
225+
$factory->createLazyConnection('localhost?timeout=0.5');
226+
```
227+
157228
### ConnectionInterface
158229

159230
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: 78 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,81 @@ 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) only once the
215+
* first request is invoked on this instance and will queue all outstanding
216+
* requests until the underlying connection is ready.
217+
*
218+
* From a consumer side this means that you can start sending queries to the
219+
* database right away while the actual connection may still be outstanding.
220+
* It will ensure that all commands will be executed in the order they are
221+
* enqueued once the connection is ready. If the database connection fails,
222+
* it will emit an `error` event, reject all outstanding commands and `close`
223+
* the connection as described in the `ConnectionInterface`. In other words,
224+
* it behaves just like a real connection and frees you from having to deal
225+
* with its async resolution.
226+
*
227+
* Note that creating the underlying connection will be deferred until the
228+
* first request is invoked. Accordingly, any eventual connection issues
229+
* will be detected once this instance is first used. Similarly, calling
230+
* `quit()` on this instance before invoking any requests will succeed
231+
* immediately and will not wait for an actual underlying connection.
232+
*
233+
* Depending on your particular use case, you may prefer this method or the
234+
* underlying `createConnection()` which resolves with a promise. For many
235+
* simple use cases it may be easier to create a lazy connection.
236+
*
237+
* The `$url` parameter must contain the database host, optional
238+
* authentication, port and database to connect to:
239+
*
240+
* ```php
241+
* $factory->createLazyConnection('user:secret@localhost:3306/database');
242+
* ```
243+
*
244+
* You can omit the port if you're connecting to default port `3306`:
245+
*
246+
* ```php
247+
* $factory->createLazyConnection('user:secret@localhost/database');
248+
* ```
249+
*
250+
* If you do not include authentication and/or database, then this method
251+
* will default to trying to connect as user `root` with an empty password
252+
* and no database selected. This may be useful when initially setting up a
253+
* database, but likely to yield an authentication error in a production system:
254+
*
255+
* ```php
256+
* $factory->createLazyConnection('localhost');
257+
* ```
258+
*
259+
* This method respects PHP's `default_socket_timeout` setting (default 60s)
260+
* as a timeout for establishing the underlying connection and waiting for
261+
* successful authentication. You can explicitly pass a custom timeout value
262+
* in seconds (or use a negative number to not apply a timeout) like this:
263+
*
264+
* ```php
265+
* $factory->createLazyConnection('localhost?timeout=0.5');
266+
* ```
267+
*
268+
* @param string $uri
269+
* @return ConnectionInterface
270+
*/
271+
public function createLazyConnection($uri)
272+
{
273+
return new LazyConnection($this, $uri);
274+
}
197275
}

0 commit comments

Comments
 (0)