diff --git a/src/Illuminate/Database/DetectsLostConnections.php b/src/Illuminate/Database/DetectsLostConnections.php
index 191eefedc891..93be53b2fdc9 100644
--- a/src/Illuminate/Database/DetectsLostConnections.php
+++ b/src/Illuminate/Database/DetectsLostConnections.php
@@ -52,6 +52,8 @@ protected function causedByLostConnection(Throwable $e)
'Temporary failure in name resolution',
'SSL: Broken pipe',
'SQLSTATE[08S01]: Communication link failure',
+ 'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',
+ 'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',
]);
}
}
diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php
index ca84d06cdbc1..a8f2fb87842c 100755
--- a/src/Illuminate/Database/Eloquent/Builder.php
+++ b/src/Illuminate/Database/Eloquent/Builder.php
@@ -1608,6 +1608,16 @@ protected static function registerMixin($mixin, $replace)
}
}
+ /**
+ * Clone the Eloquent query builder.
+ *
+ * @return static
+ */
+ public function clone()
+ {
+ return clone $this;
+ }
+
/**
* Force a clone of the underlying query builder when cloning.
*
diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
index 459b14c73399..7d660905e393 100644
--- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
+++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
@@ -1322,6 +1322,16 @@ public function getAttributes()
return $this->attributes;
}
+ /**
+ * Get all of the current attributes on the model for an insert operation.
+ *
+ * @return array
+ */
+ protected function getAttributesForInsert()
+ {
+ return $this->getAttributes();
+ }
+
/**
* Set the array of model attributes. No checking is done.
*
diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php
index 62fcd058e258..512d59eae10e 100644
--- a/src/Illuminate/Database/Eloquent/Model.php
+++ b/src/Illuminate/Database/Eloquent/Model.php
@@ -3,7 +3,6 @@
namespace Illuminate\Database\Eloquent;
use ArrayAccess;
-use Exception;
use Illuminate\Contracts\Queue\QueueableCollection;
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Contracts\Routing\UrlRoutable;
@@ -20,6 +19,7 @@
use Illuminate\Support\Str;
use Illuminate\Support\Traits\ForwardsCalls;
use JsonSerializable;
+use LogicException;
abstract class Model implements Arrayable, ArrayAccess, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
{
@@ -1011,7 +1011,7 @@ protected function performInsert(Builder $query)
// If the model has an incrementing key, we can use the "insertGetId" method on
// the query builder, which will give us back the final inserted ID for this
// table from the database. Not all tables have to be incrementing though.
- $attributes = $this->getAttributes();
+ $attributes = $this->getAttributesForInsert();
if ($this->getIncrementing()) {
$this->insertAndSetId($query, $attributes);
@@ -1097,14 +1097,14 @@ public static function destroy($ids)
*
* @return bool|null
*
- * @throws \Exception
+ * @throws \LogicException
*/
public function delete()
{
$this->mergeAttributesFromClassCasts();
if (is_null($this->getKeyName())) {
- throw new Exception('No primary key defined on model.');
+ throw new LogicException('No primary key defined on model.');
}
// If the model doesn't exist, there is nothing to delete so we'll just return
diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php
index 093e41e78a43..35b4bb92e92a 100755
--- a/src/Illuminate/Database/Migrations/Migrator.php
+++ b/src/Illuminate/Database/Migrations/Migrator.php
@@ -13,6 +13,7 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
+use ReflectionClass;
use Symfony\Component\Console\Output\OutputInterface;
class Migrator
@@ -185,9 +186,9 @@ protected function runUp($file, $batch, $pretend)
// First we will resolve a "real" instance of the migration class from this
// migration file name. Once we have the instances we can run the actual
// command such as "up" or "down", or we can just simulate the action.
- $migration = $this->resolve(
- $name = $this->getMigrationName($file)
- );
+ $migration = $this->resolvePath($file);
+
+ $name = $this->getMigrationName($file);
if ($pretend) {
return $this->pretendToRun($migration, 'up');
@@ -348,9 +349,9 @@ protected function runDown($file, $migration, $pretend)
// First we will get the file name of the migration so we can resolve out an
// instance of the migration. Once we get an instance we can either run a
// pretend execution of the migration or we can run the real migration.
- $instance = $this->resolve(
- $name = $this->getMigrationName($file)
- );
+ $instance = $this->resolvePath($file);
+
+ $name = $this->getMigrationName($file);
$this->note("Rolling back: {$name}");
@@ -413,6 +414,12 @@ protected function pretendToRun($migration, $method)
foreach ($this->getQueries($migration, $method) as $query) {
$name = get_class($migration);
+ $reflectionClass = new ReflectionClass($migration);
+
+ if ($reflectionClass->isAnonymous()) {
+ $name = $this->getMigrationName($reflectionClass->getFileName());
+ }
+
$this->note("{$name}: {$query['query']}");
}
}
@@ -448,11 +455,39 @@ protected function getQueries($migration, $method)
*/
public function resolve($file)
{
- $class = Str::studly(implode('_', array_slice(explode('_', $file), 4)));
+ $class = $this->getMigrationClass($file);
return new $class;
}
+ /**
+ * Resolve a migration instance from a migration path.
+ *
+ * @param string $path
+ * @return object
+ */
+ protected function resolvePath(string $path)
+ {
+ $class = $this->getMigrationClass($this->getMigrationName($path));
+
+ if (class_exists($class)) {
+ return new $class;
+ }
+
+ return $this->files->getRequire($path);
+ }
+
+ /**
+ * Generate a migration class name based on the migration file name.
+ *
+ * @param string $migrationName
+ * @return string
+ */
+ protected function getMigrationClass(string $migrationName): string
+ {
+ return Str::studly(implode('_', array_slice(explode('_', $migrationName), 4)));
+ }
+
/**
* Get all of the migration files in a given path.
*
diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php
index 710d0a3a568c..befc8a8cfa33 100755
--- a/src/Illuminate/Database/Query/Builder.php
+++ b/src/Illuminate/Database/Query/Builder.php
@@ -244,7 +244,7 @@ public function select($columns = ['*'])
/**
* Add a subselect expression to the query.
*
- * @param \Closure|\Illuminate\Database\Query\Builder|string $query
+ * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|string $query
* @param string $as
* @return $this
*
diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php
index 622659995410..e2b968ab6bd4 100755
--- a/src/Illuminate/Database/Schema/Blueprint.php
+++ b/src/Illuminate/Database/Schema/Blueprint.php
@@ -677,6 +677,17 @@ public function string($column, $length = null)
return $this->addColumn('string', $column, compact('length'));
}
+ /**
+ * Create a new tiny text column on the table.
+ *
+ * @param string $column
+ * @return \Illuminate\Database\Schema\ColumnDefinition
+ */
+ public function tinyText($column)
+ {
+ return $this->addColumn('tinyText', $column);
+ }
+
/**
* Create a new text column on the table.
*
diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php
index dd53b9fe9bed..37df3337b040 100755
--- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php
+++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php
@@ -490,6 +490,17 @@ protected function typeString(Fluent $column)
return "varchar({$column->length})";
}
+ /**
+ * Create the column definition for a tiny text type.
+ *
+ * @param \Illuminate\Support\Fluent $column
+ * @return string
+ */
+ protected function typeTinyText(Fluent $column)
+ {
+ return 'tinytext';
+ }
+
/**
* Create the column definition for a text type.
*
diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php
index adaf21f90e4c..fb7005b09df3 100755
--- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php
+++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php
@@ -472,6 +472,17 @@ protected function typeString(Fluent $column)
return "varchar({$column->length})";
}
+ /**
+ * Create the column definition for a tiny text type.
+ *
+ * @param \Illuminate\Support\Fluent $column
+ * @return string
+ */
+ protected function typeTinyText(Fluent $column)
+ {
+ return 'varchar(255)';
+ }
+
/**
* Create the column definition for a text type.
*
diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php
index 556d749e23b2..b7e406f578ef 100755
--- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php
+++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php
@@ -432,6 +432,17 @@ protected function typeString(Fluent $column)
return 'varchar';
}
+ /**
+ * Create the column definition for a tiny text type.
+ *
+ * @param \Illuminate\Support\Fluent $column
+ * @return string
+ */
+ protected function typeTinyText(Fluent $column)
+ {
+ return 'text';
+ }
+
/**
* Create the column definition for a text type.
*
diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php
index c3fc442e2368..b147628ec2f3 100755
--- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php
+++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php
@@ -417,6 +417,17 @@ protected function typeString(Fluent $column)
return "nvarchar({$column->length})";
}
+ /**
+ * Create the column definition for a tiny text type.
+ *
+ * @param \Illuminate\Support\Fluent $column
+ * @return string
+ */
+ protected function typeTinyText(Fluent $column)
+ {
+ return 'nvarchar(255)';
+ }
+
/**
* Create the column definition for a text type.
*
diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php
index f7d1716456d0..b9a9eecbbca9 100755
--- a/src/Illuminate/Foundation/Application.php
+++ b/src/Illuminate/Foundation/Application.php
@@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*
* @var string
*/
- const VERSION = '8.36.2';
+ const VERSION = '8.37.0';
/**
* The base path for the Laravel installation.
diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php
index 574009a68f95..faa6c64a367e 100644
--- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php
+++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithViews.php
@@ -2,6 +2,7 @@
namespace Illuminate\Foundation\Testing\Concerns;
+use Closure;
use Illuminate\Support\Facades\View as ViewFacade;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Str;
@@ -58,6 +59,10 @@ protected function component(string $componentClass, array $data = [])
$view = $component->resolveView();
+ if ($view instanceof Closure) {
+ $view = $view($data);
+ }
+
return $view instanceof View
? new TestView($view->with($component->data()))
: new TestView(view($view, $component->data()));
diff --git a/src/Illuminate/Http/Client/Factory.php b/src/Illuminate/Http/Client/Factory.php
index 4db3e1fa98a0..6fc069d390b7 100644
--- a/src/Illuminate/Http/Client/Factory.php
+++ b/src/Illuminate/Http/Client/Factory.php
@@ -34,6 +34,8 @@
* @method \Illuminate\Http\Client\PendingRequest withoutVerifying()
* @method \Illuminate\Http\Client\PendingRequest dump()
* @method \Illuminate\Http\Client\PendingRequest dd()
+ * @method \Illuminate\Http\Client\PendingRequest async()
+ * @method \Illuminate\Http\Client\Pool pool()
* @method \Illuminate\Http\Client\Response delete(string $url, array $data = [])
* @method \Illuminate\Http\Client\Response get(string $url, array $query = [])
* @method \Illuminate\Http\Client\Response head(string $url, array $query = [])
diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php
index 5801bc0b70f0..f0790c5a54a3 100644
--- a/src/Illuminate/Http/Client/PendingRequest.php
+++ b/src/Illuminate/Http/Client/PendingRequest.php
@@ -5,10 +5,13 @@
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\ConnectException;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Exception\TransferException;
use GuzzleHttp\HandlerStack;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
+use Psr\Http\Message\MessageInterface;
use Symfony\Component\VarDumper\VarDumper;
class PendingRequest
@@ -22,6 +25,13 @@ class PendingRequest
*/
protected $factory;
+ /**
+ * The Guzzle client instance.
+ *
+ * @var \GuzzleHttp\Client
+ */
+ protected $client;
+
/**
* The base URL for the request.
*
@@ -106,6 +116,20 @@ class PendingRequest
*/
protected $middleware;
+ /**
+ * Whether the requests should be asynchronous.
+ *
+ * @var bool
+ */
+ protected $async = false;
+
+ /**
+ * The pending request promise.
+ *
+ * @var \GuzzleHttp\Promise\PromiseInterface
+ */
+ protected $promise;
+
/**
* Create a new HTTP Client instance.
*
@@ -571,6 +595,27 @@ public function delete($url, $data = [])
]);
}
+ /**
+ * Send a pool of asynchronous requests concurrently.
+ *
+ * @param callable $callback
+ * @return array
+ */
+ public function pool(callable $callback)
+ {
+ $results = [];
+
+ $requests = tap(new Pool($this->factory), $callback)->getRequests();
+
+ foreach ($requests as $key => $item) {
+ $results[$key] = $item instanceof static ? $item->getPromise()->wait() : $item->wait();
+ }
+
+ ksort($results);
+
+ return $results;
+ }
+
/**
* Send the request to the given URL.
*
@@ -601,18 +646,14 @@ public function send(string $method, string $url, array $options = [])
[$this->pendingBody, $this->pendingFiles] = [null, []];
+ if ($this->async) {
+ return $this->makePromise($method, $url, $options);
+ }
+
return retry($this->tries ?? 1, function () use ($method, $url, $options) {
try {
- $laravelData = $this->parseRequestData($method, $url, $options);
-
- return tap(new Response($this->buildClient()->request($method, $url, $this->mergeOptions([
- 'laravel_data' => $laravelData,
- 'on_stats' => function ($transferStats) {
- $this->transferStats = $transferStats;
- },
- ], $options))), function ($response) {
- $response->cookies = $this->cookies;
- $response->transferStats = $this->transferStats;
+ return tap(new Response($this->sendRequest($method, $url, $options)), function ($response) {
+ $this->populateResponse($response);
if ($this->tries > 1 && ! $response->successful()) {
$response->throw();
@@ -637,6 +678,49 @@ protected function parseMultipartBodyFormat(array $data)
})->values()->all();
}
+ /**
+ * Send an asynchronous request to the given URL.
+ *
+ * @param string $method
+ * @param string $url
+ * @param array $options
+ * @return \GuzzleHttp\Promise\PromiseInterface
+ */
+ protected function makePromise(string $method, string $url, array $options = [])
+ {
+ return $this->promise = $this->sendRequest($method, $url, $options)
+ ->then(function (MessageInterface $message) {
+ return $this->populateResponse(new Response($message));
+ })
+ ->otherwise(function (TransferException $e) {
+ return $e instanceof RequestException ? $this->populateResponse(new Response($e->getResponse())) : $e;
+ });
+ }
+
+ /**
+ * Send a request either synchronously or asynchronously.
+ *
+ * @param string $method
+ * @param string $url
+ * @param array $options
+ * @return \Psr\Http\Message\MessageInterface|\GuzzleHttp\Promise\PromiseInterface
+ *
+ * @throws \Exception
+ */
+ protected function sendRequest(string $method, string $url, array $options = [])
+ {
+ $clientMethod = $this->async ? 'requestAsync' : 'request';
+
+ $laravelData = $this->parseRequestData($method, $url, $options);
+
+ return $this->buildClient()->$clientMethod($method, $url, $this->mergeOptions([
+ 'laravel_data' => $laravelData,
+ 'on_stats' => function ($transferStats) {
+ $this->transferStats = $transferStats;
+ },
+ ], $options));
+ }
+
/**
* Get the request data as an array so that we can attach it to the request for convenient assertions.
*
@@ -664,6 +748,21 @@ protected function parseRequestData($method, $url, array $options)
return $laravelData;
}
+ /**
+ * Populate the given response with additional data.
+ *
+ * @param \Illuminate\Http\Client\Response $response
+ * @return \Illuminate\Http\Client\Response
+ */
+ protected function populateResponse(Response $response)
+ {
+ $response->cookies = $this->cookies;
+
+ $response->transferStats = $this->transferStats;
+
+ return $response;
+ }
+
/**
* Build the Guzzle client.
*
@@ -671,7 +770,7 @@ protected function parseRequestData($method, $url, array $options)
*/
public function buildClient()
{
- return new Client([
+ return $this->client = $this->client ?: new Client([
'handler' => $this->buildHandlerStack(),
'cookies' => true,
]);
@@ -826,4 +925,40 @@ public function stub($callback)
return $this;
}
+
+ /**
+ * Toggle asynchronicity in requests.
+ *
+ * @param bool $async
+ * @return $this
+ */
+ public function async(bool $async = true)
+ {
+ $this->async = $async;
+
+ return $this;
+ }
+
+ /**
+ * Retrieve the pending request promise.
+ *
+ * @return \GuzzleHttp\Promise\PromiseInterface|null
+ */
+ public function getPromise()
+ {
+ return $this->promise;
+ }
+
+ /**
+ * Set the client instance.
+ *
+ * @param \GuzzleHttp\Client $client
+ * @return $this
+ */
+ public function setClient(Client $client)
+ {
+ $this->client = $client;
+
+ return $this;
+ }
}
diff --git a/src/Illuminate/Http/Client/Pool.php b/src/Illuminate/Http/Client/Pool.php
new file mode 100644
index 000000000000..15002b28e92e
--- /dev/null
+++ b/src/Illuminate/Http/Client/Pool.php
@@ -0,0 +1,83 @@
+factory = $factory ?: new Factory();
+
+ $this->client = $this->factory->buildClient();
+ }
+
+ /**
+ * Add a request to the pool with a key.
+ *
+ * @param string $key
+ * @return \Illuminate\Http\Client\PendingRequest
+ */
+ public function as(string $key)
+ {
+ return $this->pool[$key] = $this->asyncRequest();
+ }
+
+ /**
+ * Retrieve a new async pending request.
+ *
+ * @return \Illuminate\Http\Client\PendingRequest
+ */
+ protected function asyncRequest()
+ {
+ return $this->factory->setClient($this->client)->async();
+ }
+
+ /**
+ * Retrieve the requests in the pool.
+ *
+ * @return array
+ */
+ public function getRequests()
+ {
+ return $this->pool;
+ }
+
+ /**
+ * Add a request to the pool with a numeric index.
+ *
+ * @param string $method
+ * @param array $parameters
+ * @return \Illuminate\Http\Client\PendingRequest
+ */
+ public function __call($method, $parameters)
+ {
+ return $this->pool[] = $this->asyncRequest()->$method(...$parameters);
+ }
+}
diff --git a/src/Illuminate/Pagination/LengthAwarePaginator.php b/src/Illuminate/Pagination/LengthAwarePaginator.php
index 3e5adad0a316..d1c6cc711fb5 100644
--- a/src/Illuminate/Pagination/LengthAwarePaginator.php
+++ b/src/Illuminate/Pagination/LengthAwarePaginator.php
@@ -99,7 +99,7 @@ public function render($view = null, $data = [])
*
* @return \Illuminate\Support\Collection
*/
- protected function linkCollection()
+ public function linkCollection()
{
return collect($this->elements())->flatMap(function ($item) {
if (! is_array($item)) {
diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php
index 2f651b60d098..212883fecdcb 100644
--- a/src/Illuminate/Queue/Console/RetryCommand.php
+++ b/src/Illuminate/Queue/Console/RetryCommand.php
@@ -18,6 +18,7 @@ class RetryCommand extends Command
*/
protected $signature = 'queue:retry
{id?* : The ID of the failed job or "all" to retry all jobs}
+ {--queue= : Retry all of the failed jobs for the specified queue}
{--range=* : Range of job IDs (numeric) to be retried}';
/**
@@ -62,6 +63,10 @@ protected function getJobIds()
return Arr::pluck($this->laravel['queue.failer']->all(), 'id');
}
+ if ($queue = $this->option('queue')) {
+ return $this->getJobIdsByQueue($queue);
+ }
+
if ($ranges = (array) $this->option('range')) {
$ids = array_merge($ids, $this->getJobIdsByRanges($ranges));
}
@@ -69,6 +74,26 @@ protected function getJobIds()
return array_values(array_filter(array_unique($ids)));
}
+ /**
+ * Get the job IDs by queue, if applicable.
+ *
+ * @param string $queue
+ * @return array
+ */
+ protected function getJobIdsByQueue($queue)
+ {
+ $ids = collect($this->laravel['queue.failer']->all())
+ ->where('queue', $queue)
+ ->pluck('id')
+ ->toArray();
+
+ if (count($ids) === 0) {
+ $this->error("Unable to find failed jobs for queue [{$queue}].");
+ }
+
+ return $ids;
+ }
+
/**
* Get the job IDs ranges, if applicable.
*
diff --git a/src/Illuminate/Session/Store.php b/src/Illuminate/Session/Store.php
index ff2a3b966a20..151e8b6330b5 100755
--- a/src/Illuminate/Session/Store.php
+++ b/src/Illuminate/Session/Store.php
@@ -193,6 +193,17 @@ public function exists($key)
});
}
+ /**
+ * Determine if the given key is missing from the session data.
+ *
+ * @param string|array $key
+ * @return bool
+ */
+ public function missing($key)
+ {
+ return ! $this->exists($key);
+ }
+
/**
* Checks if a key is present and not null.
*
diff --git a/src/Illuminate/Support/Facades/Http.php b/src/Illuminate/Support/Facades/Http.php
index 426d574789c5..51763b6caef0 100644
--- a/src/Illuminate/Support/Facades/Http.php
+++ b/src/Illuminate/Support/Facades/Http.php
@@ -32,6 +32,8 @@
* @method static \Illuminate\Http\Client\PendingRequest withoutVerifying()
* @method static \Illuminate\Http\Client\PendingRequest dump()
* @method static \Illuminate\Http\Client\PendingRequest dd()
+ * @method static \Illuminate\Http\Client\PendingRequest async()
+ * @method static \Illuminate\Http\Client\Pool pool()
* @method static \Illuminate\Http\Client\Response delete(string $url, array $data = [])
* @method static \Illuminate\Http\Client\Response get(string $url, array $query = [])
* @method static \Illuminate\Http\Client\Response head(string $url, array $query = [])
diff --git a/src/Illuminate/View/Engines/EngineResolver.php b/src/Illuminate/View/Engines/EngineResolver.php
index d0edb7367df6..6a5b80026342 100755
--- a/src/Illuminate/View/Engines/EngineResolver.php
+++ b/src/Illuminate/View/Engines/EngineResolver.php
@@ -57,4 +57,15 @@ public function resolve($engine)
throw new InvalidArgumentException("Engine [{$engine}] not found.");
}
+
+ /**
+ * Remove a resolved engine.
+ *
+ * @param string $engine
+ * @return void
+ */
+ public function forget($engine)
+ {
+ unset($this->resolved[$engine]);
+ }
}
diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php
index 0809f8e0fe98..682545ff9b98 100755
--- a/tests/Database/DatabaseEloquentBuilderTest.php
+++ b/tests/Database/DatabaseEloquentBuilderTest.php
@@ -1497,6 +1497,18 @@ public function testWithCastsMethod()
$builder->withCasts(['foo' => 'bar']);
}
+ public function testClone()
+ {
+ $query = new BaseBuilder(m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class));
+ $builder = new Builder($query);
+ $builder->select('*')->from('users');
+ $clone = $builder->clone()->where('email', 'foo');
+
+ $this->assertNotSame($builder, $clone);
+ $this->assertSame('select * from "users"', $builder->toSql());
+ $this->assertSame('select * from "users" where "email" = ?', $clone->toSql());
+ }
+
protected function mockConnectionForModel($model, $database)
{
$grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar';
diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php
index 94303415e8f4..5247df35c3ba 100755
--- a/tests/Database/DatabaseSchemaBlueprintTest.php
+++ b/tests/Database/DatabaseSchemaBlueprintTest.php
@@ -291,4 +291,62 @@ public function testGenerateRelationshipColumnWithUuidModel()
'alter table `posts` add `eloquent_model_uuid_stub_id` char(36) not null',
], $blueprint->toSql($connection, new MySqlGrammar));
}
+
+ public function testTinyTextColumn()
+ {
+ $base = new Blueprint('posts', function ($table) {
+ $table->tinyText('note');
+ });
+
+ $connection = m::mock(Connection::class);
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table `posts` add `note` tinytext not null',
+ ], $blueprint->toSql($connection, new MySqlGrammar));
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table "posts" add column "note" text not null',
+ ], $blueprint->toSql($connection, new SQLiteGrammar));
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table "posts" add column "note" varchar(255) not null',
+ ], $blueprint->toSql($connection, new PostgresGrammar));
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table "posts" add "note" nvarchar(255) not null',
+ ], $blueprint->toSql($connection, new SqlServerGrammar));
+ }
+
+ public function testTinyTextNullableColumn()
+ {
+ $base = new Blueprint('posts', function ($table) {
+ $table->tinyText('note')->nullable();
+ });
+
+ $connection = m::mock(Connection::class);
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table `posts` add `note` tinytext null',
+ ], $blueprint->toSql($connection, new MySqlGrammar));
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table "posts" add column "note" text',
+ ], $blueprint->toSql($connection, new SQLiteGrammar));
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table "posts" add column "note" varchar(255) null',
+ ], $blueprint->toSql($connection, new PostgresGrammar));
+
+ $blueprint = clone $base;
+ $this->assertEquals([
+ 'alter table "posts" add "note" nvarchar(255) null',
+ ], $blueprint->toSql($connection, new SqlServerGrammar));
+ }
}
diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php
index 12d7a1806c21..84709fa3ba66 100644
--- a/tests/Http/HttpClientTest.php
+++ b/tests/Http/HttpClientTest.php
@@ -2,8 +2,11 @@
namespace Illuminate\Tests\Http;
+use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\Response as Psr7Response;
use Illuminate\Http\Client\Factory;
+use Illuminate\Http\Client\PendingRequest;
+use Illuminate\Http\Client\Pool;
use Illuminate\Http\Client\Request;
use Illuminate\Http\Client\RequestException;
use Illuminate\Http\Client\Response;
@@ -833,4 +836,70 @@ public function testResponseSequenceIsMacroable()
$this->assertSame('yes!', $this->factory->fakeSequence()->customMethod());
}
+
+ public function testRequestsCanBeAsync()
+ {
+ $request = new PendingRequest($this->factory);
+
+ $promise = $request->async()->get('http://foo.com');
+
+ $this->assertInstanceOf(PromiseInterface::class, $promise);
+
+ $this->assertSame($promise, $request->getPromise());
+ }
+
+ public function testClientCanBeSet()
+ {
+ $client = $this->factory->buildClient();
+
+ $request = new PendingRequest($this->factory);
+
+ $this->assertNotSame($client, $request->buildClient());
+
+ $request->setClient($client);
+
+ $this->assertSame($client, $request->buildClient());
+ }
+
+ public function testMultipleRequestsAreSentInThePool()
+ {
+ $this->factory->fake([
+ '200.com' => $this->factory::response('', 200),
+ '400.com' => $this->factory::response('', 400),
+ '500.com' => $this->factory::response('', 500),
+ ]);
+
+ $responses = $this->factory->pool(function (Pool $pool) {
+ return [
+ $pool->get('200.com'),
+ $pool->get('400.com'),
+ $pool->get('500.com'),
+ ];
+ });
+
+ $this->assertSame(200, $responses[0]->status());
+ $this->assertSame(400, $responses[1]->status());
+ $this->assertSame(500, $responses[2]->status());
+ }
+
+ public function testMultipleRequestsAreSentInThePoolWithKeys()
+ {
+ $this->factory->fake([
+ '200.com' => $this->factory::response('', 200),
+ '400.com' => $this->factory::response('', 400),
+ '500.com' => $this->factory::response('', 500),
+ ]);
+
+ $responses = $this->factory->pool(function (Pool $pool) {
+ return [
+ $pool->as('test200')->get('200.com'),
+ $pool->as('test400')->get('400.com'),
+ $pool->as('test500')->get('500.com'),
+ ];
+ });
+
+ $this->assertSame(200, $responses['test200']->status());
+ $this->assertSame(400, $responses['test400']->status());
+ $this->assertSame(500, $responses['test500']->status());
+ }
}
diff --git a/tests/Integration/Migration/MigratorTest.php b/tests/Integration/Migration/MigratorTest.php
index 50ee6f3cbd6b..08dd9c97862f 100644
--- a/tests/Integration/Migration/MigratorTest.php
+++ b/tests/Integration/Migration/MigratorTest.php
@@ -2,11 +2,29 @@
namespace Illuminate\Tests\Integration\Migration;
+use Illuminate\Support\Facades\DB;
+use Mockery;
+use Mockery\Mock;
use Orchestra\Testbench\TestCase;
-use PDOException;
+use Symfony\Component\Console\Output\OutputInterface;
class MigratorTest extends TestCase
{
+ /**
+ * @var Mock
+ */
+ private $output;
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->output = Mockery::mock(OutputInterface::class);
+ $this->subject = $this->app->make('migrator');
+ $this->subject->setOutput($this->output);
+ $this->subject->getRepository()->createRepository();
+ }
+
protected function getEnvironmentSetUp($app)
{
$app['config']->set('app.debug', 'true');
@@ -19,25 +37,55 @@ protected function getEnvironmentSetUp($app)
]);
}
- public function testDontDisplayOutputWhenOutputObjectIsNotAvailable()
+ public function testMigrate()
+ {
+ $this->expectOutput('Migrating: 2014_10_12_000000_create_people_table');
+ $this->expectOutput(Mockery::pattern('#Migrated: 2014_10_12_000000_create_people_table (.*)#'));
+ $this->expectOutput('Migrating: 2015_10_04_000000_modify_people_table');
+ $this->expectOutput(Mockery::pattern('#Migrated: 2015_10_04_000000_modify_people_table (.*)#'));
+ $this->expectOutput('Migrating: 2016_10_04_000000_modify_people_table');
+ $this->expectOutput(Mockery::pattern('#Migrated: 2016_10_04_000000_modify_people_table (.*)#'));
+
+ $this->subject->run([__DIR__.'/fixtures']);
+
+ self::assertTrue(DB::getSchemaBuilder()->hasTable('people'));
+ self::assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'first_name'));
+ self::assertTrue(DB::getSchemaBuilder()->hasColumn('people', 'last_name'));
+ }
+
+ public function testRollback()
{
- $migrator = $this->app->make('migrator');
+ $this->getConnection()->statement('CREATE TABLE people(id INT, first_name VARCHAR, last_name VARCHAR);');
+ $this->subject->getRepository()->log('2014_10_12_000000_create_people_table', 1);
+ $this->subject->getRepository()->log('2015_10_04_000000_modify_people_table', 1);
+ $this->subject->getRepository()->log('2016_10_04_000000_modify_people_table', 1);
- $migrator->getRepository()->createRepository();
+ $this->expectOutput('Rolling back: 2016_10_04_000000_modify_people_table');
+ $this->expectOutput(Mockery::pattern('#Rolled back: 2016_10_04_000000_modify_people_table (.*)#'));
+ $this->expectOutput('Rolling back: 2015_10_04_000000_modify_people_table');
+ $this->expectOutput(Mockery::pattern('#Rolled back: 2015_10_04_000000_modify_people_table (.*)#'));
+ $this->expectOutput('Rolling back: 2014_10_12_000000_create_people_table');
+ $this->expectOutput(Mockery::pattern('#Rolled back: 2014_10_12_000000_create_people_table (.*)#'));
- $migrator->run([__DIR__.'/fixtures']);
+ $this->subject->rollback([__DIR__.'/fixtures']);
- $this->assertTrue($this->tableExists('people'));
+ self::assertFalse(DB::getSchemaBuilder()->hasTable('people'));
}
- private function tableExists($table): bool
+ public function testPretendMigrate()
{
- try {
- $this->app->make('db')->select("SELECT COUNT(*) FROM $table");
- } catch (PDOException $e) {
- return false;
- }
+ $this->expectOutput('CreatePeopleTable: create table "people" ("id" integer not null primary key autoincrement, "name" varchar not null, "email" varchar not null, "password" varchar not null, "remember_token" varchar, "created_at" datetime, "updated_at" datetime)');
+ $this->expectOutput('CreatePeopleTable: create unique index "people_email_unique" on "people" ("email")');
+ $this->expectOutput('2015_10_04_000000_modify_people_table: alter table "people" add column "first_name" varchar');
+ $this->expectOutput('2016_10_04_000000_modify_people_table: alter table "people" add column "last_name" varchar');
+
+ $this->subject->run([__DIR__.'/fixtures'], ['pretend' => true]);
- return true;
+ self::assertFalse(DB::getSchemaBuilder()->hasTable('people'));
+ }
+
+ private function expectOutput($argument): void
+ {
+ $this->output->shouldReceive('writeln')->once()->with($argument);
}
}
diff --git a/tests/Integration/Migration/fixtures/2015_10_04_000000_modify_people_table.php b/tests/Integration/Migration/fixtures/2015_10_04_000000_modify_people_table.php
new file mode 100644
index 000000000000..88ac706cd12a
--- /dev/null
+++ b/tests/Integration/Migration/fixtures/2015_10_04_000000_modify_people_table.php
@@ -0,0 +1,31 @@
+string('first_name')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('people', function (Blueprint $table) {
+ $table->dropColumn('first_name');
+ });
+ }
+};
diff --git a/tests/Integration/Migration/fixtures/2016_10_04_000000_modify_people_table.php b/tests/Integration/Migration/fixtures/2016_10_04_000000_modify_people_table.php
new file mode 100644
index 000000000000..6492b6d7f55a
--- /dev/null
+++ b/tests/Integration/Migration/fixtures/2016_10_04_000000_modify_people_table.php
@@ -0,0 +1,31 @@
+string('last_name')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('people', function (Blueprint $table) {
+ $table->dropColumn('last_name');
+ });
+ }
+};
diff --git a/tests/Session/SessionStoreTest.php b/tests/Session/SessionStoreTest.php
index 5871cc657a85..188bdce4d89f 100644
--- a/tests/Session/SessionStoreTest.php
+++ b/tests/Session/SessionStoreTest.php
@@ -452,6 +452,22 @@ public function testKeyExists()
$this->assertFalse($session->exists(['hulk.two']));
}
+ public function testKeyMissing()
+ {
+ $session = $this->getSession();
+ $session->put('foo', 'bar');
+ $this->assertFalse($session->missing('foo'));
+ $session->put('baz', null);
+ $session->put('hulk', ['one' => true]);
+ $this->assertFalse($session->has('baz'));
+ $this->assertFalse($session->missing('baz'));
+ $this->assertTrue($session->missing('bogus'));
+ $this->assertFalse($session->missing(['foo', 'baz']));
+ $this->assertTrue($session->missing(['foo', 'baz', 'bogus']));
+ $this->assertFalse($session->missing(['hulk.one']));
+ $this->assertTrue($session->missing(['hulk.two']));
+ }
+
public function testRememberMethodCallsPutAndReturnsDefault()
{
$session = $this->getSession();
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy