Skip to content

Commit b523eca

Browse files
committed
Merge branch '10.x' into 11.x
# Conflicts: # CHANGELOG.md # src/Illuminate/Foundation/Application.php
2 parents 85eb158 + e052cb8 commit b523eca

File tree

4 files changed

+166
-54
lines changed

4 files changed

+166
-54
lines changed

src/Illuminate/Database/Connectors/PostgresConnector.php

+11-39
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,13 @@ public function connect(array $config)
3838

3939
$this->configureIsolationLevel($connection, $config);
4040

41-
$this->configureEncoding($connection, $config);
42-
4341
// Next, we will check to see if a timezone has been specified in this config
4442
// and if it has we will issue a statement to modify the timezone with the
4543
// database. Setting this DB timezone is an optional configuration item.
4644
$this->configureTimezone($connection, $config);
4745

4846
$this->configureSearchPath($connection, $config);
4947

50-
// Postgres allows an application_name to be set by the user and this name is
51-
// used to when monitoring the application with pg_stat_activity. So we'll
52-
// determine if the option has been specified and run a statement if so.
53-
$this->configureApplicationName($connection, $config);
54-
5548
$this->configureSynchronousCommit($connection, $config);
5649

5750
return $connection;
@@ -71,22 +64,6 @@ protected function configureIsolationLevel($connection, array $config)
7164
}
7265
}
7366

74-
/**
75-
* Set the connection character set and collation.
76-
*
77-
* @param \PDO $connection
78-
* @param array $config
79-
* @return void
80-
*/
81-
protected function configureEncoding($connection, $config)
82-
{
83-
if (! isset($config['charset'])) {
84-
return;
85-
}
86-
87-
$connection->prepare("set names '{$config['charset']}'")->execute();
88-
}
89-
9067
/**
9168
* Set the timezone on the connection.
9269
*
@@ -132,22 +109,6 @@ protected function quoteSearchPath($searchPath)
132109
return count($searchPath) === 1 ? '"'.$searchPath[0].'"' : '"'.implode('", "', $searchPath).'"';
133110
}
134111

135-
/**
136-
* Set the application name on the connection.
137-
*
138-
* @param \PDO $connection
139-
* @param array $config
140-
* @return void
141-
*/
142-
protected function configureApplicationName($connection, $config)
143-
{
144-
if (isset($config['application_name'])) {
145-
$applicationName = $config['application_name'];
146-
147-
$connection->prepare("set application_name to '$applicationName'")->execute();
148-
}
149-
}
150-
151112
/**
152113
* Create a DSN string from a configuration.
153114
*
@@ -178,6 +139,17 @@ protected function getDsn(array $config)
178139
$dsn .= ";port={$port}";
179140
}
180141

142+
if (isset($charset)) {
143+
$dsn .= ";client_encoding='{$charset}'";
144+
}
145+
146+
// Postgres allows an application_name to be set by the user and this name is
147+
// used to when monitoring the application with pg_stat_activity. So we'll
148+
// determine if the option has been specified and run a statement if so.
149+
if (isset($application_name)) {
150+
$dsn .= ";application_name='".str_replace("'", "\'", $application_name)."'";
151+
}
152+
181153
return $this->addSslOptions($dsn, $config);
182154
}
183155

src/Illuminate/Http/Client/PendingRequest.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -924,11 +924,15 @@ public function send(string $method, string $url, array $options = [])
924924
$response->throw($this->throwCallback);
925925
}
926926

927-
if ($attempt < $this->tries && $shouldRetry) {
927+
$potentialTries = is_array($this->tries)
928+
? count($this->tries) + 1
929+
: $this->tries;
930+
931+
if ($attempt < $potentialTries && $shouldRetry) {
928932
$response->throw();
929933
}
930934

931-
if ($this->tries > 1 && $this->retryThrow) {
935+
if ($potentialTries > 1 && $this->retryThrow) {
932936
$response->throw();
933937
}
934938
}

tests/Database/DatabaseConnectorTest.php

+10-13
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@ public function testMySqlConnectCallsCreateConnectionWithIsolationLevel()
7171

7272
public function testPostgresConnectCallsCreateConnectionWithProperArguments()
7373
{
74-
$dsn = 'pgsql:host=foo;dbname=\'bar\';port=111';
74+
$dsn = 'pgsql:host=foo;dbname=\'bar\';port=111;client_encoding=\'utf8\'';
7575
$config = ['host' => 'foo', 'database' => 'bar', 'port' => 111, 'charset' => 'utf8'];
7676
$connector = $this->getMockBuilder(PostgresConnector::class)->onlyMethods(['createConnection', 'getOptions'])->getMock();
7777
$connection = m::mock(stdClass::class);
7878
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']);
7979
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection);
8080
$statement = m::mock(PDOStatement::class);
81-
$connection->shouldReceive('prepare')->once()->with('set names \'utf8\'')->andReturn($statement);
82-
$statement->shouldReceive('execute')->once();
81+
$connection->shouldReceive('prepare')->zeroOrMoreTimes()->andReturn($statement);
82+
$statement->shouldReceive('execute')->zeroOrMoreTimes();
8383
$result = $connector->connect($config);
8484

8585
$this->assertSame($result, $connection);
@@ -92,16 +92,15 @@ public function testPostgresConnectCallsCreateConnectionWithProperArguments()
9292
#[DataProvider('provideSearchPaths')]
9393
public function testPostgresSearchPathIsSet($searchPath, $expectedSql)
9494
{
95-
$dsn = 'pgsql:host=foo;dbname=\'bar\'';
95+
$dsn = 'pgsql:host=foo;dbname=\'bar\';client_encoding=\'utf8\'';
9696
$config = ['host' => 'foo', 'database' => 'bar', 'search_path' => $searchPath, 'charset' => 'utf8'];
9797
$connector = $this->getMockBuilder(PostgresConnector::class)->onlyMethods(['createConnection', 'getOptions'])->getMock();
9898
$connection = m::mock(stdClass::class);
9999
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']);
100100
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection);
101101
$statement = m::mock(PDOStatement::class);
102-
$connection->shouldReceive('prepare')->once()->with('set names \'utf8\'')->andReturn($statement);
103102
$connection->shouldReceive('prepare')->once()->with($expectedSql)->andReturn($statement);
104-
$statement->shouldReceive('execute')->twice();
103+
$statement->shouldReceive('execute')->once();
105104
$result = $connector->connect($config);
106105

107106
$this->assertSame($result, $connection);
@@ -179,33 +178,31 @@ public static function provideSearchPaths()
179178

180179
public function testPostgresSearchPathFallbackToConfigKeySchema()
181180
{
182-
$dsn = 'pgsql:host=foo;dbname=\'bar\'';
181+
$dsn = 'pgsql:host=foo;dbname=\'bar\';client_encoding=\'utf8\'';
183182
$config = ['host' => 'foo', 'database' => 'bar', 'schema' => ['public', '"user"'], 'charset' => 'utf8'];
184183
$connector = $this->getMockBuilder(PostgresConnector::class)->onlyMethods(['createConnection', 'getOptions'])->getMock();
185184
$connection = m::mock(stdClass::class);
186185
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']);
187186
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection);
188187
$statement = m::mock(PDOStatement::class);
189-
$connection->shouldReceive('prepare')->once()->with('set names \'utf8\'')->andReturn($statement);
190188
$connection->shouldReceive('prepare')->once()->with('set search_path to "public", "user"')->andReturn($statement);
191-
$statement->shouldReceive('execute')->twice();
189+
$statement->shouldReceive('execute')->once();
192190
$result = $connector->connect($config);
193191

194192
$this->assertSame($result, $connection);
195193
}
196194

197195
public function testPostgresApplicationNameIsSet()
198196
{
199-
$dsn = 'pgsql:host=foo;dbname=\'bar\'';
197+
$dsn = 'pgsql:host=foo;dbname=\'bar\';client_encoding=\'utf8\';application_name=\'Laravel App\'';
200198
$config = ['host' => 'foo', 'database' => 'bar', 'charset' => 'utf8', 'application_name' => 'Laravel App'];
201199
$connector = $this->getMockBuilder(PostgresConnector::class)->onlyMethods(['createConnection', 'getOptions'])->getMock();
202200
$connection = m::mock(stdClass::class);
203201
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']);
204202
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection);
205203
$statement = m::mock(PDOStatement::class);
206-
$connection->shouldReceive('prepare')->once()->with('set names \'utf8\'')->andReturn($statement);
207-
$connection->shouldReceive('prepare')->once()->with('set application_name to \'Laravel App\'')->andReturn($statement);
208-
$statement->shouldReceive('execute')->twice();
204+
$connection->shouldReceive('prepare')->zeroOrMoreTimes()->andReturn($statement);
205+
$statement->shouldReceive('execute')->zeroOrMoreTimes();
209206
$result = $connector->connect($config);
210207

211208
$this->assertSame($result, $connection);

tests/Http/HttpClientTest.php

+139
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,28 @@ public function testRequestExceptionIsThrownWhenRetriesExhausted()
17251725
$this->factory->assertSentCount(2);
17261726
}
17271727

1728+
public function testRequestExceptionIsThrownWhenRetriesExhaustedWithBackoffArray()
1729+
{
1730+
$this->factory->fake([
1731+
'*' => $this->factory->response(['error'], 403),
1732+
]);
1733+
1734+
$exception = null;
1735+
1736+
try {
1737+
$this->factory
1738+
->retry([1], 0, null, true)
1739+
->get('http://foo.com/get');
1740+
} catch (RequestException $e) {
1741+
$exception = $e;
1742+
}
1743+
1744+
$this->assertNotNull($exception);
1745+
$this->assertInstanceOf(RequestException::class, $exception);
1746+
1747+
$this->factory->assertSentCount(2);
1748+
}
1749+
17281750
public function testRequestExceptionIsThrownWithoutRetriesIfRetryNotNecessary()
17291751
{
17301752
$this->factory->fake([
@@ -1754,6 +1776,35 @@ public function testRequestExceptionIsThrownWithoutRetriesIfRetryNotNecessary()
17541776
$this->factory->assertSentCount(1);
17551777
}
17561778

1779+
public function testRequestExceptionIsThrownWithoutRetriesIfRetryNotNecessaryWithBackoffArray()
1780+
{
1781+
$this->factory->fake([
1782+
'*' => $this->factory->response(['error'], 500),
1783+
]);
1784+
1785+
$exception = null;
1786+
$whenAttempts = 0;
1787+
1788+
try {
1789+
$this->factory
1790+
->retry([1000, 1000], 1000, function ($exception) use (&$whenAttempts) {
1791+
$whenAttempts++;
1792+
1793+
return $exception->response->status() === 403;
1794+
}, true)
1795+
->get('http://foo.com/get');
1796+
} catch (RequestException $e) {
1797+
$exception = $e;
1798+
}
1799+
1800+
$this->assertNotNull($exception);
1801+
$this->assertInstanceOf(RequestException::class, $exception);
1802+
1803+
$this->assertSame(1, $whenAttempts);
1804+
1805+
$this->factory->assertSentCount(1);
1806+
}
1807+
17571808
public function testRequestExceptionIsNotThrownWhenDisabledAndRetriesExhausted()
17581809
{
17591810
$this->factory->fake([
@@ -1769,6 +1820,21 @@ public function testRequestExceptionIsNotThrownWhenDisabledAndRetriesExhausted()
17691820
$this->factory->assertSentCount(2);
17701821
}
17711822

1823+
public function testRequestExceptionIsNotThrownWhenDisabledAndRetriesExhaustedWithBackoffArray()
1824+
{
1825+
$this->factory->fake([
1826+
'*' => $this->factory->response(['error'], 403),
1827+
]);
1828+
1829+
$response = $this->factory
1830+
->retry([1, 2], throw: false)
1831+
->get('http://foo.com/get');
1832+
1833+
$this->assertTrue($response->failed());
1834+
1835+
$this->factory->assertSentCount(3);
1836+
}
1837+
17721838
public function testRequestExceptionIsNotThrownWithoutRetriesIfRetryNotNecessary()
17731839
{
17741840
$this->factory->fake([
@@ -1792,6 +1858,29 @@ public function testRequestExceptionIsNotThrownWithoutRetriesIfRetryNotNecessary
17921858
$this->factory->assertSentCount(1);
17931859
}
17941860

1861+
public function testRequestExceptionIsNotThrownWithoutRetriesIfRetryNotNecessaryWithBackoffArray()
1862+
{
1863+
$this->factory->fake([
1864+
'*' => $this->factory->response(['error'], 500),
1865+
]);
1866+
1867+
$whenAttempts = 0;
1868+
1869+
$response = $this->factory
1870+
->retry([1, 2], 0, function ($exception) use (&$whenAttempts) {
1871+
$whenAttempts++;
1872+
1873+
return $exception->response->status() === 403;
1874+
}, false)
1875+
->get('http://foo.com/get');
1876+
1877+
$this->assertTrue($response->failed());
1878+
1879+
$this->assertSame(1, $whenAttempts);
1880+
1881+
$this->factory->assertSentCount(1);
1882+
}
1883+
17951884
public function testRequestCanBeModifiedInRetryCallback()
17961885
{
17971886
$this->factory->fake([
@@ -1817,6 +1906,31 @@ public function testRequestCanBeModifiedInRetryCallback()
18171906
});
18181907
}
18191908

1909+
public function testRequestCanBeModifiedInRetryCallbackWithBackoffArray()
1910+
{
1911+
$this->factory->fake([
1912+
'*' => $this->factory->sequence()
1913+
->push(['error'], 500)
1914+
->push(['ok'], 200),
1915+
]);
1916+
1917+
$response = $this->factory
1918+
->retry([2], when: function ($exception, $request) {
1919+
$this->assertInstanceOf(PendingRequest::class, $request);
1920+
1921+
$request->withHeaders(['Foo' => 'Bar']);
1922+
1923+
return true;
1924+
}, throw: false)
1925+
->get('http://foo.com/get');
1926+
1927+
$this->assertTrue($response->successful());
1928+
1929+
$this->factory->assertSent(function (Request $request) {
1930+
return $request->hasHeader('Foo') && $request->header('Foo') === ['Bar'];
1931+
});
1932+
}
1933+
18201934
public function testExceptionThrownInRetryCallbackWithoutRetrying()
18211935
{
18221936
$this->factory->fake([
@@ -1842,6 +1956,31 @@ public function testExceptionThrownInRetryCallbackWithoutRetrying()
18421956
$this->factory->assertSentCount(1);
18431957
}
18441958

1959+
public function testExceptionThrownInRetryCallbackWithoutRetryingWithBackoffArray()
1960+
{
1961+
$this->factory->fake([
1962+
'*' => $this->factory->response(['error'], 500),
1963+
]);
1964+
1965+
$exception = null;
1966+
1967+
try {
1968+
$this->factory
1969+
->retry([1, 2, 3], when: function ($exception) use (&$whenAttempts) {
1970+
throw new Exception('Foo bar');
1971+
}, throw: false)
1972+
->get('http://foo.com/get');
1973+
} catch (Exception $e) {
1974+
$exception = $e;
1975+
}
1976+
1977+
$this->assertNotNull($exception);
1978+
$this->assertInstanceOf(Exception::class, $exception);
1979+
$this->assertEquals('Foo bar', $exception->getMessage());
1980+
1981+
$this->factory->assertSentCount(1);
1982+
}
1983+
18451984
public function testRequestsWillBeWaitingSleepMillisecondsReceivedBeforeRetry()
18461985
{
18471986
Sleep::fake();

0 commit comments

Comments
 (0)