Upgrade framework
This commit is contained in:
1416
vendor/laravel/framework/CHANGELOG.md
vendored
Normal file
1416
vendor/laravel/framework/CHANGELOG.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
28
vendor/laravel/framework/README.md
vendored
28
vendor/laravel/framework/README.md
vendored
@@ -1,15 +1,15 @@
|
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://laravel.com/assets/img/components/logo-laravel.svg"></a></p>
|
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://poser.pugx.org/laravel/framework/d/total.svg" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://poser.pugx.org/laravel/framework/v/stable.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://poser.pugx.org/laravel/framework/license.svg" alt="License"></a>
|
||||
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||
</p>
|
||||
|
||||
## About Laravel
|
||||
|
||||
> **Note:** This repository contains the core code of the Laravel framework. If you want to build an application using Laravel 5, visit the main [Laravel repository](https://github.com/laravel/laravel).
|
||||
> **Note:** This repository contains the core code of the Laravel framework. If you want to build an application using Laravel, visit the main [Laravel repository](https://github.com/laravel/laravel).
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as:
|
||||
|
||||
@@ -20,26 +20,28 @@ Laravel is a web application framework with expressive, elegant syntax. We belie
|
||||
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||
|
||||
Laravel is accessible, yet powerful, providing tools needed for large, robust applications. A superb combination of simplicity, elegance, and innovation give you tools you need to build any application with which you are tasked.
|
||||
Laravel is accessible, yet powerful, providing tools needed for large, robust applications. A superb combination of simplicity, elegance, and innovation gives you a complete toolset required to build any application with which you are tasked.
|
||||
|
||||
## Learning Laravel
|
||||
|
||||
Laravel has the most extensive and thorough documentation and video tutorial library of any modern web application framework. The [Laravel documentation](https://laravel.com/docs) is thorough, complete, and makes it a breeze to get started learning the framework.
|
||||
Laravel has the most extensive and thorough documentation and video tutorial library of any modern web application framework. The [Laravel documentation](https://laravel.com/docs) is in-depth and complete, making it a breeze to get started learning the framework.
|
||||
|
||||
If you're not in the mood to read, [Laracasts](https://laracasts.com) contains over 900 video tutorials covering a range of topics including Laravel, modern PHP, unit testing, JavaScript, and more. Boost the skill level of yourself and your entire team by digging into our comprehensive video library.
|
||||
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
|
||||
|
||||
If you're not in the mood to read, [Laracasts](https://laracasts.com) contains over 1100 video tutorials covering a range of topics including Laravel, modern PHP, unit testing, JavaScript, and more. Boost the skill level of yourself and your entire team by digging into our comprehensive video library.
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](http://laravel.com/docs/contributions).
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed.
|
||||
Please review [our security policy](https://github.com/laravel/framework/security/policy) on how to report security vulnerabilities.
|
||||
|
||||
## License
|
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT).
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](LICENSE.md).
|
||||
|
||||
152
vendor/laravel/framework/composer.json
vendored
152
vendor/laravel/framework/composer.json
vendored
@@ -15,34 +15,45 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.4",
|
||||
"php": "^8.0.2",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"doctrine/inflector": "~1.0",
|
||||
"erusev/parsedown": "~1.6",
|
||||
"league/flysystem": "~1.0",
|
||||
"monolog/monolog": "~1.11",
|
||||
"mtdowling/cron-expression": "~1.0",
|
||||
"nesbot/carbon": "~1.20",
|
||||
"paragonie/random_compat": "~1.4|~2.0",
|
||||
"ramsey/uuid": "~3.0",
|
||||
"swiftmailer/swiftmailer": "~5.4",
|
||||
"symfony/console": "~3.2",
|
||||
"symfony/debug": "~3.2",
|
||||
"symfony/finder": "~3.2",
|
||||
"symfony/http-foundation": "~3.2",
|
||||
"symfony/http-kernel": "~3.2",
|
||||
"symfony/process": "~3.2",
|
||||
"symfony/routing": "~3.2",
|
||||
"symfony/var-dumper": "~3.2",
|
||||
"tijsverkoyen/css-to-inline-styles": "~2.2",
|
||||
"vlucas/phpdotenv": "~2.2"
|
||||
"doctrine/inflector": "^2.0",
|
||||
"dragonmantank/cron-expression": "^3.3.2",
|
||||
"egulias/email-validator": "^3.2.1",
|
||||
"fruitcake/php-cors": "^1.2",
|
||||
"laravel/serializable-closure": "^1.2.2",
|
||||
"league/commonmark": "^2.2.1",
|
||||
"league/flysystem": "^3.8.0",
|
||||
"monolog/monolog": "^2.0",
|
||||
"nesbot/carbon": "^2.62.1",
|
||||
"nunomaduro/termwind": "^1.13",
|
||||
"psr/container": "^1.1.1|^2.0.1",
|
||||
"psr/log": "^1.0|^2.0|^3.0",
|
||||
"psr/simple-cache": "^1.0|^2.0|^3.0",
|
||||
"ramsey/uuid": "^4.7",
|
||||
"symfony/console": "^6.0.9",
|
||||
"symfony/error-handler": "^6.0",
|
||||
"symfony/finder": "^6.0",
|
||||
"symfony/http-foundation": "^6.0",
|
||||
"symfony/http-kernel": "^6.0",
|
||||
"symfony/mailer": "^6.0",
|
||||
"symfony/mime": "^6.0",
|
||||
"symfony/process": "^6.0",
|
||||
"symfony/routing": "^6.0",
|
||||
"symfony/uid": "^6.0",
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"tijsverkoyen/css-to-inline-styles": "^2.2.5",
|
||||
"vlucas/phpdotenv": "^5.4.1",
|
||||
"voku/portable-ascii": "^2.0"
|
||||
},
|
||||
"replace": {
|
||||
"illuminate/auth": "self.version",
|
||||
"illuminate/broadcasting": "self.version",
|
||||
"illuminate/bus": "self.version",
|
||||
"illuminate/cache": "self.version",
|
||||
"illuminate/collections": "self.version",
|
||||
"illuminate/conditionable": "self.version",
|
||||
"illuminate/config": "self.version",
|
||||
"illuminate/console": "self.version",
|
||||
"illuminate/container": "self.version",
|
||||
@@ -51,11 +62,11 @@
|
||||
"illuminate/database": "self.version",
|
||||
"illuminate/encryption": "self.version",
|
||||
"illuminate/events": "self.version",
|
||||
"illuminate/exception": "self.version",
|
||||
"illuminate/filesystem": "self.version",
|
||||
"illuminate/hashing": "self.version",
|
||||
"illuminate/http": "self.version",
|
||||
"illuminate/log": "self.version",
|
||||
"illuminate/macroable": "self.version",
|
||||
"illuminate/mail": "self.version",
|
||||
"illuminate/notifications": "self.version",
|
||||
"illuminate/pagination": "self.version",
|
||||
@@ -65,28 +76,51 @@
|
||||
"illuminate/routing": "self.version",
|
||||
"illuminate/session": "self.version",
|
||||
"illuminate/support": "self.version",
|
||||
"illuminate/testing": "self.version",
|
||||
"illuminate/translation": "self.version",
|
||||
"illuminate/validation": "self.version",
|
||||
"illuminate/view": "self.version",
|
||||
"tightenco/collect": "self.version"
|
||||
"illuminate/view": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"aws/aws-sdk-php": "~3.0",
|
||||
"doctrine/dbal": "~2.5",
|
||||
"mockery/mockery": "~0.9.4",
|
||||
"pda/pheanstalk": "~3.0",
|
||||
"phpunit/phpunit": "~5.7",
|
||||
"predis/predis": "~1.0",
|
||||
"symfony/css-selector": "~3.2",
|
||||
"symfony/dom-crawler": "~3.2"
|
||||
"ably/ably-php": "^1.0",
|
||||
"aws/aws-sdk-php": "^3.235.5",
|
||||
"doctrine/dbal": "^2.13.3|^3.1.4",
|
||||
"fakerphp/faker": "^1.21",
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"league/flysystem-aws-s3-v3": "^3.0",
|
||||
"league/flysystem-ftp": "^3.0",
|
||||
"league/flysystem-path-prefixing": "^3.3",
|
||||
"league/flysystem-read-only": "^3.3",
|
||||
"league/flysystem-sftp-v3": "^3.0",
|
||||
"mockery/mockery": "^1.5.1",
|
||||
"orchestra/testbench-core": "^7.16",
|
||||
"pda/pheanstalk": "^4.0",
|
||||
"phpstan/phpstan": "^1.4.7",
|
||||
"phpunit/phpunit": "^9.5.8",
|
||||
"predis/predis": "^1.1.9|^2.0.2",
|
||||
"symfony/cache": "^6.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/container-implementation": "1.1|2.0",
|
||||
"psr/simple-cache-implementation": "1.0|2.0|3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"tightenco/collect": "<5.5.33"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Illuminate/Collections/helpers.php",
|
||||
"src/Illuminate/Events/functions.php",
|
||||
"src/Illuminate/Foundation/helpers.php",
|
||||
"src/Illuminate/Support/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Illuminate\\": "src/Illuminate/"
|
||||
"Illuminate\\": "src/Illuminate/",
|
||||
"Illuminate\\Support\\": [
|
||||
"src/Illuminate/Macroable/",
|
||||
"src/Illuminate/Collections/",
|
||||
"src/Illuminate/Conditionable/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
@@ -99,27 +133,49 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.4-dev"
|
||||
"dev-master": "9.x-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).",
|
||||
"doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.5).",
|
||||
"fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).",
|
||||
"guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).",
|
||||
"laravel/tinker": "Required to use the tinker console command (~1.0).",
|
||||
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
|
||||
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
|
||||
"nexmo/client": "Required to use the Nexmo transport (~1.0).",
|
||||
"pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).",
|
||||
"predis/predis": "Required to use the redis cache and queue drivers (~1.0).",
|
||||
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).",
|
||||
"symfony/css-selector": "Required to use some of the crawler integration testing tools (~3.2).",
|
||||
"symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~3.2).",
|
||||
"symfony/psr-http-message-bridge": "Required to psr7 bridging features (0.2.*)."
|
||||
"ext-bcmath": "Required to use the multiple_of validation rule.",
|
||||
"ext-ftp": "Required to use the Flysystem FTP driver.",
|
||||
"ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().",
|
||||
"ext-memcached": "Required to use the memcache cache driver.",
|
||||
"ext-pcntl": "Required to use all features of the queue worker.",
|
||||
"ext-posix": "Required to use all features of the queue worker.",
|
||||
"ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).",
|
||||
"ably/ably-php": "Required to use the Ably broadcast driver (^1.0).",
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.235.5).",
|
||||
"brianium/paratest": "Required to run tests in parallel (^6.0).",
|
||||
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.4).",
|
||||
"fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).",
|
||||
"filp/whoops": "Required for friendly error pages in development (^2.14.3).",
|
||||
"guzzlehttp/guzzle": "Required to use the HTTP Client and the ping methods on schedules (^7.5).",
|
||||
"laravel/tinker": "Required to use the tinker console command (^2.0).",
|
||||
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.0).",
|
||||
"league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.0).",
|
||||
"league/flysystem-path-prefixing": "Required to use the scoped driver (^3.3).",
|
||||
"league/flysystem-read-only": "Required to use read-only disks (^3.3)",
|
||||
"league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.0).",
|
||||
"mockery/mockery": "Required to use mocking (^1.5.1).",
|
||||
"nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).",
|
||||
"pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).",
|
||||
"phpunit/phpunit": "Required to use assertions and run tests (^9.5.8).",
|
||||
"predis/predis": "Required to use the predis connector (^1.1.9|^2.0.2).",
|
||||
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
|
||||
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
|
||||
"symfony/cache": "Required to PSR-6 cache bridge (^6.0).",
|
||||
"symfony/filesystem": "Required to enable support for relative symbolic links (^6.0).",
|
||||
"symfony/http-client": "Required to enable support for the Symfony API mail transports (^6.0).",
|
||||
"symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^6.0).",
|
||||
"symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^6.0).",
|
||||
"symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0)."
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
|
||||
@@ -3,8 +3,112 @@
|
||||
namespace Illuminate\Auth\Access;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class AuthorizationException extends Exception
|
||||
{
|
||||
//
|
||||
/**
|
||||
* The response from the gate.
|
||||
*
|
||||
* @var \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* The HTTP response status code.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Create a new authorization exception instance.
|
||||
*
|
||||
* @param string|null $message
|
||||
* @param mixed $code
|
||||
* @param \Throwable|null $previous
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($message = null, $code = null, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message ?? 'This action is unauthorized.', 0, $previous);
|
||||
|
||||
$this->code = $code ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response from the gate.
|
||||
*
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public function response()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the response from the gate.
|
||||
*
|
||||
* @param \Illuminate\Auth\Access\Response $response
|
||||
* @return $this
|
||||
*/
|
||||
public function setResponse($response)
|
||||
{
|
||||
$this->response = $response;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP response status code.
|
||||
*
|
||||
* @param int|null $status
|
||||
* @return $this
|
||||
*/
|
||||
public function withStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP response status code to 404.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function asNotFound()
|
||||
{
|
||||
return $this->withStatus(404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the HTTP status code has been set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasStatus()
|
||||
{
|
||||
return $this->status !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTP status code.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a deny response object from this exception.
|
||||
*
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public function toResponse()
|
||||
{
|
||||
return Response::deny($this->message, $this->code)->withStatus($this->status);
|
||||
}
|
||||
}
|
||||
|
||||
51
vendor/laravel/framework/src/Illuminate/Auth/Access/Events/GateEvaluated.php
vendored
Normal file
51
vendor/laravel/framework/src/Illuminate/Auth/Access/Events/GateEvaluated.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Access\Events;
|
||||
|
||||
class GateEvaluated
|
||||
{
|
||||
/**
|
||||
* The authenticatable model.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* The ability being evaluated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $ability;
|
||||
|
||||
/**
|
||||
* The result of the evaluation.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public $result;
|
||||
|
||||
/**
|
||||
* The arguments given during evaluation.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $arguments;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param string $ability
|
||||
* @param bool|null $result
|
||||
* @param array $arguments
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($user, $ability, $result, $arguments)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->ability = $ability;
|
||||
$this->result = $result;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,18 @@
|
||||
|
||||
namespace Illuminate\Auth\Access;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Illuminate\Auth\Access\Events\GateEvaluated;
|
||||
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
|
||||
class Gate implements GateContract
|
||||
{
|
||||
@@ -53,6 +61,20 @@ class Gate implements GateContract
|
||||
*/
|
||||
protected $afterCallbacks = [];
|
||||
|
||||
/**
|
||||
* All of the defined abilities using class@method notation.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $stringCallbacks = [];
|
||||
|
||||
/**
|
||||
* The callback to be used to guess policy names.
|
||||
*
|
||||
* @var callable|null
|
||||
*/
|
||||
protected $guessPolicyNamesUsingCallback;
|
||||
|
||||
/**
|
||||
* Create a new gate instance.
|
||||
*
|
||||
@@ -62,10 +84,12 @@ class Gate implements GateContract
|
||||
* @param array $policies
|
||||
* @param array $beforeCallbacks
|
||||
* @param array $afterCallbacks
|
||||
* @param callable|null $guessPolicyNamesUsingCallback
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Container $container, callable $userResolver, array $abilities = [],
|
||||
array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [])
|
||||
array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [],
|
||||
callable $guessPolicyNamesUsingCallback = null)
|
||||
{
|
||||
$this->policies = $policies;
|
||||
$this->container = $container;
|
||||
@@ -73,36 +97,109 @@ class Gate implements GateContract
|
||||
$this->userResolver = $userResolver;
|
||||
$this->afterCallbacks = $afterCallbacks;
|
||||
$this->beforeCallbacks = $beforeCallbacks;
|
||||
$this->guessPolicyNamesUsingCallback = $guessPolicyNamesUsingCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given ability has been defined.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param string|array $ability
|
||||
* @return bool
|
||||
*/
|
||||
public function has($ability)
|
||||
{
|
||||
return isset($this->abilities[$ability]);
|
||||
$abilities = is_array($ability) ? $ability : func_get_args();
|
||||
|
||||
foreach ($abilities as $ability) {
|
||||
if (! isset($this->abilities[$ability])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is false.
|
||||
*
|
||||
* @param \Illuminate\Auth\Access\Response|\Closure|bool $condition
|
||||
* @param string|null $message
|
||||
* @param string|null $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function allowIf($condition, $message = null, $code = null)
|
||||
{
|
||||
return $this->authorizeOnDemand($condition, $message, $code, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is true.
|
||||
*
|
||||
* @param \Illuminate\Auth\Access\Response|\Closure|bool $condition
|
||||
* @param string|null $message
|
||||
* @param string|null $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function denyIf($condition, $message = null, $code = null)
|
||||
{
|
||||
return $this->authorizeOnDemand($condition, $message, $code, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize a given condition or callback.
|
||||
*
|
||||
* @param \Illuminate\Auth\Access\Response|\Closure|bool $condition
|
||||
* @param string|null $message
|
||||
* @param string|null $code
|
||||
* @param bool $allowWhenResponseIs
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
protected function authorizeOnDemand($condition, $message, $code, $allowWhenResponseIs)
|
||||
{
|
||||
$user = $this->resolveUser();
|
||||
|
||||
if ($condition instanceof Closure) {
|
||||
$response = $this->canBeCalledWithUser($user, $condition)
|
||||
? $condition($user)
|
||||
: new Response(false, $message, $code);
|
||||
} else {
|
||||
$response = $condition;
|
||||
}
|
||||
|
||||
return with($response instanceof Response ? $response : new Response(
|
||||
(bool) $response === $allowWhenResponseIs, $message, $code
|
||||
))->authorize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a new ability.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param callable|string $callback
|
||||
* @param callable|array|string $callback
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function define($ability, $callback)
|
||||
{
|
||||
if (is_array($callback) && isset($callback[0]) && is_string($callback[0])) {
|
||||
$callback = $callback[0].'@'.$callback[1];
|
||||
}
|
||||
|
||||
if (is_callable($callback)) {
|
||||
$this->abilities[$ability] = $callback;
|
||||
} elseif (is_string($callback) && Str::contains($callback, '@')) {
|
||||
$this->abilities[$ability] = $this->buildAbilityCallback($callback);
|
||||
} elseif (is_string($callback)) {
|
||||
$this->stringCallbacks[$ability] = $callback;
|
||||
|
||||
$this->abilities[$ability] = $this->buildAbilityCallback($ability, $callback);
|
||||
} else {
|
||||
throw new InvalidArgumentException("Callback must be a callable or a 'Class@method' string.");
|
||||
throw new InvalidArgumentException("Callback must be a callable, callback array, or a 'Class@method' string.");
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -113,13 +210,14 @@ class Gate implements GateContract
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $class
|
||||
* @param array $abilities
|
||||
* @param array|null $abilities
|
||||
* @return $this
|
||||
*/
|
||||
public function resource($name, $class, array $abilities = null)
|
||||
{
|
||||
$abilities = $abilities ?: [
|
||||
'view' => 'view',
|
||||
'viewAny' => 'viewAny',
|
||||
'view' => 'view',
|
||||
'create' => 'create',
|
||||
'update' => 'update',
|
||||
'delete' => 'delete',
|
||||
@@ -135,15 +233,36 @@ class Gate implements GateContract
|
||||
/**
|
||||
* Create the ability callback for a callback string.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param string $callback
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function buildAbilityCallback($callback)
|
||||
protected function buildAbilityCallback($ability, $callback)
|
||||
{
|
||||
return function () use ($callback) {
|
||||
list($class, $method) = Str::parseCallback($callback);
|
||||
return function () use ($ability, $callback) {
|
||||
if (str_contains($callback, '@')) {
|
||||
[$class, $method] = Str::parseCallback($callback);
|
||||
} else {
|
||||
$class = $callback;
|
||||
}
|
||||
|
||||
return $this->resolvePolicy($class)->{$method}(...func_get_args());
|
||||
$policy = $this->resolvePolicy($class);
|
||||
|
||||
$arguments = func_get_args();
|
||||
|
||||
$user = array_shift($arguments);
|
||||
|
||||
$result = $this->callPolicyBefore(
|
||||
$policy, $user, $ability, $arguments
|
||||
);
|
||||
|
||||
if (! is_null($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return isset($method)
|
||||
? $policy->{$method}(...func_get_args())
|
||||
: $policy(...func_get_args());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -212,19 +331,41 @@ class Gate implements GateContract
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given ability should be granted for the current user.
|
||||
* Determine if all of the given abilities should be granted for the current user.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param iterable|string $abilities
|
||||
* @param array|mixed $arguments
|
||||
* @return bool
|
||||
*/
|
||||
public function check($ability, $arguments = [])
|
||||
public function check($abilities, $arguments = [])
|
||||
{
|
||||
try {
|
||||
return (bool) $this->raw($ability, $arguments);
|
||||
} catch (AuthorizationException $e) {
|
||||
return false;
|
||||
}
|
||||
return collect($abilities)->every(
|
||||
fn ($ability) => $this->inspect($ability, $arguments)->allowed()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if any one of the given abilities should be granted for the current user.
|
||||
*
|
||||
* @param iterable|string $abilities
|
||||
* @param array|mixed $arguments
|
||||
* @return bool
|
||||
*/
|
||||
public function any($abilities, $arguments = [])
|
||||
{
|
||||
return collect($abilities)->contains(fn ($ability) => $this->check($ability, $arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if all of the given abilities should be denied for the current user.
|
||||
*
|
||||
* @param iterable|string $abilities
|
||||
* @param array|mixed $arguments
|
||||
* @return bool
|
||||
*/
|
||||
public function none($abilities, $arguments = [])
|
||||
{
|
||||
return ! $this->any($abilities, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,13 +379,29 @@ class Gate implements GateContract
|
||||
*/
|
||||
public function authorize($ability, $arguments = [])
|
||||
{
|
||||
$result = $this->raw($ability, $arguments);
|
||||
return $this->inspect($ability, $arguments)->authorize();
|
||||
}
|
||||
|
||||
if ($result instanceof Response) {
|
||||
return $result;
|
||||
/**
|
||||
* Inspect the user for the given ability.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param array|mixed $arguments
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public function inspect($ability, $arguments = [])
|
||||
{
|
||||
try {
|
||||
$result = $this->raw($ability, $arguments);
|
||||
|
||||
if ($result instanceof Response) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result ? Response::allow() : Response::deny();
|
||||
} catch (AuthorizationException $e) {
|
||||
return $e->toResponse();
|
||||
}
|
||||
|
||||
return $result ? $this->allow() : $this->deny();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,14 +410,14 @@ class Gate implements GateContract
|
||||
* @param string $ability
|
||||
* @param array|mixed $arguments
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
protected function raw($ability, $arguments = [])
|
||||
public function raw($ability, $arguments = [])
|
||||
{
|
||||
if (! $user = $this->resolveUser()) {
|
||||
return false;
|
||||
}
|
||||
$arguments = Arr::wrap($arguments);
|
||||
|
||||
$arguments = array_wrap($arguments);
|
||||
$user = $this->resolveUser();
|
||||
|
||||
// First we will call the "before" callbacks for the Gate. If any of these give
|
||||
// back a non-null response, we will immediately return that result in order
|
||||
@@ -276,17 +433,97 @@ class Gate implements GateContract
|
||||
// After calling the authorization callback, we will call the "after" callbacks
|
||||
// that are registered with the Gate, which allows a developer to do logging
|
||||
// if that is required for this application. Then we'll return the result.
|
||||
$this->callAfterCallbacks(
|
||||
return tap($this->callAfterCallbacks(
|
||||
$user, $ability, $arguments, $result
|
||||
);
|
||||
), function ($result) use ($user, $ability, $arguments) {
|
||||
$this->dispatchGateEvaluatedEvent($user, $ability, $arguments, $result);
|
||||
});
|
||||
}
|
||||
|
||||
return $result;
|
||||
/**
|
||||
* Determine whether the callback/method can be called with the given user.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param \Closure|string|array $class
|
||||
* @param string|null $method
|
||||
* @return bool
|
||||
*/
|
||||
protected function canBeCalledWithUser($user, $class, $method = null)
|
||||
{
|
||||
if (! is_null($user)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! is_null($method)) {
|
||||
return $this->methodAllowsGuests($class, $method);
|
||||
}
|
||||
|
||||
if (is_array($class)) {
|
||||
$className = is_string($class[0]) ? $class[0] : get_class($class[0]);
|
||||
|
||||
return $this->methodAllowsGuests($className, $class[1]);
|
||||
}
|
||||
|
||||
return $this->callbackAllowsGuests($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given class method allows guests.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
protected function methodAllowsGuests($class, $method)
|
||||
{
|
||||
try {
|
||||
$reflection = new ReflectionClass($class);
|
||||
|
||||
$method = $reflection->getMethod($method);
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($method) {
|
||||
$parameters = $method->getParameters();
|
||||
|
||||
return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the callback allows guests.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return bool
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected function callbackAllowsGuests($callback)
|
||||
{
|
||||
$parameters = (new ReflectionFunction($callback))->getParameters();
|
||||
|
||||
return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given parameter allows guests.
|
||||
*
|
||||
* @param \ReflectionParameter $parameter
|
||||
* @return bool
|
||||
*/
|
||||
protected function parameterAllowsGuests($parameter)
|
||||
{
|
||||
return ($parameter->hasType() && $parameter->allowsNull()) ||
|
||||
($parameter->isDefaultValueAvailable() && is_null($parameter->getDefaultValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve and call the appropriate authorization callback.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
@@ -301,17 +538,19 @@ class Gate implements GateContract
|
||||
/**
|
||||
* Call all of the before callbacks and return if a result is given.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @return bool|null
|
||||
*/
|
||||
protected function callBeforeCallbacks($user, $ability, array $arguments)
|
||||
{
|
||||
$arguments = array_merge([$user, $ability], [$arguments]);
|
||||
|
||||
foreach ($this->beforeCallbacks as $before) {
|
||||
if (! is_null($result = $before(...$arguments))) {
|
||||
if (! $this->canBeCalledWithUser($user, $before)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_null($result = $before($user, $ability, $arguments))) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -324,39 +563,72 @@ class Gate implements GateContract
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @param bool $result
|
||||
* @return void
|
||||
* @return bool|null
|
||||
*/
|
||||
protected function callAfterCallbacks($user, $ability, array $arguments, $result)
|
||||
{
|
||||
$arguments = array_merge([$user, $ability, $result], [$arguments]);
|
||||
|
||||
foreach ($this->afterCallbacks as $after) {
|
||||
$after(...$arguments);
|
||||
if (! $this->canBeCalledWithUser($user, $after)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$afterResult = $after($user, $ability, $result, $arguments);
|
||||
|
||||
$result ??= $afterResult;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a gate evaluation event.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @param bool|null $result
|
||||
* @return void
|
||||
*/
|
||||
protected function dispatchGateEvaluatedEvent($user, $ability, array $arguments, $result)
|
||||
{
|
||||
if ($this->container->bound(Dispatcher::class)) {
|
||||
$this->container->make(Dispatcher::class)->dispatch(
|
||||
new GateEvaluated($user, $ability, $result, $arguments)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the callable for the given ability and arguments.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @return callable
|
||||
*/
|
||||
protected function resolveAuthCallback($user, $ability, array $arguments)
|
||||
{
|
||||
if (isset($arguments[0])) {
|
||||
if (! is_null($policy = $this->getPolicyFor($arguments[0]))) {
|
||||
return $this->resolvePolicyCallback($user, $ability, $arguments, $policy);
|
||||
if (isset($arguments[0]) &&
|
||||
! is_null($policy = $this->getPolicyFor($arguments[0])) &&
|
||||
$callback = $this->resolvePolicyCallback($user, $ability, $arguments, $policy)) {
|
||||
return $callback;
|
||||
}
|
||||
|
||||
if (isset($this->stringCallbacks[$ability])) {
|
||||
[$class, $method] = Str::parseCallback($this->stringCallbacks[$ability]);
|
||||
|
||||
if ($this->canBeCalledWithUser($user, $class, $method ?: '__invoke')) {
|
||||
return $this->abilities[$ability];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->abilities[$ability])) {
|
||||
if (isset($this->abilities[$ability]) &&
|
||||
$this->canBeCalledWithUser($user, $this->abilities[$ability])) {
|
||||
return $this->abilities[$ability];
|
||||
}
|
||||
|
||||
return function () {
|
||||
return false;
|
||||
//
|
||||
};
|
||||
}
|
||||
|
||||
@@ -373,13 +645,19 @@ class Gate implements GateContract
|
||||
}
|
||||
|
||||
if (! is_string($class)) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->policies[$class])) {
|
||||
return $this->resolvePolicy($this->policies[$class]);
|
||||
}
|
||||
|
||||
foreach ($this->guessPolicyName($class) as $guessedPolicy) {
|
||||
if (class_exists($guessedPolicy)) {
|
||||
return $this->resolvePolicy($guessedPolicy);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->policies as $expected => $policy) {
|
||||
if (is_subclass_of($class, $expected)) {
|
||||
return $this->resolvePolicy($policy);
|
||||
@@ -387,11 +665,51 @@ class Gate implements GateContract
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess the policy name for the given class.
|
||||
*
|
||||
* @param string $class
|
||||
* @return array
|
||||
*/
|
||||
protected function guessPolicyName($class)
|
||||
{
|
||||
if ($this->guessPolicyNamesUsingCallback) {
|
||||
return Arr::wrap(call_user_func($this->guessPolicyNamesUsingCallback, $class));
|
||||
}
|
||||
|
||||
$classDirname = str_replace('/', '\\', dirname(str_replace('\\', '/', $class)));
|
||||
|
||||
$classDirnameSegments = explode('\\', $classDirname);
|
||||
|
||||
return Arr::wrap(Collection::times(count($classDirnameSegments), function ($index) use ($class, $classDirnameSegments) {
|
||||
$classDirname = implode('\\', array_slice($classDirnameSegments, 0, $index));
|
||||
|
||||
return $classDirname.'\\Policies\\'.class_basename($class).'Policy';
|
||||
})->reverse()->values()->first(function ($class) {
|
||||
return class_exists($class);
|
||||
}) ?: [$classDirname.'\\Policies\\'.class_basename($class).'Policy']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a callback to be used to guess policy names.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function guessPolicyNamesUsing(callable $callback)
|
||||
{
|
||||
$this->guessPolicyNamesUsingCallback = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a policy class instance of the given type.
|
||||
*
|
||||
* @param object|string $class
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
public function resolvePolicy($class)
|
||||
{
|
||||
@@ -405,10 +723,14 @@ class Gate implements GateContract
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @param mixed $policy
|
||||
* @return callable
|
||||
* @return bool|callable
|
||||
*/
|
||||
protected function resolvePolicyCallback($user, $ability, array $arguments, $policy)
|
||||
{
|
||||
if (! is_callable([$policy, $this->formatAbilityToMethod($ability)])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return function () use ($user, $ability, $arguments, $policy) {
|
||||
// This callback will be responsible for calling the policy's before method and
|
||||
// running this policy method if necessary. This is used to when objects are
|
||||
@@ -424,18 +746,9 @@ class Gate implements GateContract
|
||||
return $result;
|
||||
}
|
||||
|
||||
$ability = $this->formatAbilityToMethod($ability);
|
||||
$method = $this->formatAbilityToMethod($ability);
|
||||
|
||||
// If this first argument is a string, that means they are passing a class name
|
||||
// to the policy. We will remove the first argument from this argument array
|
||||
// because this policy already knows what type of models it can authorize.
|
||||
if (isset($arguments[0]) && is_string($arguments[0])) {
|
||||
array_shift($arguments);
|
||||
}
|
||||
|
||||
return is_callable([$policy, $ability])
|
||||
? $policy->{$ability}($user, ...$arguments)
|
||||
: false;
|
||||
return $this->callPolicyMethod($policy, $method, $user, $arguments);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -450,11 +763,42 @@ class Gate implements GateContract
|
||||
*/
|
||||
protected function callPolicyBefore($policy, $user, $ability, $arguments)
|
||||
{
|
||||
if (method_exists($policy, 'before')) {
|
||||
if (! method_exists($policy, 'before')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->canBeCalledWithUser($user, $policy, 'before')) {
|
||||
return $policy->before($user, $ability, ...$arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the appropriate method on the given policy.
|
||||
*
|
||||
* @param mixed $policy
|
||||
* @param string $method
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
protected function callPolicyMethod($policy, $method, $user, array $arguments)
|
||||
{
|
||||
// If this first argument is a string, that means they are passing a class name
|
||||
// to the policy. We will remove the first argument from this argument array
|
||||
// because this policy already knows what type of models it can authorize.
|
||||
if (isset($arguments[0]) && is_string($arguments[0])) {
|
||||
array_shift($arguments);
|
||||
}
|
||||
|
||||
if (! is_callable([$policy, $method])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->canBeCalledWithUser($user, $policy, $method)) {
|
||||
return $policy->{$method}($user, ...$arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the policy ability into a method name.
|
||||
*
|
||||
@@ -463,7 +807,7 @@ class Gate implements GateContract
|
||||
*/
|
||||
protected function formatAbilityToMethod($ability)
|
||||
{
|
||||
return strpos($ability, '-') !== false ? Str::camel($ability) : $ability;
|
||||
return str_contains($ability, '-') ? Str::camel($ability) : $ability;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -474,13 +818,12 @@ class Gate implements GateContract
|
||||
*/
|
||||
public function forUser($user)
|
||||
{
|
||||
$callback = function () use ($user) {
|
||||
return $user;
|
||||
};
|
||||
$callback = fn () => $user;
|
||||
|
||||
return new static(
|
||||
$this->container, $callback, $this->abilities,
|
||||
$this->policies, $this->beforeCallbacks, $this->afterCallbacks
|
||||
$this->policies, $this->beforeCallbacks, $this->afterCallbacks,
|
||||
$this->guessPolicyNamesUsingCallback
|
||||
);
|
||||
}
|
||||
|
||||
@@ -503,4 +846,27 @@ class Gate implements GateContract
|
||||
{
|
||||
return $this->abilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the defined policies.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function policies()
|
||||
{
|
||||
return $this->policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the container instance used by the gate.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Container\Container $container
|
||||
* @return $this
|
||||
*/
|
||||
public function setContainer(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,23 +8,48 @@ trait HandlesAuthorization
|
||||
* Create a new access response.
|
||||
*
|
||||
* @param string|null $message
|
||||
* @param mixed $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
protected function allow($message = null)
|
||||
protected function allow($message = null, $code = null)
|
||||
{
|
||||
return new Response($message);
|
||||
return Response::allow($message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an unauthorized exception.
|
||||
*
|
||||
* @param string $message
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
* @param string|null $message
|
||||
* @param mixed|null $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
protected function deny($message = 'This action is unauthorized.')
|
||||
protected function deny($message = null, $code = null)
|
||||
{
|
||||
throw new AuthorizationException($message);
|
||||
return Response::deny($message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny with a HTTP status code.
|
||||
*
|
||||
* @param int $status
|
||||
* @param ?string $message
|
||||
* @param ?int $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public function denyWithStatus($status, $message = null, $code = null)
|
||||
{
|
||||
return Response::denyWithStatus($status, $message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny with a 404 HTTP status code.
|
||||
*
|
||||
* @param ?string $message
|
||||
* @param ?int $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public function denyAsNotFound($message = null, $code = null)
|
||||
{
|
||||
return Response::denyWithStatus(404, $message, $code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,17 @@
|
||||
|
||||
namespace Illuminate\Auth\Access;
|
||||
|
||||
class Response
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
|
||||
class Response implements Arrayable
|
||||
{
|
||||
/**
|
||||
* Indicates whether the response was allowed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $allowed;
|
||||
|
||||
/**
|
||||
* The response message.
|
||||
*
|
||||
@@ -11,16 +20,104 @@ class Response
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* The response code.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $code;
|
||||
|
||||
/**
|
||||
* The HTTP response status code.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Create a new response.
|
||||
*
|
||||
* @param string|null $message
|
||||
* @param bool $allowed
|
||||
* @param string $message
|
||||
* @param mixed $code
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($message = null)
|
||||
public function __construct($allowed, $message = '', $code = null)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->allowed = $allowed;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new "allow" Response.
|
||||
*
|
||||
* @param string|null $message
|
||||
* @param mixed $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public static function allow($message = null, $code = null)
|
||||
{
|
||||
return new static(true, $message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new "deny" Response.
|
||||
*
|
||||
* @param string|null $message
|
||||
* @param mixed $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public static function deny($message = null, $code = null)
|
||||
{
|
||||
return new static(false, $message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new "deny" Response with a HTTP status code.
|
||||
*
|
||||
* @param int $status
|
||||
* @param string|null $message
|
||||
* @param mixed $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public static function denyWithStatus($status, $message = null, $code = null)
|
||||
{
|
||||
return static::deny($message, $code)->withStatus($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new "deny" Response with a 404 HTTP status code.
|
||||
*
|
||||
* @param string|null $message
|
||||
* @param mixed $code
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*/
|
||||
public static function denyAsNotFound($message = null, $code = null)
|
||||
{
|
||||
return static::denyWithStatus(404, $message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the response was allowed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allowed()
|
||||
{
|
||||
return $this->allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the response was denied.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function denied()
|
||||
{
|
||||
return ! $this->allowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response message.
|
||||
*
|
||||
@@ -31,6 +128,81 @@ class Response
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response code / reason.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function code()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw authorization exception if response was denied.
|
||||
*
|
||||
* @return \Illuminate\Auth\Access\Response
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if ($this->denied()) {
|
||||
throw (new AuthorizationException($this->message(), $this->code()))
|
||||
->setResponse($this)
|
||||
->withStatus($this->status);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP response status code.
|
||||
*
|
||||
* @param null|int $status
|
||||
* @return $this
|
||||
*/
|
||||
public function withStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP response status code to 404.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function asNotFound()
|
||||
{
|
||||
return $this->withStatus(404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTP status code.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the response to an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'allowed' => $this->allowed(),
|
||||
'message' => $this->message(),
|
||||
'code' => $this->code(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation of the message.
|
||||
*
|
||||
@@ -38,6 +210,6 @@ class Response
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->message();
|
||||
return (string) $this->message();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Contracts\Auth\Factory as FactoryContract;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @mixin \Illuminate\Contracts\Auth\Guard
|
||||
* @mixin \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
class AuthManager implements FactoryContract
|
||||
{
|
||||
use CreatesUserProviders;
|
||||
@@ -13,7 +17,7 @@ class AuthManager implements FactoryContract
|
||||
/**
|
||||
* The application instance.
|
||||
*
|
||||
* @var \Illuminate\Foundation\Application
|
||||
* @var \Illuminate\Contracts\Foundation\Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
@@ -43,31 +47,27 @@ class AuthManager implements FactoryContract
|
||||
/**
|
||||
* Create a new Auth manager instance.
|
||||
*
|
||||
* @param \Illuminate\Foundation\Application $app
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($app)
|
||||
{
|
||||
$this->app = $app;
|
||||
|
||||
$this->userResolver = function ($guard = null) {
|
||||
return $this->guard($guard)->user();
|
||||
};
|
||||
$this->userResolver = fn ($guard = null) => $this->guard($guard)->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the guard from the local cache.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $name
|
||||
* @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
public function guard($name = null)
|
||||
{
|
||||
$name = $name ?: $this->getDefaultDriver();
|
||||
|
||||
return isset($this->guards[$name])
|
||||
? $this->guards[$name]
|
||||
: $this->guards[$name] = $this->resolve($name);
|
||||
return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,7 +96,9 @@ class AuthManager implements FactoryContract
|
||||
return $this->{$driverMethod}($name, $config);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined.");
|
||||
throw new InvalidArgumentException(
|
||||
"Auth driver [{$config['driver']}] for guard [{$name}] is not defined."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,9 +122,13 @@ class AuthManager implements FactoryContract
|
||||
*/
|
||||
public function createSessionDriver($name, $config)
|
||||
{
|
||||
$provider = $this->createUserProvider($config['provider']);
|
||||
$provider = $this->createUserProvider($config['provider'] ?? null);
|
||||
|
||||
$guard = new SessionGuard($name, $provider, $this->app['session.store']);
|
||||
$guard = new SessionGuard(
|
||||
$name,
|
||||
$provider,
|
||||
$this->app['session.store'],
|
||||
);
|
||||
|
||||
// When using the remember me functionality of the authentication services we
|
||||
// will need to be set the encryption instance of the guard, which allows
|
||||
@@ -139,6 +145,10 @@ class AuthManager implements FactoryContract
|
||||
$guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
|
||||
}
|
||||
|
||||
if (isset($config['remember'])) {
|
||||
$guard->setRememberDuration($config['remember']);
|
||||
}
|
||||
|
||||
return $guard;
|
||||
}
|
||||
|
||||
@@ -155,8 +165,11 @@ class AuthManager implements FactoryContract
|
||||
// that takes an API token field from the request and matches it to the
|
||||
// user in the database or another persistence layer where users are.
|
||||
$guard = new TokenGuard(
|
||||
$this->createUserProvider($config['provider']),
|
||||
$this->app['request']
|
||||
$this->createUserProvider($config['provider'] ?? null),
|
||||
$this->app['request'],
|
||||
$config['input_key'] ?? 'api_token',
|
||||
$config['storage_key'] ?? 'api_token',
|
||||
$config['hash'] ?? false
|
||||
);
|
||||
|
||||
$this->app->refresh('request', $guard, 'setRequest');
|
||||
@@ -197,9 +210,7 @@ class AuthManager implements FactoryContract
|
||||
|
||||
$this->setDefaultDriver($name);
|
||||
|
||||
$this->userResolver = function ($name = null) {
|
||||
return $this->guard($name)->user();
|
||||
};
|
||||
$this->userResolver = fn ($name = null) => $this->guard($name)->user();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +234,7 @@ class AuthManager implements FactoryContract
|
||||
public function viaRequest($driver, callable $callback)
|
||||
{
|
||||
return $this->extend($driver, function () use ($callback) {
|
||||
$guard = new RequestGuard($callback, $this->app['request']);
|
||||
$guard = new RequestGuard($callback, $this->app['request'], $this->createUserProvider());
|
||||
|
||||
$this->app->refresh('request', $guard, 'setRequest');
|
||||
|
||||
@@ -282,6 +293,41 @@ class AuthManager implements FactoryContract
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if any guards have already been resolved.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasResolvedGuards()
|
||||
{
|
||||
return count($this->guards) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget all of the resolved guard instances.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function forgetGuards()
|
||||
{
|
||||
$this->guards = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the application instance used by the manager.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @return $this
|
||||
*/
|
||||
public function setApplication($app)
|
||||
{
|
||||
$this->app = $app;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically call the default driver instance.
|
||||
*
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Auth\Access\Gate;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Auth\Middleware\RequirePassword;
|
||||
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||
use Illuminate\Contracts\Routing\UrlGenerator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -17,12 +20,11 @@ class AuthServiceProvider extends ServiceProvider
|
||||
public function register()
|
||||
{
|
||||
$this->registerAuthenticator();
|
||||
|
||||
$this->registerUserResolver();
|
||||
|
||||
$this->registerAccessGate();
|
||||
|
||||
$this->registerRequirePassword();
|
||||
$this->registerRequestRebindHandler();
|
||||
$this->registerEventRebindHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,18 +34,9 @@ class AuthServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected function registerAuthenticator()
|
||||
{
|
||||
$this->app->singleton('auth', function ($app) {
|
||||
// Once the authentication service has actually been requested by the developer
|
||||
// we will set a variable in the application indicating such. This helps us
|
||||
// know that we need to set any queued cookies in the after event later.
|
||||
$app['auth.loaded'] = true;
|
||||
$this->app->singleton('auth', fn ($app) => new AuthManager($app));
|
||||
|
||||
return new AuthManager($app);
|
||||
});
|
||||
|
||||
$this->app->singleton('auth.driver', function ($app) {
|
||||
return $app['auth']->guard();
|
||||
});
|
||||
$this->app->singleton('auth.driver', fn ($app) => $app['auth']->guard());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,11 +46,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected function registerUserResolver()
|
||||
{
|
||||
$this->app->bind(
|
||||
AuthenticatableContract::class, function ($app) {
|
||||
return call_user_func($app['auth']->userResolver());
|
||||
}
|
||||
);
|
||||
$this->app->bind(AuthenticatableContract::class, fn ($app) => call_user_func($app['auth']->userResolver()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,9 +57,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
protected function registerAccessGate()
|
||||
{
|
||||
$this->app->singleton(GateContract::class, function ($app) {
|
||||
return new Gate($app, function () use ($app) {
|
||||
return call_user_func($app['auth']->userResolver());
|
||||
});
|
||||
return new Gate($app, fn () => call_user_func($app['auth']->userResolver()));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,6 +66,22 @@ class AuthServiceProvider extends ServiceProvider
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerRequirePassword()
|
||||
{
|
||||
$this->app->bind(RequirePassword::class, function ($app) {
|
||||
return new RequirePassword(
|
||||
$app[ResponseFactory::class],
|
||||
$app[UrlGenerator::class],
|
||||
$app['config']->get('auth.password_timeout')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the re-binding of the request binding.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerRequestRebindHandler()
|
||||
{
|
||||
$this->app->rebinding('request', function ($app, $request) {
|
||||
@@ -87,4 +90,23 @@ class AuthServiceProvider extends ServiceProvider
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the re-binding of the event dispatcher binding.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerEventRebindHandler()
|
||||
{
|
||||
$this->app->rebinding('events', function ($app, $dispatcher) {
|
||||
if (! $app->resolved('auth') ||
|
||||
$app['auth']->hasResolvedGuards() === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (method_exists($guard = $app['auth']->guard(), 'setDispatcher')) {
|
||||
$guard->setDispatcher($dispatcher);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,16 @@ trait Authenticatable
|
||||
return $this->{$this->getAuthIdentifierName()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique broadcast identifier for the user.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAuthIdentifierForBroadcasting()
|
||||
{
|
||||
return $this->getAuthIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the password for the user.
|
||||
*
|
||||
@@ -44,12 +54,12 @@ trait Authenticatable
|
||||
/**
|
||||
* Get the token value for the "remember me" session.
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRememberToken()
|
||||
{
|
||||
if (! empty($this->getRememberTokenName())) {
|
||||
return $this->{$this->getRememberTokenName()};
|
||||
return (string) $this->{$this->getRememberTokenName()};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,18 +13,27 @@ class AuthenticationException extends Exception
|
||||
*/
|
||||
protected $guards;
|
||||
|
||||
/**
|
||||
* The path the user should be redirected to.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $redirectTo;
|
||||
|
||||
/**
|
||||
* Create a new authentication exception.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $guards
|
||||
* @param string|null $redirectTo
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($message = 'Unauthenticated.', array $guards = [])
|
||||
public function __construct($message = 'Unauthenticated.', array $guards = [], $redirectTo = null)
|
||||
{
|
||||
parent::__construct($message);
|
||||
|
||||
$this->guards = $guards;
|
||||
$this->redirectTo = $redirectTo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,4 +45,14 @@ class AuthenticationException extends Exception
|
||||
{
|
||||
return $this->guards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path the user should be redirected to.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function redirectTo()
|
||||
{
|
||||
return $this->redirectTo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
namespace Illuminate\Auth\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand(name: 'auth:clear-resets')]
|
||||
class ClearResetsCommand extends Command
|
||||
{
|
||||
/**
|
||||
@@ -13,6 +15,17 @@ class ClearResetsCommand extends Command
|
||||
*/
|
||||
protected $signature = 'auth:clear-resets {name? : The name of the password broker}';
|
||||
|
||||
/**
|
||||
* The name of the console command.
|
||||
*
|
||||
* This name is used to identify the command during lazy loading.
|
||||
*
|
||||
* @var string|null
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
protected static $defaultName = 'auth:clear-resets';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -25,10 +38,10 @@ class ClearResetsCommand extends Command
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fire()
|
||||
public function handle()
|
||||
{
|
||||
$this->laravel['auth.password']->broker($this->argument('name'))->getRepository()->deleteExpired();
|
||||
|
||||
$this->info('Expired reset tokens cleared!');
|
||||
$this->components->info('Expired reset tokens cleared successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Console\DetectsApplicationNamespace;
|
||||
|
||||
class MakeAuthCommand extends Command
|
||||
{
|
||||
use DetectsApplicationNamespace;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'make:auth
|
||||
{--views : Only scaffold the authentication views}
|
||||
{--force : Overwrite existing views by default}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Scaffold basic login and registration views and routes';
|
||||
|
||||
/**
|
||||
* The views that need to be exported.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $views = [
|
||||
'auth/login.stub' => 'auth/login.blade.php',
|
||||
'auth/register.stub' => 'auth/register.blade.php',
|
||||
'auth/passwords/email.stub' => 'auth/passwords/email.blade.php',
|
||||
'auth/passwords/reset.stub' => 'auth/passwords/reset.blade.php',
|
||||
'layouts/app.stub' => 'layouts/app.blade.php',
|
||||
'home.stub' => 'home.blade.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fire()
|
||||
{
|
||||
$this->createDirectories();
|
||||
|
||||
$this->exportViews();
|
||||
|
||||
if (! $this->option('views')) {
|
||||
file_put_contents(
|
||||
app_path('Http/Controllers/HomeController.php'),
|
||||
$this->compileControllerStub()
|
||||
);
|
||||
|
||||
file_put_contents(
|
||||
base_path('routes/web.php'),
|
||||
file_get_contents(__DIR__.'/stubs/make/routes.stub'),
|
||||
FILE_APPEND
|
||||
);
|
||||
}
|
||||
|
||||
$this->info('Authentication scaffolding generated successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the directories for the files.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createDirectories()
|
||||
{
|
||||
if (! is_dir(resource_path('views/layouts'))) {
|
||||
mkdir(resource_path('views/layouts'), 0755, true);
|
||||
}
|
||||
|
||||
if (! is_dir(resource_path('views/auth/passwords'))) {
|
||||
mkdir(resource_path('views/auth/passwords'), 0755, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the authentication views.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function exportViews()
|
||||
{
|
||||
foreach ($this->views as $key => $value) {
|
||||
if (file_exists(resource_path('views/'.$value)) && ! $this->option('force')) {
|
||||
if (! $this->confirm("The [{$value}] view already exists. Do you want to replace it?")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
copy(
|
||||
__DIR__.'/stubs/make/views/'.$key,
|
||||
resource_path('views/'.$value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the HomeController stub.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function compileControllerStub()
|
||||
{
|
||||
return str_replace(
|
||||
'{{namespace}}',
|
||||
$this->getAppNamespace(),
|
||||
file_get_contents(__DIR__.'/stubs/make/controllers/HomeController.stub')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace {{namespace}}Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application dashboard.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('home');
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
Auth::routes();
|
||||
|
||||
Route::get('/home', 'HomeController@index')->name('home');
|
||||
@@ -1,68 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Login</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="POST" action="{{ route('login') }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
|
||||
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>
|
||||
|
||||
@if ($errors->has('email'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('email') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
|
||||
<label for="password" class="col-md-4 control-label">Password</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control" name="password" required>
|
||||
|
||||
@if ($errors->has('password'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('password') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-6 col-md-offset-4">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}> Remember Me
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-8 col-md-offset-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Login
|
||||
</button>
|
||||
|
||||
<a class="btn btn-link" href="{{ route('password.request') }}">
|
||||
Forgot Your Password?
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,46 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Reset Password</div>
|
||||
<div class="panel-body">
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form class="form-horizontal" method="POST" action="{{ route('password.email') }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
|
||||
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>
|
||||
|
||||
@if ($errors->has('email'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('email') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-6 col-md-offset-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Send Password Reset Link
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,76 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Reset Password</div>
|
||||
|
||||
<div class="panel-body">
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form class="form-horizontal" method="POST" action="{{ route('password.request') }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
|
||||
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
|
||||
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control" name="email" value="{{ $email or old('email') }}" required autofocus>
|
||||
|
||||
@if ($errors->has('email'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('email') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
|
||||
<label for="password" class="col-md-4 control-label">Password</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control" name="password" required>
|
||||
|
||||
@if ($errors->has('password'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('password') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
|
||||
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
|
||||
|
||||
@if ($errors->has('password_confirmation'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('password_confirmation') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-6 col-md-offset-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Reset Password
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,76 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Register</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" method="POST" action="{{ route('register') }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
|
||||
<label for="name" class="col-md-4 control-label">Name</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}" required autofocus>
|
||||
|
||||
@if ($errors->has('name'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('name') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
|
||||
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>
|
||||
|
||||
@if ($errors->has('email'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('email') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
|
||||
<label for="password" class="col-md-4 control-label">Password</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control" name="password" required>
|
||||
|
||||
@if ($errors->has('password'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('password') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-6 col-md-offset-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Register
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,17 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Dashboard</div>
|
||||
|
||||
<div class="panel-body">
|
||||
You are logged in!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,8 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ app()->getLocale() }}">
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- CSRF Token -->
|
||||
@@ -10,71 +9,68 @@
|
||||
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="{{ asset('js/app.js') }}" defer></script>
|
||||
|
||||
<!-- Styles -->
|
||||
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<nav class="navbar navbar-default navbar-static-top">
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="{{ url('/') }}">
|
||||
{{ config('app.name', 'Laravel') }}
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<!-- Collapsed Hamburger -->
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse">
|
||||
<span class="sr-only">Toggle Navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
|
||||
<!-- Branding Image -->
|
||||
<a class="navbar-brand" href="{{ url('/') }}">
|
||||
{{ config('app.name', 'Laravel') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="app-navbar-collapse">
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<!-- Left Side Of Navbar -->
|
||||
<ul class="nav navbar-nav">
|
||||
|
||||
<ul class="navbar-nav mr-auto">
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Right Side Of Navbar -->
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<!-- Authentication Links -->
|
||||
@if (Auth::guest())
|
||||
<li><a href="{{ route('login') }}">Login</a></li>
|
||||
<li><a href="{{ route('register') }}">Register</a></li>
|
||||
@guest
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
|
||||
</li>
|
||||
@if (Route::has('register'))
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
|
||||
</li>
|
||||
@endif
|
||||
@else
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
|
||||
<li class="nav-item dropdown">
|
||||
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
|
||||
{{ Auth::user()->name }} <span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<a href="{{ route('logout') }}"
|
||||
onclick="event.preventDefault();
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item" href="{{ route('logout') }}"
|
||||
onclick="event.preventDefault();
|
||||
document.getElementById('logout-form').submit();">
|
||||
Logout
|
||||
</a>
|
||||
{{ __('Logout') }}
|
||||
</a>
|
||||
|
||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
|
||||
{{ csrf_field() }}
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
|
||||
@csrf
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
@endif
|
||||
@endguest
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@yield('content')
|
||||
<main class="py-4">
|
||||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="{{ asset('js/app.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -16,28 +16,42 @@ trait CreatesUserProviders
|
||||
/**
|
||||
* Create the user provider implementation for the driver.
|
||||
*
|
||||
* @param string $provider
|
||||
* @return \Illuminate\Contracts\Auth\UserProvider
|
||||
* @param string|null $provider
|
||||
* @return \Illuminate\Contracts\Auth\UserProvider|null
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function createUserProvider($provider)
|
||||
public function createUserProvider($provider = null)
|
||||
{
|
||||
$config = $this->app['config']['auth.providers.'.$provider];
|
||||
if (is_null($config = $this->getProviderConfiguration($provider))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->customProviderCreators[$config['driver']])) {
|
||||
if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
|
||||
return call_user_func(
|
||||
$this->customProviderCreators[$config['driver']], $this->app, $config
|
||||
$this->customProviderCreators[$driver], $this->app, $config
|
||||
);
|
||||
}
|
||||
|
||||
switch ($config['driver']) {
|
||||
case 'database':
|
||||
return $this->createDatabaseProvider($config);
|
||||
case 'eloquent':
|
||||
return $this->createEloquentProvider($config);
|
||||
default:
|
||||
throw new InvalidArgumentException("Authentication user provider [{$config['driver']}] is not defined.");
|
||||
return match ($driver) {
|
||||
'database' => $this->createDatabaseProvider($config),
|
||||
'eloquent' => $this->createEloquentProvider($config),
|
||||
default => throw new InvalidArgumentException(
|
||||
"Authentication user provider [{$driver}] is not defined."
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user provider configuration.
|
||||
*
|
||||
* @param string|null $provider
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getProviderConfiguration($provider)
|
||||
{
|
||||
if ($provider = $provider ?: $this->getDefaultUserProvider()) {
|
||||
return $this->app['config']['auth.providers.'.$provider];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +63,7 @@ trait CreatesUserProviders
|
||||
*/
|
||||
protected function createDatabaseProvider($config)
|
||||
{
|
||||
$connection = $this->app['db']->connection();
|
||||
$connection = $this->app['db']->connection($config['connection'] ?? null);
|
||||
|
||||
return new DatabaseUserProvider($connection, $this->app['hash'], $config['table']);
|
||||
}
|
||||
@@ -64,4 +78,14 @@ trait CreatesUserProviders
|
||||
{
|
||||
return new EloquentUserProvider($this->app['hash'], $config['model']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default user provider name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultUserProvider()
|
||||
{
|
||||
return $this->app['config']['auth.defaults.provider'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
|
||||
class DatabaseUserProvider implements UserProvider
|
||||
{
|
||||
@@ -15,7 +16,7 @@ class DatabaseUserProvider implements UserProvider
|
||||
*
|
||||
* @var \Illuminate\Database\ConnectionInterface
|
||||
*/
|
||||
protected $conn;
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The hasher implementation.
|
||||
@@ -34,14 +35,14 @@ class DatabaseUserProvider implements UserProvider
|
||||
/**
|
||||
* Create a new database user provider.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $conn
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param \Illuminate\Contracts\Hashing\Hasher $hasher
|
||||
* @param string $table
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ConnectionInterface $conn, HasherContract $hasher, $table)
|
||||
public function __construct(ConnectionInterface $connection, HasherContract $hasher, $table)
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->connection = $connection;
|
||||
$this->table = $table;
|
||||
$this->hasher = $hasher;
|
||||
}
|
||||
@@ -54,7 +55,7 @@ class DatabaseUserProvider implements UserProvider
|
||||
*/
|
||||
public function retrieveById($identifier)
|
||||
{
|
||||
$user = $this->conn->table($this->table)->find($identifier);
|
||||
$user = $this->connection->table($this->table)->find($identifier);
|
||||
|
||||
return $this->getGenericUser($user);
|
||||
}
|
||||
@@ -68,12 +69,12 @@ class DatabaseUserProvider implements UserProvider
|
||||
*/
|
||||
public function retrieveByToken($identifier, $token)
|
||||
{
|
||||
$user = $this->conn->table($this->table)
|
||||
->where('id', $identifier)
|
||||
->where('remember_token', $token)
|
||||
->first();
|
||||
$user = $this->getGenericUser(
|
||||
$this->connection->table($this->table)->find($identifier)
|
||||
);
|
||||
|
||||
return $this->getGenericUser($user);
|
||||
return $user && $user->getRememberToken() && hash_equals($user->getRememberToken(), $token)
|
||||
? $user : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,9 +86,9 @@ class DatabaseUserProvider implements UserProvider
|
||||
*/
|
||||
public function updateRememberToken(UserContract $user, $token)
|
||||
{
|
||||
$this->conn->table($this->table)
|
||||
->where('id', $user->getAuthIdentifier())
|
||||
->update(['remember_token' => $token]);
|
||||
$this->connection->table($this->table)
|
||||
->where($user->getAuthIdentifierName(), $user->getAuthIdentifier())
|
||||
->update([$user->getRememberTokenName() => $token]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,20 +99,34 @@ class DatabaseUserProvider implements UserProvider
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
$credentials = array_filter(
|
||||
$credentials,
|
||||
fn ($key) => ! str_contains($key, 'password'),
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
|
||||
if (empty($credentials)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First we will add each credential element to the query as a where clause.
|
||||
// Then we can execute the query and, if we found a user, return it in a
|
||||
// generic "user" object that will be utilized by the Guard instances.
|
||||
$query = $this->conn->table($this->table);
|
||||
$query = $this->connection->table($this->table);
|
||||
|
||||
foreach ($credentials as $key => $value) {
|
||||
if (! Str::contains($key, 'password')) {
|
||||
if (is_array($value) || $value instanceof Arrayable) {
|
||||
$query->whereIn($key, $value);
|
||||
} elseif ($value instanceof Closure) {
|
||||
$value($query);
|
||||
} else {
|
||||
$query->where($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we are ready to execute the query to see if we have an user matching
|
||||
// the given credentials. If not, we will just return nulls and indicate
|
||||
// that there are no matching users for these given credential arrays.
|
||||
// Now we are ready to execute the query to see if we have a user matching
|
||||
// the given credentials. If not, we will just return null and indicate
|
||||
// that there are no matching users from the given credential arrays.
|
||||
$user = $query->first();
|
||||
|
||||
return $this->getGenericUser($user);
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
|
||||
class EloquentUserProvider implements UserProvider
|
||||
{
|
||||
@@ -23,6 +24,13 @@ class EloquentUserProvider implements UserProvider
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* The callback that may modify the user retrieval queries.
|
||||
*
|
||||
* @var (\Closure(\Illuminate\Database\Eloquent\Builder):mixed)|null
|
||||
*/
|
||||
protected $queryCallback;
|
||||
|
||||
/**
|
||||
* Create a new database user provider.
|
||||
*
|
||||
@@ -46,9 +54,9 @@ class EloquentUserProvider implements UserProvider
|
||||
{
|
||||
$model = $this->createModel();
|
||||
|
||||
return $model->newQuery()
|
||||
->where($model->getAuthIdentifierName(), $identifier)
|
||||
->first();
|
||||
return $this->newModelQuery($model)
|
||||
->where($model->getAuthIdentifierName(), $identifier)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,10 +70,17 @@ class EloquentUserProvider implements UserProvider
|
||||
{
|
||||
$model = $this->createModel();
|
||||
|
||||
return $model->newQuery()
|
||||
->where($model->getAuthIdentifierName(), $identifier)
|
||||
->where($model->getRememberTokenName(), $token)
|
||||
->first();
|
||||
$retrievedModel = $this->newModelQuery($model)->where(
|
||||
$model->getAuthIdentifierName(), $identifier
|
||||
)->first();
|
||||
|
||||
if (! $retrievedModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rememberToken = $retrievedModel->getRememberToken();
|
||||
|
||||
return $rememberToken && hash_equals($rememberToken, $token) ? $retrievedModel : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,6 +111,12 @@ class EloquentUserProvider implements UserProvider
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
$credentials = array_filter(
|
||||
$credentials,
|
||||
fn ($key) => ! str_contains($key, 'password'),
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
|
||||
if (empty($credentials)) {
|
||||
return;
|
||||
}
|
||||
@@ -103,10 +124,14 @@ class EloquentUserProvider implements UserProvider
|
||||
// First we will add each credential element to the query as a where clause.
|
||||
// Then we can execute the query and, if we found a user, return it in a
|
||||
// Eloquent User "model" that will be utilized by the Guard instances.
|
||||
$query = $this->createModel()->newQuery();
|
||||
$query = $this->newModelQuery();
|
||||
|
||||
foreach ($credentials as $key => $value) {
|
||||
if (! Str::contains($key, 'password')) {
|
||||
if (is_array($value) || $value instanceof Arrayable) {
|
||||
$query->whereIn($key, $value);
|
||||
} elseif ($value instanceof Closure) {
|
||||
$value($query);
|
||||
} else {
|
||||
$query->where($key, $value);
|
||||
}
|
||||
}
|
||||
@@ -128,6 +153,23 @@ class EloquentUserProvider implements UserProvider
|
||||
return $this->hasher->check($plain, $user->getAuthPassword());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new query builder for the model instance.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model|null $model
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
protected function newModelQuery($model = null)
|
||||
{
|
||||
$query = is_null($model)
|
||||
? $this->createModel()->newQuery()
|
||||
: $model->newQuery();
|
||||
|
||||
with($query, $this->queryCallback);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the model.
|
||||
*
|
||||
@@ -185,4 +227,27 @@ class EloquentUserProvider implements UserProvider
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the callback that modifies the query before retrieving users.
|
||||
*
|
||||
* @return \Closure|null
|
||||
*/
|
||||
public function getQueryCallback()
|
||||
{
|
||||
return $this->queryCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callback to modify the query before retrieving users.
|
||||
*
|
||||
* @param (\Closure(\Illuminate\Database\Eloquent\Builder):mixed)|null $queryCallback
|
||||
* @return $this
|
||||
*/
|
||||
public function withQuery($queryCallback = null)
|
||||
{
|
||||
$this->queryCallback = $queryCallback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@ namespace Illuminate\Auth\Events;
|
||||
|
||||
class Attempting
|
||||
{
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The credentials for the user.
|
||||
*
|
||||
@@ -21,11 +28,14 @@ class Attempting
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param array $credentials
|
||||
* @param bool $remember
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($credentials, $remember)
|
||||
public function __construct($guard, $credentials, $remember)
|
||||
{
|
||||
$this->guard = $guard;
|
||||
$this->remember = $remember;
|
||||
$this->credentials = $credentials;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@ class Authenticated
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The authenticated user.
|
||||
*
|
||||
@@ -18,11 +25,13 @@ class Authenticated
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($user)
|
||||
public function __construct($guard, $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->guard = $guard;
|
||||
}
|
||||
}
|
||||
|
||||
37
vendor/laravel/framework/src/Illuminate/Auth/Events/CurrentDeviceLogout.php
vendored
Normal file
37
vendor/laravel/framework/src/Illuminate/Auth/Events/CurrentDeviceLogout.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Events;
|
||||
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CurrentDeviceLogout
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The authenticated user.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($guard, $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->guard = $guard;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,13 @@ namespace Illuminate\Auth\Events;
|
||||
|
||||
class Failed
|
||||
{
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The user the attempter was trying to authenticate as.
|
||||
*
|
||||
@@ -21,12 +28,15 @@ class Failed
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @param array $credentials
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($user, $credentials)
|
||||
public function __construct($guard, $user, $credentials)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->guard = $guard;
|
||||
$this->credentials = $credentials;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@ class Login
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The authenticated user.
|
||||
*
|
||||
@@ -25,13 +32,15 @@ class Login
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param bool $remember
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($user, $remember)
|
||||
public function __construct($guard, $user, $remember)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->guard = $guard;
|
||||
$this->remember = $remember;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@ class Logout
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The authenticated user.
|
||||
*
|
||||
@@ -18,11 +25,13 @@ class Logout
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($user)
|
||||
public function __construct($guard, $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->guard = $guard;
|
||||
}
|
||||
}
|
||||
|
||||
37
vendor/laravel/framework/src/Illuminate/Auth/Events/OtherDeviceLogout.php
vendored
Normal file
37
vendor/laravel/framework/src/Illuminate/Auth/Events/OtherDeviceLogout.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Events;
|
||||
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class OtherDeviceLogout
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The authenticated user.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($guard, $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->guard = $guard;
|
||||
}
|
||||
}
|
||||
28
vendor/laravel/framework/src/Illuminate/Auth/Events/PasswordReset.php
vendored
Normal file
28
vendor/laravel/framework/src/Illuminate/Auth/Events/PasswordReset.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Events;
|
||||
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class PasswordReset
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The user.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
}
|
||||
37
vendor/laravel/framework/src/Illuminate/Auth/Events/Validated.php
vendored
Normal file
37
vendor/laravel/framework/src/Illuminate/Auth/Events/Validated.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Events;
|
||||
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class Validated
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The authentication guard name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $guard;
|
||||
|
||||
/**
|
||||
* The user retrieved and validated from the User Provider.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $guard
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($guard, $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->guard = $guard;
|
||||
}
|
||||
}
|
||||
28
vendor/laravel/framework/src/Illuminate/Auth/Events/Verified.php
vendored
Normal file
28
vendor/laravel/framework/src/Illuminate/Auth/Events/Verified.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Events;
|
||||
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class Verified
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The verified user.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\MustVerifyEmail
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\MustVerifyEmail $user
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
}
|
||||
@@ -41,9 +41,7 @@ class GenericUser implements UserContract
|
||||
*/
|
||||
public function getAuthIdentifier()
|
||||
{
|
||||
$name = $this->getAuthIdentifierName();
|
||||
|
||||
return $this->attributes[$name];
|
||||
return $this->attributes[$this->getAuthIdentifierName()];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
|
||||
/**
|
||||
* These methods are typically the same across all guards.
|
||||
@@ -24,7 +25,7 @@ trait GuardHelpers
|
||||
protected $provider;
|
||||
|
||||
/**
|
||||
* Determine if the current user is authenticated.
|
||||
* Determine if the current user is authenticated. If not, throw an exception.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable
|
||||
*
|
||||
@@ -39,6 +40,16 @@ trait GuardHelpers
|
||||
throw new AuthenticationException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the guard has a user instance.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasUser()
|
||||
{
|
||||
return ! is_null($this->user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user is authenticated.
|
||||
*
|
||||
@@ -62,7 +73,7 @@ trait GuardHelpers
|
||||
/**
|
||||
* Get the ID for the currently authenticated user.
|
||||
*
|
||||
* @return int|null
|
||||
* @return int|string|null
|
||||
*/
|
||||
public function id()
|
||||
{
|
||||
@@ -83,4 +94,37 @@ trait GuardHelpers
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget the current user.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function forgetUser()
|
||||
{
|
||||
$this->user = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user provider used by the guard.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\UserProvider
|
||||
*/
|
||||
public function getProvider()
|
||||
{
|
||||
return $this->provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user provider used by the guard.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider $provider
|
||||
* @return void
|
||||
*/
|
||||
public function setProvider(UserProvider $provider)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
}
|
||||
}
|
||||
|
||||
21
vendor/laravel/framework/src/Illuminate/Auth/LICENSE.md
vendored
Normal file
21
vendor/laravel/framework/src/Illuminate/Auth/LICENSE.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Taylor Otwell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
22
vendor/laravel/framework/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php
vendored
Normal file
22
vendor/laravel/framework/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Listeners;
|
||||
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
|
||||
class SendEmailVerificationNotification
|
||||
{
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param \Illuminate\Auth\Events\Registered $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(Registered $event)
|
||||
{
|
||||
if ($event->user instanceof MustVerifyEmail && ! $event->user->hasVerifiedEmail()) {
|
||||
$event->user->sendEmailVerificationNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,9 @@ namespace Illuminate\Auth\Middleware;
|
||||
use Closure;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Contracts\Auth\Factory as Auth;
|
||||
use Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests;
|
||||
|
||||
class Authenticate
|
||||
class Authenticate implements AuthenticatesRequests
|
||||
{
|
||||
/**
|
||||
* The authentication factory instance.
|
||||
@@ -38,7 +39,7 @@ class Authenticate
|
||||
*/
|
||||
public function handle($request, Closure $next, ...$guards)
|
||||
{
|
||||
$this->authenticate($guards);
|
||||
$this->authenticate($request, $guards);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@@ -46,15 +47,16 @@ class Authenticate
|
||||
/**
|
||||
* Determine if the user is logged in to any of the given guards.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param array $guards
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
*/
|
||||
protected function authenticate(array $guards)
|
||||
protected function authenticate($request, array $guards)
|
||||
{
|
||||
if (empty($guards)) {
|
||||
return $this->auth->authenticate();
|
||||
$guards = [null];
|
||||
}
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
@@ -63,6 +65,33 @@ class Authenticate
|
||||
}
|
||||
}
|
||||
|
||||
throw new AuthenticationException('Unauthenticated.', $guards);
|
||||
$this->unauthenticated($request, $guards);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an unauthenticated user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param array $guards
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
*/
|
||||
protected function unauthenticated($request, array $guards)
|
||||
{
|
||||
throw new AuthenticationException(
|
||||
'Unauthenticated.', $guards, $this->redirectTo($request)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,15 @@ class AuthenticateWithBasicAuth
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @param string|null $field
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
public function handle($request, Closure $next, $guard = null, $field = null)
|
||||
{
|
||||
return $this->auth->guard($guard)->basic() ?: $next($request);
|
||||
$this->auth->guard($guard)->basic($field ?: 'email');
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,11 @@
|
||||
namespace Illuminate\Auth\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Contracts\Auth\Access\Gate;
|
||||
use Illuminate\Contracts\Auth\Factory as Auth;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Authorize
|
||||
{
|
||||
/**
|
||||
* The authentication factory instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Factory
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* The gate instance.
|
||||
*
|
||||
@@ -26,13 +18,11 @@ class Authorize
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Factory $auth
|
||||
* @param \Illuminate\Contracts\Auth\Access\Gate $gate
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Auth $auth, Gate $gate)
|
||||
public function __construct(Gate $gate)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->gate = $gate;
|
||||
}
|
||||
|
||||
@@ -42,7 +32,7 @@ class Authorize
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string $ability
|
||||
* @param array|null $models
|
||||
* @param array|null ...$models
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
@@ -50,8 +40,6 @@ class Authorize
|
||||
*/
|
||||
public function handle($request, Closure $next, $ability, ...$models)
|
||||
{
|
||||
$this->auth->authenticate();
|
||||
|
||||
$this->gate->authorize($ability, $this->getGateArguments($request, $models));
|
||||
|
||||
return $next($request);
|
||||
@@ -62,7 +50,7 @@ class Authorize
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param array|null $models
|
||||
* @return array|string|\Illuminate\Database\Eloquent\Model
|
||||
* @return \Illuminate\Database\Eloquent\Model|array|string
|
||||
*/
|
||||
protected function getGateArguments($request, $models)
|
||||
{
|
||||
@@ -80,11 +68,16 @@ class Authorize
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $model
|
||||
* @return string|\Illuminate\Database\Eloquent\Model
|
||||
* @return \Illuminate\Database\Eloquent\Model|string
|
||||
*/
|
||||
protected function getModel($request, $model)
|
||||
{
|
||||
return $this->isClassName($model) ? $model : $request->route($model);
|
||||
if ($this->isClassName($model)) {
|
||||
return trim($model);
|
||||
} else {
|
||||
return $request->route($model, null) ??
|
||||
((preg_match("/^['\"](.*)['\"]$/", trim($model), $matches)) ? $matches[1] : null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,6 +88,6 @@ class Authorize
|
||||
*/
|
||||
protected function isClassName($value)
|
||||
{
|
||||
return strpos($value, '\\') !== false;
|
||||
return str_contains($value, '\\');
|
||||
}
|
||||
}
|
||||
|
||||
32
vendor/laravel/framework/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php
vendored
Normal file
32
vendor/laravel/framework/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class EnsureEmailIsVerified
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $redirectToRoute
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse|null
|
||||
*/
|
||||
public function handle($request, Closure $next, $redirectToRoute = null)
|
||||
{
|
||||
if (! $request->user() ||
|
||||
($request->user() instanceof MustVerifyEmail &&
|
||||
! $request->user()->hasVerifiedEmail())) {
|
||||
return $request->expectsJson()
|
||||
? abort(403, 'Your email address is not verified.')
|
||||
: Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
86
vendor/laravel/framework/src/Illuminate/Auth/Middleware/RequirePassword.php
vendored
Normal file
86
vendor/laravel/framework/src/Illuminate/Auth/Middleware/RequirePassword.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||
use Illuminate\Contracts\Routing\UrlGenerator;
|
||||
|
||||
class RequirePassword
|
||||
{
|
||||
/**
|
||||
* The response factory instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Routing\ResponseFactory
|
||||
*/
|
||||
protected $responseFactory;
|
||||
|
||||
/**
|
||||
* The URL generator instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Routing\UrlGenerator
|
||||
*/
|
||||
protected $urlGenerator;
|
||||
|
||||
/**
|
||||
* The password timeout.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $passwordTimeout;
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Routing\ResponseFactory $responseFactory
|
||||
* @param \Illuminate\Contracts\Routing\UrlGenerator $urlGenerator
|
||||
* @param int|null $passwordTimeout
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ResponseFactory $responseFactory, UrlGenerator $urlGenerator, $passwordTimeout = null)
|
||||
{
|
||||
$this->responseFactory = $responseFactory;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->passwordTimeout = $passwordTimeout ?: 10800;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $redirectToRoute
|
||||
* @param int|null $passwordTimeoutSeconds
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $redirectToRoute = null, $passwordTimeoutSeconds = null)
|
||||
{
|
||||
if ($this->shouldConfirmPassword($request, $passwordTimeoutSeconds)) {
|
||||
if ($request->expectsJson()) {
|
||||
return $this->responseFactory->json([
|
||||
'message' => 'Password confirmation required.',
|
||||
], 423);
|
||||
}
|
||||
|
||||
return $this->responseFactory->redirectGuest(
|
||||
$this->urlGenerator->route($redirectToRoute ?? 'password.confirm')
|
||||
);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the confirmation timeout has expired.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int|null $passwordTimeoutSeconds
|
||||
* @return bool
|
||||
*/
|
||||
protected function shouldConfirmPassword($request, $passwordTimeoutSeconds = null)
|
||||
{
|
||||
$confirmedAt = time() - $request->session()->get('auth.password_confirmed_at', 0);
|
||||
|
||||
return $confirmedAt > ($passwordTimeoutSeconds ?? $this->passwordTimeout);
|
||||
}
|
||||
}
|
||||
50
vendor/laravel/framework/src/Illuminate/Auth/MustVerifyEmail.php
vendored
Normal file
50
vendor/laravel/framework/src/Illuminate/Auth/MustVerifyEmail.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Auth\Notifications\VerifyEmail;
|
||||
|
||||
trait MustVerifyEmail
|
||||
{
|
||||
/**
|
||||
* Determine if the user has verified their email address.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasVerifiedEmail()
|
||||
{
|
||||
return ! is_null($this->email_verified_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the given user's email as verified.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function markEmailAsVerified()
|
||||
{
|
||||
return $this->forceFill([
|
||||
'email_verified_at' => $this->freshTimestamp(),
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the email verification notification.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sendEmailVerificationNotification()
|
||||
{
|
||||
$this->notify(new VerifyEmail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email address that should be used for verification.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmailForVerification()
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Illuminate\Auth\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
|
||||
class ResetPassword extends Notification
|
||||
{
|
||||
@@ -14,6 +15,20 @@ class ResetPassword extends Notification
|
||||
*/
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* The callback that should be used to create the reset password URL.
|
||||
*
|
||||
* @var (\Closure(mixed, string): string)|null
|
||||
*/
|
||||
public static $createUrlCallback;
|
||||
|
||||
/**
|
||||
* The callback that should be used to build the mail message.
|
||||
*
|
||||
* @var (\Closure(mixed, string): \Illuminate\Notifications\Messages\MailMessage)|null
|
||||
*/
|
||||
public static $toMailCallback;
|
||||
|
||||
/**
|
||||
* Create a notification instance.
|
||||
*
|
||||
@@ -43,10 +58,67 @@ class ResetPassword extends Notification
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
if (static::$toMailCallback) {
|
||||
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
|
||||
}
|
||||
|
||||
return $this->buildMailMessage($this->resetUrl($notifiable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reset password notification mail message for the given URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
protected function buildMailMessage($url)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->line('You are receiving this email because we received a password reset request for your account.')
|
||||
->action('Reset Password', url(config('app.url').route('password.reset', $this->token, false)))
|
||||
->line('If you did not request a password reset, no further action is required.');
|
||||
->subject(Lang::get('Reset Password Notification'))
|
||||
->line(Lang::get('You are receiving this email because we received a password reset request for your account.'))
|
||||
->action(Lang::get('Reset Password'), $url)
|
||||
->line(Lang::get('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]))
|
||||
->line(Lang::get('If you did not request a password reset, no further action is required.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reset URL for the given notifiable.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return string
|
||||
*/
|
||||
protected function resetUrl($notifiable)
|
||||
{
|
||||
if (static::$createUrlCallback) {
|
||||
return call_user_func(static::$createUrlCallback, $notifiable, $this->token);
|
||||
}
|
||||
|
||||
return url(route('password.reset', [
|
||||
'token' => $this->token,
|
||||
'email' => $notifiable->getEmailForPasswordReset(),
|
||||
], false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback that should be used when creating the reset password button URL.
|
||||
*
|
||||
* @param \Closure(mixed, string): string $callback
|
||||
* @return void
|
||||
*/
|
||||
public static function createUrlUsing($callback)
|
||||
{
|
||||
static::$createUrlCallback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback that should be used when building the notification mail message.
|
||||
*
|
||||
* @param \Closure(mixed, string): \Illuminate\Notifications\Messages\MailMessage $callback
|
||||
* @return void
|
||||
*/
|
||||
public static function toMailUsing($callback)
|
||||
{
|
||||
static::$toMailCallback = $callback;
|
||||
}
|
||||
}
|
||||
|
||||
114
vendor/laravel/framework/src/Illuminate/Auth/Notifications/VerifyEmail.php
vendored
Normal file
114
vendor/laravel/framework/src/Illuminate/Auth/Notifications/VerifyEmail.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Auth\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class VerifyEmail extends Notification
|
||||
{
|
||||
/**
|
||||
* The callback that should be used to create the verify email URL.
|
||||
*
|
||||
* @var \Closure|null
|
||||
*/
|
||||
public static $createUrlCallback;
|
||||
|
||||
/**
|
||||
* The callback that should be used to build the mail message.
|
||||
*
|
||||
* @var \Closure|null
|
||||
*/
|
||||
public static $toMailCallback;
|
||||
|
||||
/**
|
||||
* Get the notification's channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array|string
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
$verificationUrl = $this->verificationUrl($notifiable);
|
||||
|
||||
if (static::$toMailCallback) {
|
||||
return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
|
||||
}
|
||||
|
||||
return $this->buildMailMessage($verificationUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the verify email notification mail message for the given URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
protected function buildMailMessage($url)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(Lang::get('Verify Email Address'))
|
||||
->line(Lang::get('Please click the button below to verify your email address.'))
|
||||
->action(Lang::get('Verify Email Address'), $url)
|
||||
->line(Lang::get('If you did not create an account, no further action is required.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the verification URL for the given notifiable.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return string
|
||||
*/
|
||||
protected function verificationUrl($notifiable)
|
||||
{
|
||||
if (static::$createUrlCallback) {
|
||||
return call_user_func(static::$createUrlCallback, $notifiable);
|
||||
}
|
||||
|
||||
return URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
|
||||
[
|
||||
'id' => $notifiable->getKey(),
|
||||
'hash' => sha1($notifiable->getEmailForVerification()),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback that should be used when creating the email verification URL.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public static function createUrlUsing($callback)
|
||||
{
|
||||
static::$createUrlCallback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback that should be used when building the notification mail message.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public static function toMailUsing($callback)
|
||||
{
|
||||
static::$toMailCallback = $callback;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Illuminate\Auth\Passwords;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
|
||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DatabaseTokenRepository implements TokenRepositoryInterface
|
||||
{
|
||||
@@ -45,6 +45,13 @@ class DatabaseTokenRepository implements TokenRepositoryInterface
|
||||
*/
|
||||
protected $expires;
|
||||
|
||||
/**
|
||||
* Minimum number of seconds before re-redefining the token.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $throttle;
|
||||
|
||||
/**
|
||||
* Create a new token repository instance.
|
||||
*
|
||||
@@ -53,16 +60,19 @@ class DatabaseTokenRepository implements TokenRepositoryInterface
|
||||
* @param string $table
|
||||
* @param string $hashKey
|
||||
* @param int $expires
|
||||
* @param int $throttle
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ConnectionInterface $connection, HasherContract $hasher,
|
||||
$table, $hashKey, $expires = 60)
|
||||
$table, $hashKey, $expires = 60,
|
||||
$throttle = 60)
|
||||
{
|
||||
$this->table = $table;
|
||||
$this->hasher = $hasher;
|
||||
$this->hashKey = $hashKey;
|
||||
$this->expires = $expires * 60;
|
||||
$this->connection = $connection;
|
||||
$this->throttle = $throttle;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,6 +149,38 @@ class DatabaseTokenRepository implements TokenRepositoryInterface
|
||||
return Carbon::parse($createdAt)->addSeconds($this->expires)->isPast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given user recently created a password reset token.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
|
||||
* @return bool
|
||||
*/
|
||||
public function recentlyCreatedToken(CanResetPasswordContract $user)
|
||||
{
|
||||
$record = (array) $this->getTable()->where(
|
||||
'email', $user->getEmailForPasswordReset()
|
||||
)->first();
|
||||
|
||||
return $record && $this->tokenRecentlyCreated($record['created_at']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the token was recently created.
|
||||
*
|
||||
* @param string $createdAt
|
||||
* @return bool
|
||||
*/
|
||||
protected function tokenRecentlyCreated($createdAt)
|
||||
{
|
||||
if ($this->throttle <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Carbon::parse($createdAt)->addSeconds(
|
||||
$this->throttle
|
||||
)->isFuture();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a token record by user.
|
||||
*
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
namespace Illuminate\Auth\Passwords;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||
use Illuminate\Contracts\Auth\PasswordBroker as PasswordBrokerContract;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Support\Arr;
|
||||
use UnexpectedValueException;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Contracts\Auth\PasswordBroker as PasswordBrokerContract;
|
||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||
|
||||
class PasswordBroker implements PasswordBrokerContract
|
||||
{
|
||||
@@ -25,13 +25,6 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
*/
|
||||
protected $users;
|
||||
|
||||
/**
|
||||
* The custom password validator callback.
|
||||
*
|
||||
* @var \Closure
|
||||
*/
|
||||
protected $passwordValidator;
|
||||
|
||||
/**
|
||||
* Create a new password broker instance.
|
||||
*
|
||||
@@ -39,8 +32,7 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider $users
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(TokenRepositoryInterface $tokens,
|
||||
UserProvider $users)
|
||||
public function __construct(TokenRepositoryInterface $tokens, UserProvider $users)
|
||||
{
|
||||
$this->users = $users;
|
||||
$this->tokens = $tokens;
|
||||
@@ -50,9 +42,10 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
* Send a password reset link to a user.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @param \Closure|null $callback
|
||||
* @return string
|
||||
*/
|
||||
public function sendResetLink(array $credentials)
|
||||
public function sendResetLink(array $credentials, Closure $callback = null)
|
||||
{
|
||||
// First we will check to see if we found a user at the given credentials and
|
||||
// if we did not we will redirect back to this current URI with a piece of
|
||||
@@ -63,12 +56,20 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
return static::INVALID_USER;
|
||||
}
|
||||
|
||||
// Once we have the reset token, we are ready to send the message out to this
|
||||
// user with a link to reset their password. We will then redirect back to
|
||||
// the current URI having nothing set in the session to indicate errors.
|
||||
$user->sendPasswordResetNotification(
|
||||
$this->tokens->create($user)
|
||||
);
|
||||
if ($this->tokens->recentlyCreatedToken($user)) {
|
||||
return static::RESET_THROTTLED;
|
||||
}
|
||||
|
||||
$token = $this->tokens->create($user);
|
||||
|
||||
if ($callback) {
|
||||
$callback($user, $token);
|
||||
} else {
|
||||
// Once we have the reset token, we are ready to send the message out to this
|
||||
// user with a link to reset their password. We will then redirect back to
|
||||
// the current URI having nothing set in the session to indicate errors.
|
||||
$user->sendPasswordResetNotification($token);
|
||||
}
|
||||
|
||||
return static::RESET_LINK_SENT;
|
||||
}
|
||||
@@ -82,11 +83,11 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
*/
|
||||
public function reset(array $credentials, Closure $callback)
|
||||
{
|
||||
$user = $this->validateReset($credentials);
|
||||
|
||||
// If the responses from the validate method is not a user instance, we will
|
||||
// assume that it is a redirect and simply return it from this method and
|
||||
// the user is properly redirected having an error message on the post.
|
||||
$user = $this->validateReset($credentials);
|
||||
|
||||
if (! $user instanceof CanResetPasswordContract) {
|
||||
return $user;
|
||||
}
|
||||
@@ -107,7 +108,7 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
* Validate a password reset for the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\CanResetPassword
|
||||
* @return \Illuminate\Contracts\Auth\CanResetPassword|string
|
||||
*/
|
||||
protected function validateReset(array $credentials)
|
||||
{
|
||||
@@ -115,10 +116,6 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
return static::INVALID_USER;
|
||||
}
|
||||
|
||||
if (! $this->validateNewPassword($credentials)) {
|
||||
return static::INVALID_PASSWORD;
|
||||
}
|
||||
|
||||
if (! $this->tokens->exists($user, $credentials['token'])) {
|
||||
return static::INVALID_TOKEN;
|
||||
}
|
||||
@@ -126,60 +123,11 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom password validator.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public function validator(Closure $callback)
|
||||
{
|
||||
$this->passwordValidator = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the passwords match for the request.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return bool
|
||||
*/
|
||||
public function validateNewPassword(array $credentials)
|
||||
{
|
||||
if (isset($this->passwordValidator)) {
|
||||
list($password, $confirm) = [
|
||||
$credentials['password'],
|
||||
$credentials['password_confirmation'],
|
||||
];
|
||||
|
||||
return call_user_func(
|
||||
$this->passwordValidator, $credentials
|
||||
) && $password === $confirm;
|
||||
}
|
||||
|
||||
return $this->validatePasswordWithDefaults($credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the passwords are valid for the request.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return bool
|
||||
*/
|
||||
protected function validatePasswordWithDefaults(array $credentials)
|
||||
{
|
||||
list($password, $confirm) = [
|
||||
$credentials['password'],
|
||||
$credentials['password_confirmation'],
|
||||
];
|
||||
|
||||
return $password === $confirm && mb_strlen($password) >= 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user for the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\CanResetPassword
|
||||
* @return \Illuminate\Contracts\Auth\CanResetPassword|null
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
@@ -199,7 +147,7 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
/**
|
||||
* Create a new password reset token for the given user.
|
||||
*
|
||||
* @param CanResetPasswordContract $user
|
||||
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
|
||||
* @return string
|
||||
*/
|
||||
public function createToken(CanResetPasswordContract $user)
|
||||
@@ -210,7 +158,7 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
/**
|
||||
* Delete password reset tokens of the given user.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
|
||||
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
|
||||
* @return void
|
||||
*/
|
||||
public function deleteToken(CanResetPasswordContract $user)
|
||||
@@ -221,8 +169,8 @@ class PasswordBroker implements PasswordBrokerContract
|
||||
/**
|
||||
* Validate the given password reset token.
|
||||
*
|
||||
* @param CanResetPasswordContract $user
|
||||
* @param string $token
|
||||
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
|
||||
* @param string $token
|
||||
* @return bool
|
||||
*/
|
||||
public function tokenExists(CanResetPasswordContract $user, $token)
|
||||
|
||||
@@ -2,16 +2,18 @@
|
||||
|
||||
namespace Illuminate\Auth\Passwords;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Contracts\Auth\PasswordBrokerFactory as FactoryContract;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @mixin \Illuminate\Contracts\Auth\PasswordBroker
|
||||
*/
|
||||
class PasswordBrokerManager implements FactoryContract
|
||||
{
|
||||
/**
|
||||
* The application instance.
|
||||
*
|
||||
* @var \Illuminate\Foundation\Application
|
||||
* @var \Illuminate\Contracts\Foundation\Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
@@ -25,7 +27,7 @@ class PasswordBrokerManager implements FactoryContract
|
||||
/**
|
||||
* Create a new PasswordBroker manager instance.
|
||||
*
|
||||
* @param \Illuminate\Foundation\Application $app
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($app)
|
||||
@@ -36,16 +38,14 @@ class PasswordBrokerManager implements FactoryContract
|
||||
/**
|
||||
* Attempt to get the broker from the local cache.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $name
|
||||
* @return \Illuminate\Contracts\Auth\PasswordBroker
|
||||
*/
|
||||
public function broker($name = null)
|
||||
{
|
||||
$name = $name ?: $this->getDefaultDriver();
|
||||
|
||||
return isset($this->brokers[$name])
|
||||
? $this->brokers[$name]
|
||||
: $this->brokers[$name] = $this->resolve($name);
|
||||
return $this->brokers[$name] ?? ($this->brokers[$name] = $this->resolve($name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +69,7 @@ class PasswordBrokerManager implements FactoryContract
|
||||
// aggregate service of sorts providing a convenient interface for resets.
|
||||
return new PasswordBroker(
|
||||
$this->createTokenRepository($config),
|
||||
$this->app['auth']->createUserProvider($config['provider'])
|
||||
$this->app['auth']->createUserProvider($config['provider'] ?? null)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,18 +83,19 @@ class PasswordBrokerManager implements FactoryContract
|
||||
{
|
||||
$key = $this->app['config']['app.key'];
|
||||
|
||||
if (Str::startsWith($key, 'base64:')) {
|
||||
if (str_starts_with($key, 'base64:')) {
|
||||
$key = base64_decode(substr($key, 7));
|
||||
}
|
||||
|
||||
$connection = isset($config['connection']) ? $config['connection'] : null;
|
||||
$connection = $config['connection'] ?? null;
|
||||
|
||||
return new DatabaseTokenRepository(
|
||||
$this->app['db']->connection($connection),
|
||||
$this->app['hash'],
|
||||
$config['table'],
|
||||
$key,
|
||||
$config['expire']
|
||||
$config['expire'],
|
||||
$config['throttle'] ?? 0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -134,7 +135,7 @@ class PasswordBrokerManager implements FactoryContract
|
||||
* Dynamically call the default driver instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
|
||||
@@ -2,17 +2,11 @@
|
||||
|
||||
namespace Illuminate\Auth\Passwords;
|
||||
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class PasswordResetServiceProvider extends ServiceProvider
|
||||
class PasswordResetServiceProvider extends ServiceProvider implements DeferrableProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if loading of the provider is deferred.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $defer = true;
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,14 @@ interface TokenRepositoryInterface
|
||||
*/
|
||||
public function exists(CanResetPasswordContract $user, $token);
|
||||
|
||||
/**
|
||||
* Determine if the given user recently created a password reset token.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
|
||||
* @return bool
|
||||
*/
|
||||
public function recentlyCreatedToken(CanResetPasswordContract $user);
|
||||
|
||||
/**
|
||||
* Delete a token record.
|
||||
*
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Recaller
|
||||
{
|
||||
/**
|
||||
@@ -21,7 +19,7 @@ class Recaller
|
||||
*/
|
||||
public function __construct($recaller)
|
||||
{
|
||||
$this->recaller = $recaller;
|
||||
$this->recaller = @unserialize($recaller, ['allowed_classes' => false]) ?: $recaller;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,7 +29,7 @@ class Recaller
|
||||
*/
|
||||
public function id()
|
||||
{
|
||||
return explode('|', $this->recaller, 2)[0];
|
||||
return explode('|', $this->recaller, 3)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +39,17 @@ class Recaller
|
||||
*/
|
||||
public function token()
|
||||
{
|
||||
return explode('|', $this->recaller, 2)[1];
|
||||
return explode('|', $this->recaller, 3)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the password from the recaller.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function hash()
|
||||
{
|
||||
return explode('|', $this->recaller, 4)[2];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +59,7 @@ class Recaller
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->properString() && $this->hasBothSegments();
|
||||
return $this->properString() && $this->hasAllSegments();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,18 +69,28 @@ class Recaller
|
||||
*/
|
||||
protected function properString()
|
||||
{
|
||||
return is_string($this->recaller) && Str::contains($this->recaller, '|');
|
||||
return is_string($this->recaller) && str_contains($this->recaller, '|');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the recaller has both segments.
|
||||
* Determine if the recaller has all segments.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasBothSegments()
|
||||
protected function hasAllSegments()
|
||||
{
|
||||
$segments = explode('|', $this->recaller);
|
||||
|
||||
return count($segments) == 2 && trim($segments[0]) !== '' && trim($segments[1]) !== '';
|
||||
return count($segments) >= 3 && trim($segments[0]) !== '' && trim($segments[1]) !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recaller's segments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function segments()
|
||||
{
|
||||
return explode('|', $this->recaller);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
|
||||
class RequestGuard implements Guard
|
||||
@@ -29,12 +30,14 @@ class RequestGuard implements Guard
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider|null $provider
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(callable $callback, Request $request)
|
||||
public function __construct(callable $callback, Request $request, UserProvider $provider = null)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->callback = $callback;
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +55,7 @@ class RequestGuard implements Guard
|
||||
}
|
||||
|
||||
return $this->user = call_user_func(
|
||||
$this->callback, $this->request
|
||||
$this->callback, $this->request, $this->getProvider()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,7 +68,7 @@ class RequestGuard implements Guard
|
||||
public function validate(array $credentials = [])
|
||||
{
|
||||
return ! is_null((new static(
|
||||
$this->callback, $credentials['request']
|
||||
$this->callback, $credentials['request'], $this->getProvider()
|
||||
))->user());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,25 +2,37 @@
|
||||
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use RuntimeException;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Illuminate\Contracts\Auth\SupportsBasicAuth;
|
||||
use Illuminate\Contracts\Cookie\QueueingFactory as CookieJar;
|
||||
use Illuminate\Auth\Events\Attempting;
|
||||
use Illuminate\Auth\Events\Authenticated;
|
||||
use Illuminate\Auth\Events\CurrentDeviceLogout;
|
||||
use Illuminate\Auth\Events\Failed;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Auth\Events\Logout;
|
||||
use Illuminate\Auth\Events\OtherDeviceLogout;
|
||||
use Illuminate\Auth\Events\Validated;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Illuminate\Contracts\Auth\SupportsBasicAuth;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Contracts\Cookie\QueueingFactory as CookieJar;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Timebox;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
{
|
||||
use GuardHelpers, Macroable;
|
||||
|
||||
/**
|
||||
* The name of the Guard. Typically "session".
|
||||
* The name of the guard. Typically "web".
|
||||
*
|
||||
* Corresponds to guard name in authentication configuration.
|
||||
*
|
||||
@@ -42,6 +54,13 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected $viaRemember = false;
|
||||
|
||||
/**
|
||||
* The number of minutes that the "remember me" cookie should be valid for.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $rememberDuration = 576000;
|
||||
|
||||
/**
|
||||
* The session used by the guard.
|
||||
*
|
||||
@@ -70,6 +89,13 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* The timebox instance.
|
||||
*
|
||||
* @var \Illuminate\Support\Timebox
|
||||
*/
|
||||
protected $timebox;
|
||||
|
||||
/**
|
||||
* Indicates if the logout method has been called.
|
||||
*
|
||||
@@ -90,18 +116,21 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
* @param string $name
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider $provider
|
||||
* @param \Illuminate\Contracts\Session\Session $session
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* @param \Symfony\Component\HttpFoundation\Request|null $request
|
||||
* @param \Illuminate\Support\Timebox|null $timebox
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name,
|
||||
UserProvider $provider,
|
||||
Session $session,
|
||||
Request $request = null)
|
||||
Request $request = null,
|
||||
Timebox $timebox = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->session = $session;
|
||||
$this->request = $request;
|
||||
$this->provider = $provider;
|
||||
$this->timebox = $timebox ?: new Timebox;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,30 +156,24 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
// First we will try to load the user using the identifier in the session if
|
||||
// one exists. Otherwise we will check for a "remember me" cookie in this
|
||||
// request, and if one exists, attempt to retrieve the user using that.
|
||||
$user = null;
|
||||
|
||||
if (! is_null($id)) {
|
||||
if ($user = $this->provider->retrieveById($id)) {
|
||||
$this->fireAuthenticatedEvent($user);
|
||||
}
|
||||
if (! is_null($id) && $this->user = $this->provider->retrieveById($id)) {
|
||||
$this->fireAuthenticatedEvent($this->user);
|
||||
}
|
||||
|
||||
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
|
||||
// pull the user data on that cookie which serves as a remember cookie on
|
||||
// the application. Once we have a user we can return it to the caller.
|
||||
$recaller = $this->recaller();
|
||||
if (is_null($this->user) && ! is_null($recaller = $this->recaller())) {
|
||||
$this->user = $this->userFromRecaller($recaller);
|
||||
|
||||
if (is_null($user) && ! is_null($recaller)) {
|
||||
$user = $this->userFromRecaller($recaller);
|
||||
if ($this->user) {
|
||||
$this->updateSession($this->user->getAuthIdentifier());
|
||||
|
||||
if ($user) {
|
||||
$this->updateSession($user->getAuthIdentifier());
|
||||
|
||||
$this->fireLoginEvent($user, true);
|
||||
$this->fireLoginEvent($this->user, true);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user = $user;
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +219,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
/**
|
||||
* Get the ID for the currently authenticated user.
|
||||
*
|
||||
* @return int|null
|
||||
* @return int|string|null
|
||||
*/
|
||||
public function id()
|
||||
{
|
||||
@@ -264,6 +287,8 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
* @param string $field
|
||||
* @param array $extraConditions
|
||||
* @return \Symfony\Component\HttpFoundation\Response|null
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
|
||||
*/
|
||||
public function basic($field = 'email', $extraConditions = [])
|
||||
{
|
||||
@@ -287,6 +312,8 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
* @param string $field
|
||||
* @param array $extraConditions
|
||||
* @return \Symfony\Component\HttpFoundation\Response|null
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
|
||||
*/
|
||||
public function onceBasic($field = 'email', $extraConditions = [])
|
||||
{
|
||||
@@ -317,7 +344,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the credential array for a HTTP Basic request.
|
||||
* Get the credential array for an HTTP Basic request.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* @param string $field
|
||||
@@ -331,18 +358,20 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
/**
|
||||
* Get the response for basic authentication.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @return void
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
|
||||
*/
|
||||
protected function failedBasicResponse()
|
||||
{
|
||||
return new Response('Invalid credentials.', 401, ['WWW-Authenticate' => 'Basic']);
|
||||
throw new UnauthorizedHttpException('Basic', 'Invalid credentials.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to authenticate a user using the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @param bool $remember
|
||||
* @param bool $remember
|
||||
* @return bool
|
||||
*/
|
||||
public function attempt(array $credentials = [], $remember = false)
|
||||
@@ -368,6 +397,34 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to authenticate a user with credentials and additional callbacks.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @param array|callable|null $callbacks
|
||||
* @param bool $remember
|
||||
* @return bool
|
||||
*/
|
||||
public function attemptWhen(array $credentials = [], $callbacks = null, $remember = false)
|
||||
{
|
||||
$this->fireAttemptEvent($credentials, $remember);
|
||||
|
||||
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
|
||||
|
||||
// This method does the exact same thing as attempt, but also executes callbacks after
|
||||
// the user is retrieved and validated. If one of the callbacks returns falsy we do
|
||||
// not login the user. Instead, we will fail the specific authentication attempt.
|
||||
if ($this->hasValidCredentials($user, $credentials) && $this->shouldLogin($callbacks, $user)) {
|
||||
$this->login($user, $remember);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->fireFailedEvent($user, $credentials);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user matches the credentials.
|
||||
*
|
||||
@@ -377,14 +434,42 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected function hasValidCredentials($user, $credentials)
|
||||
{
|
||||
return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
|
||||
return $this->timebox->call(function ($timebox) use ($user, $credentials) {
|
||||
$validated = ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
|
||||
|
||||
if ($validated) {
|
||||
$timebox->returnEarly();
|
||||
|
||||
$this->fireValidatedEvent($user);
|
||||
}
|
||||
|
||||
return $validated;
|
||||
}, 200 * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user should login by executing the given callbacks.
|
||||
*
|
||||
* @param array|callable|null $callbacks
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return bool
|
||||
*/
|
||||
protected function shouldLogin($callbacks, AuthenticatableContract $user)
|
||||
{
|
||||
foreach (Arr::wrap($callbacks) as $callback) {
|
||||
if (! $callback($user, $this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the given user ID into the application.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param bool $remember
|
||||
* @param bool $remember
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|false
|
||||
*/
|
||||
public function loginUsingId($id, $remember = false)
|
||||
@@ -461,7 +546,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
protected function queueRecallerCookie(AuthenticatableContract $user)
|
||||
{
|
||||
$this->getCookieJar()->queue($this->createRecaller(
|
||||
$user->getAuthIdentifier().'|'.$user->getRememberToken()
|
||||
$user->getAuthIdentifier().'|'.$user->getRememberToken().'|'.$user->getAuthPassword()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -473,7 +558,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected function createRecaller($value)
|
||||
{
|
||||
return $this->getCookieJar()->forever($this->getRecallerName(), $value);
|
||||
return $this->getCookieJar()->make($this->getRecallerName(), $value, $this->getRememberDuration());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,17 +570,45 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
{
|
||||
$user = $this->user();
|
||||
|
||||
// If we have an event dispatcher instance, we can fire off the logout event
|
||||
// so any further processing can be done. This allows the developer to be
|
||||
// listening for anytime a user signs out of this application manually.
|
||||
$this->clearUserDataFromStorage();
|
||||
|
||||
if (! is_null($this->user)) {
|
||||
if (! is_null($this->user) && ! empty($user->getRememberToken())) {
|
||||
$this->cycleRememberToken($user);
|
||||
}
|
||||
|
||||
// If we have an event dispatcher instance, we can fire off the logout event
|
||||
// so any further processing can be done. This allows the developer to be
|
||||
// listening for anytime a user signs out of this application manually.
|
||||
if (isset($this->events)) {
|
||||
$this->events->dispatch(new Events\Logout($user));
|
||||
$this->events->dispatch(new Logout($this->name, $user));
|
||||
}
|
||||
|
||||
// Once we have fired the logout event we will clear the users out of memory
|
||||
// so they are no longer available as the user is no longer considered as
|
||||
// being signed into this application and should not be available here.
|
||||
$this->user = null;
|
||||
|
||||
$this->loggedOut = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the user out of the application on their current device only.
|
||||
*
|
||||
* This method does not cycle the "remember" token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function logoutCurrentDevice()
|
||||
{
|
||||
$user = $this->user();
|
||||
|
||||
$this->clearUserDataFromStorage();
|
||||
|
||||
// If we have an event dispatcher instance, we can fire off the logout event
|
||||
// so any further processing can be done. This allows the developer to be
|
||||
// listening for anytime a user signs out of this application manually.
|
||||
if (isset($this->events)) {
|
||||
$this->events->dispatch(new CurrentDeviceLogout($this->name, $user));
|
||||
}
|
||||
|
||||
// Once we have fired the logout event we will clear the users out of memory
|
||||
@@ -515,9 +628,12 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
{
|
||||
$this->session->remove($this->getName());
|
||||
|
||||
$this->getCookieJar()->unqueue($this->getRecallerName());
|
||||
|
||||
if (! is_null($this->recaller())) {
|
||||
$this->getCookieJar()->queue($this->getCookieJar()
|
||||
->forget($this->getRecallerName()));
|
||||
$this->getCookieJar()->queue(
|
||||
$this->getCookieJar()->forget($this->getRecallerName())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,6 +650,55 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
$this->provider->updateRememberToken($user, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate other sessions for the current user.
|
||||
*
|
||||
* The application must be using the AuthenticateSession middleware.
|
||||
*
|
||||
* @param string $password
|
||||
* @param string $attribute
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*
|
||||
* @throws \Illuminate\Auth\AuthenticationException
|
||||
*/
|
||||
public function logoutOtherDevices($password, $attribute = 'password')
|
||||
{
|
||||
if (! $this->user()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->rehashUserPassword($password, $attribute);
|
||||
|
||||
if ($this->recaller() ||
|
||||
$this->getCookieJar()->hasQueued($this->getRecallerName())) {
|
||||
$this->queueRecallerCookie($this->user());
|
||||
}
|
||||
|
||||
$this->fireOtherDeviceLogoutEvent($this->user());
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rehash the current user's password.
|
||||
*
|
||||
* @param string $password
|
||||
* @param string $attribute
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function rehashUserPassword($password, $attribute)
|
||||
{
|
||||
if (! Hash::check($password, $this->user()->{$attribute})) {
|
||||
throw new InvalidArgumentException('The given password does not match the current password.');
|
||||
}
|
||||
|
||||
return tap($this->user()->forceFill([
|
||||
$attribute => Hash::make($password),
|
||||
]))->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an authentication attempt event listener.
|
||||
*
|
||||
@@ -542,9 +707,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
public function attempting($callback)
|
||||
{
|
||||
if (isset($this->events)) {
|
||||
$this->events->listen(Events\Attempting::class, $callback);
|
||||
}
|
||||
$this->events?->listen(Events\Attempting::class, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,11 +719,18 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected function fireAttemptEvent(array $credentials, $remember = false)
|
||||
{
|
||||
if (isset($this->events)) {
|
||||
$this->events->dispatch(new Events\Attempting(
|
||||
$credentials, $remember
|
||||
));
|
||||
}
|
||||
$this->events?->dispatch(new Attempting($this->name, $credentials, $remember));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the validated event if the dispatcher is set.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
protected function fireValidatedEvent($user)
|
||||
{
|
||||
$this->events?->dispatch(new Validated($this->name, $user));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,9 +742,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected function fireLoginEvent($user, $remember = false)
|
||||
{
|
||||
if (isset($this->events)) {
|
||||
$this->events->dispatch(new Events\Login($user, $remember));
|
||||
}
|
||||
$this->events?->dispatch(new Login($this->name, $user, $remember));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -585,9 +753,18 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected function fireAuthenticatedEvent($user)
|
||||
{
|
||||
if (isset($this->events)) {
|
||||
$this->events->dispatch(new Events\Authenticated($user));
|
||||
}
|
||||
$this->events?->dispatch(new Authenticated($this->name, $user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the other device logout event if the dispatcher is set.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
protected function fireOtherDeviceLogoutEvent($user)
|
||||
{
|
||||
$this->events?->dispatch(new OtherDeviceLogout($this->name, $user));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -599,9 +776,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
*/
|
||||
protected function fireFailedEvent($user, array $credentials)
|
||||
{
|
||||
if (isset($this->events)) {
|
||||
$this->events->dispatch(new Events\Failed($user, $credentials));
|
||||
}
|
||||
$this->events?->dispatch(new Failed($this->name, $user, $credentials));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,6 +819,29 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
return $this->viaRemember;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of minutes the remember me cookie should be valid for.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getRememberDuration()
|
||||
{
|
||||
return $this->rememberDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of minutes the remember me cookie should be valid for.
|
||||
*
|
||||
* @param int $minutes
|
||||
* @return $this
|
||||
*/
|
||||
public function setRememberDuration($minutes)
|
||||
{
|
||||
$this->rememberDuration = $minutes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cookie creator instance used by the guard.
|
||||
*
|
||||
@@ -695,34 +893,13 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
/**
|
||||
* Get the session store used by the guard.
|
||||
*
|
||||
* @return \Illuminate\Session\Store
|
||||
* @return \Illuminate\Contracts\Session\Session
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user provider used by the guard.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Auth\UserProvider
|
||||
*/
|
||||
public function getProvider()
|
||||
{
|
||||
return $this->provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user provider used by the guard.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider $provider
|
||||
* @return void
|
||||
*/
|
||||
public function setProvider(UserProvider $provider)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently cached user.
|
||||
*
|
||||
@@ -772,4 +949,14 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timebox instance used by the guard.
|
||||
*
|
||||
* @return \Illuminate\Support\Timebox
|
||||
*/
|
||||
public function getTimebox()
|
||||
{
|
||||
return $this->timebox;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace Illuminate\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TokenGuard implements Guard
|
||||
{
|
||||
@@ -31,19 +31,35 @@ class TokenGuard implements Guard
|
||||
*/
|
||||
protected $storageKey;
|
||||
|
||||
/**
|
||||
* Indicates if the API token is hashed in storage.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $hash = false;
|
||||
|
||||
/**
|
||||
* Create a new authentication guard.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider $provider
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $inputKey
|
||||
* @param string $storageKey
|
||||
* @param bool $hash
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(UserProvider $provider, Request $request)
|
||||
public function __construct(
|
||||
UserProvider $provider,
|
||||
Request $request,
|
||||
$inputKey = 'api_token',
|
||||
$storageKey = 'api_token',
|
||||
$hash = false)
|
||||
{
|
||||
$this->hash = $hash;
|
||||
$this->request = $request;
|
||||
$this->provider = $provider;
|
||||
$this->inputKey = 'api_token';
|
||||
$this->storageKey = 'api_token';
|
||||
$this->inputKey = $inputKey;
|
||||
$this->storageKey = $storageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,9 +81,9 @@ class TokenGuard implements Guard
|
||||
$token = $this->getTokenForRequest();
|
||||
|
||||
if (! empty($token)) {
|
||||
$user = $this->provider->retrieveByCredentials(
|
||||
[$this->storageKey => $token]
|
||||
);
|
||||
$user = $this->provider->retrieveByCredentials([
|
||||
$this->storageKey => $this->hash ? hash('sha256', $token) : $token,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->user = $user;
|
||||
|
||||
@@ -14,12 +14,13 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.4",
|
||||
"illuminate/contracts": "5.4.*",
|
||||
"illuminate/http": "5.4.*",
|
||||
"illuminate/queue": "5.4.*",
|
||||
"illuminate/support": "5.4.*",
|
||||
"nesbot/carbon": "~1.20"
|
||||
"php": "^8.0.2",
|
||||
"illuminate/collections": "^9.0",
|
||||
"illuminate/contracts": "^9.0",
|
||||
"illuminate/http": "^9.0",
|
||||
"illuminate/macroable": "^9.0",
|
||||
"illuminate/queue": "^9.0",
|
||||
"illuminate/support": "^9.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -28,13 +29,13 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.4-dev"
|
||||
"dev-master": "9.x-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/console": "Required to use the auth:clear-resets command (5.4.*).",
|
||||
"illuminate/queue": "Required to fire login / logout events (5.4.*).",
|
||||
"illuminate/session": "Required to use the session based guard (5.4.*)."
|
||||
"illuminate/console": "Required to use the auth:clear-resets command (^9.0).",
|
||||
"illuminate/queue": "Required to fire login / logout events (^9.0).",
|
||||
"illuminate/session": "Required to use the session based guard (^9.0)."
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Illuminate\Broadcasting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Broadcast;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
class BroadcastController extends Controller
|
||||
{
|
||||
@@ -16,6 +17,28 @@ class BroadcastController extends Controller
|
||||
*/
|
||||
public function authenticate(Request $request)
|
||||
{
|
||||
if ($request->hasSession()) {
|
||||
$request->session()->reflash();
|
||||
}
|
||||
|
||||
return Broadcast::auth($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the current user.
|
||||
*
|
||||
* See: https://pusher.com/docs/channels/server_api/authenticating-users/#user-authentication.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function authenticateUser(Request $request)
|
||||
{
|
||||
if ($request->hasSession()) {
|
||||
$request->session()->reflash();
|
||||
}
|
||||
|
||||
return Broadcast::resolveAuthenticatedUser($request)
|
||||
?? throw new AccessDeniedHttpException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionProperty;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\Job;
|
||||
use Illuminate\Contracts\Broadcasting\Factory as BroadcastingFactory;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Broadcasting\Broadcaster;
|
||||
use Illuminate\Support\Arr;
|
||||
use ReflectionClass;
|
||||
use ReflectionProperty;
|
||||
|
||||
class BroadcastEvent implements ShouldQueue
|
||||
{
|
||||
@@ -21,6 +21,27 @@ class BroadcastEvent implements ShouldQueue
|
||||
*/
|
||||
public $event;
|
||||
|
||||
/**
|
||||
* The number of times the job may be attempted.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $tries;
|
||||
|
||||
/**
|
||||
* The number of seconds the job can run before timing out.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $timeout;
|
||||
|
||||
/**
|
||||
* The number of seconds to wait before retrying the job when encountering an uncaught exception.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $backoff;
|
||||
|
||||
/**
|
||||
* Create a new job handler instance.
|
||||
*
|
||||
@@ -30,23 +51,40 @@ class BroadcastEvent implements ShouldQueue
|
||||
public function __construct($event)
|
||||
{
|
||||
$this->event = $event;
|
||||
$this->tries = property_exists($event, 'tries') ? $event->tries : null;
|
||||
$this->timeout = property_exists($event, 'timeout') ? $event->timeout : null;
|
||||
$this->backoff = property_exists($event, 'backoff') ? $event->backoff : null;
|
||||
$this->afterCommit = property_exists($event, 'afterCommit') ? $event->afterCommit : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the queued job.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Broadcasting\Broadcaster $broadcaster
|
||||
* @param \Illuminate\Contracts\Broadcasting\Factory $manager
|
||||
* @return void
|
||||
*/
|
||||
public function handle(Broadcaster $broadcaster)
|
||||
public function handle(BroadcastingFactory $manager)
|
||||
{
|
||||
$name = method_exists($this->event, 'broadcastAs')
|
||||
? $this->event->broadcastAs() : get_class($this->event);
|
||||
|
||||
$broadcaster->broadcast(
|
||||
array_wrap($this->event->broadcastOn()), $name,
|
||||
$this->getPayloadFromEvent($this->event)
|
||||
);
|
||||
$channels = Arr::wrap($this->event->broadcastOn());
|
||||
|
||||
if (empty($channels)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connections = method_exists($this->event, 'broadcastConnections')
|
||||
? $this->event->broadcastConnections()
|
||||
: [null];
|
||||
|
||||
$payload = $this->getPayloadFromEvent($this->event);
|
||||
|
||||
foreach ($connections as $connection) {
|
||||
$manager->connection($connection)->broadcast(
|
||||
$channels, $name, $payload
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,10 +95,9 @@ class BroadcastEvent implements ShouldQueue
|
||||
*/
|
||||
protected function getPayloadFromEvent($event)
|
||||
{
|
||||
if (method_exists($event, 'broadcastWith')) {
|
||||
return array_merge(
|
||||
$event->broadcastWith(), ['socket' => data_get($event, 'socket')]
|
||||
);
|
||||
if (method_exists($event, 'broadcastWith') &&
|
||||
! is_null($payload = $event->broadcastWith())) {
|
||||
return array_merge($payload, ['socket' => data_get($event, 'socket')]);
|
||||
}
|
||||
|
||||
$payload = [];
|
||||
@@ -98,4 +135,14 @@ class BroadcastEvent implements ShouldQueue
|
||||
{
|
||||
return get_class($this->event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the instance for cloning.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->event = clone $this->event;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,24 +2,34 @@
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
use Pusher;
|
||||
use Ably\AblyRest;
|
||||
use Closure;
|
||||
use Illuminate\Support\Arr;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use InvalidArgumentException;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use Illuminate\Broadcasting\Broadcasters\AblyBroadcaster;
|
||||
use Illuminate\Broadcasting\Broadcasters\LogBroadcaster;
|
||||
use Illuminate\Broadcasting\Broadcasters\NullBroadcaster;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
use Illuminate\Broadcasting\Broadcasters\RedisBroadcaster;
|
||||
use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
|
||||
use Illuminate\Broadcasting\Broadcasters\RedisBroadcaster;
|
||||
use Illuminate\Bus\UniqueLock;
|
||||
use Illuminate\Contracts\Broadcasting\Factory as FactoryContract;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract;
|
||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||
use Illuminate\Contracts\Foundation\CachesRoutes;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Pusher\Pusher;
|
||||
|
||||
/**
|
||||
* @mixin \Illuminate\Contracts\Broadcasting\Broadcaster
|
||||
*/
|
||||
class BroadcastManager implements FactoryContract
|
||||
{
|
||||
/**
|
||||
* The application instance.
|
||||
*
|
||||
* @var \Illuminate\Foundation\Application
|
||||
* @var \Illuminate\Contracts\Container\Container
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
@@ -40,7 +50,7 @@ class BroadcastManager implements FactoryContract
|
||||
/**
|
||||
* Create a new manager instance.
|
||||
*
|
||||
* @param \Illuminate\Foundation\Application $app
|
||||
* @param \Illuminate\Contracts\Container\Container $app
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($app)
|
||||
@@ -49,24 +59,62 @@ class BroadcastManager implements FactoryContract
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the routes for handling broadcast authentication and sockets.
|
||||
* Register the routes for handling broadcast channel authentication and sockets.
|
||||
*
|
||||
* @param array|null $attributes
|
||||
* @return void
|
||||
*/
|
||||
public function routes(array $attributes = null)
|
||||
{
|
||||
if ($this->app->routesAreCached()) {
|
||||
if ($this->app instanceof CachesRoutes && $this->app->routesAreCached()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = $attributes ?: ['middleware' => ['web']];
|
||||
|
||||
$this->app['router']->group($attributes, function ($router) {
|
||||
$router->post('/broadcasting/auth', BroadcastController::class.'@authenticate');
|
||||
$router->match(
|
||||
['get', 'post'], '/broadcasting/auth',
|
||||
'\\'.BroadcastController::class.'@authenticate'
|
||||
)->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the routes for handling broadcast user authentication.
|
||||
*
|
||||
* @param array|null $attributes
|
||||
* @return void
|
||||
*/
|
||||
public function userRoutes(array $attributes = null)
|
||||
{
|
||||
if ($this->app instanceof CachesRoutes && $this->app->routesAreCached()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = $attributes ?: ['middleware' => ['web']];
|
||||
|
||||
$this->app['router']->group($attributes, function ($router) {
|
||||
$router->match(
|
||||
['get', 'post'], '/broadcasting/user-auth',
|
||||
'\\'.BroadcastController::class.'@authenticateUser'
|
||||
)->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the routes for handling broadcast authentication and sockets.
|
||||
*
|
||||
* Alias of "routes" method.
|
||||
*
|
||||
* @param array|null $attributes
|
||||
* @return void
|
||||
*/
|
||||
public function channelRoutes(array $attributes = null)
|
||||
{
|
||||
return $this->routes($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the socket ID for the given request.
|
||||
*
|
||||
@@ -81,16 +129,14 @@ class BroadcastManager implements FactoryContract
|
||||
|
||||
$request = $request ?: $this->app['request'];
|
||||
|
||||
if ($request->hasHeader('X-Socket-ID')) {
|
||||
return $request->header('X-Socket-ID');
|
||||
}
|
||||
return $request->header('X-Socket-ID');
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin broadcasting an event.
|
||||
*
|
||||
* @param mixed|null $event
|
||||
* @return \Illuminate\Broadcasting\PendingBroadcast|void
|
||||
* @return \Illuminate\Broadcasting\PendingBroadcast
|
||||
*/
|
||||
public function event($event = null)
|
||||
{
|
||||
@@ -105,10 +151,11 @@ class BroadcastManager implements FactoryContract
|
||||
*/
|
||||
public function queue($event)
|
||||
{
|
||||
$connection = $event instanceof ShouldBroadcastNow ? 'sync' : null;
|
||||
|
||||
if (is_null($connection) && isset($event->connection)) {
|
||||
$connection = $event->connection;
|
||||
if ($event instanceof ShouldBroadcastNow ||
|
||||
(is_object($event) &&
|
||||
method_exists($event, 'shouldBroadcastNow') &&
|
||||
$event->shouldBroadcastNow())) {
|
||||
return $this->app->make(BusDispatcherContract::class)->dispatchNow(new BroadcastEvent(clone $event));
|
||||
}
|
||||
|
||||
$queue = null;
|
||||
@@ -121,15 +168,40 @@ class BroadcastManager implements FactoryContract
|
||||
$queue = $event->queue;
|
||||
}
|
||||
|
||||
$this->app->make('queue')->connection($connection)->pushOn(
|
||||
$queue, new BroadcastEvent(clone $event)
|
||||
);
|
||||
$broadcastEvent = new BroadcastEvent(clone $event);
|
||||
|
||||
if ($event instanceof ShouldBeUnique) {
|
||||
$broadcastEvent = new UniqueBroadcastEvent(clone $event);
|
||||
|
||||
if ($this->mustBeUniqueAndCannotAcquireLock($broadcastEvent)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->app->make('queue')
|
||||
->connection($event->connection ?? null)
|
||||
->pushOn($queue, $broadcastEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the broadcastable event must be unique and determine if we can acquire the necessary lock.
|
||||
*
|
||||
* @param mixed $event
|
||||
* @return bool
|
||||
*/
|
||||
protected function mustBeUniqueAndCannotAcquireLock($event)
|
||||
{
|
||||
return ! (new UniqueLock(
|
||||
method_exists($event, 'uniqueVia')
|
||||
? $event->uniqueVia()
|
||||
: $this->app->make(Cache::class)
|
||||
))->acquire($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
* @param string|null $driver
|
||||
* @return mixed
|
||||
*/
|
||||
public function connection($driver = null)
|
||||
@@ -140,7 +212,7 @@ class BroadcastManager implements FactoryContract
|
||||
/**
|
||||
* Get a driver instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function driver($name = null)
|
||||
@@ -158,11 +230,11 @@ class BroadcastManager implements FactoryContract
|
||||
*/
|
||||
protected function get($name)
|
||||
{
|
||||
return isset($this->drivers[$name]) ? $this->drivers[$name] : $this->resolve($name);
|
||||
return $this->drivers[$name] ?? $this->resolve($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given store.
|
||||
* Resolve the given broadcaster.
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Illuminate\Contracts\Broadcasting\Broadcaster
|
||||
@@ -174,7 +246,7 @@ class BroadcastManager implements FactoryContract
|
||||
$config = $this->getConfig($name);
|
||||
|
||||
if (is_null($config)) {
|
||||
throw new InvalidArgumentException("Broadcaster [{$name}] is not defined.");
|
||||
throw new InvalidArgumentException("Broadcast connection [{$name}] is not defined.");
|
||||
}
|
||||
|
||||
if (isset($this->customCreators[$config['driver']])) {
|
||||
@@ -209,10 +281,54 @@ class BroadcastManager implements FactoryContract
|
||||
*/
|
||||
protected function createPusherDriver(array $config)
|
||||
{
|
||||
return new PusherBroadcaster(
|
||||
new Pusher($config['key'], $config['secret'],
|
||||
$config['app_id'], Arr::get($config, 'options', []))
|
||||
return new PusherBroadcaster($this->pusher($config));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Pusher instance for the given configuration.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Pusher\Pusher
|
||||
*/
|
||||
public function pusher(array $config)
|
||||
{
|
||||
$pusher = new Pusher(
|
||||
$config['key'],
|
||||
$config['secret'],
|
||||
$config['app_id'],
|
||||
$config['options'] ?? [],
|
||||
isset($config['client_options']) && ! empty($config['client_options'])
|
||||
? new GuzzleClient($config['client_options'])
|
||||
: null,
|
||||
);
|
||||
|
||||
if ($config['log'] ?? false) {
|
||||
$pusher->setLogger($this->app->make(LoggerInterface::class));
|
||||
}
|
||||
|
||||
return $pusher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the driver.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Illuminate\Contracts\Broadcasting\Broadcaster
|
||||
*/
|
||||
protected function createAblyDriver(array $config)
|
||||
{
|
||||
return new AblyBroadcaster($this->ably($config));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Ably instance for the given configuration.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Ably\AblyRest
|
||||
*/
|
||||
public function ably(array $config)
|
||||
{
|
||||
return new AblyRest($config);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,7 +340,8 @@ class BroadcastManager implements FactoryContract
|
||||
protected function createRedisDriver(array $config)
|
||||
{
|
||||
return new RedisBroadcaster(
|
||||
$this->app->make('redis'), Arr::get($config, 'connection')
|
||||
$this->app->make('redis'), $config['connection'] ?? null,
|
||||
$this->app['config']->get('database.redis.options.prefix', '')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -260,7 +377,11 @@ class BroadcastManager implements FactoryContract
|
||||
*/
|
||||
protected function getConfig($name)
|
||||
{
|
||||
return $this->app['config']["broadcasting.connections.{$name}"];
|
||||
if (! is_null($name) && $name !== 'null') {
|
||||
return $this->app['config']["broadcasting.connections.{$name}"];
|
||||
}
|
||||
|
||||
return ['driver' => 'null'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,10 +405,23 @@ class BroadcastManager implements FactoryContract
|
||||
$this->app['config']['broadcasting.default'] = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the given disk and remove from local cache.
|
||||
*
|
||||
* @param string|null $name
|
||||
* @return void
|
||||
*/
|
||||
public function purge($name = null)
|
||||
{
|
||||
$name ??= $this->getDefaultDriver();
|
||||
|
||||
unset($this->drivers[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom driver creator Closure.
|
||||
*
|
||||
* @param string $driver
|
||||
* @param string $driver
|
||||
* @param \Closure $callback
|
||||
* @return $this
|
||||
*/
|
||||
@@ -298,11 +432,46 @@ class BroadcastManager implements FactoryContract
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application instance used by the manager.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
return $this->app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the application instance used by the manager.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @return $this
|
||||
*/
|
||||
public function setApplication($app)
|
||||
{
|
||||
$this->app = $app;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget all of the resolved driver instances.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function forgetDrivers()
|
||||
{
|
||||
$this->drivers = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically call the default driver instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
|
||||
@@ -2,19 +2,13 @@
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Contracts\Broadcasting\Factory as BroadcastingFactory;
|
||||
use Illuminate\Contracts\Broadcasting\Broadcaster as BroadcasterContract;
|
||||
use Illuminate\Contracts\Broadcasting\Factory as BroadcastingFactory;
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class BroadcastServiceProvider extends ServiceProvider
|
||||
class BroadcastServiceProvider extends ServiceProvider implements DeferrableProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if loading of the provider is deferred.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $defer = true;
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
|
||||
235
vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php
vendored
Normal file
235
vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Broadcasting\Broadcasters;
|
||||
|
||||
use Ably\AblyRest;
|
||||
use Ably\Exceptions\AblyException;
|
||||
use Ably\Models\Message as AblyMessage;
|
||||
use Illuminate\Broadcasting\BroadcastException;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* @author Matthew Hall (matthall28@gmail.com)
|
||||
* @author Taylor Otwell (taylor@laravel.com)
|
||||
*/
|
||||
class AblyBroadcaster extends Broadcaster
|
||||
{
|
||||
/**
|
||||
* The AblyRest SDK instance.
|
||||
*
|
||||
* @var \Ably\AblyRest
|
||||
*/
|
||||
protected $ably;
|
||||
|
||||
/**
|
||||
* Create a new broadcaster instance.
|
||||
*
|
||||
* @param \Ably\AblyRest $ably
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AblyRest $ably)
|
||||
{
|
||||
$this->ably = $ably;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the incoming request for a given channel.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
public function auth($request)
|
||||
{
|
||||
$channelName = $this->normalizeChannelName($request->channel_name);
|
||||
|
||||
if (empty($request->channel_name) ||
|
||||
($this->isGuardedChannel($request->channel_name) &&
|
||||
! $this->retrieveUser($request, $channelName))) {
|
||||
throw new AccessDeniedHttpException;
|
||||
}
|
||||
|
||||
return parent::verifyUserCanAccessChannel(
|
||||
$request, $channelName
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the valid authentication response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param mixed $result
|
||||
* @return mixed
|
||||
*/
|
||||
public function validAuthenticationResponse($request, $result)
|
||||
{
|
||||
if (str_starts_with($request->channel_name, 'private')) {
|
||||
$signature = $this->generateAblySignature(
|
||||
$request->channel_name, $request->socket_id
|
||||
);
|
||||
|
||||
return ['auth' => $this->getPublicToken().':'.$signature];
|
||||
}
|
||||
|
||||
$channelName = $this->normalizeChannelName($request->channel_name);
|
||||
|
||||
$user = $this->retrieveUser($request, $channelName);
|
||||
|
||||
$broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting')
|
||||
? $user->getAuthIdentifierForBroadcasting()
|
||||
: $user->getAuthIdentifier();
|
||||
|
||||
$signature = $this->generateAblySignature(
|
||||
$request->channel_name,
|
||||
$request->socket_id,
|
||||
$userData = array_filter([
|
||||
'user_id' => (string) $broadcastIdentifier,
|
||||
'user_info' => $result,
|
||||
])
|
||||
);
|
||||
|
||||
return [
|
||||
'auth' => $this->getPublicToken().':'.$signature,
|
||||
'channel_data' => json_encode($userData),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the signature needed for Ably authentication headers.
|
||||
*
|
||||
* @param string $channelName
|
||||
* @param string $socketId
|
||||
* @param array|null $userData
|
||||
* @return string
|
||||
*/
|
||||
public function generateAblySignature($channelName, $socketId, $userData = null)
|
||||
{
|
||||
return hash_hmac(
|
||||
'sha256',
|
||||
sprintf('%s:%s%s', $socketId, $channelName, $userData ? ':'.json_encode($userData) : ''),
|
||||
$this->getPrivateToken(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast the given event.
|
||||
*
|
||||
* @param array $channels
|
||||
* @param string $event
|
||||
* @param array $payload
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Broadcasting\BroadcastException
|
||||
*/
|
||||
public function broadcast(array $channels, $event, array $payload = [])
|
||||
{
|
||||
try {
|
||||
foreach ($this->formatChannels($channels) as $channel) {
|
||||
$this->ably->channels->get($channel)->publish(
|
||||
$this->buildAblyMessage($event, $payload)
|
||||
);
|
||||
}
|
||||
} catch (AblyException $e) {
|
||||
throw new BroadcastException(
|
||||
sprintf('Ably error: %s', $e->getMessage())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an Ably message object for broadcasting.
|
||||
*
|
||||
* @param string $event
|
||||
* @param array $payload
|
||||
* @return \Ably\Models\Message
|
||||
*/
|
||||
protected function buildAblyMessage($event, array $payload = [])
|
||||
{
|
||||
return tap(new AblyMessage, function ($message) use ($event, $payload) {
|
||||
$message->name = $event;
|
||||
$message->data = $payload;
|
||||
$message->connectionKey = data_get($payload, 'socket');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the channel is protected by authentication.
|
||||
*
|
||||
* @param string $channel
|
||||
* @return bool
|
||||
*/
|
||||
public function isGuardedChannel($channel)
|
||||
{
|
||||
return Str::startsWith($channel, ['private-', 'presence-']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove prefix from channel name.
|
||||
*
|
||||
* @param string $channel
|
||||
* @return string
|
||||
*/
|
||||
public function normalizeChannelName($channel)
|
||||
{
|
||||
if ($this->isGuardedChannel($channel)) {
|
||||
return str_starts_with($channel, 'private-')
|
||||
? Str::replaceFirst('private-', '', $channel)
|
||||
: Str::replaceFirst('presence-', '', $channel);
|
||||
}
|
||||
|
||||
return $channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the channel array into an array of strings.
|
||||
*
|
||||
* @param array $channels
|
||||
* @return array
|
||||
*/
|
||||
protected function formatChannels(array $channels)
|
||||
{
|
||||
return array_map(function ($channel) {
|
||||
$channel = (string) $channel;
|
||||
|
||||
if (Str::startsWith($channel, ['private-', 'presence-'])) {
|
||||
return str_starts_with($channel, 'private-')
|
||||
? Str::replaceFirst('private-', 'private:', $channel)
|
||||
: Str::replaceFirst('presence-', 'presence:', $channel);
|
||||
}
|
||||
|
||||
return 'public:'.$channel;
|
||||
}, $channels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the public token value from the Ably key.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getPublicToken()
|
||||
{
|
||||
return Str::before($this->ably->options->key, ':');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the private token value from the Ably key.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getPrivateToken()
|
||||
{
|
||||
return Str::after($this->ably->options->key, ':');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying Ably SDK instance.
|
||||
*
|
||||
* @return \Ably\AblyRest
|
||||
*/
|
||||
public function getAbly()
|
||||
{
|
||||
return $this->ably;
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,28 @@
|
||||
|
||||
namespace Illuminate\Broadcasting\Broadcasters;
|
||||
|
||||
use ReflectionFunction;
|
||||
use ReflectionParameter;
|
||||
use Illuminate\Support\Str;
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Contracts\Routing\BindingRegistrar;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Illuminate\Contracts\Broadcasting\Broadcaster as BroadcasterContract;
|
||||
use Illuminate\Contracts\Broadcasting\HasBroadcastChannel;
|
||||
use Illuminate\Contracts\Routing\BindingRegistrar;
|
||||
use Illuminate\Contracts\Routing\UrlRoutable;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Reflector;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
abstract class Broadcaster implements BroadcasterContract
|
||||
{
|
||||
/**
|
||||
* The callback to resolve the authenticated user information.
|
||||
*
|
||||
* @var \Closure|null
|
||||
*/
|
||||
protected $authenticatedUserCallback = null;
|
||||
|
||||
/**
|
||||
* The registered channel authenticators.
|
||||
*
|
||||
@@ -20,24 +31,68 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
*/
|
||||
protected $channels = [];
|
||||
|
||||
/**
|
||||
* The registered channel options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $channelOptions = [];
|
||||
|
||||
/**
|
||||
* The binding registrar instance.
|
||||
*
|
||||
* @var BindingRegistrar
|
||||
* @var \Illuminate\Contracts\Routing\BindingRegistrar
|
||||
*/
|
||||
protected $bindingRegistrar;
|
||||
|
||||
/**
|
||||
* Resolve the authenticated user payload for the incoming connection request.
|
||||
*
|
||||
* See: https://pusher.com/docs/channels/library_auth_reference/auth-signatures/#user-authentication.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|null
|
||||
*/
|
||||
public function resolveAuthenticatedUser($request)
|
||||
{
|
||||
if ($this->authenticatedUserCallback) {
|
||||
return $this->authenticatedUserCallback->__invoke($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the user retrieval callback used to authenticate connections.
|
||||
*
|
||||
* See: https://pusher.com/docs/channels/library_auth_reference/auth-signatures/#user-authentication.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public function resolveAuthenticatedUserUsing(Closure $callback)
|
||||
{
|
||||
$this->authenticatedUserCallback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a channel authenticator.
|
||||
*
|
||||
* @param string $channel
|
||||
* @param callable $callback
|
||||
* @param \Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $channel
|
||||
* @param callable|string $callback
|
||||
* @param array $options
|
||||
* @return $this
|
||||
*/
|
||||
public function channel($channel, callable $callback)
|
||||
public function channel($channel, $callback, $options = [])
|
||||
{
|
||||
if ($channel instanceof HasBroadcastChannel) {
|
||||
$channel = $channel->broadcastChannelRoute();
|
||||
} elseif (is_string($channel) && class_exists($channel) && is_a($channel, HasBroadcastChannel::class, true)) {
|
||||
$channel = (new $channel)->broadcastChannelRoute();
|
||||
}
|
||||
|
||||
$this->channels[$channel] = $callback;
|
||||
|
||||
$this->channelOptions[$channel] = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -47,22 +102,30 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $channel
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
protected function verifyUserCanAccessChannel($request, $channel)
|
||||
{
|
||||
foreach ($this->channels as $pattern => $callback) {
|
||||
if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) {
|
||||
if (! $this->channelNameMatchesPattern($channel, $pattern)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parameters = $this->extractAuthParameters($pattern, $channel, $callback);
|
||||
|
||||
if ($result = $callback($request->user(), ...$parameters)) {
|
||||
$handler = $this->normalizeChannelHandlerToCallable($callback);
|
||||
|
||||
$result = $handler($this->retrieveUser($request, $channel), ...$parameters);
|
||||
|
||||
if ($result === false) {
|
||||
throw new AccessDeniedHttpException;
|
||||
} elseif ($result) {
|
||||
return $this->validAuthenticationResponse($request, $result);
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpException(403);
|
||||
throw new AccessDeniedHttpException;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,12 +133,12 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param string $channel
|
||||
* @param callable $callback
|
||||
* @param callable|string $callback
|
||||
* @return array
|
||||
*/
|
||||
protected function extractAuthParameters($pattern, $channel, $callback)
|
||||
{
|
||||
$callbackParameters = (new ReflectionFunction($callback))->getParameters();
|
||||
$callbackParameters = $this->extractParameters($callback);
|
||||
|
||||
return collect($this->extractChannelKeys($pattern, $channel))->reject(function ($value, $key) {
|
||||
return is_numeric($key);
|
||||
@@ -84,6 +147,44 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
})->values()->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the parameters out of what the user passed to handle the channel authentication.
|
||||
*
|
||||
* @param callable|string $callback
|
||||
* @return \ReflectionParameter[]
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function extractParameters($callback)
|
||||
{
|
||||
if (is_callable($callback)) {
|
||||
return (new ReflectionFunction($callback))->getParameters();
|
||||
} elseif (is_string($callback)) {
|
||||
return $this->extractParametersFromClass($callback);
|
||||
}
|
||||
|
||||
throw new Exception('Given channel handler is an unknown type.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the parameters out of a class channel's "join" method.
|
||||
*
|
||||
* @param string $callback
|
||||
* @return \ReflectionParameter[]
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function extractParametersFromClass($callback)
|
||||
{
|
||||
$reflection = new ReflectionClass($callback);
|
||||
|
||||
if (! $reflection->hasMethod('join')) {
|
||||
throw new Exception('Class based channel must define a "join" method.');
|
||||
}
|
||||
|
||||
return $reflection->getMethod('join')->getParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the channel keys from the incoming channel name.
|
||||
*
|
||||
@@ -140,6 +241,8 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
* @param mixed $value
|
||||
* @param array $callbackParameters
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
protected function resolveImplicitBindingIfPossible($key, $value, $callbackParameters)
|
||||
{
|
||||
@@ -148,11 +251,13 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
continue;
|
||||
}
|
||||
|
||||
$model = $parameter->getClass()->newInstance();
|
||||
$className = Reflector::getParameterClassName($parameter);
|
||||
|
||||
return $model->where($model->getRouteKeyName(), $value)->firstOr(function () {
|
||||
throw new HttpException(403);
|
||||
});
|
||||
if (is_null($model = (new $className)->resolveRouteBinding($value))) {
|
||||
throw new AccessDeniedHttpException;
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
return $value;
|
||||
@@ -162,13 +267,13 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
* Determine if a given key and parameter is implicitly bindable.
|
||||
*
|
||||
* @param string $key
|
||||
* @param ReflectionParameter $parameter
|
||||
* @param \ReflectionParameter $parameter
|
||||
* @return bool
|
||||
*/
|
||||
protected function isImplicitlyBindable($key, $parameter)
|
||||
{
|
||||
return $parameter->name === $key && $parameter->getClass() &&
|
||||
$parameter->getClass()->isSubclassOf(Model::class);
|
||||
return $parameter->getName() === $key &&
|
||||
Reflector::isParameterSubclassOf($parameter, UrlRoutable::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,7 +292,7 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
/**
|
||||
* Get the model binding registrar instance.
|
||||
*
|
||||
* @return BindingRegistrar
|
||||
* @return \Illuminate\Contracts\Routing\BindingRegistrar
|
||||
*/
|
||||
protected function binder()
|
||||
{
|
||||
@@ -198,4 +303,74 @@ abstract class Broadcaster implements BroadcasterContract
|
||||
|
||||
return $this->bindingRegistrar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the given callback into a callable.
|
||||
*
|
||||
* @param mixed $callback
|
||||
* @return callable
|
||||
*/
|
||||
protected function normalizeChannelHandlerToCallable($callback)
|
||||
{
|
||||
return is_callable($callback) ? $callback : function (...$args) use ($callback) {
|
||||
return Container::getInstance()
|
||||
->make($callback)
|
||||
->join(...$args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the authenticated user using the configured guard (if any).
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $channel
|
||||
* @return mixed
|
||||
*/
|
||||
protected function retrieveUser($request, $channel)
|
||||
{
|
||||
$options = $this->retrieveChannelOptions($channel);
|
||||
|
||||
$guards = $options['guards'] ?? null;
|
||||
|
||||
if (is_null($guards)) {
|
||||
return $request->user();
|
||||
}
|
||||
|
||||
foreach (Arr::wrap($guards) as $guard) {
|
||||
if ($user = $request->user($guard)) {
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve options for a certain channel.
|
||||
*
|
||||
* @param string $channel
|
||||
* @return array
|
||||
*/
|
||||
protected function retrieveChannelOptions($channel)
|
||||
{
|
||||
foreach ($this->channelOptions as $pattern => $options) {
|
||||
if (! $this->channelNameMatchesPattern($channel, $pattern)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the channel name from the request matches a pattern from registered channels.
|
||||
*
|
||||
* @param string $channel
|
||||
* @param string $pattern
|
||||
* @return bool
|
||||
*/
|
||||
protected function channelNameMatchesPattern($channel, $pattern)
|
||||
{
|
||||
return preg_match('/'.preg_replace('/\{(.*?)\}/', '([^\.]+)', $pattern).'$/', $channel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,28 @@
|
||||
|
||||
namespace Illuminate\Broadcasting\Broadcasters;
|
||||
|
||||
use Pusher;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Broadcasting\BroadcastException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pusher\ApiErrorException;
|
||||
use Pusher\Pusher;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
class PusherBroadcaster extends Broadcaster
|
||||
{
|
||||
use UsePusherChannelConventions;
|
||||
|
||||
/**
|
||||
* The Pusher SDK instance.
|
||||
*
|
||||
* @var \Pusher
|
||||
* @var \Pusher\Pusher
|
||||
*/
|
||||
protected $pusher;
|
||||
|
||||
/**
|
||||
* Create a new broadcaster instance.
|
||||
*
|
||||
* @param \Pusher $pusher
|
||||
* @param \Pusher\Pusher $pusher
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Pusher $pusher)
|
||||
@@ -28,22 +31,56 @@ class PusherBroadcaster extends Broadcaster
|
||||
$this->pusher = $pusher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the authenticated user payload for an incoming connection request.
|
||||
*
|
||||
* See: https://pusher.com/docs/channels/library_auth_reference/auth-signatures/#user-authentication
|
||||
* See: https://pusher.com/docs/channels/server_api/authenticating-users/#response
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|null
|
||||
*/
|
||||
public function resolveAuthenticatedUser($request)
|
||||
{
|
||||
if (! $user = parent::resolveAuthenticatedUser($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (method_exists($this->pusher, 'authenticateUser')) {
|
||||
return $this->pusher->authenticateUser($request->socket_id, $user);
|
||||
}
|
||||
|
||||
$settings = $this->pusher->getSettings();
|
||||
$encodedUser = json_encode($user);
|
||||
$decodedString = "{$request->socket_id}::user::{$encodedUser}";
|
||||
|
||||
$auth = $settings['auth_key'].':'.hash_hmac(
|
||||
'sha256', $decodedString, $settings['secret']
|
||||
);
|
||||
|
||||
return [
|
||||
'auth' => $auth,
|
||||
'user_data' => $encodedUser,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the incoming request for a given channel.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
public function auth($request)
|
||||
{
|
||||
if (Str::startsWith($request->channel_name, ['private-', 'presence-']) &&
|
||||
! $request->user()) {
|
||||
throw new HttpException(403);
|
||||
}
|
||||
$channelName = $this->normalizeChannelName($request->channel_name);
|
||||
|
||||
$channelName = Str::startsWith($request->channel_name, 'private-')
|
||||
? Str::replaceFirst('private-', '', $request->channel_name)
|
||||
: Str::replaceFirst('presence-', '', $request->channel_name);
|
||||
if (empty($request->channel_name) ||
|
||||
($this->isGuardedChannel($request->channel_name) &&
|
||||
! $this->retrieveUser($request, $channelName))) {
|
||||
throw new AccessDeniedHttpException;
|
||||
}
|
||||
|
||||
return parent::verifyUserCanAccessChannel(
|
||||
$request, $channelName
|
||||
@@ -59,27 +96,46 @@ class PusherBroadcaster extends Broadcaster
|
||||
*/
|
||||
public function validAuthenticationResponse($request, $result)
|
||||
{
|
||||
if (Str::startsWith($request->channel_name, 'private')) {
|
||||
if (str_starts_with($request->channel_name, 'private')) {
|
||||
return $this->decodePusherResponse(
|
||||
$this->pusher->socket_auth($request->channel_name, $request->socket_id)
|
||||
$request,
|
||||
method_exists($this->pusher, 'authorizeChannel')
|
||||
? $this->pusher->authorizeChannel($request->channel_name, $request->socket_id)
|
||||
: $this->pusher->socket_auth($request->channel_name, $request->socket_id)
|
||||
);
|
||||
}
|
||||
|
||||
$channelName = $this->normalizeChannelName($request->channel_name);
|
||||
|
||||
$user = $this->retrieveUser($request, $channelName);
|
||||
|
||||
$broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting')
|
||||
? $user->getAuthIdentifierForBroadcasting()
|
||||
: $user->getAuthIdentifier();
|
||||
|
||||
return $this->decodePusherResponse(
|
||||
$this->pusher->presence_auth(
|
||||
$request->channel_name, $request->socket_id, $request->user()->getAuthIdentifier(), $result)
|
||||
$request,
|
||||
method_exists($this->pusher, 'authorizePresenceChannel')
|
||||
? $this->pusher->authorizePresenceChannel($request->channel_name, $request->socket_id, $broadcastIdentifier, $result)
|
||||
: $this->pusher->presence_auth($request->channel_name, $request->socket_id, $broadcastIdentifier, $result)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the given Pusher response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param mixed $response
|
||||
* @return array
|
||||
*/
|
||||
protected function decodePusherResponse($response)
|
||||
protected function decodePusherResponse($request, $response)
|
||||
{
|
||||
return json_decode($response, true);
|
||||
if (! $request->input('callback', false)) {
|
||||
return json_decode($response, true);
|
||||
}
|
||||
|
||||
return response()->json(json_decode($response, true))
|
||||
->withCallback($request->callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,32 +145,46 @@ class PusherBroadcaster extends Broadcaster
|
||||
* @param string $event
|
||||
* @param array $payload
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Broadcasting\BroadcastException
|
||||
*/
|
||||
public function broadcast(array $channels, $event, array $payload = [])
|
||||
{
|
||||
$socket = Arr::pull($payload, 'socket');
|
||||
|
||||
$response = $this->pusher->trigger(
|
||||
$this->formatChannels($channels), $event, $payload, $socket, true
|
||||
);
|
||||
$parameters = $socket !== null ? ['socket_id' => $socket] : [];
|
||||
|
||||
if ((is_array($response) && $response['status'] >= 200 && $response['status'] <= 299)
|
||||
|| $response === true) {
|
||||
return;
|
||||
$channels = Collection::make($this->formatChannels($channels));
|
||||
|
||||
try {
|
||||
$channels->chunk(100)->each(function ($channels) use ($event, $payload, $parameters) {
|
||||
$this->pusher->trigger($channels->toArray(), $event, $payload, $parameters);
|
||||
});
|
||||
} catch (ApiErrorException $e) {
|
||||
throw new BroadcastException(
|
||||
sprintf('Pusher error: %s.', $e->getMessage())
|
||||
);
|
||||
}
|
||||
|
||||
throw new BroadcastException(
|
||||
is_bool($response) ? 'Failed to connect to Pusher.' : $response['body']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Pusher SDK instance.
|
||||
*
|
||||
* @return \Pusher
|
||||
* @return \Pusher\Pusher
|
||||
*/
|
||||
public function getPusher()
|
||||
{
|
||||
return $this->pusher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Pusher SDK instance.
|
||||
*
|
||||
* @param \Pusher\Pusher $pusher
|
||||
* @return void
|
||||
*/
|
||||
public function setPusher($pusher)
|
||||
{
|
||||
$this->pusher = $pusher;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
|
||||
namespace Illuminate\Broadcasting\Broadcasters;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Broadcasting\BroadcastException;
|
||||
use Illuminate\Contracts\Redis\Factory as Redis;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Predis\Connection\ConnectionException;
|
||||
use RedisException;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
class RedisBroadcaster extends Broadcaster
|
||||
{
|
||||
use UsePusherChannelConventions;
|
||||
|
||||
/**
|
||||
* The Redis instance.
|
||||
*
|
||||
@@ -19,20 +23,29 @@ class RedisBroadcaster extends Broadcaster
|
||||
/**
|
||||
* The Redis connection to use for broadcasting.
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
protected $connection = null;
|
||||
|
||||
/**
|
||||
* The Redis key prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connection;
|
||||
protected $prefix = '';
|
||||
|
||||
/**
|
||||
* Create a new broadcaster instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Redis\Factory $redis
|
||||
* @param string $connection
|
||||
* @param string|null $connection
|
||||
* @param string $prefix
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Redis $redis, $connection = null)
|
||||
public function __construct(Redis $redis, $connection = null, $prefix = '')
|
||||
{
|
||||
$this->redis = $redis;
|
||||
$this->prefix = $prefix;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
@@ -41,17 +54,20 @@ class RedisBroadcaster extends Broadcaster
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
public function auth($request)
|
||||
{
|
||||
if (Str::startsWith($request->channel_name, ['private-', 'presence-']) &&
|
||||
! $request->user()) {
|
||||
throw new HttpException(403);
|
||||
}
|
||||
$channelName = $this->normalizeChannelName(
|
||||
str_replace($this->prefix, '', $request->channel_name)
|
||||
);
|
||||
|
||||
$channelName = Str::startsWith($request->channel_name, 'private-')
|
||||
? Str::replaceFirst('private-', '', $request->channel_name)
|
||||
: Str::replaceFirst('presence-', '', $request->channel_name);
|
||||
if (empty($request->channel_name) ||
|
||||
($this->isGuardedChannel($request->channel_name) &&
|
||||
! $this->retrieveUser($request, $channelName))) {
|
||||
throw new AccessDeniedHttpException;
|
||||
}
|
||||
|
||||
return parent::verifyUserCanAccessChannel(
|
||||
$request, $channelName
|
||||
@@ -71,8 +87,16 @@ class RedisBroadcaster extends Broadcaster
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
$channelName = $this->normalizeChannelName($request->channel_name);
|
||||
|
||||
$user = $this->retrieveUser($request, $channelName);
|
||||
|
||||
$broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting')
|
||||
? $user->getAuthIdentifierForBroadcasting()
|
||||
: $user->getAuthIdentifier();
|
||||
|
||||
return json_encode(['channel_data' => [
|
||||
'user_id' => $request->user()->getAuthIdentifier(),
|
||||
'user_id' => $broadcastIdentifier,
|
||||
'user_info' => $result,
|
||||
]]);
|
||||
}
|
||||
@@ -84,9 +108,15 @@ class RedisBroadcaster extends Broadcaster
|
||||
* @param string $event
|
||||
* @param array $payload
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Broadcasting\BroadcastException
|
||||
*/
|
||||
public function broadcast(array $channels, $event, array $payload = [])
|
||||
{
|
||||
if (empty($channels)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connection = $this->redis->connection($this->connection);
|
||||
|
||||
$payload = json_encode([
|
||||
@@ -95,8 +125,45 @@ class RedisBroadcaster extends Broadcaster
|
||||
'socket' => Arr::pull($payload, 'socket'),
|
||||
]);
|
||||
|
||||
foreach ($this->formatChannels($channels) as $channel) {
|
||||
$connection->publish($channel, $payload);
|
||||
try {
|
||||
$connection->eval(
|
||||
$this->broadcastMultipleChannelsScript(),
|
||||
0, $payload, ...$this->formatChannels($channels)
|
||||
);
|
||||
} catch (ConnectionException|RedisException $e) {
|
||||
throw new BroadcastException(
|
||||
sprintf('Redis error: %s.', $e->getMessage())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Lua script for broadcasting to multiple channels.
|
||||
*
|
||||
* ARGV[1] - The payload
|
||||
* ARGV[2...] - The channels
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function broadcastMultipleChannelsScript()
|
||||
{
|
||||
return <<<'LUA'
|
||||
for i = 2, #ARGV do
|
||||
redis.call('publish', ARGV[i], ARGV[1])
|
||||
end
|
||||
LUA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the channel array into an array of strings.
|
||||
*
|
||||
* @param array $channels
|
||||
* @return array
|
||||
*/
|
||||
protected function formatChannels(array $channels)
|
||||
{
|
||||
return array_map(function ($channel) {
|
||||
return $this->prefix.$channel;
|
||||
}, parent::formatChannels($channels));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Broadcasting\Broadcasters;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait UsePusherChannelConventions
|
||||
{
|
||||
/**
|
||||
* Return true if the channel is protected by authentication.
|
||||
*
|
||||
* @param string $channel
|
||||
* @return bool
|
||||
*/
|
||||
public function isGuardedChannel($channel)
|
||||
{
|
||||
return Str::startsWith($channel, ['private-', 'presence-']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove prefix from channel name.
|
||||
*
|
||||
* @param string $channel
|
||||
* @return string
|
||||
*/
|
||||
public function normalizeChannelName($channel)
|
||||
{
|
||||
foreach (['private-encrypted-', 'private-', 'presence-'] as $prefix) {
|
||||
if (Str::startsWith($channel, $prefix)) {
|
||||
return Str::replaceFirst($prefix, '', $channel);
|
||||
}
|
||||
}
|
||||
|
||||
return $channel;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
use Illuminate\Contracts\Broadcasting\HasBroadcastChannel;
|
||||
|
||||
class Channel
|
||||
{
|
||||
/**
|
||||
@@ -14,12 +16,12 @@ class Channel
|
||||
/**
|
||||
* Create a new channel instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->name = $name instanceof HasBroadcastChannel ? $name->broadcastChannel() : $name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
17
vendor/laravel/framework/src/Illuminate/Broadcasting/EncryptedPrivateChannel.php
vendored
Normal file
17
vendor/laravel/framework/src/Illuminate/Broadcasting/EncryptedPrivateChannel.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
class EncryptedPrivateChannel extends Channel
|
||||
{
|
||||
/**
|
||||
* Create a new channel instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
parent::__construct('private-encrypted-'.$name);
|
||||
}
|
||||
}
|
||||
40
vendor/laravel/framework/src/Illuminate/Broadcasting/InteractsWithBroadcasting.php
vendored
Normal file
40
vendor/laravel/framework/src/Illuminate/Broadcasting/InteractsWithBroadcasting.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait InteractsWithBroadcasting
|
||||
{
|
||||
/**
|
||||
* The broadcaster connection to use to broadcast the event.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $broadcastConnection = [null];
|
||||
|
||||
/**
|
||||
* Broadcast the event using a specific broadcaster.
|
||||
*
|
||||
* @param array|string|null $connection
|
||||
* @return $this
|
||||
*/
|
||||
public function broadcastVia($connection = null)
|
||||
{
|
||||
$this->broadcastConnection = is_null($connection)
|
||||
? [null]
|
||||
: Arr::wrap($connection);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the broadcaster connections the event should be broadcast on.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function broadcastConnections()
|
||||
{
|
||||
return $this->broadcastConnection;
|
||||
}
|
||||
}
|
||||
21
vendor/laravel/framework/src/Illuminate/Broadcasting/LICENSE.md
vendored
Normal file
21
vendor/laravel/framework/src/Illuminate/Broadcasting/LICENSE.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Taylor Otwell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -33,6 +33,21 @@ class PendingBroadcast
|
||||
$this->events = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast the event using a specific broadcaster.
|
||||
*
|
||||
* @param string|null $connection
|
||||
* @return $this
|
||||
*/
|
||||
public function via($connection = null)
|
||||
{
|
||||
if (method_exists($this->event, 'broadcastVia')) {
|
||||
$this->event->broadcastVia($connection);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast the event to everyone except the current user.
|
||||
*
|
||||
|
||||
@@ -2,16 +2,20 @@
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
use Illuminate\Contracts\Broadcasting\HasBroadcastChannel;
|
||||
|
||||
class PrivateChannel extends Channel
|
||||
{
|
||||
/**
|
||||
* Create a new channel instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
$name = $name instanceof HasBroadcastChannel ? $name->broadcastChannel() : $name;
|
||||
|
||||
parent::__construct('private-'.$name);
|
||||
}
|
||||
}
|
||||
|
||||
61
vendor/laravel/framework/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php
vendored
Normal file
61
vendor/laravel/framework/src/Illuminate/Broadcasting/UniqueBroadcastEvent.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Broadcasting;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Contracts\Cache\Repository;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
|
||||
class UniqueBroadcastEvent extends BroadcastEvent implements ShouldBeUnique
|
||||
{
|
||||
/**
|
||||
* The unique lock identifier.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $uniqueId;
|
||||
|
||||
/**
|
||||
* The number of seconds the unique lock should be maintained.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $uniqueFor;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param mixed $event
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($event)
|
||||
{
|
||||
$this->uniqueId = get_class($event);
|
||||
|
||||
if (method_exists($event, 'uniqueId')) {
|
||||
$this->uniqueId .= $event->uniqueId();
|
||||
} elseif (property_exists($event, 'uniqueId')) {
|
||||
$this->uniqueId .= $event->uniqueId;
|
||||
}
|
||||
|
||||
if (method_exists($event, 'uniqueFor')) {
|
||||
$this->uniqueFor = $event->uniqueFor();
|
||||
} elseif (property_exists($event, 'uniqueFor')) {
|
||||
$this->uniqueFor = $event->uniqueFor;
|
||||
}
|
||||
|
||||
parent::__construct($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the cache implementation that should manage the event's uniqueness.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Cache\Repository
|
||||
*/
|
||||
public function uniqueVia()
|
||||
{
|
||||
return method_exists($this->event, 'uniqueVia')
|
||||
? $this->event->uniqueVia()
|
||||
: Container::getInstance()->make(Repository::class);
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,15 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.4",
|
||||
"illuminate/bus": "5.4.*",
|
||||
"illuminate/contracts": "5.4.*",
|
||||
"illuminate/queue": "5.4.*",
|
||||
"illuminate/support": "5.4.*"
|
||||
"php": "^8.0.2",
|
||||
"ext-json": "*",
|
||||
"psr/log": "^1.0|^2.0|^3.0",
|
||||
"illuminate/bus": "^9.0",
|
||||
"illuminate/collections": "^9.0",
|
||||
"illuminate/container": "^9.0",
|
||||
"illuminate/contracts": "^9.0",
|
||||
"illuminate/queue": "^9.0",
|
||||
"illuminate/support": "^9.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -27,11 +31,12 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.4-dev"
|
||||
"dev-master": "9.x-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0)."
|
||||
"ably/ably-php": "Required to use the Ably broadcast driver (^1.0).",
|
||||
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0)."
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
|
||||
480
vendor/laravel/framework/src/Illuminate/Bus/Batch.php
vendored
Normal file
480
vendor/laravel/framework/src/Illuminate/Bus/Batch.php
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Queue\Factory as QueueFactory;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Queue\CallQueuedClosure;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use JsonSerializable;
|
||||
use Throwable;
|
||||
|
||||
class Batch implements Arrayable, JsonSerializable
|
||||
{
|
||||
/**
|
||||
* The queue factory implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Queue\Factory
|
||||
*/
|
||||
protected $queue;
|
||||
|
||||
/**
|
||||
* The repository implementation.
|
||||
*
|
||||
* @var \Illuminate\Bus\BatchRepository
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* The batch ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The batch name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* The total number of jobs that belong to the batch.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $totalJobs;
|
||||
|
||||
/**
|
||||
* The total number of jobs that are still pending.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $pendingJobs;
|
||||
|
||||
/**
|
||||
* The total number of jobs that have failed.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $failedJobs;
|
||||
|
||||
/**
|
||||
* The IDs of the jobs that have failed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $failedJobIds;
|
||||
|
||||
/**
|
||||
* The batch options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $options;
|
||||
|
||||
/**
|
||||
* The date indicating when the batch was created.
|
||||
*
|
||||
* @var \Carbon\CarbonImmutable
|
||||
*/
|
||||
public $createdAt;
|
||||
|
||||
/**
|
||||
* The date indicating when the batch was cancelled.
|
||||
*
|
||||
* @var \Carbon\CarbonImmutable|null
|
||||
*/
|
||||
public $cancelledAt;
|
||||
|
||||
/**
|
||||
* The date indicating when the batch was finished.
|
||||
*
|
||||
* @var \Carbon\CarbonImmutable|null
|
||||
*/
|
||||
public $finishedAt;
|
||||
|
||||
/**
|
||||
* Create a new batch instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Queue\Factory $queue
|
||||
* @param \Illuminate\Bus\BatchRepository $repository
|
||||
* @param string $id
|
||||
* @param string $name
|
||||
* @param int $totalJobs
|
||||
* @param int $pendingJobs
|
||||
* @param int $failedJobs
|
||||
* @param array $failedJobIds
|
||||
* @param array $options
|
||||
* @param \Carbon\CarbonImmutable $createdAt
|
||||
* @param \Carbon\CarbonImmutable|null $cancelledAt
|
||||
* @param \Carbon\CarbonImmutable|null $finishedAt
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(QueueFactory $queue,
|
||||
BatchRepository $repository,
|
||||
string $id,
|
||||
string $name,
|
||||
int $totalJobs,
|
||||
int $pendingJobs,
|
||||
int $failedJobs,
|
||||
array $failedJobIds,
|
||||
array $options,
|
||||
CarbonImmutable $createdAt,
|
||||
?CarbonImmutable $cancelledAt = null,
|
||||
?CarbonImmutable $finishedAt = null)
|
||||
{
|
||||
$this->queue = $queue;
|
||||
$this->repository = $repository;
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->totalJobs = $totalJobs;
|
||||
$this->pendingJobs = $pendingJobs;
|
||||
$this->failedJobs = $failedJobs;
|
||||
$this->failedJobIds = $failedJobIds;
|
||||
$this->options = $options;
|
||||
$this->createdAt = $createdAt;
|
||||
$this->cancelledAt = $cancelledAt;
|
||||
$this->finishedAt = $finishedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fresh instance of the batch represented by this ID.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function fresh()
|
||||
{
|
||||
return $this->repository->find($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional jobs to the batch.
|
||||
*
|
||||
* @param \Illuminate\Support\Enumerable|object|array $jobs
|
||||
* @return self
|
||||
*/
|
||||
public function add($jobs)
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
$jobs = Collection::wrap($jobs)->map(function ($job) use (&$count) {
|
||||
$job = $job instanceof Closure ? CallQueuedClosure::create($job) : $job;
|
||||
|
||||
if (is_array($job)) {
|
||||
$count += count($job);
|
||||
|
||||
return with($this->prepareBatchedChain($job), function ($chain) {
|
||||
return $chain->first()
|
||||
->allOnQueue($this->options['queue'] ?? null)
|
||||
->allOnConnection($this->options['connection'] ?? null)
|
||||
->chain($chain->slice(1)->values()->all());
|
||||
});
|
||||
} else {
|
||||
$job->withBatchId($this->id);
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $job;
|
||||
});
|
||||
|
||||
$this->repository->transaction(function () use ($jobs, $count) {
|
||||
$this->repository->incrementTotalJobs($this->id, $count);
|
||||
|
||||
$this->queue->connection($this->options['connection'] ?? null)->bulk(
|
||||
$jobs->all(),
|
||||
$data = '',
|
||||
$this->options['queue'] ?? null
|
||||
);
|
||||
});
|
||||
|
||||
return $this->fresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a chain that exists within the jobs being added.
|
||||
*
|
||||
* @param array $chain
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
protected function prepareBatchedChain(array $chain)
|
||||
{
|
||||
return collect($chain)->map(function ($job) {
|
||||
$job = $job instanceof Closure ? CallQueuedClosure::create($job) : $job;
|
||||
|
||||
return $job->withBatchId($this->id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of jobs that have been processed by the batch thus far.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function processedJobs()
|
||||
{
|
||||
return $this->totalJobs - $this->pendingJobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the percentage of jobs that have been processed (between 0-100).
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function progress()
|
||||
{
|
||||
return $this->totalJobs > 0 ? round(($this->processedJobs() / $this->totalJobs) * 100) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that a job within the batch finished successfully, executing any callbacks if necessary.
|
||||
*
|
||||
* @param string $jobId
|
||||
* @return void
|
||||
*/
|
||||
public function recordSuccessfulJob(string $jobId)
|
||||
{
|
||||
$counts = $this->decrementPendingJobs($jobId);
|
||||
|
||||
if ($counts->pendingJobs === 0) {
|
||||
$this->repository->markAsFinished($this->id);
|
||||
}
|
||||
|
||||
if ($counts->pendingJobs === 0 && $this->hasThenCallbacks()) {
|
||||
$batch = $this->fresh();
|
||||
|
||||
collect($this->options['then'])->each(function ($handler) use ($batch) {
|
||||
$this->invokeHandlerCallback($handler, $batch);
|
||||
});
|
||||
}
|
||||
|
||||
if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) {
|
||||
$batch = $this->fresh();
|
||||
|
||||
collect($this->options['finally'])->each(function ($handler) use ($batch) {
|
||||
$this->invokeHandlerCallback($handler, $batch);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the pending jobs for the batch.
|
||||
*
|
||||
* @param string $jobId
|
||||
* @return \Illuminate\Bus\UpdatedBatchJobCounts
|
||||
*/
|
||||
public function decrementPendingJobs(string $jobId)
|
||||
{
|
||||
return $this->repository->decrementPendingJobs($this->id, $jobId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch has finished executing.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function finished()
|
||||
{
|
||||
return ! is_null($this->finishedAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch has "success" callbacks.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasThenCallbacks()
|
||||
{
|
||||
return isset($this->options['then']) && ! empty($this->options['then']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch allows jobs to fail without cancelling the batch.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allowsFailures()
|
||||
{
|
||||
return Arr::get($this->options, 'allowFailures', false) === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch has job failures.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasFailures()
|
||||
{
|
||||
return $this->failedJobs > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that a job within the batch failed to finish successfully, executing any callbacks if necessary.
|
||||
*
|
||||
* @param string $jobId
|
||||
* @param \Throwable $e
|
||||
* @return void
|
||||
*/
|
||||
public function recordFailedJob(string $jobId, $e)
|
||||
{
|
||||
$counts = $this->incrementFailedJobs($jobId);
|
||||
|
||||
if ($counts->failedJobs === 1 && ! $this->allowsFailures()) {
|
||||
$this->cancel();
|
||||
}
|
||||
|
||||
if ($counts->failedJobs === 1 && $this->hasCatchCallbacks()) {
|
||||
$batch = $this->fresh();
|
||||
|
||||
collect($this->options['catch'])->each(function ($handler) use ($batch, $e) {
|
||||
$this->invokeHandlerCallback($handler, $batch, $e);
|
||||
});
|
||||
}
|
||||
|
||||
if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) {
|
||||
$batch = $this->fresh();
|
||||
|
||||
collect($this->options['finally'])->each(function ($handler) use ($batch, $e) {
|
||||
$this->invokeHandlerCallback($handler, $batch, $e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the failed jobs for the batch.
|
||||
*
|
||||
* @param string $jobId
|
||||
* @return \Illuminate\Bus\UpdatedBatchJobCounts
|
||||
*/
|
||||
public function incrementFailedJobs(string $jobId)
|
||||
{
|
||||
return $this->repository->incrementFailedJobs($this->id, $jobId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch has "catch" callbacks.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCatchCallbacks()
|
||||
{
|
||||
return isset($this->options['catch']) && ! empty($this->options['catch']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch has "finally" callbacks.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasFinallyCallbacks()
|
||||
{
|
||||
return isset($this->options['finally']) && ! empty($this->options['finally']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the batch.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cancel()
|
||||
{
|
||||
$this->repository->cancel($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch has been cancelled.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canceled()
|
||||
{
|
||||
return $this->cancelled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch has been cancelled.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function cancelled()
|
||||
{
|
||||
return ! is_null($this->cancelledAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the batch from storage.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$this->repository->delete($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a batch callback handler.
|
||||
*
|
||||
* @param callable $handler
|
||||
* @param \Illuminate\Bus\Batch $batch
|
||||
* @param \Throwable|null $e
|
||||
* @return void
|
||||
*/
|
||||
protected function invokeHandlerCallback($handler, Batch $batch, Throwable $e = null)
|
||||
{
|
||||
try {
|
||||
return $handler($batch, $e);
|
||||
} catch (Throwable $e) {
|
||||
if (function_exists('report')) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the batch to an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'totalJobs' => $this->totalJobs,
|
||||
'pendingJobs' => $this->pendingJobs,
|
||||
'processedJobs' => $this->processedJobs(),
|
||||
'progress' => $this->progress(),
|
||||
'failedJobs' => $this->failedJobs,
|
||||
'options' => $this->options,
|
||||
'createdAt' => $this->createdAt,
|
||||
'cancelledAt' => $this->cancelledAt,
|
||||
'finishedAt' => $this->finishedAt,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON serializable representation of the object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically access the batch's "options" via properties.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
return $this->options[$key] ?? null;
|
||||
}
|
||||
}
|
||||
58
vendor/laravel/framework/src/Illuminate/Bus/BatchFactory.php
vendored
Normal file
58
vendor/laravel/framework/src/Illuminate/Bus/BatchFactory.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Contracts\Queue\Factory as QueueFactory;
|
||||
|
||||
class BatchFactory
|
||||
{
|
||||
/**
|
||||
* The queue factory implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Queue\Factory
|
||||
*/
|
||||
protected $queue;
|
||||
|
||||
/**
|
||||
* Create a new batch factory instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Queue\Factory $queue
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(QueueFactory $queue)
|
||||
{
|
||||
$this->queue = $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new batch instance.
|
||||
*
|
||||
* @param \Illuminate\Bus\BatchRepository $repository
|
||||
* @param string $id
|
||||
* @param string $name
|
||||
* @param int $totalJobs
|
||||
* @param int $pendingJobs
|
||||
* @param int $failedJobs
|
||||
* @param array $failedJobIds
|
||||
* @param array $options
|
||||
* @param \Carbon\CarbonImmutable $createdAt
|
||||
* @param \Carbon\CarbonImmutable|null $cancelledAt
|
||||
* @param \Carbon\CarbonImmutable|null $finishedAt
|
||||
* @return \Illuminate\Bus\Batch
|
||||
*/
|
||||
public function make(BatchRepository $repository,
|
||||
string $id,
|
||||
string $name,
|
||||
int $totalJobs,
|
||||
int $pendingJobs,
|
||||
int $failedJobs,
|
||||
array $failedJobIds,
|
||||
array $options,
|
||||
CarbonImmutable $createdAt,
|
||||
?CarbonImmutable $cancelledAt,
|
||||
?CarbonImmutable $finishedAt)
|
||||
{
|
||||
return new Batch($this->queue, $repository, $id, $name, $totalJobs, $pendingJobs, $failedJobs, $failedJobIds, $options, $createdAt, $cancelledAt, $finishedAt);
|
||||
}
|
||||
}
|
||||
92
vendor/laravel/framework/src/Illuminate/Bus/BatchRepository.php
vendored
Normal file
92
vendor/laravel/framework/src/Illuminate/Bus/BatchRepository.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Closure;
|
||||
|
||||
interface BatchRepository
|
||||
{
|
||||
/**
|
||||
* Retrieve a list of batches.
|
||||
*
|
||||
* @param int $limit
|
||||
* @param mixed $before
|
||||
* @return \Illuminate\Bus\Batch[]
|
||||
*/
|
||||
public function get($limit, $before);
|
||||
|
||||
/**
|
||||
* Retrieve information about an existing batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return \Illuminate\Bus\Batch|null
|
||||
*/
|
||||
public function find(string $batchId);
|
||||
|
||||
/**
|
||||
* Store a new pending batch.
|
||||
*
|
||||
* @param \Illuminate\Bus\PendingBatch $batch
|
||||
* @return \Illuminate\Bus\Batch
|
||||
*/
|
||||
public function store(PendingBatch $batch);
|
||||
|
||||
/**
|
||||
* Increment the total number of jobs within the batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @param int $amount
|
||||
* @return void
|
||||
*/
|
||||
public function incrementTotalJobs(string $batchId, int $amount);
|
||||
|
||||
/**
|
||||
* Decrement the total number of pending jobs for the batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @param string $jobId
|
||||
* @return \Illuminate\Bus\UpdatedBatchJobCounts
|
||||
*/
|
||||
public function decrementPendingJobs(string $batchId, string $jobId);
|
||||
|
||||
/**
|
||||
* Increment the total number of failed jobs for the batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @param string $jobId
|
||||
* @return \Illuminate\Bus\UpdatedBatchJobCounts
|
||||
*/
|
||||
public function incrementFailedJobs(string $batchId, string $jobId);
|
||||
|
||||
/**
|
||||
* Mark the batch that has the given ID as finished.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return void
|
||||
*/
|
||||
public function markAsFinished(string $batchId);
|
||||
|
||||
/**
|
||||
* Cancel the batch that has the given ID.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return void
|
||||
*/
|
||||
public function cancel(string $batchId);
|
||||
|
||||
/**
|
||||
* Delete the batch that has the given ID.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return void
|
||||
*/
|
||||
public function delete(string $batchId);
|
||||
|
||||
/**
|
||||
* Execute the given Closure within a storage specific transaction.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return mixed
|
||||
*/
|
||||
public function transaction(Closure $callback);
|
||||
}
|
||||
108
vendor/laravel/framework/src/Illuminate/Bus/Batchable.php
vendored
Normal file
108
vendor/laravel/framework/src/Illuminate/Bus/Batchable.php
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Testing\Fakes\BatchFake;
|
||||
|
||||
trait Batchable
|
||||
{
|
||||
/**
|
||||
* The batch ID (if applicable).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $batchId;
|
||||
|
||||
/**
|
||||
* The fake batch, if applicable.
|
||||
*
|
||||
* @var \Illuminate\Support\Testing\BatchFake
|
||||
*/
|
||||
private $fakeBatch;
|
||||
|
||||
/**
|
||||
* Get the batch instance for the job, if applicable.
|
||||
*
|
||||
* @return \Illuminate\Bus\Batch|null
|
||||
*/
|
||||
public function batch()
|
||||
{
|
||||
if ($this->fakeBatch) {
|
||||
return $this->fakeBatch;
|
||||
}
|
||||
|
||||
if ($this->batchId) {
|
||||
return Container::getInstance()->make(BatchRepository::class)->find($this->batchId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the batch is still active and processing.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function batching()
|
||||
{
|
||||
$batch = $this->batch();
|
||||
|
||||
return $batch && ! $batch->cancelled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch ID on the job.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return $this
|
||||
*/
|
||||
public function withBatchId(string $batchId)
|
||||
{
|
||||
$this->batchId = $batchId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the job should use a fake batch.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $name
|
||||
* @param int $totalJobs
|
||||
* @param int $pendingJobs
|
||||
* @param int $failedJobs
|
||||
* @param array $failedJobIds
|
||||
* @param array $options
|
||||
* @param \Carbon\CarbonImmutable $createdAt
|
||||
* @param \Carbon\CarbonImmutable|null $cancelledAt
|
||||
* @param \Carbon\CarbonImmutable|null $finishedAt
|
||||
* @return array{0: $this, 1: \Illuminate\Support\Testing\BatchFake}
|
||||
*/
|
||||
public function withFakeBatch(string $id = '',
|
||||
string $name = '',
|
||||
int $totalJobs = 0,
|
||||
int $pendingJobs = 0,
|
||||
int $failedJobs = 0,
|
||||
array $failedJobIds = [],
|
||||
array $options = [],
|
||||
CarbonImmutable $createdAt = null,
|
||||
?CarbonImmutable $cancelledAt = null,
|
||||
?CarbonImmutable $finishedAt = null)
|
||||
{
|
||||
$this->fakeBatch = new BatchFake(
|
||||
empty($id) ? (string) Str::uuid() : $id,
|
||||
$name,
|
||||
$totalJobs,
|
||||
$pendingJobs,
|
||||
$failedJobs,
|
||||
$failedJobIds,
|
||||
$options,
|
||||
$createdAt ?? CarbonImmutable::now(),
|
||||
$cancelledAt,
|
||||
$finishedAt,
|
||||
);
|
||||
|
||||
return [$this, $this->fakeBatch];
|
||||
}
|
||||
}
|
||||
@@ -2,20 +2,14 @@
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Contracts\Bus\Dispatcher as DispatcherContract;
|
||||
use Illuminate\Contracts\Queue\Factory as QueueFactoryContract;
|
||||
use Illuminate\Contracts\Bus\QueueingDispatcher as QueueingDispatcherContract;
|
||||
use Illuminate\Contracts\Queue\Factory as QueueFactoryContract;
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class BusServiceProvider extends ServiceProvider
|
||||
class BusServiceProvider extends ServiceProvider implements DeferrableProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if loading of the provider is deferred.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $defer = true;
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
@@ -29,6 +23,8 @@ class BusServiceProvider extends ServiceProvider
|
||||
});
|
||||
});
|
||||
|
||||
$this->registerBatchServices();
|
||||
|
||||
$this->app->alias(
|
||||
Dispatcher::class, DispatcherContract::class
|
||||
);
|
||||
@@ -38,6 +34,24 @@ class BusServiceProvider extends ServiceProvider
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the batch handling services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerBatchServices()
|
||||
{
|
||||
$this->app->singleton(BatchRepository::class, DatabaseBatchRepository::class);
|
||||
|
||||
$this->app->singleton(DatabaseBatchRepository::class, function ($app) {
|
||||
return new DatabaseBatchRepository(
|
||||
$app->make(BatchFactory::class),
|
||||
$app->make('db')->connection($app->config->get('queue.batching.database')),
|
||||
$app->config->get('queue.batching.table', 'job_batches')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
@@ -49,6 +63,8 @@ class BusServiceProvider extends ServiceProvider
|
||||
Dispatcher::class,
|
||||
DispatcherContract::class,
|
||||
QueueingDispatcherContract::class,
|
||||
BatchRepository::class,
|
||||
DatabaseBatchRepository::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
388
vendor/laravel/framework/src/Illuminate/Bus/DatabaseBatchRepository.php
vendored
Normal file
388
vendor/laravel/framework/src/Illuminate/Bus/DatabaseBatchRepository.php
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Closure;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\PostgresConnection;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DatabaseBatchRepository implements PrunableBatchRepository
|
||||
{
|
||||
/**
|
||||
* The batch factory instance.
|
||||
*
|
||||
* @var \Illuminate\Bus\BatchFactory
|
||||
*/
|
||||
protected $factory;
|
||||
|
||||
/**
|
||||
* The database connection instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The database table to use to store batch information.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* Create a new batch repository instance.
|
||||
*
|
||||
* @param \Illuminate\Bus\BatchFactory $factory
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @param string $table
|
||||
*/
|
||||
public function __construct(BatchFactory $factory, Connection $connection, string $table)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->connection = $connection;
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of batches.
|
||||
*
|
||||
* @param int $limit
|
||||
* @param mixed $before
|
||||
* @return \Illuminate\Bus\Batch[]
|
||||
*/
|
||||
public function get($limit = 50, $before = null)
|
||||
{
|
||||
return $this->connection->table($this->table)
|
||||
->orderByDesc('id')
|
||||
->take($limit)
|
||||
->when($before, fn ($q) => $q->where('id', '<', $before))
|
||||
->get()
|
||||
->map(function ($batch) {
|
||||
return $this->toBatch($batch);
|
||||
})
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve information about an existing batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return \Illuminate\Bus\Batch|null
|
||||
*/
|
||||
public function find(string $batchId)
|
||||
{
|
||||
$batch = $this->connection->table($this->table)
|
||||
->useWritePdo()
|
||||
->where('id', $batchId)
|
||||
->first();
|
||||
|
||||
if ($batch) {
|
||||
return $this->toBatch($batch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new pending batch.
|
||||
*
|
||||
* @param \Illuminate\Bus\PendingBatch $batch
|
||||
* @return \Illuminate\Bus\Batch
|
||||
*/
|
||||
public function store(PendingBatch $batch)
|
||||
{
|
||||
$id = (string) Str::orderedUuid();
|
||||
|
||||
$this->connection->table($this->table)->insert([
|
||||
'id' => $id,
|
||||
'name' => $batch->name,
|
||||
'total_jobs' => 0,
|
||||
'pending_jobs' => 0,
|
||||
'failed_jobs' => 0,
|
||||
'failed_job_ids' => '[]',
|
||||
'options' => $this->serialize($batch->options),
|
||||
'created_at' => time(),
|
||||
'cancelled_at' => null,
|
||||
'finished_at' => null,
|
||||
]);
|
||||
|
||||
return $this->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the total number of jobs within the batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @param int $amount
|
||||
* @return void
|
||||
*/
|
||||
public function incrementTotalJobs(string $batchId, int $amount)
|
||||
{
|
||||
$this->connection->table($this->table)->where('id', $batchId)->update([
|
||||
'total_jobs' => new Expression('total_jobs + '.$amount),
|
||||
'pending_jobs' => new Expression('pending_jobs + '.$amount),
|
||||
'finished_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the total number of pending jobs for the batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @param string $jobId
|
||||
* @return \Illuminate\Bus\UpdatedBatchJobCounts
|
||||
*/
|
||||
public function decrementPendingJobs(string $batchId, string $jobId)
|
||||
{
|
||||
$values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) {
|
||||
return [
|
||||
'pending_jobs' => $batch->pending_jobs - 1,
|
||||
'failed_jobs' => $batch->failed_jobs,
|
||||
'failed_job_ids' => json_encode(array_values(array_diff(json_decode($batch->failed_job_ids, true), [$jobId]))),
|
||||
];
|
||||
});
|
||||
|
||||
return new UpdatedBatchJobCounts(
|
||||
$values['pending_jobs'],
|
||||
$values['failed_jobs']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the total number of failed jobs for the batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @param string $jobId
|
||||
* @return \Illuminate\Bus\UpdatedBatchJobCounts
|
||||
*/
|
||||
public function incrementFailedJobs(string $batchId, string $jobId)
|
||||
{
|
||||
$values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) {
|
||||
return [
|
||||
'pending_jobs' => $batch->pending_jobs,
|
||||
'failed_jobs' => $batch->failed_jobs + 1,
|
||||
'failed_job_ids' => json_encode(array_values(array_unique(array_merge(json_decode($batch->failed_job_ids, true), [$jobId])))),
|
||||
];
|
||||
});
|
||||
|
||||
return new UpdatedBatchJobCounts(
|
||||
$values['pending_jobs'],
|
||||
$values['failed_jobs']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an atomic value within the batch.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @param \Closure $callback
|
||||
* @return int|null
|
||||
*/
|
||||
protected function updateAtomicValues(string $batchId, Closure $callback)
|
||||
{
|
||||
return $this->connection->transaction(function () use ($batchId, $callback) {
|
||||
$batch = $this->connection->table($this->table)->where('id', $batchId)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
|
||||
return is_null($batch) ? [] : tap($callback($batch), function ($values) use ($batchId) {
|
||||
$this->connection->table($this->table)->where('id', $batchId)->update($values);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the batch that has the given ID as finished.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return void
|
||||
*/
|
||||
public function markAsFinished(string $batchId)
|
||||
{
|
||||
$this->connection->table($this->table)->where('id', $batchId)->update([
|
||||
'finished_at' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the batch that has the given ID.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return void
|
||||
*/
|
||||
public function cancel(string $batchId)
|
||||
{
|
||||
$this->connection->table($this->table)->where('id', $batchId)->update([
|
||||
'cancelled_at' => time(),
|
||||
'finished_at' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the batch that has the given ID.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return void
|
||||
*/
|
||||
public function delete(string $batchId)
|
||||
{
|
||||
$this->connection->table($this->table)->where('id', $batchId)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune all of the entries older than the given date.
|
||||
*
|
||||
* @param \DateTimeInterface $before
|
||||
* @return int
|
||||
*/
|
||||
public function prune(DateTimeInterface $before)
|
||||
{
|
||||
$query = $this->connection->table($this->table)
|
||||
->whereNotNull('finished_at')
|
||||
->where('finished_at', '<', $before->getTimestamp());
|
||||
|
||||
$totalDeleted = 0;
|
||||
|
||||
do {
|
||||
$deleted = $query->take(1000)->delete();
|
||||
|
||||
$totalDeleted += $deleted;
|
||||
} while ($deleted !== 0);
|
||||
|
||||
return $totalDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune all of the unfinished entries older than the given date.
|
||||
*
|
||||
* @param \DateTimeInterface $before
|
||||
* @return int
|
||||
*/
|
||||
public function pruneUnfinished(DateTimeInterface $before)
|
||||
{
|
||||
$query = $this->connection->table($this->table)
|
||||
->whereNull('finished_at')
|
||||
->where('created_at', '<', $before->getTimestamp());
|
||||
|
||||
$totalDeleted = 0;
|
||||
|
||||
do {
|
||||
$deleted = $query->take(1000)->delete();
|
||||
|
||||
$totalDeleted += $deleted;
|
||||
} while ($deleted !== 0);
|
||||
|
||||
return $totalDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune all of the cancelled entries older than the given date.
|
||||
*
|
||||
* @param \DateTimeInterface $before
|
||||
* @return int
|
||||
*/
|
||||
public function pruneCancelled(DateTimeInterface $before)
|
||||
{
|
||||
$query = $this->connection->table($this->table)
|
||||
->whereNotNull('cancelled_at')
|
||||
->where('created_at', '<', $before->getTimestamp());
|
||||
|
||||
$totalDeleted = 0;
|
||||
|
||||
do {
|
||||
$deleted = $query->take(1000)->delete();
|
||||
|
||||
$totalDeleted += $deleted;
|
||||
} while ($deleted !== 0);
|
||||
|
||||
return $totalDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given Closure within a storage specific transaction.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return mixed
|
||||
*/
|
||||
public function transaction(Closure $callback)
|
||||
{
|
||||
return $this->connection->transaction(fn () => $callback());
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
protected function serialize($value)
|
||||
{
|
||||
$serialized = serialize($value);
|
||||
|
||||
return $this->connection instanceof PostgresConnection
|
||||
? base64_encode($serialized)
|
||||
: $serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize the given value.
|
||||
*
|
||||
* @param string $serialized
|
||||
* @return mixed
|
||||
*/
|
||||
protected function unserialize($serialized)
|
||||
{
|
||||
if ($this->connection instanceof PostgresConnection &&
|
||||
! Str::contains($serialized, [':', ';'])) {
|
||||
$serialized = base64_decode($serialized);
|
||||
}
|
||||
|
||||
return unserialize($serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given raw batch to a Batch object.
|
||||
*
|
||||
* @param object $batch
|
||||
* @return \Illuminate\Bus\Batch
|
||||
*/
|
||||
protected function toBatch($batch)
|
||||
{
|
||||
return $this->factory->make(
|
||||
$this,
|
||||
$batch->id,
|
||||
$batch->name,
|
||||
(int) $batch->total_jobs,
|
||||
(int) $batch->pending_jobs,
|
||||
(int) $batch->failed_jobs,
|
||||
json_decode($batch->failed_job_ids, true),
|
||||
$this->unserialize($batch->options),
|
||||
CarbonImmutable::createFromTimestamp($batch->created_at),
|
||||
$batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at) : $batch->cancelled_at,
|
||||
$batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at) : $batch->finished_at
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying database connection.
|
||||
*
|
||||
* @return \Illuminate\Database\Connection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying database connection.
|
||||
*
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @return void
|
||||
*/
|
||||
public function setConnection(Connection $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,16 @@
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Closure;
|
||||
use RuntimeException;
|
||||
use Illuminate\Pipeline\Pipeline;
|
||||
use Illuminate\Contracts\Bus\QueueingDispatcher;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\Queue\Queue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\Bus\QueueingDispatcher;
|
||||
use Illuminate\Foundation\Bus\PendingChain;
|
||||
use Illuminate\Pipeline\Pipeline;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Jobs\SyncJob;
|
||||
use Illuminate\Support\Collection;
|
||||
use RuntimeException;
|
||||
|
||||
class Dispatcher implements QueueingDispatcher
|
||||
{
|
||||
@@ -69,35 +73,100 @@ class Dispatcher implements QueueingDispatcher
|
||||
*/
|
||||
public function dispatch($command)
|
||||
{
|
||||
if ($this->queueResolver && $this->commandShouldBeQueued($command)) {
|
||||
return $this->dispatchToQueue($command);
|
||||
} else {
|
||||
return $this->dispatchNow($command);
|
||||
}
|
||||
return $this->queueResolver && $this->commandShouldBeQueued($command)
|
||||
? $this->dispatchToQueue($command)
|
||||
: $this->dispatchNow($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a command to its appropriate handler in the current process.
|
||||
*
|
||||
* Queueable jobs will be dispatched to the "sync" queue.
|
||||
*
|
||||
* @param mixed $command
|
||||
* @param mixed $handler
|
||||
* @return mixed
|
||||
*/
|
||||
public function dispatchSync($command, $handler = null)
|
||||
{
|
||||
if ($this->queueResolver &&
|
||||
$this->commandShouldBeQueued($command) &&
|
||||
method_exists($command, 'onConnection')) {
|
||||
return $this->dispatchToQueue($command->onConnection('sync'));
|
||||
}
|
||||
|
||||
return $this->dispatchNow($command, $handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a command to its appropriate handler in the current process without using the synchronous queue.
|
||||
*
|
||||
* @param mixed $command
|
||||
* @param mixed $handler
|
||||
* @return mixed
|
||||
*/
|
||||
public function dispatchNow($command, $handler = null)
|
||||
{
|
||||
$uses = class_uses_recursive($command);
|
||||
|
||||
if (in_array(InteractsWithQueue::class, $uses) &&
|
||||
in_array(Queueable::class, $uses) &&
|
||||
! $command->job) {
|
||||
$command->setJob(new SyncJob($this->container, json_encode([]), 'sync', 'sync'));
|
||||
}
|
||||
|
||||
if ($handler || $handler = $this->getCommandHandler($command)) {
|
||||
$callback = function ($command) use ($handler) {
|
||||
return $handler->handle($command);
|
||||
$method = method_exists($handler, 'handle') ? 'handle' : '__invoke';
|
||||
|
||||
return $handler->{$method}($command);
|
||||
};
|
||||
} else {
|
||||
$callback = function ($command) {
|
||||
return $this->container->call([$command, 'handle']);
|
||||
$method = method_exists($command, 'handle') ? 'handle' : '__invoke';
|
||||
|
||||
return $this->container->call([$command, $method]);
|
||||
};
|
||||
}
|
||||
|
||||
return $this->pipeline->send($command)->through($this->pipes)->then($callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find the batch with the given ID.
|
||||
*
|
||||
* @param string $batchId
|
||||
* @return \Illuminate\Bus\Batch|null
|
||||
*/
|
||||
public function findBatch(string $batchId)
|
||||
{
|
||||
return $this->container->make(BatchRepository::class)->find($batchId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new batch of queueable jobs.
|
||||
*
|
||||
* @param \Illuminate\Support\Collection|array|mixed $jobs
|
||||
* @return \Illuminate\Bus\PendingBatch
|
||||
*/
|
||||
public function batch($jobs)
|
||||
{
|
||||
return new PendingBatch($this->container, Collection::wrap($jobs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new chain of queueable jobs.
|
||||
*
|
||||
* @param \Illuminate\Support\Collection|array $jobs
|
||||
* @return \Illuminate\Foundation\Bus\PendingChain
|
||||
*/
|
||||
public function chain($jobs)
|
||||
{
|
||||
$jobs = Collection::wrap($jobs);
|
||||
|
||||
return new PendingChain($jobs->shift(), $jobs->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given command has a handler.
|
||||
*
|
||||
@@ -145,7 +214,7 @@ class Dispatcher implements QueueingDispatcher
|
||||
*/
|
||||
public function dispatchToQueue($command)
|
||||
{
|
||||
$connection = isset($command->connection) ? $command->connection : null;
|
||||
$connection = $command->connection ?? null;
|
||||
|
||||
$queue = call_user_func($this->queueResolver, $connection);
|
||||
|
||||
@@ -155,9 +224,9 @@ class Dispatcher implements QueueingDispatcher
|
||||
|
||||
if (method_exists($command, 'queue')) {
|
||||
return $command->queue($queue, $command);
|
||||
} else {
|
||||
return $this->pushCommandToQueue($queue, $command);
|
||||
}
|
||||
|
||||
return $this->pushCommandToQueue($queue, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,6 +253,20 @@ class Dispatcher implements QueueingDispatcher
|
||||
return $queue->push($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a command to its appropriate handler after the current process.
|
||||
*
|
||||
* @param mixed $command
|
||||
* @param mixed $handler
|
||||
* @return void
|
||||
*/
|
||||
public function dispatchAfterResponse($command, $handler = null)
|
||||
{
|
||||
$this->container->terminating(function () use ($command, $handler) {
|
||||
$this->dispatchNow($command, $handler);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pipes through which commands should be piped before dispatching.
|
||||
*
|
||||
|
||||
26
vendor/laravel/framework/src/Illuminate/Bus/Events/BatchDispatched.php
vendored
Normal file
26
vendor/laravel/framework/src/Illuminate/Bus/Events/BatchDispatched.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus\Events;
|
||||
|
||||
use Illuminate\Bus\Batch;
|
||||
|
||||
class BatchDispatched
|
||||
{
|
||||
/**
|
||||
* The batch instance.
|
||||
*
|
||||
* @var \Illuminate\Bus\Batch
|
||||
*/
|
||||
public $batch;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \Illuminate\Bus\Batch $batch
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Batch $batch)
|
||||
{
|
||||
$this->batch = $batch;
|
||||
}
|
||||
}
|
||||
21
vendor/laravel/framework/src/Illuminate/Bus/LICENSE.md
vendored
Normal file
21
vendor/laravel/framework/src/Illuminate/Bus/LICENSE.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Taylor Otwell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
319
vendor/laravel/framework/src/Illuminate/Bus/PendingBatch.php
vendored
Normal file
319
vendor/laravel/framework/src/Illuminate/Bus/PendingBatch.php
vendored
Normal file
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Bus\Events\BatchDispatched;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\SerializableClosure\SerializableClosure;
|
||||
use Throwable;
|
||||
|
||||
class PendingBatch
|
||||
{
|
||||
/**
|
||||
* The IoC container instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Container\Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* The batch name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* The jobs that belong to the batch.
|
||||
*
|
||||
* @var \Illuminate\Support\Collection
|
||||
*/
|
||||
public $jobs;
|
||||
|
||||
/**
|
||||
* The batch options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $options = [];
|
||||
|
||||
/**
|
||||
* Create a new pending batch instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Container\Container $container
|
||||
* @param \Illuminate\Support\Collection $jobs
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Container $container, Collection $jobs)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->jobs = $jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add jobs to the batch.
|
||||
*
|
||||
* @param iterable|object|array $jobs
|
||||
* @return $this
|
||||
*/
|
||||
public function add($jobs)
|
||||
{
|
||||
$jobs = is_iterable($jobs) ? $jobs : Arr::wrap($jobs);
|
||||
|
||||
foreach ($jobs as $job) {
|
||||
$this->jobs->push($job);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback to be executed after all jobs in the batch have executed successfully.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function then($callback)
|
||||
{
|
||||
$this->options['then'][] = $callback instanceof Closure
|
||||
? new SerializableClosure($callback)
|
||||
: $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "then" callbacks that have been registered with the pending batch.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function thenCallbacks()
|
||||
{
|
||||
return $this->options['then'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback to be executed after the first failing job in the batch.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function catch($callback)
|
||||
{
|
||||
$this->options['catch'][] = $callback instanceof Closure
|
||||
? new SerializableClosure($callback)
|
||||
: $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "catch" callbacks that have been registered with the pending batch.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function catchCallbacks()
|
||||
{
|
||||
return $this->options['catch'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback to be executed after the batch has finished executing.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function finally($callback)
|
||||
{
|
||||
$this->options['finally'][] = $callback instanceof Closure
|
||||
? new SerializableClosure($callback)
|
||||
: $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "finally" callbacks that have been registered with the pending batch.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function finallyCallbacks()
|
||||
{
|
||||
return $this->options['finally'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the batch should not be cancelled when a job within the batch fails.
|
||||
*
|
||||
* @param bool $allowFailures
|
||||
* @return $this
|
||||
*/
|
||||
public function allowFailures($allowFailures = true)
|
||||
{
|
||||
$this->options['allowFailures'] = $allowFailures;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the pending batch allows jobs to fail without cancelling the batch.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allowsFailures()
|
||||
{
|
||||
return Arr::get($this->options, 'allowFailures', false) === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name for the batch.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function name(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the queue connection that the batched jobs should run on.
|
||||
*
|
||||
* @param string $connection
|
||||
* @return $this
|
||||
*/
|
||||
public function onConnection(string $connection)
|
||||
{
|
||||
$this->options['connection'] = $connection;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the connection used by the pending batch.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function connection()
|
||||
{
|
||||
return $this->options['connection'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the queue that the batched jobs should run on.
|
||||
*
|
||||
* @param string $queue
|
||||
* @return $this
|
||||
*/
|
||||
public function onQueue(string $queue)
|
||||
{
|
||||
$this->options['queue'] = $queue;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the queue used by the pending batch.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function queue()
|
||||
{
|
||||
return $this->options['queue'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional data into the batch's options array.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
*/
|
||||
public function withOption(string $key, $value)
|
||||
{
|
||||
$this->options[$key] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the batch.
|
||||
*
|
||||
* @return \Illuminate\Bus\Batch
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function dispatch()
|
||||
{
|
||||
$repository = $this->container->make(BatchRepository::class);
|
||||
|
||||
try {
|
||||
$batch = $repository->store($this);
|
||||
|
||||
$batch = $batch->add($this->jobs);
|
||||
} catch (Throwable $e) {
|
||||
if (isset($batch)) {
|
||||
$repository->delete($batch->id);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->container->make(EventDispatcher::class)->dispatch(
|
||||
new BatchDispatched($batch)
|
||||
);
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the batch after the response is sent to the browser.
|
||||
*
|
||||
* @return \Illuminate\Bus\Batch
|
||||
*/
|
||||
public function dispatchAfterResponse()
|
||||
{
|
||||
$repository = $this->container->make(BatchRepository::class);
|
||||
|
||||
$batch = $repository->store($this);
|
||||
|
||||
if ($batch) {
|
||||
$this->container->terminating(function () use ($batch) {
|
||||
$this->dispatchExistingBatch($batch);
|
||||
});
|
||||
}
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch an existing batch.
|
||||
*
|
||||
* @param \Illuminate\Bus\Batch $batch
|
||||
* @return void
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
protected function dispatchExistingBatch($batch)
|
||||
{
|
||||
try {
|
||||
$batch = $batch->add($this->jobs);
|
||||
} catch (Throwable $e) {
|
||||
if (isset($batch)) {
|
||||
$batch->delete();
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->container->make(EventDispatcher::class)->dispatch(
|
||||
new BatchDispatched($batch)
|
||||
);
|
||||
}
|
||||
}
|
||||
16
vendor/laravel/framework/src/Illuminate/Bus/PrunableBatchRepository.php
vendored
Normal file
16
vendor/laravel/framework/src/Illuminate/Bus/PrunableBatchRepository.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use DateTimeInterface;
|
||||
|
||||
interface PrunableBatchRepository extends BatchRepository
|
||||
{
|
||||
/**
|
||||
* Prune all of the entries older than the given date.
|
||||
*
|
||||
* @param \DateTimeInterface $before
|
||||
* @return int
|
||||
*/
|
||||
public function prune(DateTimeInterface $before);
|
||||
}
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Queue\CallQueuedClosure;
|
||||
use Illuminate\Support\Arr;
|
||||
use RuntimeException;
|
||||
|
||||
trait Queueable
|
||||
{
|
||||
/**
|
||||
@@ -18,13 +23,55 @@ trait Queueable
|
||||
*/
|
||||
public $queue;
|
||||
|
||||
/**
|
||||
* The name of the connection the chain should be sent to.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $chainConnection;
|
||||
|
||||
/**
|
||||
* The name of the queue the chain should be sent to.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $chainQueue;
|
||||
|
||||
/**
|
||||
* The callbacks to be executed on chain failure.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
public $chainCatchCallbacks;
|
||||
|
||||
/**
|
||||
* The number of seconds before the job should be made available.
|
||||
*
|
||||
* @var \DateTime|int|null
|
||||
* @var \DateTimeInterface|\DateInterval|array|int|null
|
||||
*/
|
||||
public $delay;
|
||||
|
||||
/**
|
||||
* Indicates whether the job should be dispatched after all database transactions have committed.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public $afterCommit;
|
||||
|
||||
/**
|
||||
* The middleware the job should be dispatched through.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $middleware = [];
|
||||
|
||||
/**
|
||||
* The jobs that should run if this job is successful.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $chained = [];
|
||||
|
||||
/**
|
||||
* Set the desired connection for the job.
|
||||
*
|
||||
@@ -52,9 +99,37 @@ trait Queueable
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the desired delay for the job.
|
||||
* Set the desired connection for the chain.
|
||||
*
|
||||
* @param \DateTime|int|null $delay
|
||||
* @param string|null $connection
|
||||
* @return $this
|
||||
*/
|
||||
public function allOnConnection($connection)
|
||||
{
|
||||
$this->chainConnection = $connection;
|
||||
$this->connection = $connection;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the desired queue for the chain.
|
||||
*
|
||||
* @param string|null $queue
|
||||
* @return $this
|
||||
*/
|
||||
public function allOnQueue($queue)
|
||||
{
|
||||
$this->chainQueue = $queue;
|
||||
$this->queue = $queue;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the desired delay in seconds for the job.
|
||||
*
|
||||
* @param \DateTimeInterface|\DateInterval|array|int|null $delay
|
||||
* @return $this
|
||||
*/
|
||||
public function delay($delay)
|
||||
@@ -63,4 +138,139 @@ trait Queueable
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the job should be dispatched after all database transactions have committed.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function afterCommit()
|
||||
{
|
||||
$this->afterCommit = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the job should not wait until database transactions have been committed before dispatching.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function beforeCommit()
|
||||
{
|
||||
$this->afterCommit = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the middleware the job should be dispatched through.
|
||||
*
|
||||
* @param array|object $middleware
|
||||
* @return $this
|
||||
*/
|
||||
public function through($middleware)
|
||||
{
|
||||
$this->middleware = Arr::wrap($middleware);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the jobs that should run if this job is successful.
|
||||
*
|
||||
* @param array $chain
|
||||
* @return $this
|
||||
*/
|
||||
public function chain($chain)
|
||||
{
|
||||
$this->chained = collect($chain)->map(function ($job) {
|
||||
return $this->serializeJob($job);
|
||||
})->all();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend a job to the current chain so that it is run after the currently running job.
|
||||
*
|
||||
* @param mixed $job
|
||||
* @return $this
|
||||
*/
|
||||
public function prependToChain($job)
|
||||
{
|
||||
$this->chained = Arr::prepend($this->chained, $this->serializeJob($job));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a job to the end of the current chain.
|
||||
*
|
||||
* @param mixed $job
|
||||
* @return $this
|
||||
*/
|
||||
public function appendToChain($job)
|
||||
{
|
||||
$this->chained = array_merge($this->chained, [$this->serializeJob($job)]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a job for queuing.
|
||||
*
|
||||
* @param mixed $job
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function serializeJob($job)
|
||||
{
|
||||
if ($job instanceof Closure) {
|
||||
if (! class_exists(CallQueuedClosure::class)) {
|
||||
throw new RuntimeException(
|
||||
'To enable support for closure jobs, please install the illuminate/queue package.'
|
||||
);
|
||||
}
|
||||
|
||||
$job = CallQueuedClosure::create($job);
|
||||
}
|
||||
|
||||
return serialize($job);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the next job on the chain.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dispatchNextJobInChain()
|
||||
{
|
||||
if (! empty($this->chained)) {
|
||||
dispatch(tap(unserialize(array_shift($this->chained)), function ($next) {
|
||||
$next->chained = $this->chained;
|
||||
|
||||
$next->onConnection($next->connection ?: $this->chainConnection);
|
||||
$next->onQueue($next->queue ?: $this->chainQueue);
|
||||
|
||||
$next->chainConnection = $this->chainConnection;
|
||||
$next->chainQueue = $this->chainQueue;
|
||||
$next->chainCatchCallbacks = $this->chainCatchCallbacks;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke all of the chain's failed job callbacks.
|
||||
*
|
||||
* @param \Throwable $e
|
||||
* @return void
|
||||
*/
|
||||
public function invokeChainCatchCallbacks($e)
|
||||
{
|
||||
collect($this->chainCatchCallbacks)->each(function ($callback) use ($e) {
|
||||
$callback($e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
75
vendor/laravel/framework/src/Illuminate/Bus/UniqueLock.php
vendored
Normal file
75
vendor/laravel/framework/src/Illuminate/Bus/UniqueLock.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
use Illuminate\Contracts\Cache\Repository as Cache;
|
||||
|
||||
class UniqueLock
|
||||
{
|
||||
/**
|
||||
* The cache repository implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Cache\Repository
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Create a new unique lock manager instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Cache\Repository $cache
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Cache $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to acquire a lock for the given job.
|
||||
*
|
||||
* @param mixed $job
|
||||
* @return bool
|
||||
*/
|
||||
public function acquire($job)
|
||||
{
|
||||
$uniqueFor = method_exists($job, 'uniqueFor')
|
||||
? $job->uniqueFor()
|
||||
: ($job->uniqueFor ?? 0);
|
||||
|
||||
$cache = method_exists($job, 'uniqueVia')
|
||||
? $job->uniqueVia()
|
||||
: $this->cache;
|
||||
|
||||
return (bool) $cache->lock($this->getKey($job), $uniqueFor)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the lock for the given job.
|
||||
*
|
||||
* @param mixed $job
|
||||
* @return void
|
||||
*/
|
||||
public function release($job)
|
||||
{
|
||||
$cache = method_exists($job, 'uniqueVia')
|
||||
? $job->uniqueVia()
|
||||
: $this->cache;
|
||||
|
||||
$cache->lock($this->getKey($job))->forceRelease();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the lock key for the given job.
|
||||
*
|
||||
* @param mixed $job
|
||||
* @return string
|
||||
*/
|
||||
protected function getKey($job)
|
||||
{
|
||||
$uniqueId = method_exists($job, 'uniqueId')
|
||||
? $job->uniqueId()
|
||||
: ($job->uniqueId ?? '');
|
||||
|
||||
return 'laravel_unique_job:'.get_class($job).$uniqueId;
|
||||
}
|
||||
}
|
||||
43
vendor/laravel/framework/src/Illuminate/Bus/UpdatedBatchJobCounts.php
vendored
Normal file
43
vendor/laravel/framework/src/Illuminate/Bus/UpdatedBatchJobCounts.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Bus;
|
||||
|
||||
class UpdatedBatchJobCounts
|
||||
{
|
||||
/**
|
||||
* The number of pending jobs remaining for the batch.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $pendingJobs;
|
||||
|
||||
/**
|
||||
* The number of failed jobs that belong to the batch.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $failedJobs;
|
||||
|
||||
/**
|
||||
* Create a new batch job counts object.
|
||||
*
|
||||
* @param int $pendingJobs
|
||||
* @param int $failedJobs
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(int $pendingJobs = 0, int $failedJobs = 0)
|
||||
{
|
||||
$this->pendingJobs = $pendingJobs;
|
||||
$this->failedJobs = $failedJobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if all jobs have run exactly once.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allJobsHaveRanExactlyOnce()
|
||||
{
|
||||
return ($this->pendingJobs - $this->failedJobs) === 0;
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,11 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.4",
|
||||
"illuminate/contracts": "5.4.*",
|
||||
"illuminate/pipeline": "5.4.*",
|
||||
"illuminate/support": "5.4.*"
|
||||
"php": "^8.0.2",
|
||||
"illuminate/collections": "^9.0",
|
||||
"illuminate/contracts": "^9.0",
|
||||
"illuminate/pipeline": "^9.0",
|
||||
"illuminate/support": "^9.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -26,9 +27,12 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.4-dev"
|
||||
"dev-master": "9.x-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/queue": "Required to use closures when chaining jobs (^7.0)."
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
namespace Illuminate\Cache;
|
||||
|
||||
use Illuminate\Contracts\Cache\Store;
|
||||
|
||||
class ApcStore extends TaggableStore implements Store
|
||||
class ApcStore extends TaggableStore
|
||||
{
|
||||
use RetrievesMultipleKeys;
|
||||
|
||||
@@ -51,23 +49,23 @@ class ApcStore extends TaggableStore implements Store
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an item in the cache for a given number of minutes.
|
||||
* Store an item in the cache for a given number of seconds.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param float|int $minutes
|
||||
* @return void
|
||||
* @param mixed $value
|
||||
* @param int $seconds
|
||||
* @return bool
|
||||
*/
|
||||
public function put($key, $value, $minutes)
|
||||
public function put($key, $value, $seconds)
|
||||
{
|
||||
$this->apc->put($this->prefix.$key, $value, (int) ($minutes * 60));
|
||||
return $this->apc->put($this->prefix.$key, $value, $seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the value of an item in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param mixed $value
|
||||
* @return int|bool
|
||||
*/
|
||||
public function increment($key, $value = 1)
|
||||
@@ -79,7 +77,7 @@ class ApcStore extends TaggableStore implements Store
|
||||
* Decrement the value of an item in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param mixed $value
|
||||
* @return int|bool
|
||||
*/
|
||||
public function decrement($key, $value = 1)
|
||||
@@ -91,12 +89,12 @@ class ApcStore extends TaggableStore implements Store
|
||||
* Store an item in the cache indefinitely.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function forever($key, $value)
|
||||
{
|
||||
$this->put($key, $value, 0);
|
||||
return $this->put($key, $value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,8 +36,8 @@ class ApcWrapper
|
||||
* Store an item in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $seconds
|
||||
* @param mixed $value
|
||||
* @param int $seconds
|
||||
* @return array|bool
|
||||
*/
|
||||
public function put($key, $value, $seconds)
|
||||
@@ -49,7 +49,7 @@ class ApcWrapper
|
||||
* Increment the value of an item in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param mixed $value
|
||||
* @return int|bool
|
||||
*/
|
||||
public function increment($key, $value)
|
||||
@@ -61,7 +61,7 @@ class ApcWrapper
|
||||
* Decrement the value of an item in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param mixed $value
|
||||
* @return int|bool
|
||||
*/
|
||||
public function decrement($key, $value)
|
||||
|
||||
102
vendor/laravel/framework/src/Illuminate/Cache/ArrayLock.php
vendored
Normal file
102
vendor/laravel/framework/src/Illuminate/Cache/ArrayLock.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Cache;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ArrayLock extends Lock
|
||||
{
|
||||
/**
|
||||
* The parent array cache store.
|
||||
*
|
||||
* @var \Illuminate\Cache\ArrayStore
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* Create a new lock instance.
|
||||
*
|
||||
* @param \Illuminate\Cache\ArrayStore $store
|
||||
* @param string $name
|
||||
* @param int $seconds
|
||||
* @param string|null $owner
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($store, $name, $seconds, $owner = null)
|
||||
{
|
||||
parent::__construct($name, $seconds, $owner);
|
||||
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to acquire the lock.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function acquire()
|
||||
{
|
||||
$expiration = $this->store->locks[$this->name]['expiresAt'] ?? Carbon::now()->addSecond();
|
||||
|
||||
if ($this->exists() && $expiration->isFuture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->store->locks[$this->name] = [
|
||||
'owner' => $this->owner,
|
||||
'expiresAt' => $this->seconds === 0 ? null : Carbon::now()->addSeconds($this->seconds),
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current lock exists.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function exists()
|
||||
{
|
||||
return isset($this->store->locks[$this->name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the lock.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function release()
|
||||
{
|
||||
if (! $this->exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->isOwnedByCurrentProcess()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->forceRelease();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owner value written into the driver for this lock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getCurrentOwner()
|
||||
{
|
||||
return $this->store->locks[$this->name]['owner'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases this lock in disregard of ownership.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function forceRelease()
|
||||
{
|
||||
unset($this->store->locks[$this->name]);
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace Illuminate\Cache;
|
||||
|
||||
use Illuminate\Contracts\Cache\Store;
|
||||
use Illuminate\Contracts\Cache\LockProvider;
|
||||
use Illuminate\Support\InteractsWithTime;
|
||||
|
||||
class ArrayStore extends TaggableStore implements Store
|
||||
class ArrayStore extends TaggableStore implements LockProvider
|
||||
{
|
||||
use RetrievesMultipleKeys;
|
||||
use InteractsWithTime, RetrievesMultipleKeys;
|
||||
|
||||
/**
|
||||
* The array of stored values.
|
||||
@@ -15,6 +16,31 @@ class ArrayStore extends TaggableStore implements Store
|
||||
*/
|
||||
protected $storage = [];
|
||||
|
||||
/**
|
||||
* The array of locks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $locks = [];
|
||||
|
||||
/**
|
||||
* Indicates if values are serialized within the store.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $serializesValues;
|
||||
|
||||
/**
|
||||
* Create a new Array store.
|
||||
*
|
||||
* @param bool $serializesValues
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($serializesValues = false)
|
||||
{
|
||||
$this->serializesValues = $serializesValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache by key.
|
||||
*
|
||||
@@ -23,44 +49,68 @@ class ArrayStore extends TaggableStore implements Store
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
if (array_key_exists($key, $this->storage)) {
|
||||
return $this->storage[$key];
|
||||
if (! isset($this->storage[$key])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = $this->storage[$key];
|
||||
|
||||
$expiresAt = $item['expiresAt'] ?? 0;
|
||||
|
||||
if ($expiresAt !== 0 && $this->currentTime() > $expiresAt) {
|
||||
$this->forget($key);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->serializesValues ? unserialize($item['value']) : $item['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an item in the cache for a given number of minutes.
|
||||
* Store an item in the cache for a given number of seconds.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param float|int $minutes
|
||||
* @return void
|
||||
* @param mixed $value
|
||||
* @param int $seconds
|
||||
* @return bool
|
||||
*/
|
||||
public function put($key, $value, $minutes)
|
||||
public function put($key, $value, $seconds)
|
||||
{
|
||||
$this->storage[$key] = $value;
|
||||
$this->storage[$key] = [
|
||||
'value' => $this->serializesValues ? serialize($value) : $value,
|
||||
'expiresAt' => $this->calculateExpiration($seconds),
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the value of an item in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param mixed $value
|
||||
* @return int
|
||||
*/
|
||||
public function increment($key, $value = 1)
|
||||
{
|
||||
$this->storage[$key] = ! isset($this->storage[$key])
|
||||
? $value : ((int) $this->storage[$key]) + $value;
|
||||
if (! is_null($existing = $this->get($key))) {
|
||||
return tap(((int) $existing) + $value, function ($incremented) use ($key) {
|
||||
$value = $this->serializesValues ? serialize($incremented) : $incremented;
|
||||
|
||||
return $this->storage[$key];
|
||||
$this->storage[$key]['value'] = $value;
|
||||
});
|
||||
}
|
||||
|
||||
$this->forever($key, $value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the value of an item in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param mixed $value
|
||||
* @return int
|
||||
*/
|
||||
public function decrement($key, $value = 1)
|
||||
@@ -72,12 +122,12 @@ class ArrayStore extends TaggableStore implements Store
|
||||
* Store an item in the cache indefinitely.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function forever($key, $value)
|
||||
{
|
||||
$this->put($key, $value, 0);
|
||||
return $this->put($key, $value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,9 +138,13 @@ class ArrayStore extends TaggableStore implements Store
|
||||
*/
|
||||
public function forget($key)
|
||||
{
|
||||
unset($this->storage[$key]);
|
||||
if (array_key_exists($key, $this->storage)) {
|
||||
unset($this->storage[$key]);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,4 +168,51 @@ class ArrayStore extends TaggableStore implements Store
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiration time of the key.
|
||||
*
|
||||
* @param int $seconds
|
||||
* @return int
|
||||
*/
|
||||
protected function calculateExpiration($seconds)
|
||||
{
|
||||
return $this->toTimestamp($seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UNIX timestamp for the given number of seconds.
|
||||
*
|
||||
* @param int $seconds
|
||||
* @return int
|
||||
*/
|
||||
protected function toTimestamp($seconds)
|
||||
{
|
||||
return $seconds > 0 ? $this->availableAt($seconds) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a lock instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $seconds
|
||||
* @param string|null $owner
|
||||
* @return \Illuminate\Contracts\Cache\Lock
|
||||
*/
|
||||
public function lock($name, $seconds = 0, $owner = null)
|
||||
{
|
||||
return new ArrayLock($this, $name, $seconds, $owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a lock instance using the owner identifier.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $owner
|
||||
* @return \Illuminate\Contracts\Cache\Lock
|
||||
*/
|
||||
public function restoreLock($name, $owner)
|
||||
{
|
||||
return $this->lock($name, 0, $owner);
|
||||
}
|
||||
}
|
||||
|
||||
85
vendor/laravel/framework/src/Illuminate/Cache/CacheLock.php
vendored
Normal file
85
vendor/laravel/framework/src/Illuminate/Cache/CacheLock.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Cache;
|
||||
|
||||
class CacheLock extends Lock
|
||||
{
|
||||
/**
|
||||
* The cache store implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Cache\Store
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* Create a new lock instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Cache\Store $store
|
||||
* @param string $name
|
||||
* @param int $seconds
|
||||
* @param string|null $owner
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($store, $name, $seconds, $owner = null)
|
||||
{
|
||||
parent::__construct($name, $seconds, $owner);
|
||||
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to acquire the lock.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function acquire()
|
||||
{
|
||||
if (method_exists($this->store, 'add') && $this->seconds > 0) {
|
||||
return $this->store->add(
|
||||
$this->name, $this->owner, $this->seconds
|
||||
);
|
||||
}
|
||||
|
||||
if (! is_null($this->store->get($this->name))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ($this->seconds > 0)
|
||||
? $this->store->put($this->name, $this->owner, $this->seconds)
|
||||
: $this->store->forever($this->name, $this->owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the lock.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function release()
|
||||
{
|
||||
if ($this->isOwnedByCurrentProcess()) {
|
||||
return $this->store->forget($this->name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases this lock regardless of ownership.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function forceRelease()
|
||||
{
|
||||
$this->store->forget($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owner value written into the driver for this lock.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getCurrentOwner()
|
||||
{
|
||||
return $this->store->get($this->name);
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,24 @@
|
||||
|
||||
namespace Illuminate\Cache;
|
||||
|
||||
use Aws\DynamoDb\DynamoDbClient;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Cache\Factory as FactoryContract;
|
||||
use Illuminate\Contracts\Cache\Store;
|
||||
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
|
||||
use Illuminate\Support\Arr;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Contracts\Cache\Store;
|
||||
use Illuminate\Contracts\Cache\Factory as FactoryContract;
|
||||
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
|
||||
|
||||
/**
|
||||
* @mixin \Illuminate\Cache\Repository
|
||||
* @mixin \Illuminate\Contracts\Cache\LockProvider
|
||||
*/
|
||||
class CacheManager implements FactoryContract
|
||||
{
|
||||
/**
|
||||
* The application instance.
|
||||
*
|
||||
* @var \Illuminate\Foundation\Application
|
||||
* @var \Illuminate\Contracts\Foundation\Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
@@ -35,7 +40,7 @@ class CacheManager implements FactoryContract
|
||||
/**
|
||||
* Create a new Cache manager instance.
|
||||
*
|
||||
* @param \Illuminate\Foundation\Application $app
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($app)
|
||||
@@ -44,10 +49,10 @@ class CacheManager implements FactoryContract
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cache store instance by name.
|
||||
* Get a cache store instance by name, wrapped in a repository.
|
||||
*
|
||||
* @param string|null $name
|
||||
* @return mixed
|
||||
* @return \Illuminate\Contracts\Cache\Repository
|
||||
*/
|
||||
public function store($name = null)
|
||||
{
|
||||
@@ -59,8 +64,8 @@ class CacheManager implements FactoryContract
|
||||
/**
|
||||
* Get a cache driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
* @return mixed
|
||||
* @param string|null $driver
|
||||
* @return \Illuminate\Contracts\Cache\Repository
|
||||
*/
|
||||
public function driver($driver = null)
|
||||
{
|
||||
@@ -75,7 +80,7 @@ class CacheManager implements FactoryContract
|
||||
*/
|
||||
protected function get($name)
|
||||
{
|
||||
return isset($this->stores[$name]) ? $this->stores[$name] : $this->resolve($name);
|
||||
return $this->stores[$name] ?? $this->resolve($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +127,7 @@ class CacheManager implements FactoryContract
|
||||
* Create an instance of the APC cache driver.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Illuminate\Cache\ApcStore
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createApcDriver(array $config)
|
||||
{
|
||||
@@ -134,29 +139,30 @@ class CacheManager implements FactoryContract
|
||||
/**
|
||||
* Create an instance of the array cache driver.
|
||||
*
|
||||
* @return \Illuminate\Cache\ArrayStore
|
||||
* @param array $config
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createArrayDriver()
|
||||
protected function createArrayDriver(array $config)
|
||||
{
|
||||
return $this->repository(new ArrayStore);
|
||||
return $this->repository(new ArrayStore($config['serialize'] ?? false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the file cache driver.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Illuminate\Cache\FileStore
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createFileDriver(array $config)
|
||||
{
|
||||
return $this->repository(new FileStore($this->app['files'], $config['path']));
|
||||
return $this->repository(new FileStore($this->app['files'], $config['path'], $config['permission'] ?? null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Memcached cache driver.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Illuminate\Cache\MemcachedStore
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createMemcachedDriver(array $config)
|
||||
{
|
||||
@@ -164,9 +170,9 @@ class CacheManager implements FactoryContract
|
||||
|
||||
$memcached = $this->app['memcached.connector']->connect(
|
||||
$config['servers'],
|
||||
array_get($config, 'persistent_id'),
|
||||
array_get($config, 'options', []),
|
||||
array_filter(array_get($config, 'sasl', []))
|
||||
$config['persistent_id'] ?? null,
|
||||
$config['options'] ?? [],
|
||||
array_filter($config['sasl'] ?? [])
|
||||
);
|
||||
|
||||
return $this->repository(new MemcachedStore($memcached, $prefix));
|
||||
@@ -175,7 +181,7 @@ class CacheManager implements FactoryContract
|
||||
/**
|
||||
* Create an instance of the Null cache driver.
|
||||
*
|
||||
* @return \Illuminate\Cache\NullStore
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createNullDriver()
|
||||
{
|
||||
@@ -186,34 +192,88 @@ class CacheManager implements FactoryContract
|
||||
* Create an instance of the Redis cache driver.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Illuminate\Cache\RedisStore
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createRedisDriver(array $config)
|
||||
{
|
||||
$redis = $this->app['redis'];
|
||||
|
||||
$connection = Arr::get($config, 'connection', 'default');
|
||||
$connection = $config['connection'] ?? 'default';
|
||||
|
||||
return $this->repository(new RedisStore($redis, $this->getPrefix($config), $connection));
|
||||
$store = new RedisStore($redis, $this->getPrefix($config), $connection);
|
||||
|
||||
return $this->repository(
|
||||
$store->setLockConnection($config['lock_connection'] ?? $connection)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the database cache driver.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Illuminate\Cache\DatabaseStore
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createDatabaseDriver(array $config)
|
||||
{
|
||||
$connection = $this->app['db']->connection(Arr::get($config, 'connection'));
|
||||
$connection = $this->app['db']->connection($config['connection'] ?? null);
|
||||
|
||||
$store = new DatabaseStore(
|
||||
$connection,
|
||||
$config['table'],
|
||||
$this->getPrefix($config),
|
||||
$config['lock_table'] ?? 'cache_locks',
|
||||
$config['lock_lottery'] ?? [2, 100]
|
||||
);
|
||||
|
||||
return $this->repository($store->setLockConnection(
|
||||
$this->app['db']->connection($config['lock_connection'] ?? $config['connection'] ?? null)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the DynamoDB cache driver.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Illuminate\Cache\Repository
|
||||
*/
|
||||
protected function createDynamodbDriver(array $config)
|
||||
{
|
||||
$client = $this->newDynamodbClient($config);
|
||||
|
||||
return $this->repository(
|
||||
new DatabaseStore(
|
||||
$connection, $this->app['encrypter'], $config['table'], $this->getPrefix($config)
|
||||
new DynamoDbStore(
|
||||
$client,
|
||||
$config['table'],
|
||||
$config['attributes']['key'] ?? 'key',
|
||||
$config['attributes']['value'] ?? 'value',
|
||||
$config['attributes']['expiration'] ?? 'expires_at',
|
||||
$this->getPrefix($config)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new DynamoDb Client instance.
|
||||
*
|
||||
* @return \Aws\DynamoDb\DynamoDbClient
|
||||
*/
|
||||
protected function newDynamodbClient(array $config)
|
||||
{
|
||||
$dynamoConfig = [
|
||||
'region' => $config['region'],
|
||||
'version' => 'latest',
|
||||
'endpoint' => $config['endpoint'] ?? null,
|
||||
];
|
||||
|
||||
if (isset($config['key'], $config['secret'])) {
|
||||
$dynamoConfig['credentials'] = Arr::only(
|
||||
$config, ['key', 'secret', 'token']
|
||||
);
|
||||
}
|
||||
|
||||
return new DynamoDbClient($dynamoConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new cache repository with the given implementation.
|
||||
*
|
||||
@@ -222,15 +282,36 @@ class CacheManager implements FactoryContract
|
||||
*/
|
||||
public function repository(Store $store)
|
||||
{
|
||||
$repository = new Repository($store);
|
||||
return tap(new Repository($store), function ($repository) {
|
||||
$this->setEventDispatcher($repository);
|
||||
});
|
||||
}
|
||||
|
||||
if ($this->app->bound(DispatcherContract::class)) {
|
||||
$repository->setEventDispatcher(
|
||||
$this->app[DispatcherContract::class]
|
||||
);
|
||||
/**
|
||||
* Set the event dispatcher on the given repository instance.
|
||||
*
|
||||
* @param \Illuminate\Cache\Repository $repository
|
||||
* @return void
|
||||
*/
|
||||
protected function setEventDispatcher(Repository $repository)
|
||||
{
|
||||
if (! $this->app->bound(DispatcherContract::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $repository;
|
||||
$repository->setEventDispatcher(
|
||||
$this->app[DispatcherContract::class]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set the event dispatcher on all resolved cache repositories.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function refreshEventDispatcher()
|
||||
{
|
||||
array_map([$this, 'setEventDispatcher'], $this->stores);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,18 +322,22 @@ class CacheManager implements FactoryContract
|
||||
*/
|
||||
protected function getPrefix(array $config)
|
||||
{
|
||||
return Arr::get($config, 'prefix') ?: $this->app['config']['cache.prefix'];
|
||||
return $config['prefix'] ?? $this->app['config']['cache.prefix'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache connection configuration.
|
||||
*
|
||||
* @param string $name
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getConfig($name)
|
||||
{
|
||||
return $this->app['config']["cache.stores.{$name}"];
|
||||
if (! is_null($name) && $name !== 'null') {
|
||||
return $this->app['config']["cache.stores.{$name}"];
|
||||
}
|
||||
|
||||
return ['driver' => 'null'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,10 +361,42 @@ class CacheManager implements FactoryContract
|
||||
$this->app['config']['cache.default'] = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset the given driver instances.
|
||||
*
|
||||
* @param array|string|null $name
|
||||
* @return $this
|
||||
*/
|
||||
public function forgetDriver($name = null)
|
||||
{
|
||||
$name ??= $this->getDefaultDriver();
|
||||
|
||||
foreach ((array) $name as $cacheName) {
|
||||
if (isset($this->stores[$cacheName])) {
|
||||
unset($this->stores[$cacheName]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the given driver and remove from local cache.
|
||||
*
|
||||
* @param string|null $name
|
||||
* @return void
|
||||
*/
|
||||
public function purge($name = null)
|
||||
{
|
||||
$name ??= $this->getDefaultDriver();
|
||||
|
||||
unset($this->stores[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom driver creator Closure.
|
||||
*
|
||||
* @param string $driver
|
||||
* @param string $driver
|
||||
* @param \Closure $callback
|
||||
* @return $this
|
||||
*/
|
||||
@@ -294,7 +411,7 @@ class CacheManager implements FactoryContract
|
||||
* Dynamically call the default driver instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
|
||||
@@ -2,17 +2,12 @@
|
||||
|
||||
namespace Illuminate\Cache;
|
||||
|
||||
use Illuminate\Contracts\Support\DeferrableProvider;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Symfony\Component\Cache\Adapter\Psr16Adapter;
|
||||
|
||||
class CacheServiceProvider extends ServiceProvider
|
||||
class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if loading of the provider is deferred.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $defer = true;
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
@@ -28,9 +23,19 @@ class CacheServiceProvider extends ServiceProvider
|
||||
return $app['cache']->driver();
|
||||
});
|
||||
|
||||
$this->app->singleton('cache.psr6', function ($app) {
|
||||
return new Psr16Adapter($app['cache.store']);
|
||||
});
|
||||
|
||||
$this->app->singleton('memcached.connector', function () {
|
||||
return new MemcachedConnector;
|
||||
});
|
||||
|
||||
$this->app->singleton(RateLimiter::class, function ($app) {
|
||||
return new RateLimiter($app->make('cache')->driver(
|
||||
$app['config']->get('cache.limiter')
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +46,7 @@ class CacheServiceProvider extends ServiceProvider
|
||||
public function provides()
|
||||
{
|
||||
return [
|
||||
'cache', 'cache.store', 'memcached.connector',
|
||||
'cache', 'cache.store', 'cache.psr6', 'memcached.connector', RateLimiter::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
namespace Illuminate\Cache\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Composer;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Composer;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand(name: 'cache:table')]
|
||||
class CacheTableCommand extends Command
|
||||
{
|
||||
/**
|
||||
@@ -15,6 +17,17 @@ class CacheTableCommand extends Command
|
||||
*/
|
||||
protected $name = 'cache:table';
|
||||
|
||||
/**
|
||||
* The name of the console command.
|
||||
*
|
||||
* This name is used to identify the command during lazy loading.
|
||||
*
|
||||
* @var string|null
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
protected static $defaultName = 'cache:table';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -54,13 +67,13 @@ class CacheTableCommand extends Command
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fire()
|
||||
public function handle()
|
||||
{
|
||||
$fullPath = $this->createBaseMigration();
|
||||
|
||||
$this->files->put($fullPath, $this->files->get(__DIR__.'/stubs/cache.stub'));
|
||||
|
||||
$this->info('Migration created successfully!');
|
||||
$this->components->info('Migration created successfully.');
|
||||
|
||||
$this->composer->dumpAutoloads();
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
namespace Illuminate\Cache\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Cache\CacheManager;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand(name: 'cache:clear')]
|
||||
class ClearCommand extends Command
|
||||
{
|
||||
/**
|
||||
@@ -16,6 +19,17 @@ class ClearCommand extends Command
|
||||
*/
|
||||
protected $name = 'cache:clear';
|
||||
|
||||
/**
|
||||
* The name of the console command.
|
||||
*
|
||||
* This name is used to identify the command during lazy loading.
|
||||
*
|
||||
* @var string|null
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
protected static $defaultName = 'cache:clear';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -30,17 +44,26 @@ class ClearCommand extends Command
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* The filesystem instance.
|
||||
*
|
||||
* @var \Illuminate\Filesystem\Filesystem
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* Create a new cache clear command instance.
|
||||
*
|
||||
* @param \Illuminate\Cache\CacheManager $cache
|
||||
* @param \Illuminate\Filesystem\Filesystem $files
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(CacheManager $cache)
|
||||
public function __construct(CacheManager $cache, Filesystem $files)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->cache = $cache;
|
||||
$this->files = $files;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,13 +73,41 @@ class ClearCommand extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->laravel['events']->fire('cache:clearing', [$this->argument('store'), $this->tags()]);
|
||||
$this->laravel['events']->dispatch(
|
||||
'cache:clearing', [$this->argument('store'), $this->tags()]
|
||||
);
|
||||
|
||||
$this->cache()->flush();
|
||||
$successful = $this->cache()->flush();
|
||||
|
||||
$this->laravel['events']->fire('cache:cleared', [$this->argument('store'), $this->tags()]);
|
||||
$this->flushFacades();
|
||||
|
||||
$this->info('Cache cleared successfully.');
|
||||
if (! $successful) {
|
||||
return $this->components->error('Failed to clear cache. Make sure you have the appropriate permissions.');
|
||||
}
|
||||
|
||||
$this->laravel['events']->dispatch(
|
||||
'cache:cleared', [$this->argument('store'), $this->tags()]
|
||||
);
|
||||
|
||||
$this->components->info('Application cache cleared successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the real-time facades stored in the cache directory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flushFacades()
|
||||
{
|
||||
if (! $this->files->exists($storagePath = storage_path('framework/cache'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->files->files($storagePath) as $file) {
|
||||
if (preg_match('/facade-.*\.php$/', $file)) {
|
||||
$this->files->delete($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,7 +129,7 @@ class ClearCommand extends Command
|
||||
*/
|
||||
protected function tags()
|
||||
{
|
||||
return array_filter(explode(',', $this->option('tags')));
|
||||
return array_filter(explode(',', $this->option('tags') ?? ''));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +140,7 @@ class ClearCommand extends Command
|
||||
protected function getArguments()
|
||||
{
|
||||
return [
|
||||
['store', InputArgument::OPTIONAL, 'The name of the store you would like to clear.'],
|
||||
['store', InputArgument::OPTIONAL, 'The name of the store you would like to clear'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -101,7 +152,7 @@ class ClearCommand extends Command
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['tags', null, InputOption::VALUE_OPTIONAL, 'The cache tags you would like to clear.', null],
|
||||
['tags', null, InputOption::VALUE_OPTIONAL, 'The cache tags you would like to clear', null],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
namespace Illuminate\Cache\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Cache\CacheManager;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand(name: 'cache:forget')]
|
||||
class ForgetCommand extends Command
|
||||
{
|
||||
/**
|
||||
@@ -14,6 +16,17 @@ class ForgetCommand extends Command
|
||||
*/
|
||||
protected $signature = 'cache:forget {key : The key to remove} {store? : The store to remove the key from}';
|
||||
|
||||
/**
|
||||
* The name of the console command.
|
||||
*
|
||||
* This name is used to identify the command during lazy loading.
|
||||
*
|
||||
* @var string|null
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
protected static $defaultName = 'cache:forget';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -52,6 +65,6 @@ class ForgetCommand extends Command
|
||||
$this->argument('key')
|
||||
);
|
||||
|
||||
$this->info('The ['.$this->argument('key').'] key has been removed from the cache.');
|
||||
$this->components->info('The ['.$this->argument('key').'] key has been removed from the cache.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateCacheTable extends Migration
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
@@ -14,8 +14,14 @@ class CreateCacheTable extends Migration
|
||||
public function up()
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->unique();
|
||||
$table->text('value');
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
}
|
||||
@@ -28,5 +34,6 @@ class CreateCacheTable extends Migration
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user