This commit is contained in:
Paolo A
2024-08-13 13:44:16 +00:00
parent 1bbb23088d
commit e796d76612
4001 changed files with 30101 additions and 40075 deletions

2
vendor/laravel/framework/src/Illuminate/Foundation/AliasLoader.php vendored Normal file → Executable file
View File

@@ -100,7 +100,7 @@ class AliasLoader
*/
protected function ensureFacadeExists($alias)
{
if (file_exists($path = storage_path('framework/cache/facade-'.sha1($alias).'.php'))) {
if (is_file($path = storage_path('framework/cache/facade-'.sha1($alias).'.php'))) {
return $path;
}

202
vendor/laravel/framework/src/Illuminate/Foundation/Application.php vendored Normal file → Executable file
View File

@@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*
* @var string
*/
const VERSION = '7.30.6';
const VERSION = '8.83.27';
/**
* The base path for the Laravel installation.
@@ -112,6 +112,13 @@ class Application extends Container implements ApplicationContract, CachesConfig
*/
protected $databasePath;
/**
* The custom language file path defined by the developer.
*
* @var string
*/
protected $langPath;
/**
* The custom storage path defined by the developer.
*
@@ -150,7 +157,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
/**
* The prefixes of absolute cache paths for use during normalization.
*
* @var array
* @var string[]
*/
protected $absoluteCachePathPrefixes = ['/', '\\'];
@@ -241,7 +248,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*/
public function afterLoadingEnvironment(Closure $callback)
{
return $this->afterBootstrapping(
$this->afterBootstrapping(
LoadEnvironmentVariables::class, $callback
);
}
@@ -344,7 +351,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
/**
* Get the base path of the Laravel installation.
*
* @param string $path Optionally, a path to append to the base path
* @param string $path
* @return string
*/
public function basePath($path = '')
@@ -355,7 +362,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
/**
* Get the path to the bootstrap directory.
*
* @param string $path Optionally, a path to append to the bootstrap path
* @param string $path
* @return string
*/
public function bootstrapPath($path = '')
@@ -366,7 +373,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
/**
* Get the path to the application configuration files.
*
* @param string $path Optionally, a path to append to the config path
* @param string $path
* @return string
*/
public function configPath($path = '')
@@ -377,7 +384,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
/**
* Get the path to the database directory.
*
* @param string $path Optionally, a path to append to the database path
* @param string $path
* @return string
*/
public function databasePath($path = '')
@@ -407,7 +414,30 @@ class Application extends Container implements ApplicationContract, CachesConfig
*/
public function langPath()
{
return $this->resourcePath().DIRECTORY_SEPARATOR.'lang';
if ($this->langPath) {
return $this->langPath;
}
if (is_dir($path = $this->resourcePath().DIRECTORY_SEPARATOR.'lang')) {
return $path;
}
return $this->basePath().DIRECTORY_SEPARATOR.'lang';
}
/**
* Set the language file directory.
*
* @param string $path
* @return $this
*/
public function useLangPath($path)
{
$this->langPath = $path;
$this->instance('path.lang', $path);
return $this;
}
/**
@@ -456,6 +486,21 @@ class Application extends Container implements ApplicationContract, CachesConfig
return $this->basePath.DIRECTORY_SEPARATOR.'resources'.($path ? DIRECTORY_SEPARATOR.$path : $path);
}
/**
* Get the path to the views directory.
*
* This method returns the first configured path in the array of view paths.
*
* @param string $path
* @return string
*/
public function viewPath($path = '')
{
$basePath = $this['config']->get('view.paths')[0];
return rtrim($basePath, DIRECTORY_SEPARATOR).($path ? DIRECTORY_SEPARATOR.$path : $path);
}
/**
* Get the path to the environment file directory.
*
@@ -530,7 +575,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
}
/**
* Determine if application is in local environment.
* Determine if the application is in the local environment.
*
* @return bool
*/
@@ -540,7 +585,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
}
/**
* Determine if application is in production environment.
* Determine if the application is in the production environment.
*
* @return bool
*/
@@ -583,7 +628,17 @@ class Application extends Container implements ApplicationContract, CachesConfig
*/
public function runningUnitTests()
{
return $this['env'] === 'testing';
return $this->bound('env') && $this['env'] === 'testing';
}
/**
* Determine if the application is running with debug mode enabled.
*
* @return bool
*/
public function hasDebugModeEnabled()
{
return (bool) $this['config']->get('app.debug');
}
/**
@@ -593,7 +648,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*/
public function registerConfiguredProviders()
{
$providers = Collection::make($this->config['app.providers'])
$providers = Collection::make($this->make('config')->get('app.providers'))
->partition(function ($provider) {
return strpos($provider, 'Illuminate\\') === 0;
});
@@ -859,13 +914,17 @@ class Application extends Container implements ApplicationContract, CachesConfig
* Boot the given service provider.
*
* @param \Illuminate\Support\ServiceProvider $provider
* @return mixed
* @return void
*/
protected function bootProvider(ServiceProvider $provider)
{
$provider->callBootingCallbacks();
if (method_exists($provider, 'boot')) {
return $this->call([$provider, 'boot']);
$this->call([$provider, 'boot']);
}
$provider->callBootedCallbacks();
}
/**
@@ -890,7 +949,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
$this->bootedCallbacks[] = $callback;
if ($this->isBooted()) {
$this->fireAppCallbacks([$callback]);
$callback($this);
}
}
@@ -900,15 +959,21 @@ class Application extends Container implements ApplicationContract, CachesConfig
* @param callable[] $callbacks
* @return void
*/
protected function fireAppCallbacks(array $callbacks)
protected function fireAppCallbacks(array &$callbacks)
{
foreach ($callbacks as $callback) {
$callback($this);
$index = 0;
while ($index < count($callbacks)) {
$callbacks[$index]($this);
$index++;
}
}
/**
* {@inheritdoc}
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle(SymfonyRequest $request, int $type = self::MASTER_REQUEST, bool $catch = true)
{
@@ -953,7 +1018,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*/
public function configurationIsCached()
{
return file_exists($this->getCachedConfigPath());
return is_file($this->getCachedConfigPath());
}
/**
@@ -1053,7 +1118,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
* @param int $code
* @param string $message
* @param array $headers
* @return void
* @return never
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
@@ -1087,8 +1152,12 @@ class Application extends Container implements ApplicationContract, CachesConfig
*/
public function terminate()
{
foreach ($this->terminatingCallbacks as $terminating) {
$this->call($terminating);
$index = 0;
while ($index < count($this->terminatingCallbacks)) {
$this->call($this->terminatingCallbacks[$index]);
$index++;
}
}
@@ -1177,6 +1246,16 @@ class Application extends Container implements ApplicationContract, CachesConfig
return $this['config']->get('app.locale');
}
/**
* Get the current application locale.
*
* @return string
*/
public function currentLocale()
{
return $this->getLocale();
}
/**
* Get the current application fallback locale.
*
@@ -1216,7 +1295,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
}
/**
* Determine if application locale is the given locale.
* Determine if the application locale is the given locale.
*
* @param string $locale
* @return bool
@@ -1234,44 +1313,44 @@ class Application extends Container implements ApplicationContract, CachesConfig
public function registerCoreContainerAliases()
{
foreach ([
'app' => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
'auth.driver' => [\Illuminate\Contracts\Auth\Guard::class],
'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class, \Psr\SimpleCache\CacheInterface::class],
'cache.psr6' => [\Symfony\Component\Cache\Adapter\Psr16Adapter::class, \Symfony\Component\Cache\Adapter\AdapterInterface::class, \Psr\Cache\CacheItemPoolInterface::class],
'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
'cookie' => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class],
'db' => [\Illuminate\Database\DatabaseManager::class, \Illuminate\Database\ConnectionResolverInterface::class],
'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
'files' => [\Illuminate\Filesystem\Filesystem::class],
'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class],
'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
'hash' => [\Illuminate\Hashing\HashManager::class],
'hash.driver' => [\Illuminate\Contracts\Hashing\Hasher::class],
'translator' => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
'log' => [\Illuminate\Log\LogManager::class, \Psr\Log\LoggerInterface::class],
'mail.manager' => [\Illuminate\Mail\MailManager::class, \Illuminate\Contracts\Mail\Factory::class],
'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
'auth.password' => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
'app' => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
'auth.driver' => [\Illuminate\Contracts\Auth\Guard::class],
'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class, \Psr\SimpleCache\CacheInterface::class],
'cache.psr6' => [\Symfony\Component\Cache\Adapter\Psr16Adapter::class, \Symfony\Component\Cache\Adapter\AdapterInterface::class, \Psr\Cache\CacheItemPoolInterface::class],
'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
'cookie' => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
'db' => [\Illuminate\Database\DatabaseManager::class, \Illuminate\Database\ConnectionResolverInterface::class],
'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\StringEncrypter::class],
'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
'files' => [\Illuminate\Filesystem\Filesystem::class],
'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class],
'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
'hash' => [\Illuminate\Hashing\HashManager::class],
'hash.driver' => [\Illuminate\Contracts\Hashing\Hasher::class],
'translator' => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
'log' => [\Illuminate\Log\LogManager::class, \Psr\Log\LoggerInterface::class],
'mail.manager' => [\Illuminate\Mail\MailManager::class, \Illuminate\Contracts\Mail\Factory::class],
'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
'auth.password' => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
'queue' => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
'queue.connection' => [\Illuminate\Contracts\Queue\Queue::class],
'queue.failer' => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
'redirect' => [\Illuminate\Routing\Redirector::class],
'redis' => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
'redis.connection' => [\Illuminate\Redis\Connections\Connection::class, \Illuminate\Contracts\Redis\Connection::class],
'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
'router' => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
'session' => [\Illuminate\Session\SessionManager::class],
'session.store' => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
'url' => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
'queue' => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
'queue.connection' => [\Illuminate\Contracts\Queue\Queue::class],
'queue.failer' => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
'redirect' => [\Illuminate\Routing\Redirector::class],
'redis' => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
'redis.connection' => [\Illuminate\Redis\Connections\Connection::class, \Illuminate\Contracts\Redis\Connection::class],
'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
'router' => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
'session' => [\Illuminate\Session\SessionManager::class],
'session.store' => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
'url' => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
] as $key => $aliases) {
foreach ($aliases as $alias) {
$this->alias($key, $alias);
@@ -1297,8 +1376,11 @@ class Application extends Container implements ApplicationContract, CachesConfig
$this->serviceProviders = [];
$this->resolvingCallbacks = [];
$this->terminatingCallbacks = [];
$this->beforeResolvingCallbacks = [];
$this->afterResolvingCallbacks = [];
$this->globalBeforeResolvingCallbacks = [];
$this->globalResolvingCallbacks = [];
$this->globalAfterResolvingCallbacks = [];
}
/**

View File

@@ -18,6 +18,18 @@ trait Authorizable
return app(Gate::class)->forUser($this)->check($abilities, $arguments);
}
/**
* Determine if the entity has any of the given abilities.
*
* @param iterable|string $abilities
* @param array|mixed $arguments
* @return bool
*/
public function canAny($abilities, $arguments = [])
{
return app(Gate::class)->forUser($this)->any($abilities, $arguments);
}
/**
* Determine if the entity does not have the given abilities.
*

View File

@@ -74,14 +74,18 @@ trait AuthorizesRequests
/**
* Authorize a resource action based on the incoming request.
*
* @param string $model
* @param string|null $parameter
* @param string|array $model
* @param string|array|null $parameter
* @param array $options
* @param \Illuminate\Http\Request|null $request
* @return void
*/
public function authorizeResource($model, $parameter = null, array $options = [], $request = null)
{
$model = is_array($model) ? implode(',', $model) : $model;
$parameter = is_array($parameter) ? implode(',', $parameter) : $parameter;
$parameter = $parameter ?: Str::snake(class_basename($model));
$middleware = [];

View File

@@ -6,6 +6,8 @@ use ErrorException;
use Exception;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Log\LogManager;
use Monolog\Handler\NullHandler;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\ErrorHandler\Error\FatalError;
use Throwable;
@@ -34,7 +36,7 @@ class HandleExceptions
*/
public function bootstrap(Application $app)
{
self::$reservedMemory = str_repeat('x', 10240);
self::$reservedMemory = str_repeat('x', 32768);
$this->app = $app;
@@ -52,7 +54,7 @@ class HandleExceptions
}
/**
* Convert PHP errors to ErrorException instances.
* Report PHP deprecations, or convert PHP errors to ErrorException instances.
*
* @param int $level
* @param string $message
@@ -65,11 +67,86 @@ class HandleExceptions
*/
public function handleError($level, $message, $file = '', $line = 0, $context = [])
{
if ($this->isDeprecation($level)) {
return $this->handleDeprecation($message, $file, $line);
}
if (error_reporting() & $level) {
throw new ErrorException($message, 0, $level, $file, $line);
}
}
/**
* Reports a deprecation to the "deprecations" logger.
*
* @param string $message
* @param string $file
* @param int $line
* @return void
*/
public function handleDeprecation($message, $file, $line)
{
if (! class_exists(LogManager::class)
|| ! $this->app->hasBeenBootstrapped()
|| $this->app->runningUnitTests()
) {
return;
}
try {
$logger = $this->app->make(LogManager::class);
} catch (Exception $e) {
return;
}
$this->ensureDeprecationLoggerIsConfigured();
with($logger->channel('deprecations'), function ($log) use ($message, $file, $line) {
$log->warning(sprintf('%s in %s on line %s',
$message, $file, $line
));
});
}
/**
* Ensure the "deprecations" logger is configured.
*
* @return void
*/
protected function ensureDeprecationLoggerIsConfigured()
{
with($this->app['config'], function ($config) {
if ($config->get('logging.channels.deprecations')) {
return;
}
$this->ensureNullLogDriverIsConfigured();
$driver = $config->get('logging.deprecations') ?? 'null';
$config->set('logging.channels.deprecations', $config->get("logging.channels.{$driver}"));
});
}
/**
* Ensure the "null" log driver is configured.
*
* @return void
*/
protected function ensureNullLogDriverIsConfigured()
{
with($this->app['config'], function ($config) {
if ($config->get('logging.channels.null')) {
return;
}
$config->set('logging.channels.null', [
'driver' => 'monolog',
'handler' => NullHandler::class,
]);
});
}
/**
* Handle an uncaught exception from the application.
*
@@ -82,9 +159,9 @@ class HandleExceptions
*/
public function handleException(Throwable $e)
{
try {
self::$reservedMemory = null;
self::$reservedMemory = null;
try {
$this->getExceptionHandler()->report($e);
} catch (Exception $e) {
//
@@ -126,6 +203,8 @@ class HandleExceptions
*/
public function handleShutdown()
{
self::$reservedMemory = null;
if (! is_null($error = error_get_last()) && $this->isFatal($error['type'])) {
$this->handleException($this->fatalErrorFromPhpError($error, 0));
}
@@ -143,6 +222,17 @@ class HandleExceptions
return new FatalError($error['message'], 0, $error, $traceOffset);
}
/**
* Determine if the error level is a deprecation.
*
* @param int $level
* @return bool
*/
protected function isDeprecation($level)
{
return in_array($level, [E_DEPRECATED, E_USER_DEPRECATED]);
}
/**
* Determine if the error type is fatal.
*

View File

@@ -68,7 +68,7 @@ class LoadEnvironmentVariables
*/
protected function setEnvironmentFilePath($app, $file)
{
if (file_exists($app->environmentPath().'/'.$file)) {
if (is_file($app->environmentPath().'/'.$file)) {
$app->loadEnvironmentFrom($file);
return true;

View File

@@ -12,15 +12,16 @@ trait Dispatchable
*
* @return \Illuminate\Foundation\Bus\PendingDispatch
*/
public static function dispatch()
public static function dispatch(...$arguments)
{
return new PendingDispatch(new static(...func_get_args()));
return new PendingDispatch(new static(...$arguments));
}
/**
* Dispatch the job with the given arguments if the given truth test passes.
*
* @param bool $boolean
* @param mixed ...$arguments
* @return \Illuminate\Foundation\Bus\PendingDispatch|\Illuminate\Support\Fluent
*/
public static function dispatchIf($boolean, ...$arguments)
@@ -34,6 +35,7 @@ trait Dispatchable
* Dispatch the job with the given arguments unless the given truth test passes.
*
* @param bool $boolean
* @param mixed ...$arguments
* @return \Illuminate\Foundation\Bus\PendingDispatch|\Illuminate\Support\Fluent
*/
public static function dispatchUnless($boolean, ...$arguments)
@@ -46,11 +48,25 @@ trait Dispatchable
/**
* Dispatch a command to its appropriate handler in the current process.
*
* Queueable jobs will be dispatched to the "sync" queue.
*
* @return mixed
*/
public static function dispatchNow()
public static function dispatchSync(...$arguments)
{
return app(Dispatcher::class)->dispatchNow(new static(...func_get_args()));
return app(Dispatcher::class)->dispatchSync(new static(...$arguments));
}
/**
* Dispatch a command to its appropriate handler in the current process.
*
* @return mixed
*
* @deprecated Will be removed in a future Laravel version.
*/
public static function dispatchNow(...$arguments)
{
return app(Dispatcher::class)->dispatchNow(new static(...$arguments));
}
/**
@@ -58,9 +74,9 @@ trait Dispatchable
*
* @return mixed
*/
public static function dispatchAfterResponse()
public static function dispatchAfterResponse(...$arguments)
{
return app(Dispatcher::class)->dispatchAfterResponse(new static(...func_get_args()));
return app(Dispatcher::class)->dispatchAfterResponse(new static(...$arguments));
}
/**

View File

@@ -22,9 +22,24 @@ trait DispatchesJobs
*
* @param mixed $job
* @return mixed
*
* @deprecated Will be removed in a future Laravel version.
*/
public function dispatchNow($job)
{
return app(Dispatcher::class)->dispatchNow($job);
}
/**
* Dispatch a job to its appropriate handler in the current process.
*
* Queueable jobs will be dispatched to the "sync" queue.
*
* @param mixed $job
* @return mixed
*/
public function dispatchSync($job)
{
return app(Dispatcher::class)->dispatchSync($job);
}
}

View File

@@ -3,7 +3,9 @@
namespace Illuminate\Foundation\Bus;
use Closure;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Queue\CallQueuedClosure;
use Illuminate\Queue\SerializableClosureFactory;
class PendingChain
{
@@ -21,6 +23,34 @@ class PendingChain
*/
public $chain;
/**
* The name of the connection the chain should be sent to.
*
* @var string|null
*/
public $connection;
/**
* The name of the queue the chain should be sent to.
*
* @var string|null
*/
public $queue;
/**
* The number of seconds before the chain should be made available.
*
* @var \DateTimeInterface|\DateInterval|int|null
*/
public $delay;
/**
* The callbacks to be executed on failure.
*
* @var array
*/
public $catchCallbacks = [];
/**
* Create a new PendingChain instance.
*
@@ -34,6 +64,70 @@ class PendingChain
$this->chain = $chain;
}
/**
* Set the desired connection for the job.
*
* @param string|null $connection
* @return $this
*/
public function onConnection($connection)
{
$this->connection = $connection;
return $this;
}
/**
* Set the desired queue for the job.
*
* @param string|null $queue
* @return $this
*/
public function onQueue($queue)
{
$this->queue = $queue;
return $this;
}
/**
* Set the desired delay for the chain.
*
* @param \DateTimeInterface|\DateInterval|int|null $delay
* @return $this
*/
public function delay($delay)
{
$this->delay = $delay;
return $this;
}
/**
* Add a callback to be executed on job failure.
*
* @param callable $callback
* @return $this
*/
public function catch($callback)
{
$this->catchCallbacks[] = $callback instanceof Closure
? SerializableClosureFactory::make($callback)
: $callback;
return $this;
}
/**
* Get the "catch" callbacks that have been registered.
*
* @return array
*/
public function catchCallbacks()
{
return $this->catchCallbacks ?? [];
}
/**
* Dispatch the job with the given arguments.
*
@@ -49,6 +143,23 @@ class PendingChain
$firstJob = $this->job;
}
return (new PendingDispatch($firstJob))->chain($this->chain);
if ($this->connection) {
$firstJob->chainConnection = $this->connection;
$firstJob->connection = $firstJob->connection ?: $this->connection;
}
if ($this->queue) {
$firstJob->chainQueue = $this->queue;
$firstJob->queue = $firstJob->queue ?: $this->queue;
}
if ($this->delay) {
$firstJob->delay = ! is_null($firstJob->delay) ? $firstJob->delay : $this->delay;
}
$firstJob->chain($this->chain);
$firstJob->chainCatchCallbacks = $this->catchCallbacks();
return app(Dispatcher::class)->dispatch($firstJob);
}
}

View File

@@ -2,7 +2,11 @@
namespace Illuminate\Foundation\Bus;
use Illuminate\Bus\UniqueLock;
use Illuminate\Container\Container;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Contracts\Queue\ShouldBeUnique;
class PendingDispatch
{
@@ -96,6 +100,30 @@ class PendingDispatch
return $this;
}
/**
* Indicate that the job should be dispatched after all database transactions have committed.
*
* @return $this
*/
public function afterCommit()
{
$this->job->afterCommit();
return $this;
}
/**
* Indicate that the job should not wait until database transactions have been committed before dispatching.
*
* @return $this
*/
public function beforeCommit()
{
$this->job->beforeCommit();
return $this;
}
/**
* Set the jobs that should run if this job is successful.
*
@@ -121,6 +149,35 @@ class PendingDispatch
return $this;
}
/**
* Determine if the job should be dispatched.
*
* @return bool
*/
protected function shouldDispatch()
{
if (! $this->job instanceof ShouldBeUnique) {
return true;
}
return (new UniqueLock(Container::getInstance()->make(Cache::class)))
->acquire($this->job);
}
/**
* Dynamically proxy methods to the underlying job.
*
* @param string $method
* @param array $parameters
* @return $this
*/
public function __call($method, $parameters)
{
$this->job->{$method}(...$parameters);
return $this;
}
/**
* Handle the object's destruction.
*
@@ -128,7 +185,9 @@ class PendingDispatch
*/
public function __destruct()
{
if ($this->afterResponse) {
if (! $this->shouldDispatch()) {
return;
} elseif ($this->afterResponse) {
app(Dispatcher::class)->dispatchAfterResponse($this->job);
} else {
app(Dispatcher::class)->dispatch($this->job);

View File

@@ -54,11 +54,15 @@ class ComposerScripts
{
$laravel = new Application(getcwd());
if (file_exists($servicesPath = $laravel->getCachedServicesPath())) {
if (is_file($configPath = $laravel->getCachedConfigPath())) {
@unlink($configPath);
}
if (is_file($servicesPath = $laravel->getCachedServicesPath())) {
@unlink($servicesPath);
}
if (file_exists($packagesPath = $laravel->getCachedPackagesPath())) {
if (is_file($packagesPath = $laravel->getCachedPackagesPath())) {
@unlink($packagesPath);
}
}

View File

@@ -34,7 +34,20 @@ class CastMakeCommand extends GeneratorCommand
*/
protected function getStub()
{
return __DIR__.'/stubs/cast.stub';
return $this->resolveStubPath('/stubs/cast.stub');
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**

View File

@@ -36,7 +36,7 @@ class ChannelMakeCommand extends GeneratorCommand
protected function buildClass($name)
{
return str_replace(
'DummyUser',
['DummyUser', '{{ userModel }}'],
class_basename($this->userProviderModel()),
parent::buildClass($name)
);

View File

@@ -27,11 +27,11 @@ class ClearCompiledCommand extends Command
*/
public function handle()
{
if (file_exists($servicesPath = $this->laravel->getCachedServicesPath())) {
if (is_file($servicesPath = $this->laravel->getCachedServicesPath())) {
@unlink($servicesPath);
}
if (file_exists($packagesPath = $this->laravel->getCachedPackagesPath())) {
if (is_file($packagesPath = $this->laravel->getCachedPackagesPath())) {
@unlink($packagesPath);
}

View File

@@ -56,6 +56,17 @@ class ClosureCommand extends Command
);
}
/**
* Set the description for the command.
*
* @param string $description
* @return $this
*/
public function purpose($description)
{
return $this->describe($description);
}
/**
* Set the description for the command.
*

View File

@@ -54,15 +54,21 @@ class ComponentMakeCommand extends GeneratorCommand
protected function writeView()
{
$path = $this->viewPath(
str_replace('.', '/', 'components.'.$this->getView())
str_replace('.', '/', 'components.'.$this->getView()).'.blade.php'
);
if (! $this->files->isDirectory(dirname($path))) {
$this->files->makeDirectory(dirname($path), 0777, true, true);
}
if ($this->files->exists($path) && ! $this->option('force')) {
$this->error('View already exists!');
return;
}
file_put_contents(
$path.'.blade.php',
$path,
'<div>
<!-- '.Inspiring::quote().' -->
</div>'
@@ -79,14 +85,14 @@ class ComponentMakeCommand extends GeneratorCommand
{
if ($this->option('inline')) {
return str_replace(
'DummyView',
['DummyView', '{{ view }}'],
"<<<'blade'\n<div>\n <!-- ".Inspiring::quote()." -->\n</div>\nblade",
parent::buildClass($name)
);
}
return str_replace(
'DummyView',
['DummyView', '{{ view }}'],
'view(\'components.'.$this->getView().'\')',
parent::buildClass($name)
);
@@ -115,7 +121,20 @@ class ComponentMakeCommand extends GeneratorCommand
*/
protected function getStub()
{
return __DIR__.'/stubs/view-component.stub';
return $this->resolveStubPath('/stubs/view-component.stub');
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**

View File

@@ -2,12 +2,15 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ConsoleMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*

View File

@@ -2,29 +2,33 @@
namespace Illuminate\Foundation\Console;
use App\Http\Middleware\PreventRequestsDuringMaintenance;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Foundation\Events\MaintenanceModeEnabled;
use Illuminate\Foundation\Exceptions\RegisterErrorViewPaths;
use Throwable;
class DownCommand extends Command
{
use InteractsWithTime;
/**
* The console command signature.
*
* @var string
*/
protected $signature = 'down {--message= : The message for the maintenance mode}
protected $signature = 'down {--redirect= : The path that users should be redirected to}
{--render= : The view that should be prerendered for display during maintenance mode}
{--retry= : The number of seconds after which the request may be retried}
{--allow=* : IP or networks allowed to access the application while in maintenance mode}';
{--refresh= : The number of seconds after which the browser may refresh}
{--secret= : The secret phrase that may be used to bypass maintenance mode}
{--status=503 : The status code that should be used when returning the maintenance mode response}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Put the application into maintenance mode';
protected $description = 'Put the application into maintenance / demo mode';
/**
* Execute the console command.
@@ -34,15 +38,23 @@ class DownCommand extends Command
public function handle()
{
try {
if (file_exists(storage_path('framework/down'))) {
if (is_file(storage_path('framework/down'))) {
$this->comment('Application is already down.');
return true;
return 0;
}
file_put_contents(storage_path('framework/down'),
json_encode($this->getDownFilePayload(),
JSON_PRETTY_PRINT));
file_put_contents(
storage_path('framework/down'),
json_encode($this->getDownFilePayload(), JSON_PRETTY_PRINT)
);
file_put_contents(
storage_path('framework/maintenance.php'),
file_get_contents(__DIR__.'/stubs/maintenance-mode.stub')
);
$this->laravel->get('events')->dispatch(MaintenanceModeEnabled::class);
$this->comment('Application is now in maintenance mode.');
} catch (Exception $e) {
@@ -62,13 +74,58 @@ class DownCommand extends Command
protected function getDownFilePayload()
{
return [
'time' => $this->currentTime(),
'message' => $this->option('message'),
'except' => $this->excludedPaths(),
'redirect' => $this->redirectPath(),
'retry' => $this->getRetryTime(),
'allowed' => $this->option('allow'),
'refresh' => $this->option('refresh'),
'secret' => $this->option('secret'),
'status' => (int) $this->option('status', 503),
'template' => $this->option('render') ? $this->prerenderView() : null,
];
}
/**
* Get the paths that should be excluded from maintenance mode.
*
* @return array
*/
protected function excludedPaths()
{
try {
return $this->laravel->make(PreventRequestsDuringMaintenance::class)->getExcludedPaths();
} catch (Throwable $e) {
return [];
}
}
/**
* Get the path that users should be redirected to.
*
* @return string
*/
protected function redirectPath()
{
if ($this->option('redirect') && $this->option('redirect') !== '/') {
return '/'.trim($this->option('redirect'), '/');
}
return $this->option('redirect');
}
/**
* Prerender the specified view so that it can be rendered even before loading Composer.
*
* @return string
*/
protected function prerenderView()
{
(new RegisterErrorViewPaths)();
return view($this->option('render'), [
'retryAfter' => $this->option('retry'),
])->render();
}
/**
* Get the number of seconds the client should wait before retrying their request.
*

View File

@@ -46,7 +46,20 @@ class EventMakeCommand extends GeneratorCommand
*/
protected function getStub()
{
return __DIR__.'/stubs/event.stub';
return $this->resolveStubPath('/stubs/event.stub');
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**

View File

@@ -2,11 +2,14 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputOption;
class JobMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*

View File

@@ -57,7 +57,7 @@ class Kernel implements KernelContract
/**
* The bootstrap classes for the application.
*
* @var array
* @var string[]
*/
protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
@@ -111,7 +111,7 @@ class Kernel implements KernelContract
*/
protected function scheduleCache()
{
return Env::get('SCHEDULE_CACHE_DRIVER');
return $this->app['config']->get('cache.schedule_store', Env::get('SCHEDULE_CACHE_DRIVER'));
}
/**
@@ -172,7 +172,7 @@ class Kernel implements KernelContract
}
/**
* Register the Closure based commands for the application.
* Register the commands for the application.
*
* @return void
*/
@@ -223,7 +223,7 @@ class Kernel implements KernelContract
$command = $namespace.str_replace(
['/', '.php'],
['\\', ''],
Str::after($command->getPathname(), realpath(app_path()).DIRECTORY_SEPARATOR)
Str::after($command->getRealPath(), realpath(app_path()).DIRECTORY_SEPARATOR)
);
if (is_subclass_of($command, Command::class) &&

View File

@@ -2,12 +2,15 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;
class ListenerMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*
@@ -44,15 +47,15 @@ class ListenerMakeCommand extends GeneratorCommand
'Illuminate',
'\\',
])) {
$event = $this->laravel->getNamespace().'Events\\'.$event;
$event = $this->laravel->getNamespace().'Events\\'.str_replace('/', '\\', $event);
}
$stub = str_replace(
'DummyEvent', class_basename($event), parent::buildClass($name)
['DummyEvent', '{{ event }}'], class_basename($event), parent::buildClass($name)
);
return str_replace(
'DummyFullEvent', trim($event, '\\'), $stub
['DummyFullEvent', '{{ eventNamespace }}'], trim($event, '\\'), $stub
);
}

View File

@@ -2,11 +2,15 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;
class MailMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*
@@ -39,7 +43,7 @@ class MailMakeCommand extends GeneratorCommand
return;
}
if ($this->option('markdown')) {
if ($this->option('markdown') !== false) {
$this->writeMarkdownTemplate();
}
}
@@ -52,7 +56,7 @@ class MailMakeCommand extends GeneratorCommand
protected function writeMarkdownTemplate()
{
$path = $this->viewPath(
str_replace('.', '/', $this->option('markdown')).'.blade.php'
str_replace('.', '/', $this->getView()).'.blade.php'
);
if (! $this->files->isDirectory(dirname($path))) {
@@ -72,13 +76,29 @@ class MailMakeCommand extends GeneratorCommand
{
$class = parent::buildClass($name);
if ($this->option('markdown')) {
$class = str_replace('DummyView', $this->option('markdown'), $class);
if ($this->option('markdown') !== false) {
$class = str_replace(['DummyView', '{{ view }}'], $this->getView(), $class);
}
return $class;
}
/**
* Get the view name.
*
* @return string
*/
protected function getView()
{
$view = $this->option('markdown');
if (! $view) {
$view = 'mail.'.Str::kebab(class_basename($this->argument('name')));
}
return $view;
}
/**
* Get the stub file for the generator.
*
@@ -86,9 +106,23 @@ class MailMakeCommand extends GeneratorCommand
*/
protected function getStub()
{
return $this->option('markdown')
? __DIR__.'/stubs/markdown-mail.stub'
: __DIR__.'/stubs/mail.stub';
return $this->resolveStubPath(
$this->option('markdown') !== false
? '/stubs/markdown-mail.stub'
: '/stubs/mail.stub');
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**
@@ -112,7 +146,7 @@ class MailMakeCommand extends GeneratorCommand
return [
['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the mailable already exists'],
['markdown', 'm', InputOption::VALUE_OPTIONAL, 'Create a new Markdown template for the mailable'],
['markdown', 'm', InputOption::VALUE_OPTIONAL, 'Create a new Markdown template for the mailable', false],
];
}
}

View File

@@ -2,12 +2,15 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;
class ModelMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*
@@ -45,6 +48,7 @@ class ModelMakeCommand extends GeneratorCommand
$this->input->setOption('seed', true);
$this->input->setOption('migration', true);
$this->input->setOption('controller', true);
$this->input->setOption('policy', true);
$this->input->setOption('resource', true);
}
@@ -63,6 +67,10 @@ class ModelMakeCommand extends GeneratorCommand
if ($this->option('controller') || $this->option('resource') || $this->option('api')) {
$this->createController();
}
if ($this->option('policy')) {
$this->createPolicy();
}
}
/**
@@ -72,7 +80,7 @@ class ModelMakeCommand extends GeneratorCommand
*/
protected function createFactory()
{
$factory = Str::studly(class_basename($this->argument('name')));
$factory = Str::studly($this->argument('name'));
$this->call('make:factory', [
'name' => "{$factory}Factory",
@@ -108,7 +116,7 @@ class ModelMakeCommand extends GeneratorCommand
{
$seeder = Str::studly(class_basename($this->argument('name')));
$this->call('make:seed', [
$this->call('make:seeder', [
'name' => "{$seeder}Seeder",
]);
}
@@ -125,12 +133,28 @@ class ModelMakeCommand extends GeneratorCommand
$modelName = $this->qualifyClass($this->getNameInput());
$this->call('make:controller', array_filter([
'name' => "{$controller}Controller",
'name' => "{$controller}Controller",
'--model' => $this->option('resource') || $this->option('api') ? $modelName : null,
'--api' => $this->option('api'),
'--requests' => $this->option('requests') || $this->option('all'),
]));
}
/**
* Create a policy file for the model.
*
* @return void
*/
protected function createPolicy()
{
$policy = Str::studly(class_basename($this->argument('name')));
$this->call('make:policy', [
'name' => "{$policy}Policy",
'--model' => $this->qualifyClass($this->getNameInput()),
]);
}
/**
* Get the stub file for the generator.
*
@@ -156,6 +180,17 @@ class ModelMakeCommand extends GeneratorCommand
: __DIR__.$stub;
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return is_dir(app_path('Models')) ? $rootNamespace.'\\Models' : $rootNamespace;
}
/**
* Get the console command options.
*
@@ -164,15 +199,17 @@ class ModelMakeCommand extends GeneratorCommand
protected function getOptions()
{
return [
['all', 'a', InputOption::VALUE_NONE, 'Generate a migration, seeder, factory, and resource controller for the model'],
['all', 'a', InputOption::VALUE_NONE, 'Generate a migration, seeder, factory, policy, and resource controller for the model'],
['controller', 'c', InputOption::VALUE_NONE, 'Create a new controller for the model'],
['factory', 'f', InputOption::VALUE_NONE, 'Create a new factory for the model'],
['force', null, InputOption::VALUE_NONE, 'Create the class even if the model already exists'],
['migration', 'm', InputOption::VALUE_NONE, 'Create a new migration file for the model'],
['seed', 's', InputOption::VALUE_NONE, 'Create a new seeder file for the model'],
['policy', null, InputOption::VALUE_NONE, 'Create a new policy for the model'],
['seed', 's', InputOption::VALUE_NONE, 'Create a new seeder for the model'],
['pivot', 'p', InputOption::VALUE_NONE, 'Indicates if the generated model should be a custom intermediate table model'],
['resource', 'r', InputOption::VALUE_NONE, 'Indicates if the generated controller should be a resource controller'],
['api', null, InputOption::VALUE_NONE, 'Indicates if the generated controller should be an API controller'],
['requests', 'R', InputOption::VALUE_NONE, 'Create new form request classes and use them in the resource controller'],
];
}
}

View File

@@ -2,11 +2,14 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputOption;
class NotificationMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*
@@ -73,7 +76,7 @@ class NotificationMakeCommand extends GeneratorCommand
$class = parent::buildClass($name);
if ($this->option('markdown')) {
$class = str_replace('DummyView', $this->option('markdown'), $class);
$class = str_replace(['DummyView', '{{ view }}'], $this->option('markdown'), $class);
}
return $class;
@@ -87,8 +90,21 @@ class NotificationMakeCommand extends GeneratorCommand
protected function getStub()
{
return $this->option('markdown')
? __DIR__.'/stubs/markdown-notification.stub'
: __DIR__.'/stubs/notification.stub';
? $this->resolveStubPath('/stubs/markdown-notification.stub')
: $this->resolveStubPath('/stubs/notification.stub');
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**

View File

@@ -3,7 +3,7 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;
class ObserverMakeCommand extends GeneratorCommand
@@ -44,18 +44,6 @@ class ObserverMakeCommand extends GeneratorCommand
return $model ? $this->replaceModel($stub, $model) : $stub;
}
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return $this->option('model')
? __DIR__.'/stubs/observer.stub'
: __DIR__.'/stubs/observer.plain.stub';
}
/**
* Replace the model for the given stub.
*
@@ -65,27 +53,65 @@ class ObserverMakeCommand extends GeneratorCommand
*/
protected function replaceModel($stub, $model)
{
$model = str_replace('/', '\\', $model);
$modelClass = $this->parseModel($model);
$namespaceModel = $this->laravel->getNamespace().$model;
$replace = [
'DummyFullModelClass' => $modelClass,
'{{ namespacedModel }}' => $modelClass,
'{{namespacedModel}}' => $modelClass,
'DummyModelClass' => class_basename($modelClass),
'{{ model }}' => class_basename($modelClass),
'{{model}}' => class_basename($modelClass),
'DummyModelVariable' => lcfirst(class_basename($modelClass)),
'{{ modelVariable }}' => lcfirst(class_basename($modelClass)),
'{{modelVariable}}' => lcfirst(class_basename($modelClass)),
];
if (Str::startsWith($model, '\\')) {
$stub = str_replace('NamespacedDummyModel', trim($model, '\\'), $stub);
} else {
$stub = str_replace('NamespacedDummyModel', $namespaceModel, $stub);
return str_replace(
array_keys($replace), array_values($replace), $stub
);
}
/**
* Get the fully-qualified model class name.
*
* @param string $model
* @return string
*
* @throws \InvalidArgumentException
*/
protected function parseModel($model)
{
if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
throw new InvalidArgumentException('Model name contains invalid characters.');
}
$stub = str_replace(
"use {$namespaceModel};\nuse {$namespaceModel};", "use {$namespaceModel};", $stub
);
return $this->qualifyModel($model);
}
$model = class_basename(trim($model, '\\'));
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return $this->option('model')
? $this->resolveStubPath('/stubs/observer.stub')
: $this->resolveStubPath('/stubs/observer.plain.stub');
}
$stub = str_replace('DocDummyModel', Str::snake($model, ' '), $stub);
$stub = str_replace('DummyModel', $model, $stub);
return str_replace('dummyModel', Str::camel($model), $stub);
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**

View File

@@ -27,6 +27,7 @@ class OptimizeClearCommand extends Command
*/
public function handle()
{
$this->call('event:clear');
$this->call('view:clear');
$this->call('cache:clear');
$this->call('route:clear');

View File

@@ -4,6 +4,7 @@ namespace Illuminate\Foundation\Console;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use LogicException;
use Symfony\Component\Console\Input\InputOption;
class PolicyMakeCommand extends GeneratorCommand
@@ -71,6 +72,8 @@ class PolicyMakeCommand extends GeneratorCommand
* Get the model for the guard's user provider.
*
* @return string|null
*
* @throws \LogicException
*/
protected function userProviderModel()
{
@@ -78,8 +81,16 @@ class PolicyMakeCommand extends GeneratorCommand
$guard = $this->option('guard') ?: $config->get('auth.defaults.guard');
if (is_null($guardProvider = $config->get('auth.guards.'.$guard.'.provider'))) {
throw new LogicException('The ['.$guard.'] guard is not defined in your "auth" configuration file.');
}
if (! $config->get('auth.providers.'.$guardProvider.'.model')) {
return 'App\\Models\\User';
}
return $config->get(
'auth.providers.'.$config->get('auth.guards.'.$guard.'.provider').'.model'
'auth.providers.'.$guardProvider.'.model'
);
}
@@ -97,7 +108,7 @@ class PolicyMakeCommand extends GeneratorCommand
if (Str::startsWith($model, '\\')) {
$namespacedModel = trim($model, '\\');
} else {
$namespacedModel = $this->laravel->getNamespace().$model;
$namespacedModel = $this->qualifyModel($model);
}
$model = class_basename(trim($model, '\\'));
@@ -126,8 +137,13 @@ class PolicyMakeCommand extends GeneratorCommand
array_keys($replace), array_values($replace), $stub
);
return str_replace(
"use {$namespacedModel};\nuse {$namespacedModel};", "use {$namespacedModel};", $stub
return preg_replace(
vsprintf('/use %s;[\r\n]+use %s;/', [
preg_quote($namespacedModel, '/'),
preg_quote($namespacedModel, '/'),
]),
"use {$namespacedModel};",
$stub
);
}

View File

@@ -34,7 +34,20 @@ class ProviderMakeCommand extends GeneratorCommand
*/
protected function getStub()
{
return __DIR__.'/stubs/provider.stub';
return $this->resolveStubPath('/stubs/provider.stub');
}
/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}
/**

View File

@@ -36,14 +36,14 @@ class RouteListCommand extends Command
/**
* The table headers for the command.
*
* @var array
* @var string[]
*/
protected $headers = ['Domain', 'Method', 'URI', 'Name', 'Action', 'Middleware'];
/**
* The columns to display when using the "compact" flag.
*
* @var array
* @var string[]
*/
protected $compactColumns = ['method', 'uri', 'action'];
@@ -67,6 +67,8 @@ class RouteListCommand extends Command
*/
public function handle()
{
$this->router->flushMiddlewareGroups();
if (empty($this->router->getRoutes())) {
return $this->error("Your application doesn't have any routes.");
}
@@ -89,7 +91,7 @@ class RouteListCommand extends Command
return $this->getRouteInformation($route);
})->filter()->all();
if ($sort = $this->option('sort')) {
if (($sort = $this->option('sort')) !== 'precedence') {
$routes = $this->sortRoutes($sort, $routes);
}
@@ -111,8 +113,8 @@ class RouteListCommand extends Command
return $this->filterRoute([
'domain' => $route->domain(),
'method' => implode('|', $route->methods()),
'uri' => $route->uri(),
'name' => $route->getName(),
'uri' => $route->uri(),
'name' => $route->getName(),
'action' => ltrim($route->getActionName(), '\\'),
'middleware' => $this->getMiddleware($route),
]);
@@ -154,7 +156,7 @@ class RouteListCommand extends Command
protected function displayRoutes(array $routes)
{
if ($this->option('json')) {
$this->line(json_encode(array_values($routes)));
$this->line($this->asJson($routes));
return;
}
@@ -163,7 +165,7 @@ class RouteListCommand extends Command
}
/**
* Get before filters.
* Get the middleware for the route.
*
* @param \Illuminate\Routing\Route $route
* @return string
@@ -189,6 +191,14 @@ class RouteListCommand extends Command
return;
}
if ($this->option('except-path')) {
foreach (explode(',', $this->option('except-path')) as $path) {
if (Str::contains($route['uri'], $path)) {
return;
}
}
}
return $route;
}
@@ -243,6 +253,24 @@ class RouteListCommand extends Command
return array_map('strtolower', $results);
}
/**
* Convert the given routes to JSON.
*
* @param array $routes
* @return string
*/
protected function asJson(array $routes)
{
return collect($routes)
->map(function ($route) {
$route['middleware'] = empty($route['middleware']) ? [] : explode("\n", $route['middleware']);
return $route;
})
->values()
->toJson();
}
/**
* Get the console command options.
*
@@ -256,9 +284,10 @@ class RouteListCommand extends Command
['json', null, InputOption::VALUE_NONE, 'Output the route list as JSON'],
['method', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by method'],
['name', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by name'],
['path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by path'],
['path', null, InputOption::VALUE_OPTIONAL, 'Only show routes matching the given path pattern'],
['except-path', null, InputOption::VALUE_OPTIONAL, 'Do not display the routes matching the given path pattern'],
['reverse', 'r', InputOption::VALUE_NONE, 'Reverse the ordering of the routes'],
['sort', null, InputOption::VALUE_OPTIONAL, 'The column (domain, method, uri, name, action, middleware) to sort by', 'uri'],
['sort', null, InputOption::VALUE_OPTIONAL, 'The column (precedence, domain, method, uri, name, action, middleware) to sort by', 'uri'],
];
}
}

View File

@@ -3,6 +3,7 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputOption;
class RuleMakeCommand extends GeneratorCommand
{
@@ -27,6 +28,23 @@ class RuleMakeCommand extends GeneratorCommand
*/
protected $type = 'Rule';
/**
* Build the class with the given name.
*
* @param string $name
* @return string
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function buildClass($name)
{
return str_replace(
'{{ ruleType }}',
$this->option('implicit') ? 'ImplicitRule' : 'Rule',
parent::buildClass($name)
);
}
/**
* Get the stub file for the generator.
*
@@ -51,4 +69,16 @@ class RuleMakeCommand extends GeneratorCommand
{
return $rootNamespace.'\Rules';
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['implicit', 'i', InputOption::VALUE_NONE, 'Generate an implicit rule.'],
];
}
}

View File

@@ -4,9 +4,9 @@ namespace Illuminate\Foundation\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Env;
use Illuminate\Support\ProcessUtils;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
class ServeCommand extends Command
{
@@ -42,9 +42,41 @@ class ServeCommand extends Command
{
chdir(public_path());
$this->line("<info>Laravel development server started:</info> http://{$this->host()}:{$this->port()}");
$this->line("<info>Starting Laravel development server:</info> http://{$this->host()}:{$this->port()}");
passthru($this->serverCommand(), $status);
$environmentFile = $this->option('env')
? base_path('.env').'.'.$this->option('env')
: base_path('.env');
$hasEnvironment = file_exists($environmentFile);
$environmentLastModified = $hasEnvironment
? filemtime($environmentFile)
: now()->addDays(30)->getTimestamp();
$process = $this->startProcess($hasEnvironment);
while ($process->isRunning()) {
if ($hasEnvironment) {
clearstatcache(false, $environmentFile);
}
if (! $this->option('no-reload') &&
$hasEnvironment &&
filemtime($environmentFile) > $environmentLastModified) {
$environmentLastModified = filemtime($environmentFile);
$this->comment('Environment modified. Restarting server...');
$process->stop(5);
$process = $this->startProcess($hasEnvironment);
}
usleep(500 * 1000);
}
$status = $process->getExitCode();
if ($status && $this->canTryAnotherPort()) {
$this->portOffset += 1;
@@ -55,19 +87,51 @@ class ServeCommand extends Command
return $status;
}
/**
* Start a new server process.
*
* @param bool $hasEnvironment
* @return \Symfony\Component\Process\Process
*/
protected function startProcess($hasEnvironment)
{
$process = new Process($this->serverCommand(), null, collect($_ENV)->mapWithKeys(function ($value, $key) use ($hasEnvironment) {
if ($this->option('no-reload') || ! $hasEnvironment) {
return [$key => $value];
}
return in_array($key, [
'APP_ENV',
'LARAVEL_SAIL',
'PHP_CLI_SERVER_WORKERS',
'PHP_IDE_CONFIG',
'SYSTEMROOT',
'XDEBUG_CONFIG',
'XDEBUG_MODE',
'XDEBUG_SESSION',
]) ? [$key => $value] : [$key => false];
})->all());
$process->start(function ($type, $buffer) {
$this->output->write($buffer);
});
return $process;
}
/**
* Get the full server command.
*
* @return string
* @return array
*/
protected function serverCommand()
{
return sprintf('%s -S %s:%s %s',
ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)),
$this->host(),
$this->port(),
ProcessUtils::escapeArgument(base_path('server.php'))
);
return [
(new PhpExecutableFinder)->find(false),
'-S',
$this->host().':'.$this->port(),
base_path('server.php'),
];
}
/**
@@ -77,7 +141,9 @@ class ServeCommand extends Command
*/
protected function host()
{
return $this->input->getOption('host');
[$host, ] = $this->getHostAndPort();
return $host;
}
/**
@@ -87,13 +153,34 @@ class ServeCommand extends Command
*/
protected function port()
{
$port = $this->input->getOption('port') ?: 8000;
$port = $this->input->getOption('port');
if (is_null($port)) {
[, $port] = $this->getHostAndPort();
}
$port = $port ?: 8000;
return $port + $this->portOffset;
}
/**
* Check if command has reached its max amount of port tries.
* Get the host and port from the host option string.
*
* @return array
*/
protected function getHostAndPort()
{
$hostParts = explode(':', $this->input->getOption('host'));
return [
$hostParts[0],
$hostParts[1] ?? null,
];
}
/**
* Check if the command has reached its max amount of port tries.
*
* @return bool
*/
@@ -112,10 +199,9 @@ class ServeCommand extends Command
{
return [
['host', null, InputOption::VALUE_OPTIONAL, 'The host address to serve the application on', '127.0.0.1'],
['port', null, InputOption::VALUE_OPTIONAL, 'The port to serve the application on', Env::get('SERVER_PORT')],
['tries', null, InputOption::VALUE_OPTIONAL, 'The max number of ports to attempt to serve from', 10],
['no-reload', null, InputOption::VALUE_NONE, 'Do not reload the development server on .env file changes'],
];
}
}

View File

@@ -3,8 +3,6 @@
namespace Illuminate\Foundation\Console;
use Illuminate\Console\Command;
use RuntimeException;
use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
class StorageLinkCommand extends Command
{
@@ -13,7 +11,9 @@ class StorageLinkCommand extends Command
*
* @var string
*/
protected $signature = 'storage:link {--relative : Create the symbolic link using relative paths}';
protected $signature = 'storage:link
{--relative : Create the symbolic link using relative paths}
{--force : Recreate existing symbolic links}';
/**
* The console command description.
@@ -29,18 +29,25 @@ class StorageLinkCommand extends Command
*/
public function handle()
{
$relative = $this->option('relative');
foreach ($this->links() as $link => $target) {
if (file_exists($link)) {
if (file_exists($link) && ! $this->isRemovableSymlink($link, $this->option('force'))) {
$this->error("The [$link] link already exists.");
} else {
if ($this->option('relative')) {
$target = $this->getRelativeTarget($link, $target);
}
$this->laravel->make('files')->link($target, $link);
$this->info("The [$link] link has been connected to [$target].");
continue;
}
if (is_link($link)) {
$this->laravel->make('files')->delete($link);
}
if ($relative) {
$this->laravel->make('files')->relativeLink($target, $link);
} else {
$this->laravel->make('files')->link($target, $link);
}
$this->info("The [$link] link has been connected to [$target].");
}
$this->info('The links have been created.');
@@ -58,18 +65,14 @@ class StorageLinkCommand extends Command
}
/**
* Get the relative path to the target.
* Determine if the provided path is a symlink that can be removed.
*
* @param string $link
* @param string $target
* @return string
* @param bool $force
* @return bool
*/
protected function getRelativeTarget($link, $target)
protected function isRemovableSymlink(string $link, bool $force): bool
{
if (! class_exists(SymfonyFilesystem::class)) {
throw new RuntimeException('To enable support for relative links, please install the symfony/filesystem package.');
}
return (new SymfonyFilesystem)->makePathRelative($target, dirname($link));
return is_link($link) && $force;
}
}

View File

@@ -33,24 +33,34 @@ class StubPublishCommand extends Command
}
$files = [
__DIR__.'/stubs/cast.stub' => $stubsPath.'/cast.stub',
__DIR__.'/stubs/console.stub' => $stubsPath.'/console.stub',
__DIR__.'/stubs/event.stub' => $stubsPath.'/event.stub',
__DIR__.'/stubs/job.queued.stub' => $stubsPath.'/job.queued.stub',
__DIR__.'/stubs/job.stub' => $stubsPath.'/job.stub',
__DIR__.'/stubs/mail.stub' => $stubsPath.'/mail.stub',
__DIR__.'/stubs/markdown-mail.stub' => $stubsPath.'/markdown-mail.stub',
__DIR__.'/stubs/markdown-notification.stub' => $stubsPath.'/markdown-notification.stub',
__DIR__.'/stubs/model.pivot.stub' => $stubsPath.'/model.pivot.stub',
__DIR__.'/stubs/model.stub' => $stubsPath.'/model.stub',
__DIR__.'/stubs/notification.stub' => $stubsPath.'/notification.stub',
__DIR__.'/stubs/observer.plain.stub' => $stubsPath.'/observer.plain.stub',
__DIR__.'/stubs/observer.stub' => $stubsPath.'/observer.stub',
__DIR__.'/stubs/policy.plain.stub' => $stubsPath.'/policy.plain.stub',
__DIR__.'/stubs/policy.stub' => $stubsPath.'/policy.stub',
__DIR__.'/stubs/provider.stub' => $stubsPath.'/provider.stub',
__DIR__.'/stubs/request.stub' => $stubsPath.'/request.stub',
__DIR__.'/stubs/resource.stub' => $stubsPath.'/resource.stub',
__DIR__.'/stubs/resource-collection.stub' => $stubsPath.'/resource-collection.stub',
__DIR__.'/stubs/resource.stub' => $stubsPath.'/resource.stub',
__DIR__.'/stubs/rule.stub' => $stubsPath.'/rule.stub',
__DIR__.'/stubs/test.stub' => $stubsPath.'/test.stub',
__DIR__.'/stubs/test.unit.stub' => $stubsPath.'/test.unit.stub',
__DIR__.'/stubs/view-component.stub' => $stubsPath.'/view-component.stub',
realpath(__DIR__.'/../../Database/Console/Factories/stubs/factory.stub') => $stubsPath.'/factory.stub',
realpath(__DIR__.'/../../Database/Console/Seeds/stubs/seeder.stub') => $stubsPath.'/seeder.stub',
realpath(__DIR__.'/../../Database/Migrations/stubs/migration.create.stub') => $stubsPath.'/migration.create.stub',
realpath(__DIR__.'/../../Database/Migrations/stubs/migration.stub') => $stubsPath.'/migration.stub',
realpath(__DIR__.'/../../Database/Migrations/stubs/migration.update.stub') => $stubsPath.'/migration.update.stub',
realpath(__DIR__.'/../../Foundation/Console/stubs/console.stub') => $stubsPath.'/console.stub',
realpath(__DIR__.'/../../Foundation/Console/stubs/policy.plain.stub') => $stubsPath.'/policy.plain.stub',
realpath(__DIR__.'/../../Foundation/Console/stubs/policy.stub') => $stubsPath.'/policy.stub',
realpath(__DIR__.'/../../Foundation/Console/stubs/rule.stub') => $stubsPath.'/rule.stub',
realpath(__DIR__.'/../../Routing/Console/stubs/controller.api.stub') => $stubsPath.'/controller.api.stub',
realpath(__DIR__.'/../../Routing/Console/stubs/controller.invokable.stub') => $stubsPath.'/controller.invokable.stub',
realpath(__DIR__.'/../../Routing/Console/stubs/controller.model.api.stub') => $stubsPath.'/controller.model.api.stub',

View File

@@ -4,6 +4,7 @@ namespace Illuminate\Foundation\Console;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;
class TestMakeCommand extends GeneratorCommand
{
@@ -12,7 +13,7 @@ class TestMakeCommand extends GeneratorCommand
*
* @var string
*/
protected $signature = 'make:test {name : The name of the class} {--unit : Create a unit test}';
protected $name = 'make:test';
/**
* The console command description.
@@ -35,9 +36,11 @@ class TestMakeCommand extends GeneratorCommand
*/
protected function getStub()
{
return $this->option('unit')
? $this->resolveStubPath('/stubs/test.unit.stub')
: $this->resolveStubPath('/stubs/test.stub');
$suffix = $this->option('unit') ? '.unit.stub' : '.stub';
return $this->option('pest')
? $this->resolveStubPath('/stubs/pest'.$suffix)
: $this->resolveStubPath('/stubs/test'.$suffix);
}
/**
@@ -90,4 +93,17 @@ class TestMakeCommand extends GeneratorCommand
{
return 'Tests';
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['unit', 'u', InputOption::VALUE_NONE, 'Create a unit test.'],
['pest', 'p', InputOption::VALUE_NONE, 'Create a Pest test.'],
];
}
}

View File

@@ -4,6 +4,7 @@ namespace Illuminate\Foundation\Console;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Foundation\Events\MaintenanceModeDisabled;
class UpCommand extends Command
{
@@ -29,14 +30,20 @@ class UpCommand extends Command
public function handle()
{
try {
if (! file_exists(storage_path('framework/down'))) {
if (! is_file(storage_path('framework/down'))) {
$this->comment('Application is already up.');
return true;
return 0;
}
unlink(storage_path('framework/down'));
if (is_file(storage_path('framework/maintenance.php'))) {
unlink(storage_path('framework/maintenance.php'));
}
$this->laravel->get('events')->dispatch(MaintenanceModeDisabled::class);
$this->info('Application is now live.');
} catch (Exception $e) {
$this->error('Failed to disable maintenance mode.');

View File

@@ -4,6 +4,7 @@ namespace Illuminate\Foundation\Console;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Foundation\Events\VendorTagPublished;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
use League\Flysystem\Adapter\Local as LocalAdapter;
@@ -159,14 +160,18 @@ class VendorPublishCommand extends Command
{
$published = false;
foreach ($this->pathsToPublish($tag) as $from => $to) {
$pathsToPublish = $this->pathsToPublish($tag);
foreach ($pathsToPublish as $from => $to) {
$this->publishItem($from, $to);
$published = true;
}
if ($published === false) {
$this->error('Unable to locate publishable resources.');
$this->comment('No publishable resources for tag ['.$tag.'].');
} else {
$this->laravel['events']->dispatch(new VendorTagPublished($tag, $pathsToPublish));
}
}

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class DummyClass implements CastsAttributes
class {{ class }} implements CastsAttributes
{
/**
* Cast the given value.
@@ -15,7 +15,7 @@ class DummyClass implements CastsAttributes
* @param array $attributes
* @return mixed
*/
public function get($model, $key, $value, $attributes)
public function get($model, string $key, $value, array $attributes)
{
return $value;
}
@@ -25,11 +25,11 @@ class DummyClass implements CastsAttributes
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param array $value
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function set($model, $key, $value, $attributes)
public function set($model, string $key, $value, array $attributes)
{
return $value;
}

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use NamespacedDummyUserModel;
use {{ namespacedUserModel }};
class DummyClass
class {{ class }}
{
/**
* Create a new channel instance.
@@ -19,10 +19,10 @@ class DummyClass
/**
* Authenticate the user's access to the channel.
*
* @param \NamespacedDummyUserModel $user
* @param \{{ namespacedUserModel }} $user
* @return array|bool
*/
public function join(DummyUser $user)
public function join({{ userModel }} $user)
{
//
}

View File

@@ -1,6 +1,6 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
@@ -10,7 +10,7 @@ use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class DummyClass
class {{ class }}
{
use Dispatchable, InteractsWithSockets, SerializesModels;

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Exception;
class DummyClass extends Exception
class {{ class }} extends Exception
{
/**
* Report the exception.

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Exception;
class DummyClass extends Exception
class {{ class }} extends Exception
{
/**
* Render the exception as an HTTP response.

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Exception;
class DummyClass extends Exception
class {{ class }} extends Exception
{
/**
* Report the exception.

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Exception;
class DummyClass extends Exception
class {{ class }} extends Exception
{
//
}

View File

@@ -3,6 +3,7 @@
namespace {{ namespace }};
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;

View File

@@ -1,11 +1,11 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class DummyClass
class {{ class }}
{
/**
* Create the event listener.

View File

@@ -1,11 +1,11 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class DummyClass implements ShouldQueue
class {{ class }} implements ShouldQueue
{
use InteractsWithQueue;

View File

@@ -1,12 +1,12 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use DummyFullEvent;
use {{ eventNamespace }};
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class DummyClass implements ShouldQueue
class {{ class }} implements ShouldQueue
{
use InteractsWithQueue;
@@ -23,10 +23,10 @@ class DummyClass implements ShouldQueue
/**
* Handle the event.
*
* @param DummyEvent $event
* @param {{ eventNamespace }} $event
* @return void
*/
public function handle(DummyEvent $event)
public function handle({{ event }} $event)
{
//
}

View File

@@ -1,12 +1,12 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use DummyFullEvent;
use {{ eventNamespace }};
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class DummyClass
class {{ class }}
{
/**
* Create the event listener.
@@ -21,10 +21,10 @@ class DummyClass
/**
* Handle the event.
*
* @param DummyEvent $event
* @param \{{ eventNamespace }} $event
* @return void
*/
public function handle(DummyEvent $event)
public function handle({{ event }} $event)
{
//
}

View File

@@ -1,13 +1,13 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class DummyClass extends Mailable
class {{ class }} extends Mailable
{
use Queueable, SerializesModels;

View File

@@ -1,13 +1,13 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class DummyClass extends Mailable
class {{ class }} extends Mailable
{
use Queueable, SerializesModels;
@@ -28,6 +28,6 @@ class DummyClass extends Mailable
*/
public function build()
{
return $this->markdown('DummyView');
return $this->markdown('{{ view }}');
}
}

View File

@@ -1,13 +1,13 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class DummyClass extends Notification
class {{ class }} extends Notification
{
use Queueable;
@@ -40,7 +40,7 @@ class DummyClass extends Notification
*/
public function toMail($notifiable)
{
return (new MailMessage)->markdown('DummyView');
return (new MailMessage)->markdown('{{ view }}');
}
/**

View File

@@ -2,9 +2,10 @@
namespace {{ namespace }};
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class {{ class }} extends Model
{
//
use HasFactory;
}

View File

@@ -1,13 +1,13 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class DummyClass extends Notification
class {{ class }} extends Notification
{
use Queueable;

View File

@@ -1,8 +1,8 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
class DummyClass
class {{ class }}
{
//
}

View File

@@ -1,62 +1,62 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use NamespacedDummyModel;
use {{ namespacedModel }};
class DummyClass
class {{ class }}
{
/**
* Handle the DocDummyModel "created" event.
* Handle the {{ model }} "created" event.
*
* @param \NamespacedDummyModel $dummyModel
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return void
*/
public function created(DummyModel $dummyModel)
public function created({{ model }} ${{ modelVariable }})
{
//
}
/**
* Handle the DocDummyModel "updated" event.
* Handle the {{ model }} "updated" event.
*
* @param \NamespacedDummyModel $dummyModel
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return void
*/
public function updated(DummyModel $dummyModel)
public function updated({{ model }} ${{ modelVariable }})
{
//
}
/**
* Handle the DocDummyModel "deleted" event.
* Handle the {{ model }} "deleted" event.
*
* @param \NamespacedDummyModel $dummyModel
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return void
*/
public function deleted(DummyModel $dummyModel)
public function deleted({{ model }} ${{ modelVariable }})
{
//
}
/**
* Handle the DocDummyModel "restored" event.
* Handle the {{ model }} "restored" event.
*
* @param \NamespacedDummyModel $dummyModel
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return void
*/
public function restored(DummyModel $dummyModel)
public function restored({{ model }} ${{ modelVariable }})
{
//
}
/**
* Handle the DocDummyModel "force deleted" event.
* Handle the {{ model }} "force deleted" event.
*
* @param \NamespacedDummyModel $dummyModel
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return void
*/
public function forceDeleted(DummyModel $dummyModel)
public function forceDeleted({{ model }} ${{ modelVariable }})
{
//
}

View File

@@ -14,7 +14,7 @@ class {{ class }}
* Determine whether the user can view any models.
*
* @param \{{ namespacedUserModel }} $user
* @return mixed
* @return \Illuminate\Auth\Access\Response|bool
*/
public function viewAny({{ user }} $user)
{
@@ -26,7 +26,7 @@ class {{ class }}
*
* @param \{{ namespacedUserModel }} $user
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return mixed
* @return \Illuminate\Auth\Access\Response|bool
*/
public function view({{ user }} $user, {{ model }} ${{ modelVariable }})
{
@@ -37,7 +37,7 @@ class {{ class }}
* Determine whether the user can create models.
*
* @param \{{ namespacedUserModel }} $user
* @return mixed
* @return \Illuminate\Auth\Access\Response|bool
*/
public function create({{ user }} $user)
{
@@ -49,7 +49,7 @@ class {{ class }}
*
* @param \{{ namespacedUserModel }} $user
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return mixed
* @return \Illuminate\Auth\Access\Response|bool
*/
public function update({{ user }} $user, {{ model }} ${{ modelVariable }})
{
@@ -61,7 +61,7 @@ class {{ class }}
*
* @param \{{ namespacedUserModel }} $user
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return mixed
* @return \Illuminate\Auth\Access\Response|bool
*/
public function delete({{ user }} $user, {{ model }} ${{ modelVariable }})
{
@@ -73,7 +73,7 @@ class {{ class }}
*
* @param \{{ namespacedUserModel }} $user
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return mixed
* @return \Illuminate\Auth\Access\Response|bool
*/
public function restore({{ user }} $user, {{ model }} ${{ modelVariable }})
{
@@ -85,7 +85,7 @@ class {{ class }}
*
* @param \{{ namespacedUserModel }} $user
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return mixed
* @return \Illuminate\Auth\Access\Response|bool
*/
public function forceDelete({{ user }} $user, {{ model }} ${{ modelVariable }})
{

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\Support\ServiceProvider;
class DummyClass extends ServiceProvider
class {{ class }} extends ServiceProvider
{
/**
* Register services.

View File

@@ -10,7 +10,7 @@ class {{ class }} extends ResourceCollection
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{

View File

@@ -10,7 +10,7 @@ class {{ class }} extends JsonResource
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{

View File

@@ -2,9 +2,9 @@
namespace {{ namespace }};
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\{{ ruleType }};
class {{ class }} implements Rule
class {{ class }} implements {{ ruleType }}
{
/**
* Create a new rule instance.

View File

@@ -13,7 +13,7 @@ class {{ class }} extends TestCase
*
* @return void
*/
public function testExample()
public function test_example()
{
$response = $this->get('/');

View File

@@ -11,7 +11,7 @@ class {{ class }} extends TestCase
*
* @return void
*/
public function testExample()
public function test_example()
{
$this->assertTrue(true);
}

View File

@@ -1,10 +1,10 @@
<?php
namespace DummyNamespace;
namespace {{ namespace }};
use Illuminate\View\Component;
class DummyClass extends Component
class {{ class }} extends Component
{
/**
* Create a new component instance.
@@ -19,10 +19,10 @@ class DummyClass extends Component
/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\View\View|string
* @return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
return DummyView;
return {{ view }};
}
}

View File

@@ -21,11 +21,23 @@ class DiscoverEvents
*/
public static function within($listenerPath, $basePath)
{
return collect(static::getListenerEvents(
$listeners = collect(static::getListenerEvents(
(new Finder)->files()->in($listenerPath), $basePath
))->mapToDictionary(function ($event, $listener) {
return [$event => $listener];
})->all();
));
$discoveredEvents = [];
foreach ($listeners as $listener => $events) {
foreach ($events as $event) {
if (! isset($discoveredEvents[$event])) {
$discoveredEvents[$event] = [];
}
$discoveredEvents[$event][] = $listener;
}
}
return $discoveredEvents;
}
/**
@@ -59,7 +71,7 @@ class DiscoverEvents
}
$listenerEvents[$listener->name.'@'.$method->name] =
Reflector::getParameterClassName($method->getParameters()[0]);
Reflector::getParameterClassNames($method->getParameters()[0]);
}
}

View File

@@ -18,6 +18,7 @@ trait Dispatchable
* Dispatch the event with the given arguments if the given truth test passes.
*
* @param bool $boolean
* @param mixed ...$arguments
* @return void
*/
public static function dispatchIf($boolean, ...$arguments)
@@ -31,6 +32,7 @@ trait Dispatchable
* Dispatch the event with the given arguments unless the given truth test passes.
*
* @param bool $boolean
* @param mixed ...$arguments
* @return void
*/
public static function dispatchUnless($boolean, ...$arguments)

View File

@@ -2,6 +2,7 @@
namespace Illuminate\Foundation\Exceptions;
use Closure;
use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
@@ -10,6 +11,8 @@ use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\MultipleRecordsFoundException;
use Illuminate\Database\RecordsNotFoundException;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
@@ -18,10 +21,11 @@ use Illuminate\Routing\Router;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Reflector;
use Illuminate\Support\Traits\ReflectsClosures;
use Illuminate\Support\ViewErrorBag;
use Illuminate\Validation\ValidationException;
use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
@@ -38,6 +42,8 @@ use Whoops\Run as Whoops;
class Handler implements ExceptionHandlerContract
{
use ReflectsClosures;
/**
* The container implementation.
*
@@ -48,14 +54,35 @@ class Handler implements ExceptionHandlerContract
/**
* A list of the exception types that are not reported.
*
* @var array
* @var string[]
*/
protected $dontReport = [];
/**
* The callbacks that should be used during reporting.
*
* @var \Illuminate\Foundation\Exceptions\ReportableHandler[]
*/
protected $reportCallbacks = [];
/**
* The callbacks that should be used during rendering.
*
* @var \Closure[]
*/
protected $renderCallbacks = [];
/**
* The registered exception mappings.
*
* @var array<string, \Closure>
*/
protected $exceptionMap = [];
/**
* A list of the internal exception types that should not be reported.
*
* @var array
* @var string[]
*/
protected $internalDontReport = [
AuthenticationException::class,
@@ -63,6 +90,8 @@ class Handler implements ExceptionHandlerContract
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
MultipleRecordsFoundException::class,
RecordsNotFoundException::class,
SuspiciousOperationException::class,
TokenMismatchException::class,
ValidationException::class,
@@ -71,9 +100,10 @@ class Handler implements ExceptionHandlerContract
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
* @var string[]
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
@@ -87,6 +117,95 @@ class Handler implements ExceptionHandlerContract
public function __construct(Container $container)
{
$this->container = $container;
$this->register();
}
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
//
}
/**
* Register a reportable callback.
*
* @param callable $reportUsing
* @return \Illuminate\Foundation\Exceptions\ReportableHandler
*/
public function reportable(callable $reportUsing)
{
if (! $reportUsing instanceof Closure) {
$reportUsing = Closure::fromCallable($reportUsing);
}
return tap(new ReportableHandler($reportUsing), function ($callback) {
$this->reportCallbacks[] = $callback;
});
}
/**
* Register a renderable callback.
*
* @param callable $renderUsing
* @return $this
*/
public function renderable(callable $renderUsing)
{
if (! $renderUsing instanceof Closure) {
$renderUsing = Closure::fromCallable($renderUsing);
}
$this->renderCallbacks[] = $renderUsing;
return $this;
}
/**
* Register a new exception mapping.
*
* @param \Closure|string $from
* @param \Closure|string|null $to
* @return $this
*
* @throws \InvalidArgumentException
*/
public function map($from, $to = null)
{
if (is_string($to)) {
$to = function ($exception) use ($to) {
return new $to('', 0, $exception);
};
}
if (is_callable($from) && is_null($to)) {
$from = $this->firstClosureParameterType($to = $from);
}
if (! is_string($from) || ! $to instanceof Closure) {
throw new InvalidArgumentException('Invalid exception mapping.');
}
$this->exceptionMap[$from] = $to;
return $this;
}
/**
* Indicate that the given exception type should not be reported.
*
* @param string $class
* @return $this
*/
protected function ignore(string $class)
{
$this->dontReport[] = $class;
return $this;
}
/**
@@ -99,14 +218,24 @@ class Handler implements ExceptionHandlerContract
*/
public function report(Throwable $e)
{
$e = $this->mapException($e);
if ($this->shouldntReport($e)) {
return;
}
if (Reflector::isCallable($reportCallable = [$e, 'report'])) {
$this->container->call($reportCallable);
if ($this->container->call($reportCallable) !== false) {
return;
}
}
return;
foreach ($this->reportCallbacks as $reportCallback) {
if ($reportCallback->handles($e)) {
if ($reportCallback($e) === false) {
return;
}
}
}
try {
@@ -159,6 +288,10 @@ class Handler implements ExceptionHandlerContract
*/
protected function exceptionContext(Throwable $e)
{
if (method_exists($e, 'context')) {
return $e->context();
}
return [];
}
@@ -196,7 +329,19 @@ class Handler implements ExceptionHandlerContract
return $e->toResponse($request);
}
$e = $this->prepareException($e);
$e = $this->prepareException($this->mapException($e));
foreach ($this->renderCallbacks as $renderCallback) {
foreach ($this->firstClosureParameterTypes($renderCallback) as $type) {
if (is_a($e, $type)) {
$response = $renderCallback($e, $request);
if (! is_null($response)) {
return $response;
}
}
}
}
if ($e instanceof HttpResponseException) {
return $e->getResponse();
@@ -206,11 +351,28 @@ class Handler implements ExceptionHandlerContract
return $this->convertValidationExceptionToResponse($e, $request);
}
return $request->expectsJson()
return $this->shouldReturnJson($request, $e)
? $this->prepareJsonResponse($request, $e)
: $this->prepareResponse($request, $e);
}
/**
* Map the exception using a registered mapper if possible.
*
* @param \Throwable $e
* @return \Throwable
*/
protected function mapException(Throwable $e)
{
foreach ($this->exceptionMap as $class => $mapper) {
if (is_a($e, $class)) {
return $mapper($e);
}
}
return $e;
}
/**
* Prepare exception for rendering.
*
@@ -227,6 +389,8 @@ class Handler implements ExceptionHandlerContract
$e = new HttpException(419, $e->getMessage(), $e);
} elseif ($e instanceof SuspiciousOperationException) {
$e = new NotFoundHttpException('Bad hostname provided.', $e);
} elseif ($e instanceof RecordsNotFoundException) {
$e = new NotFoundHttpException('Not found.', $e);
}
return $e;
@@ -241,7 +405,7 @@ class Handler implements ExceptionHandlerContract
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
return $request->expectsJson()
return $this->shouldReturnJson($request, $exception)
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest($exception->redirectTo() ?? route('login'));
}
@@ -259,7 +423,7 @@ class Handler implements ExceptionHandlerContract
return $e->response;
}
return $request->expectsJson()
return $this->shouldReturnJson($request, $e)
? $this->invalidJson($request, $e)
: $this->invalid($request, $e);
}
@@ -275,7 +439,7 @@ class Handler implements ExceptionHandlerContract
{
return redirect($exception->redirectTo ?? url()->previous())
->withInput(Arr::except($request->input(), $this->dontFlash))
->withErrors($exception->errors(), $exception->errorBag);
->withErrors($exception->errors(), $request->input('_error_bag', $exception->errorBag));
}
/**
@@ -293,6 +457,18 @@ class Handler implements ExceptionHandlerContract
], $exception->status);
}
/**
* Determine if the exception handler response should be JSON.
*
* @param \Illuminate\Http\Request $request
* @param \Throwable $e
* @return bool
*/
protected function shouldReturnJson($request, Throwable $e)
{
return $request->expectsJson();
}
/**
* Prepare a response for the given exception.
*
@@ -419,11 +595,7 @@ class Handler implements ExceptionHandlerContract
*/
protected function registerErrorViewPaths()
{
$paths = collect(config('view.paths'));
View::replaceNamespace('errors', $paths->map(function ($path) {
return "{$path}/errors";
})->push(__DIR__.'/views')->all());
(new RegisterErrorViewPaths)();
}
/**

View File

@@ -2,4 +2,4 @@
@section('title', __('Service Unavailable'))
@section('code', '503')
@section('message', __($exception->getMessage() ?: 'Service Unavailable'))
@section('message', __('Service Unavailable'))

View File

@@ -7,8 +7,8 @@
<title>@yield('title')</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<!-- Styles -->
<style>

View File

@@ -7,8 +7,8 @@
<title>@yield('title')</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet" type="text/css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<!-- Styles -->
<style>

File diff suppressed because one or more lines are too long

View File

@@ -7,6 +7,9 @@ use Illuminate\Support\Facades\Date;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
use Throwable;
/**
* @deprecated Will be removed in a future Laravel version.
*/
class MaintenanceModeException extends ServiceUnavailableHttpException
{
/**

View File

@@ -3,6 +3,7 @@
namespace Illuminate\Foundation\Http;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\Access\Response;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Contracts\Validation\ValidatesWhenResolved;
@@ -58,6 +59,13 @@ class FormRequest extends Request implements ValidatesWhenResolved
*/
protected $errorBag = 'default';
/**
* Indicates whether validation should stop after the first rule failure.
*
* @var bool
*/
protected $stopOnFirstFailure = false;
/**
* The validator instance.
*
@@ -104,7 +112,7 @@ class FormRequest extends Request implements ValidatesWhenResolved
return $factory->make(
$this->validationData(), $this->container->call([$this, 'rules']),
$this->messages(), $this->attributes()
);
)->stopOnFirstFailure($this->stopOnFirstFailure);
}
/**
@@ -156,11 +164,15 @@ class FormRequest extends Request implements ValidatesWhenResolved
* Determine if the request passes the authorization check.
*
* @return bool
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
protected function passesAuthorization()
{
if (method_exists($this, 'authorize')) {
return $this->container->call([$this, 'authorize']);
$result = $this->container->call([$this, 'authorize']);
return $result instanceof Response ? $result->authorize() : $result;
}
return true;
@@ -178,6 +190,19 @@ class FormRequest extends Request implements ValidatesWhenResolved
throw new AuthorizationException;
}
/**
* Get a validated input container for the validated input.
*
* @param array|null $keys
* @return \Illuminate\Support\ValidatedInput|array
*/
public function safe(array $keys = null)
{
return is_array($keys)
? $this->validator->safe()->only($keys)
: $this->validator->safe();
}
/**
* Get the validated data from the request.
*

View File

@@ -31,7 +31,7 @@ class Kernel implements KernelContract
/**
* The bootstrap classes for the application.
*
* @var array
* @var string[]
*/
protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
@@ -68,13 +68,15 @@ class Kernel implements KernelContract
*
* Forces non-global middleware to always be in the given order.
*
* @var array
* @var string[]
*/
protected $middlewarePriority = [
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
@@ -253,7 +255,7 @@ class Kernel implements KernelContract
}
/**
* Add a new middleware to beginning of the stack if it does not already exist.
* Add a new middleware to the beginning of the stack if it does not already exist.
*
* @param string $middleware
* @return $this
@@ -382,6 +384,16 @@ class Kernel implements KernelContract
}
}
/**
* Get the priority-sorted list of middleware.
*
* @return array
*/
public function getMiddlewarePriority()
{
return $this->middlewarePriority;
}
/**
* Get the bootstrap classes for the application.
*
@@ -444,4 +456,17 @@ class Kernel implements KernelContract
{
return $this->app;
}
/**
* Set the Laravel application instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return $this
*/
public function setApplication(Application $app)
{
$this->app = $app;
return $this;
}
}

View File

@@ -2,85 +2,7 @@
namespace Illuminate\Foundation\Http\Middleware;
use Closure;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Http\Exceptions\MaintenanceModeException;
use Symfony\Component\HttpFoundation\IpUtils;
class CheckForMaintenanceMode
class CheckForMaintenanceMode extends PreventRequestsDuringMaintenance
{
/**
* The application implementation.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* The URIs that should be accessible while maintenance mode is enabled.
*
* @var array
*/
protected $except = [];
/**
* Create a new middleware instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function __construct(Application $app)
{
$this->app = $app;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* @throws \Illuminate\Foundation\Http\Exceptions\MaintenanceModeException
*/
public function handle($request, Closure $next)
{
if ($this->app->isDownForMaintenance()) {
$data = json_decode(file_get_contents($this->app->storagePath().'/framework/down'), true);
if (isset($data['allowed']) && IpUtils::checkIp($request->ip(), (array) $data['allowed'])) {
return $next($request);
}
if ($this->inExceptArray($request)) {
return $next($request);
}
throw new MaintenanceModeException($data['time'], $data['retry'], $data['message']);
}
return $next($request);
}
/**
* Determine if the request has a URI that should be accessible in maintenance mode.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function inExceptArray($request)
{
foreach ($this->except as $except) {
if ($except !== '/') {
$except = trim($except, '/');
}
if ($request->fullUrlIs($except) || $request->is($except)) {
return true;
}
}
return false;
}
//
}

View File

@@ -2,8 +2,35 @@
namespace Illuminate\Foundation\Http\Middleware;
use Closure;
class ConvertEmptyStringsToNull extends TransformsRequest
{
/**
* All of the registered skip callbacks.
*
* @var array
*/
protected static $skipCallbacks = [];
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
foreach (static::$skipCallbacks as $callback) {
if ($callback($request)) {
return $next($request);
}
}
return parent::handle($request, $next);
}
/**
* Transform the given value.
*
@@ -15,4 +42,15 @@ class ConvertEmptyStringsToNull extends TransformsRequest
{
return is_string($value) && $value === '' ? null : $value;
}
/**
* Register a callback that instructs the middleware to be skipped.
*
* @param \Closure $callback
* @return void
*/
public static function skipWhen(Closure $callback)
{
static::$skipCallbacks[] = $callback;
}
}

View File

@@ -58,9 +58,11 @@ class TransformsRequest
*/
protected function cleanArray(array $data, $keyPrefix = '')
{
return collect($data)->map(function ($value, $key) use ($keyPrefix) {
return $this->cleanValue($keyPrefix.$key, $value);
})->all();
foreach ($data as $key => $value) {
$data[$key] = $this->cleanValue($keyPrefix.$key, $value);
}
return collect($data)->all();
}
/**

View File

@@ -2,8 +2,17 @@
namespace Illuminate\Foundation\Http\Middleware;
use Closure;
class TrimStrings extends TransformsRequest
{
/**
* All of the registered skip callbacks.
*
* @var array
*/
protected static $skipCallbacks = [];
/**
* The attributes that should not be trimmed.
*
@@ -13,6 +22,24 @@ class TrimStrings extends TransformsRequest
//
];
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
foreach (static::$skipCallbacks as $callback) {
if ($callback($request)) {
return $next($request);
}
}
return parent::handle($request, $next);
}
/**
* Transform the given value.
*
@@ -28,4 +55,15 @@ class TrimStrings extends TransformsRequest
return is_string($value) ? trim($value) : $value;
}
/**
* Register a callback that instructs the middleware to be skipped.
*
* @param \Closure $callback
* @return void
*/
public static function skipWhen(Closure $callback)
{
static::$skipCallbacks[] = $callback;
}
}

View File

@@ -23,15 +23,20 @@ class Inspiring
'Act only according to that maxim whereby you can, at the same time, will that it should become a universal law. - Immanuel Kant',
'An unexamined life is not worth living. - Socrates',
'Be present above all else. - Naval Ravikant',
'Do what you can, with what you have, where you are. - Theodore Roosevelt',
'Happiness is not something readymade. It comes from your own actions. - Dalai Lama',
'He who is contented is rich. - Laozi',
'I begin to speak only when I am certain what I will say is not better left unsaid - Cato the Younger',
'I begin to speak only when I am certain what I will say is not better left unsaid. - Cato the Younger',
'I have not failed. I\'ve just found 10,000 ways that won\'t work. - Thomas Edison',
'If you do not have a consistent goal in life, you can not live it in a consistent way. - Marcus Aurelius',
'It is never too late to be what you might have been. - George Eliot',
'It is not the man who has too little, but the man who craves more, that is poor. - Seneca',
'It is quality rather than quantity that matters. - Lucius Annaeus Seneca',
'Knowing is not enough; we must apply. Being willing is not enough; we must do. - Leonardo da Vinci',
'Let all your things have their places; let each part of your business have its time. - Benjamin Franklin',
'Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi',
'No surplus words or unnecessary actions. - Marcus Aurelius',
'Nothing worth having comes easy. - Theodore Roosevelt',
'Order your soul. Reduce your wants. - Augustine',
'People find pleasure in different ways. I find it in keeping my mind clear. - Marcus Aurelius',
'Simplicity is an acquired taste. - Katharine Gerould',
@@ -41,10 +46,16 @@ class Inspiring
'Smile, breathe, and go slowly. - Thich Nhat Hanh',
'The only way to do great work is to love what you do. - Steve Jobs',
'The whole future lies in uncertainty: live immediately. - Seneca',
'Very little is needed to make a happy life. - Marcus Antoninus',
'Very little is needed to make a happy life. - Marcus Aurelius',
'Waste no more time arguing what a good man should be, be one. - Marcus Aurelius',
'Well begun is half done. - Aristotle',
'When there is no desire, all things are at peace. - Laozi',
'Walk as if you are kissing the Earth with your feet. - Thich Nhat Hanh',
'Because you are alive, everything is possible. - Thich Nhat Hanh',
'Breathing in, I calm body and mind. Breathing out, I smile. - Thich Nhat Hanh',
'Life is available only in the present moment. - Thich Nhat Hanh',
'The best way to take care of the future is to take care of the present moment. - Thich Nhat Hanh',
'Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less. - Marie Curie',
])->random();
}
}

View File

@@ -29,9 +29,15 @@ class Mix
$manifestDirectory = "/{$manifestDirectory}";
}
if (file_exists(public_path($manifestDirectory.'/hot'))) {
if (is_file(public_path($manifestDirectory.'/hot'))) {
$url = rtrim(file_get_contents(public_path($manifestDirectory.'/hot')));
$customUrl = app('config')->get('app.mix_hot_proxy_url');
if (! empty($customUrl)) {
return new HtmlString("{$customUrl}{$path}");
}
if (Str::startsWith($url, ['http://', 'https://'])) {
return new HtmlString(Str::after($url, ':').$path);
}
@@ -42,7 +48,7 @@ class Mix
$manifestPath = public_path($manifestDirectory.'/mix-manifest.json');
if (! isset($manifests[$manifestPath])) {
if (! file_exists($manifestPath)) {
if (! is_file($manifestPath)) {
throw new Exception('The Mix manifest does not exist.');
}

View File

@@ -102,11 +102,11 @@ class PackageManifest
return $this->manifest;
}
if (! file_exists($this->manifestPath)) {
if (! is_file($this->manifestPath)) {
$this->build();
}
return $this->manifest = file_exists($this->manifestPath) ?
return $this->manifest = is_file($this->manifestPath) ?
$this->files->getRequire($this->manifestPath) : [];
}
@@ -154,7 +154,7 @@ class PackageManifest
*/
protected function packagesToIgnore()
{
if (! file_exists($this->basePath.'/composer.json')) {
if (! is_file($this->basePath.'/composer.json')) {
return [];
}

View File

View File

@@ -6,10 +6,17 @@ use Illuminate\Auth\Console\ClearResetsCommand;
use Illuminate\Cache\Console\CacheTableCommand;
use Illuminate\Cache\Console\ClearCommand as CacheClearCommand;
use Illuminate\Cache\Console\ForgetCommand as CacheForgetCommand;
use Illuminate\Console\Scheduling\ScheduleClearCacheCommand;
use Illuminate\Console\Scheduling\ScheduleFinishCommand;
use Illuminate\Console\Scheduling\ScheduleListCommand;
use Illuminate\Console\Scheduling\ScheduleRunCommand;
use Illuminate\Console\Scheduling\ScheduleTestCommand;
use Illuminate\Console\Scheduling\ScheduleWorkCommand;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Database\Console\DbCommand;
use Illuminate\Database\Console\DumpCommand;
use Illuminate\Database\Console\Factories\FactoryMakeCommand;
use Illuminate\Database\Console\PruneCommand;
use Illuminate\Database\Console\Seeds\SeedCommand;
use Illuminate\Database\Console\Seeds\SeederMakeCommand;
use Illuminate\Database\Console\WipeCommand;
@@ -55,12 +62,18 @@ use Illuminate\Foundation\Console\VendorPublishCommand;
use Illuminate\Foundation\Console\ViewCacheCommand;
use Illuminate\Foundation\Console\ViewClearCommand;
use Illuminate\Notifications\Console\NotificationTableCommand;
use Illuminate\Queue\Console\BatchesTableCommand;
use Illuminate\Queue\Console\ClearCommand as QueueClearCommand;
use Illuminate\Queue\Console\FailedTableCommand;
use Illuminate\Queue\Console\FlushFailedCommand as FlushFailedQueueCommand;
use Illuminate\Queue\Console\ForgetFailedCommand as ForgetFailedQueueCommand;
use Illuminate\Queue\Console\ListenCommand as QueueListenCommand;
use Illuminate\Queue\Console\ListFailedCommand as ListFailedQueueCommand;
use Illuminate\Queue\Console\MonitorCommand as QueueMonitorCommand;
use Illuminate\Queue\Console\PruneBatchesCommand as PruneBatchesQueueCommand;
use Illuminate\Queue\Console\PruneFailedJobsCommand;
use Illuminate\Queue\Console\RestartCommand as QueueRestartCommand;
use Illuminate\Queue\Console\RetryBatchCommand as QueueRetryBatchCommand;
use Illuminate\Queue\Console\RetryCommand as QueueRetryCommand;
use Illuminate\Queue\Console\TableCommand;
use Illuminate\Queue\Console\WorkCommand as QueueWorkCommand;
@@ -83,6 +96,8 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
'ClearResets' => 'command.auth.resets.clear',
'ConfigCache' => 'command.config.cache',
'ConfigClear' => 'command.config.clear',
'Db' => DbCommand::class,
'DbPrune' => 'command.db.prune',
'DbWipe' => 'command.db.wipe',
'Down' => 'command.down',
'Environment' => 'command.environment',
@@ -93,19 +108,29 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
'Optimize' => 'command.optimize',
'OptimizeClear' => 'command.optimize.clear',
'PackageDiscover' => 'command.package.discover',
'QueueClear' => 'command.queue.clear',
'QueueFailed' => 'command.queue.failed',
'QueueFlush' => 'command.queue.flush',
'QueueForget' => 'command.queue.forget',
'QueueListen' => 'command.queue.listen',
'QueueMonitor' => 'command.queue.monitor',
'QueuePruneBatches' => 'command.queue.prune-batches',
'QueuePruneFailedJobs' => 'command.queue.prune-failed-jobs',
'QueueRestart' => 'command.queue.restart',
'QueueRetry' => 'command.queue.retry',
'QueueRetryBatch' => 'command.queue.retry-batch',
'QueueWork' => 'command.queue.work',
'RouteCache' => 'command.route.cache',
'RouteClear' => 'command.route.clear',
'RouteList' => 'command.route.list',
'SchemaDump' => 'command.schema.dump',
'Seed' => 'command.seed',
'ScheduleFinish' => ScheduleFinishCommand::class,
'ScheduleList' => ScheduleListCommand::class,
'ScheduleRun' => ScheduleRunCommand::class,
'ScheduleClearCache' => ScheduleClearCacheCommand::class,
'ScheduleTest' => ScheduleTestCommand::class,
'ScheduleWork' => ScheduleWorkCommand::class,
'StorageLink' => 'command.storage.link',
'Up' => 'command.up',
'ViewCache' => 'command.view.cache',
@@ -140,6 +165,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
'ProviderMake' => 'command.provider.make',
'QueueFailedTable' => 'command.queue.failed-table',
'QueueTable' => 'command.queue.table',
'QueueBatchesTable' => 'command.queue.batches-table',
'RequestMake' => 'command.request.make',
'ResourceMake' => 'command.resource.make',
'RuleMake' => 'command.rule.make',
@@ -322,6 +348,28 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerDbCommand()
{
$this->app->singleton(DbCommand::class);
}
/**
* Register the command.
*
* @return void
*/
protected function registerDbPruneCommand()
{
$this->app->singleton('command.db.prune', function ($app) {
return new PruneCommand($app['events']);
});
}
/**
* Register the command.
*
@@ -438,7 +486,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
protected function registerEventListCommand()
{
$this->app->singleton('command.event.list', function () {
return new EventListCommand();
return new EventListCommand;
});
}
@@ -658,6 +706,42 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerQueueMonitorCommand()
{
$this->app->singleton('command.queue.monitor', function ($app) {
return new QueueMonitorCommand($app['queue'], $app['events']);
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerQueuePruneBatchesCommand()
{
$this->app->singleton('command.queue.prune-batches', function () {
return new PruneBatchesQueueCommand;
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerQueuePruneFailedJobsCommand()
{
$this->app->singleton('command.queue.prune-failed-jobs', function () {
return new PruneFailedJobsCommand;
});
}
/**
* Register the command.
*
@@ -682,6 +766,18 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerQueueRetryBatchCommand()
{
$this->app->singleton('command.queue.retry-batch', function () {
return new QueueRetryBatchCommand;
});
}
/**
* Register the command.
*
@@ -694,6 +790,18 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerQueueClearCommand()
{
$this->app->singleton('command.queue.clear', function () {
return new QueueClearCommand;
});
}
/**
* Register the command.
*
@@ -718,6 +826,18 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerQueueBatchesTableCommand()
{
$this->app->singleton('command.queue.batches-table', function ($app) {
return new BatchesTableCommand($app['files'], $app['composer']);
});
}
/**
* Register the command.
*
@@ -826,6 +946,18 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerSchemaDumpCommand()
{
$this->app->singleton('command.schema.dump', function () {
return new DumpCommand;
});
}
/**
* Register the command.
*
@@ -838,6 +970,16 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
});
}
/**
* Register the command.
*
* @return void
*/
protected function registerScheduleClearCacheCommand()
{
$this->app->singleton(ScheduleClearCacheCommand::class);
}
/**
* Register the command.
*
@@ -848,6 +990,16 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
$this->app->singleton(ScheduleFinishCommand::class);
}
/**
* Register the command.
*
* @return void
*/
protected function registerScheduleListCommand()
{
$this->app->singleton(ScheduleListCommand::class);
}
/**
* Register the command.
*
@@ -858,6 +1010,26 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
$this->app->singleton(ScheduleRunCommand::class);
}
/**
* Register the command.
*
* @return void
*/
protected function registerScheduleTestCommand()
{
$this->app->singleton(ScheduleTestCommand::class);
}
/**
* Register the command.
*
* @return void
*/
protected function registerScheduleWorkCommand()
{
$this->app->singleton(ScheduleWorkCommand::class);
}
/**
* Register the command.
*

View File

@@ -11,7 +11,7 @@ class ConsoleSupportServiceProvider extends AggregateServiceProvider implements
/**
* The provider class names.
*
* @var array
* @var string[]
*/
protected $providers = [
ArtisanServiceProvider::class,

View File

@@ -3,8 +3,11 @@
namespace Illuminate\Foundation\Providers;
use Illuminate\Http\Request;
use Illuminate\Log\Events\MessageLogged;
use Illuminate\Support\AggregateServiceProvider;
use Illuminate\Support\Facades\URL;
use Illuminate\Testing\LoggedExceptionCollection;
use Illuminate\Testing\ParallelTestingServiceProvider;
use Illuminate\Validation\ValidationException;
class FoundationServiceProvider extends AggregateServiceProvider
@@ -12,10 +15,11 @@ class FoundationServiceProvider extends AggregateServiceProvider
/**
* The provider class names.
*
* @var array
* @var string[]
*/
protected $providers = [
FormRequestServiceProvider::class,
ParallelTestingServiceProvider::class,
];
/**
@@ -43,6 +47,7 @@ class FoundationServiceProvider extends AggregateServiceProvider
$this->registerRequestValidation();
$this->registerRequestSignatureValidation();
$this->registerExceptionTracking();
}
/**
@@ -79,5 +84,33 @@ class FoundationServiceProvider extends AggregateServiceProvider
Request::macro('hasValidSignature', function ($absolute = true) {
return URL::hasValidSignature($this, $absolute);
});
Request::macro('hasValidRelativeSignature', function () {
return URL::hasValidSignature($this, $absolute = false);
});
}
/**
* Register an event listener to track logged exceptions.
*
* @return void
*/
protected function registerExceptionTracking()
{
if (! $this->app->runningUnitTests()) {
return;
}
$this->app->instance(
LoggedExceptionCollection::class,
new LoggedExceptionCollection
);
$this->app->make('events')->listen(MessageLogged::class, function ($event) {
if (isset($event->context['exception'])) {
$this->app->make(LoggedExceptionCollection::class)
->push($event->context['exception']);
}
});
}
}

View File

@@ -27,19 +27,31 @@ class EventServiceProvider extends ServiceProvider
*
* @return void
*/
public function register()
{
$this->booting(function () {
$events = $this->getEvents();
foreach ($events as $event => $listeners) {
foreach (array_unique($listeners) as $listener) {
Event::listen($event, $listener);
}
}
foreach ($this->subscribe as $subscriber) {
Event::subscribe($subscriber);
}
});
}
/**
* Boot any application services.
*
* @return void
*/
public function boot()
{
$events = $this->getEvents();
foreach ($events as $event => $listeners) {
foreach (array_unique($listeners) as $listener) {
Event::listen($event, $listener);
}
}
foreach ($this->subscribe as $subscriber) {
Event::subscribe($subscriber);
}
//
}
/**
@@ -107,7 +119,7 @@ class EventServiceProvider extends ServiceProvider
->reduce(function ($discovered, $directory) {
return array_merge_recursive(
$discovered,
DiscoverEvents::within($directory, base_path())
DiscoverEvents::within($directory, $this->eventDiscoveryBasePath())
);
}, []);
}
@@ -123,4 +135,14 @@ class EventServiceProvider extends ServiceProvider
$this->app->path('Listeners'),
];
}
/**
* Get the base path to be used during event discovery.
*
* @return string
*/
protected function eventDiscoveryBasePath()
{
return base_path();
}
}

View File

@@ -2,6 +2,7 @@
namespace Illuminate\Foundation\Support\Providers;
use Closure;
use Illuminate\Contracts\Routing\UrlGenerator;
use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider;
@@ -21,6 +22,36 @@ class RouteServiceProvider extends ServiceProvider
*/
protected $namespace;
/**
* The callback that should be used to load the application's routes.
*
* @var \Closure|null
*/
protected $loadRoutesUsing;
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->booted(function () {
$this->setRootControllerNamespace();
if ($this->routesAreCached()) {
$this->loadCachedRoutes();
} else {
$this->loadRoutes();
$this->app->booted(function () {
$this->app['router']->getRoutes()->refreshNameLookups();
$this->app['router']->getRoutes()->refreshActionLookups();
});
}
});
}
/**
* Bootstrap any application services.
*
@@ -28,18 +59,20 @@ class RouteServiceProvider extends ServiceProvider
*/
public function boot()
{
$this->setRootControllerNamespace();
//
}
if ($this->routesAreCached()) {
$this->loadCachedRoutes();
} else {
$this->loadRoutes();
/**
* Register the callback that will be used to load the application's routes.
*
* @param \Closure $routesCallback
* @return $this
*/
protected function routes(Closure $routesCallback)
{
$this->loadRoutesUsing = $routesCallback;
$this->app->booted(function () {
$this->app['router']->getRoutes()->refreshNameLookups();
$this->app['router']->getRoutes()->refreshActionLookups();
});
}
return $this;
}
/**
@@ -83,7 +116,9 @@ class RouteServiceProvider extends ServiceProvider
*/
protected function loadRoutes()
{
if (method_exists($this, 'map')) {
if (! is_null($this->loadRoutesUsing)) {
$this->app->call($this->loadRoutesUsing);
} elseif (method_exists($this, 'map')) {
$this->app->call([$this, 'map']);
}
}

View File

@@ -10,30 +10,30 @@ trait InteractsWithAuthentication
* Set the currently logged in user for the application.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string|null $driver
* @param string|null $guard
* @return $this
*/
public function actingAs(UserContract $user, $driver = null)
public function actingAs(UserContract $user, $guard = null)
{
return $this->be($user, $driver);
return $this->be($user, $guard);
}
/**
* Set the currently logged in user for the application.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string|null $driver
* @param string|null $guard
* @return $this
*/
public function be(UserContract $user, $driver = null)
public function be(UserContract $user, $guard = null)
{
if (isset($user->wasRecentlyCreated) && $user->wasRecentlyCreated) {
$user->wasRecentlyCreated = false;
}
$this->app['auth']->guard($driver)->setUser($user);
$this->app['auth']->guard($guard)->setUser($user);
$this->app['auth']->shouldUse($driver);
$this->app['auth']->shouldUse($guard);
return $this;
}

View File

@@ -23,7 +23,14 @@ trait InteractsWithConsole
public $expectedOutput = [];
/**
* All of the expected ouput tables.
* All of the output lines that aren't expected to be displayed.
*
* @var array
*/
public $unexpectedOutput = [];
/**
* All of the expected output tables.
*
* @var array
*/

View File

@@ -77,6 +77,19 @@ trait InteractsWithContainer
return $this->instance($abstract, Mockery::spy(...array_filter(func_get_args())));
}
/**
* Instruct the container to forget a previously mocked / spied instance of an object.
*
* @param string $abstract
* @return $this
*/
protected function forgetMock($abstract)
{
$this->app->forgetInstance($abstract);
return $this;
}
/**
* Register an empty handler for Laravel Mix in the container.
*

View File

@@ -2,11 +2,14 @@
namespace Illuminate\Foundation\Testing\Concerns;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Testing\Constraints\CountInDatabase;
use Illuminate\Testing\Constraints\HasInDatabase;
use Illuminate\Testing\Constraints\NotSoftDeletedInDatabase;
use Illuminate\Testing\Constraints\SoftDeletedInDatabase;
use PHPUnit\Framework\Constraint\LogicalNot as ReverseConstraint;
@@ -15,7 +18,7 @@ trait InteractsWithDatabase
/**
* Assert that a given where condition exists in the database.
*
* @param string $table
* @param \Illuminate\Database\Eloquent\Model|string $table
* @param array $data
* @param string|null $connection
* @return $this
@@ -23,7 +26,7 @@ trait InteractsWithDatabase
protected function assertDatabaseHas($table, array $data, $connection = null)
{
$this->assertThat(
$table, new HasInDatabase($this->getConnection($connection), $data)
$this->getTable($table), new HasInDatabase($this->getConnection($connection), $data)
);
return $this;
@@ -32,7 +35,7 @@ trait InteractsWithDatabase
/**
* Assert that a given where condition does not exist in the database.
*
* @param string $table
* @param \Illuminate\Database\Eloquent\Model|string $table
* @param array $data
* @param string|null $connection
* @return $this
@@ -43,7 +46,7 @@ trait InteractsWithDatabase
new HasInDatabase($this->getConnection($connection), $data)
);
$this->assertThat($table, $constraint);
$this->assertThat($this->getTable($table), $constraint);
return $this;
}
@@ -51,7 +54,7 @@ trait InteractsWithDatabase
/**
* Assert the count of table entries.
*
* @param string $table
* @param \Illuminate\Database\Eloquent\Model|string $table
* @param int $count
* @param string|null $connection
* @return $this
@@ -59,7 +62,7 @@ trait InteractsWithDatabase
protected function assertDatabaseCount($table, int $count, $connection = null)
{
$this->assertThat(
$table, new CountInDatabase($this->getConnection($connection), $count)
$this->getTable($table), new CountInDatabase($this->getConnection($connection), $count)
);
return $this;
@@ -79,7 +82,7 @@ trait InteractsWithDatabase
return $this->assertDatabaseMissing($table->getTable(), [$table->getKeyName() => $table->getKey()], $table->getConnectionName());
}
$this->assertDatabaseMissing($table, $data, $connection);
$this->assertDatabaseMissing($this->getTable($table), $data, $connection);
return $this;
}
@@ -96,16 +99,78 @@ trait InteractsWithDatabase
protected function assertSoftDeleted($table, array $data = [], $connection = null, $deletedAtColumn = 'deleted_at')
{
if ($this->isSoftDeletableModel($table)) {
return $this->assertSoftDeleted($table->getTable(), [$table->getKeyName() => $table->getKey()], $table->getConnectionName(), $table->getDeletedAtColumn());
return $this->assertSoftDeleted(
$table->getTable(),
array_merge($data, [$table->getKeyName() => $table->getKey()]),
$table->getConnectionName(),
$table->getDeletedAtColumn()
);
}
$this->assertThat(
$table, new SoftDeletedInDatabase($this->getConnection($connection), $data, $deletedAtColumn)
$this->getTable($table), new SoftDeletedInDatabase($this->getConnection($connection), $data, $deletedAtColumn)
);
return $this;
}
/**
* Assert the given record has not been "soft deleted".
*
* @param \Illuminate\Database\Eloquent\Model|string $table
* @param array $data
* @param string|null $connection
* @param string|null $deletedAtColumn
* @return $this
*/
protected function assertNotSoftDeleted($table, array $data = [], $connection = null, $deletedAtColumn = 'deleted_at')
{
if ($this->isSoftDeletableModel($table)) {
return $this->assertNotSoftDeleted(
$table->getTable(),
array_merge($data, [$table->getKeyName() => $table->getKey()]),
$table->getConnectionName(),
$table->getDeletedAtColumn()
);
}
$this->assertThat(
$this->getTable($table), new NotSoftDeletedInDatabase($this->getConnection($connection), $data, $deletedAtColumn)
);
return $this;
}
/**
* Assert the given model exists in the database.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return $this
*/
protected function assertModelExists($model)
{
return $this->assertDatabaseHas(
$model->getTable(),
[$model->getKeyName() => $model->getKey()],
$model->getConnectionName()
);
}
/**
* Assert the given model does not exist in the database.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return $this
*/
protected function assertModelMissing($model)
{
return $this->assertDatabaseMissing(
$model->getTable(),
[$model->getKeyName() => $model->getKey()],
$model->getConnectionName()
);
}
/**
* Determine if the argument is a soft deletable model.
*
@@ -118,6 +183,25 @@ trait InteractsWithDatabase
&& in_array(SoftDeletes::class, class_uses_recursive($model));
}
/**
* Cast a JSON string to a database compatible type.
*
* @param array|string $value
* @return \Illuminate\Database\Query\Expression
*/
public function castAsJson($value)
{
if ($value instanceof Jsonable) {
$value = $value->toJson();
} elseif (is_array($value) || is_object($value)) {
$value = json_encode($value);
}
$value = DB::connection()->getPdo()->quote($value);
return DB::raw("CAST($value AS JSON)");
}
/**
* Get the database connection.
*
@@ -133,13 +217,24 @@ trait InteractsWithDatabase
return $database->connection($connection);
}
/**
* Get the table name from the given model or string.
*
* @param \Illuminate\Database\Eloquent\Model|string $table
* @return string
*/
protected function getTable($table)
{
return is_subclass_of($table, Model::class) ? (new $table)->getTable() : $table;
}
/**
* Seed a given database connection.
*
* @param array|string $class
* @return $this
*/
public function seed($class = 'DatabaseSeeder')
public function seed($class = 'Database\\Seeders\\DatabaseSeeder')
{
foreach (Arr::wrap($class) as $class) {
$this->artisan('db:seed', ['--class' => $class, '--no-interaction' => true]);

View File

@@ -125,7 +125,7 @@ trait InteractsWithExceptionHandling
if ($e instanceof NotFoundHttpException) {
throw new NotFoundHttpException(
"{$request->method()} {$request->url()}", null, $e->getCode()
"{$request->method()} {$request->url()}", $e, $e->getCode()
);
}

View File

@@ -30,22 +30,18 @@ trait InteractsWithRedis
*/
public function setUpRedis()
{
$app = $this->app ?? new Application;
$host = Env::get('REDIS_HOST', '127.0.0.1');
$port = Env::get('REDIS_PORT', 6379);
if (! extension_loaded('redis')) {
$this->markTestSkipped('The redis extension is not installed. Please install the extension to enable '.__CLASS__);
return;
}
if (static::$connectionFailedOnceWithDefaultsSkip) {
$this->markTestSkipped('Trying default host/port failed, please set environment variable REDIS_HOST & REDIS_PORT to enable '.__CLASS__);
return;
}
$app = $this->app ?? new Application;
$host = Env::get('REDIS_HOST', '127.0.0.1');
$port = Env::get('REDIS_PORT', 6379);
foreach ($this->redisDriverProvider() as $driver) {
$this->redis[$driver[0]] = new RedisManager($app, $driver[0], [
'cluster' => false,
@@ -57,6 +53,7 @@ trait InteractsWithRedis
'port' => $port,
'database' => 5,
'timeout' => 0.5,
'name' => 'default',
],
]);
}
@@ -66,6 +63,7 @@ trait InteractsWithRedis
} catch (Exception $e) {
if ($host === '127.0.0.1' && $port === 6379 && Env::get('REDIS_HOST') === null) {
static::$connectionFailedOnceWithDefaultsSkip = true;
$this->markTestSkipped('Trying default host/port failed, please set environment variable REDIS_HOST & REDIS_PORT to enable '.__CLASS__);
}
}

View File

@@ -6,6 +6,7 @@ use Illuminate\Contracts\Http\Kernel as HttpKernel;
use Illuminate\Cookie\CookieValuePrefix;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Testing\LoggedExceptionCollection;
use Illuminate\Testing\TestResponse;
use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
@@ -509,12 +510,12 @@ trait MakesHttpRequests
$request = Request::createFromBase($symfonyRequest)
);
$kernel->terminate($request, $response);
if ($this->followRedirects) {
$response = $this->followRedirects($response);
}
$kernel->terminate($request, $response);
return $this->createTestResponse($response);
}
@@ -624,12 +625,12 @@ trait MakesHttpRequests
*/
protected function followRedirects($response)
{
$this->followRedirects = false;
while ($response->isRedirect()) {
$response = $this->get($response->headers->get('Location'));
}
$this->followRedirects = false;
return $response;
}
@@ -641,6 +642,12 @@ trait MakesHttpRequests
*/
protected function createTestResponse($response)
{
return TestResponse::fromBaseResponse($response);
return tap(TestResponse::fromBaseResponse($response), function ($response) {
$response->withExceptions(
$this->app->bound(LoggedExceptionCollection::class)
? $this->app->make(LoggedExceptionCollection::class)
: new LoggedExceptionCollection
);
});
}
}

View File

@@ -8,6 +8,9 @@ use Illuminate\Contracts\Notifications\Dispatcher as NotificationDispatcher;
use Illuminate\Support\Facades\Event;
use Mockery;
/**
* @deprecated Will be removed in a future Laravel version.
*/
trait MocksApplicationServices
{
/**

View File

@@ -3,9 +3,12 @@
namespace Illuminate\Foundation\Testing;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\Traits\CanConfigureMigrationCommands;
trait DatabaseMigrations
{
use CanConfigureMigrationCommands;
/**
* Define hooks to migrate the database before and after each test.
*
@@ -13,7 +16,7 @@ trait DatabaseMigrations
*/
public function runDatabaseMigrations()
{
$this->artisan('migrate:fresh');
$this->artisan('migrate:fresh', $this->migrateFreshUsing());
$this->app[Kernel::class]->setArtisan(null);

View File

@@ -14,14 +14,22 @@ trait DatabaseTransactions
$database = $this->app->make('db');
foreach ($this->connectionsToTransact() as $name) {
$database->connection($name)->beginTransaction();
$connection = $database->connection($name);
$dispatcher = $connection->getEventDispatcher();
$connection->unsetEventDispatcher();
$connection->beginTransaction();
$connection->setEventDispatcher($dispatcher);
}
$this->beforeApplicationDestroyed(function () use ($database) {
foreach ($this->connectionsToTransact() as $name) {
$connection = $database->connection($name);
$dispatcher = $connection->getEventDispatcher();
$connection->unsetEventDispatcher();
$connection->rollBack();
$connection->setEventDispatcher($dispatcher);
$connection->disconnect();
}
});

View File

@@ -3,9 +3,12 @@
namespace Illuminate\Foundation\Testing;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\Traits\CanConfigureMigrationCommands;
trait RefreshDatabase
{
use CanConfigureMigrationCommands;
/**
* Define hooks to migrate the database before and after each test.
*
@@ -16,6 +19,8 @@ trait RefreshDatabase
$this->usingInMemoryDatabase()
? $this->refreshInMemoryDatabase()
: $this->refreshTestDatabase();
$this->afterRefreshingDatabase();
}
/**
@@ -49,7 +54,10 @@ trait RefreshDatabase
*/
protected function migrateUsing()
{
return [];
return [
'--seed' => $this->shouldSeed(),
'--seeder' => $this->seeder(),
];
}
/**
@@ -70,19 +78,6 @@ trait RefreshDatabase
$this->beginDatabaseTransaction();
}
/**
* The parameters that should be used when running "migrate:fresh".
*
* @return array
*/
protected function migrateFreshUsing()
{
return [
'--drop-views' => $this->shouldDropViews(),
'--drop-types' => $this->shouldDropTypes(),
];
}
/**
* Begin a database transaction on the testing database.
*
@@ -107,7 +102,7 @@ trait RefreshDatabase
$dispatcher = $connection->getEventDispatcher();
$connection->unsetEventDispatcher();
$connection->rollback();
$connection->rollBack();
$connection->setEventDispatcher($dispatcher);
$connection->disconnect();
}
@@ -126,24 +121,12 @@ trait RefreshDatabase
}
/**
* Determine if views should be dropped when refreshing the database.
* Perform any work that should take place once the database has finished refreshing.
*
* @return bool
* @return void
*/
protected function shouldDropViews()
protected function afterRefreshingDatabase()
{
return property_exists($this, 'dropViews')
? $this->dropViews : false;
}
/**
* Determine if types should be dropped when refreshing the database.
*
* @return bool
*/
protected function shouldDropTypes()
{
return property_exists($this, 'dropTypes')
? $this->dropTypes : false;
// ...
}
}

View File

@@ -10,4 +10,11 @@ class RefreshDatabaseState
* @var bool
*/
public static $migrated = false;
/**
* Indicates if a lazy refresh hook has been invoked.
*
* @var bool
*/
public static $lazilyRefreshed = false;
}

Some files were not shown because too many files have changed in this diff Show More