laravel-6 support

This commit is contained in:
RafficMohammed
2023-01-08 01:17:22 +05:30
parent 1a5c16ae4b
commit 774eed8b0e
4962 changed files with 279380 additions and 297961 deletions

View File

@@ -1,7 +1,7 @@
<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://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://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>
@@ -9,7 +9,7 @@
## 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:
@@ -34,7 +34,7 @@ Thank you for considering contributing to the Laravel framework! The contributio
## 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
@@ -42,4 +42,4 @@ Please review [our security policy](https://github.com/laravel/framework/securit
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
The Laravel framework is open-sourced software licensed under the [MIT license](LICENSE.md).

View File

@@ -1,102 +0,0 @@
# Security Policy
**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).**
## Supported Versions
Version | Security Fixes Until
--- | ---
5.8 | February 26th, 2020
5.7 | September 4th, 2019
5.6 | February 7th, 2019
5.5 (LTS) | August 30th, 2020
5.4 | January 24th, 2018
5.3 | August 23rd, 2017
5.2 | December 21st, 2016
5.1 (LTS) | June 9th, 2018
5.0 | February 4th, 2016
## Reporting a Vulnerability
If you discover a security vulnerability within Laravel, please send an email to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed.
### Public PGP Key
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: OpenPGP v2.0.8
Comment: https://sela.io/pgp/
xsFNBFugFSQBEACxEKhIY9IoJzcouVTIYKJfWFGvwFgbRjQWBiH3QdHId5vCrbWo
s2l+4Rv03gMG+yHLJ3rWElnNdRaNdQv59+lShrZF7Bvu7Zvc0mMNmFOM/mQ/K2Lt
OK/8bh6iwNNbEuyOhNQlarEy/w8hF8Yf55hBeu/rajGtcyURJDloQ/vNzcx4RWGK
G3CLr8ka7zPYIjIFUvHLt27mcYFF9F4/G7b4HKpn75ICKC4vPoQSaYNAHlHQBLFb
Jg/WPl93SySHLugU5F58sICs+fBZadXYQG5dWmbaF5OWB1K2XgRs45BQaBzf/8oS
qq0scN8wVhAdBeYlVFf0ImDOxGlZ2suLK1BKJboR6zCIkBAwufKss4NV1R9KSUMv
YGn3mq13PGme0QoIkvQkua5VjTwWfQx7wFDxZ3VQSsjIlbVyRL/Ac/hq71eAmiIR
t6ZMNMPFpuSwBfYimrXqqb4EOffrfsTzRenG1Cxm4jNZRzX/6P4an7F/euoqXeXZ
h37TiC7df+eHKcBI4mL+qOW4ibBqg8WwWPJ+jvuhANyQpRVzf3NNEOwJYCNbQPM/
PbqYvMruAH+gg7uyu9u0jX3o/yLSxJMV7kF4x/SCDuBKIxSSUI4cgbjIlnxWLXZC
wl7KW4xAKkerO3wgIPnxNfxQoiYiEKA1c3PShWRA0wHIMt3rVRJxwGM4CwARAQAB
zRJ0YXlsb3JAbGFyYXZlbC5jb23CwXAEEwEKABoFAlugFSQCGy8DCwkHAxUKCAIe
AQIXgAIZAQAKCRDKAI7r/Ml7Zo0SD/9zwu9K87rbqXbvZ3TVu7TnN+z7mPvVBzl+
SFEK360TYq8a4GosghZuGm4aNEyZ90CeUjPQwc5fHwa26tIwqgLRppsG21B/mZwu
0m8c5RaBFRFX/mCTEjlpvBkOwMJZ8f05nNdaktq6W98DbMN03neUwnpWlNSLeoNI
u4KYZmJopNFLEax5WGaaDpmqD1J+WDr/aPHx39MUAg2ZVuC3Gj/IjYZbD1nCh0xD
a09uDODje8a9uG33cKRBcKKPRLZjWEt5SWReLx0vsTuqJSWhCybHRBl9BQTc/JJR
gJu5V4X3f1IYMTNRm9GggxcXrlOAiDCjE2J8ZTUt0cSxedQFnNyGfKxe/l94oTFP
wwFHbdKhsSDZ1OyxPNIY5OHlMfMvvJaNbOw0xPPAEutPwr1aqX9sbgPeeiJwAdyw
mPw2x/wNQvKJITRv6atw56TtLxSevQIZGPHCYTSlsIoi9jqh9/6vfq2ruMDYItCq
+8uzei6TyH6w+fUpp/uFmcwZdrDwgNVqW+Ptu+pD2WmthqESF8UEQVoOv7OPgA5E
ofOMaeH2ND74r2UgcXjPxZuUp1RkhHE2jJeiuLtbvOgrWwv3KOaatyEbVl+zHA1e
1RHdJRJRPK+S7YThxxduqfOBX7E03arbbhHdS1HKhPwMc2e0hNnQDoNxQcv0GQp4
2Y6UyCRaus7ATQRboBUkAQgA0h5j3EO2HNvp8YuT1t/VF00uUwbQaz2LIoZogqgC
14Eb77diuIPM9MnuG7bEOnNtPVMFXxI5UYBIlzhLMxf7pfbrsoR4lq7Ld+7KMzdm
eREqJRgUNfjZhtRZ9Z+jiFPr8AGpYxwmJk4v387uQGh1GC9JCc3CCLJoI62I9t/1
K2b25KiOzW/FVZ/vYFj1WbISRd5GqS8SEFh4ifU79LUlJ/nEsFv4JxAXN9RqjU0e
H4S/m1Nb24UCtYAv1JKymcf5O0G7kOzvI0w06uKxk0hNwspjDcOebD8Vv9IdYtGl
0bn7PpBlVO1Az3s8s6Xoyyw+9Us+VLNtVka3fcrdaV/n0wARAQABwsKEBBgBCgAP
BQJboBUkBQkPCZwAAhsuASkJEMoAjuv8yXtmwF0gBBkBCgAGBQJboBUkAAoJEA1I
8aTLtYHmjpIH/A1ZKwTGetHFokJxsd2omvbqv+VtpAjnUbvZEi5g3yZXn+dHJV+K
UR/DNlfGxLWEcY6datJ3ziNzzD5u8zcPp2CqeTlCxOky8F74FjEL9tN/EqUbvvmR
td2LXsSFjHnLJRK5lYfZ3rnjKA5AjqC9MttILBovY2rI7lyVt67kbS3hMHi8AZl8
EgihnHRJxGZjEUxyTxcB13nhfjAvxQq58LOj5754Rpe9ePSKbT8DNMjHbGpLrESz
cmyn0VzDMLfxg8AA9uQFMwdlKqve7yRZXzeqvy08AatUpJaL7DsS4LKOItwvBub6
tHbCE3mqrUw5lSNyUahO3vOcMAHnF7fd4W++eA//WIQKnPX5t3CwCedKn8Qkb3Ow
oj8xUNl2T6kEtQJnO85lKBFXaMOUykopu6uB9EEXEr0ShdunOKX/UdDbkv46F2AB
7TtltDSLB6s/QeHExSb8Jo3qra86JkDUutWdJxV7DYFUttBga8I0GqdPu4yRRoc/
0irVXsdDY9q7jz6l7fw8mSeJR96C0Puhk70t4M1Vg/tu/ONRarXQW7fJ8kl21PcD
UKNWWa242gji/+GLRI8AIpGMsBiX7pHhqmMMth3u7+ne5BZGGJz0uX+CzWboOHyq
kWgfY4a62t3hM0vwnUkl/D7VgSGy4LiKQrapd3LvU2uuEfFsMu3CDicZBRXPqoXj
PBjkkPKhwUTNlwEQrGF3QsZhNe0M9ptM2fC34qtxZtMIMB2NLvE4S621rmQ05oQv
sT0B9WgUL3GYRKdx700+ojHEuwZ79bcLgo1dezvkfPtu/++2CXtieFthDlWHy8x5
XJJjI1pDfGO+BgX0rS3QrQEYlF/uPQynKwxe6cGI62eZ0ug0hNrPvKEcfMLVqBQv
w4VH6iGp9yNKMUOgAECLCs4YCxK+Eka9Prq/Gh4wuqjWiX8m66z8YvKf27sFL3fR
OwGaz3LsnRSxbk/8oSiZuOVLfn44XRcxsHebteZat23lwD93oq54rtKnlJgmZHJY
4vMgk1jpS4laGnvhZj7OwE0EW6AVJAEIAKJSrUvXRyK3XQnLp3Kfj82uj0St8Dt2
h8BMeVbrAbg38wCN8XQZzVR9+bRZRR+aCzpKSqwhEQVtH7gdKgfdNdGNhG2DFAVk
SihMhQz190FKttUZgwY00enzD7uaaA5VwNAZzRIr8skwiASB7UoO+lIhrAYgcQCA
LpwCSMrUNB3gY1IVa2xi9FljEbS2uMABfOsTfl7z4L4T4DRv/ovDf+ihyZOXsXiH
RVoUTIpN8ZILCZiiKubE1sMj4fSQwCs06UyDy17HbOG5/dO9awR/LHW53O3nZCxE
JbCqr5iHa2MdHMC12+luxWJKD9DbVB01LiiPZCTkuKUDswCyi7otpVEAEQEAAcLC
hAQYAQoADwUCW6AVJAUJDwmcAAIbLgEpCRDKAI7r/Ml7ZsBdIAQZAQoABgUCW6AV
JAAKCRDxrCjKN7eORjt2B/9EnKVJ9lwB1JwXcQp6bZgJ21r6ghyXBssv24N9UF+v
5QDz/tuSkTsKK1UoBrBDEinF/xTP2z+xXIeyP4c3mthMHsYdMl7AaGpcCwVJiL62
fZvd+AiYNX3C+Bepwnwoziyhx4uPaqoezSEMD8G2WQftt6Gqttmm0Di5RVysCECF
EyhkHwvCcbpXb5Qq+4XFzCUyaIZuGpe+oeO7U8B1CzOC16hEUu0Uhbk09Xt6dSbS
ZERoxFjrGU+6bk424MkZkKvNS8FdTN2s3kQuHoNmhbMY+fRzKX5JNrcQ4dQQufiB
zFcc2Ba0JVU0nYAMftTeT5ALakhwSqr3AcdD2avJZp3EYfYP/3smPGTeg1cDJV3E
WIlCtSlhbwviUjvWEWJUE+n9MjhoUNU0TJtHIliUYUajKMG/At5wJZTXJaKVUx32
UCWr4ioKfSzlbp1ngBuFlvU7LgZRcKbBZWvKj/KRYpxpfvPyPElmegCjAk6oiZYV
LOV+jFfnMkk9PnR91ZZfTNx/bK+BwjOnO+g7oE8V2g2bA90vHdeSUHR52SnaVN/b
9ytt07R0f+YtyKojuPmlNsbyAaUYUtJ1o+XNCwdVxzarYEuUabhAfDiVTu9n8wTr
YVvnriSFOjNvOY9wdLAa56n7/qM8bzuGpoBS5SilXgJvITvQfWPvg7I9C3QhwK1S
F6B1uquQGbBSze2wlnMbKXmhyGLlv9XpOqpkkejQo3o58B+Sqj4B8DuYixSjoknr
pRbj8gqgqBKlcpf1wD5X9qCrl9vq19asVOHaKhiFZGxZIVbBpBOdvAKaMj4p/uln
yklN3YFIfgmGPYbL0elvXVn7XfvwSV1mCQV5LtMbLHsFf0VsA16UsG8A/tLWtwgt
0antzftRHXb+DI4qr+qEYKFkv9F3oCOXyH4QBhPA42EzKqhMXByEkEK9bu6skioL
mHhDQ7yHjTWcxstqQjkUQ0T/IF9ls+Sm5u7rVXEifpyI7MCb+76kSCDawesvInKt
WBGOG/qJGDlNiqBYYt2xNqzHCJoC
=zXOv
-----END PGP PUBLIC KEY BLOCK-----
```

View File

@@ -15,30 +15,31 @@
}
],
"require": {
"php": "^7.1.3",
"php": "^7.2.5|^8.0",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"doctrine/inflector": "^1.1",
"dragonmantank/cron-expression": "^2.0",
"egulias/email-validator": "^2.0",
"erusev/parsedown": "^1.7",
"league/flysystem": "^1.0.8",
"monolog/monolog": "^1.12",
"nesbot/carbon": "^1.26.3 || ^2.0",
"opis/closure": "^3.1",
"doctrine/inflector": "^1.4|^2.0",
"dragonmantank/cron-expression": "^2.3.1",
"egulias/email-validator": "^2.1.10",
"league/commonmark": "^1.3",
"league/flysystem": "^1.1",
"monolog/monolog": "^1.12|^2.0",
"nesbot/carbon": "^2.31",
"opis/closure": "^3.6",
"psr/container": "^1.0",
"psr/simple-cache": "^1.0",
"ramsey/uuid": "^3.7",
"swiftmailer/swiftmailer": "^6.0",
"symfony/console": "^4.2",
"symfony/debug": "^4.2",
"symfony/finder": "^4.2",
"symfony/http-foundation": "^4.2",
"symfony/http-kernel": "^4.2",
"symfony/process": "^4.2",
"symfony/routing": "^4.2",
"symfony/var-dumper": "^4.2",
"symfony/console": "^4.3.4",
"symfony/debug": "^4.3.4",
"symfony/finder": "^4.3.4",
"symfony/http-foundation": "^4.3.4",
"symfony/http-kernel": "^4.3.4",
"symfony/polyfill-php73": "^1.17",
"symfony/process": "^4.3.4",
"symfony/routing": "^4.3.4",
"symfony/var-dumper": "^4.3.4",
"tijsverkoyen/css-to-inline-styles": "^2.2.1",
"vlucas/phpdotenv": "^3.3"
},
@@ -76,20 +77,18 @@
"tightenco/collect": "<5.5.33"
},
"require-dev": {
"aws/aws-sdk-php": "^3.0",
"aws/aws-sdk-php": "^3.155",
"doctrine/dbal": "^2.6",
"filp/whoops": "^2.1.4",
"guzzlehttp/guzzle": "^6.3",
"filp/whoops": "^2.8",
"guzzlehttp/guzzle": "^6.3.1|^7.0.1",
"league/flysystem-cached-adapter": "^1.0",
"mockery/mockery": "^1.0",
"mockery/mockery": "~1.3.3|^1.4.2",
"moontoast/math": "^1.1",
"orchestra/testbench-core": "3.8.*",
"orchestra/testbench-core": "^4.8",
"pda/pheanstalk": "^4.0",
"phpunit/phpunit": "^7.5|^8.0",
"phpunit/phpunit": "^7.5.15|^8.4|^9.3.3",
"predis/predis": "^1.1.1",
"symfony/css-selector": "^4.2",
"symfony/dom-crawler": "^4.2",
"true/punycode": "^2.1"
"symfony/cache": "^4.3.4"
},
"autoload": {
"files": [
@@ -110,31 +109,33 @@
},
"extra": {
"branch-alias": {
"dev-master": "5.8-dev"
"dev-master": "6.x-dev"
}
},
"suggest": {
"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.",
"aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (^3.0).",
"ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).",
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).",
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).",
"filp/whoops": "Required for friendly error pages in development (^2.1.4).",
"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).",
"filp/whoops": "Required for friendly error pages in development (^2.8).",
"fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).",
"guzzlehttp/guzzle": "Required to use the Mailgun mail driver and the ping methods on schedules (^6.3.1|^7.0.1).",
"laravel/tinker": "Required to use the tinker console command (^2.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).",
"league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).",
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (^1.0).",
"league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).",
"moontoast/math": "Required to use ordered UUIDs (^1.1).",
"nexmo/client": "Required to use the Nexmo transport (^1.0).",
"nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).",
"pda/pheanstalk": "Required to use the beanstalk queue driver (^4.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 (^3.0).",
"symfony/css-selector": "Required to use some of the crawler integration testing tools (^4.2).",
"symfony/dom-crawler": "Required to use most of the crawler integration testing tools (^4.2).",
"symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^1.1).",
"predis/predis": "Required to use the predis connector (^1.1.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 (^4.0).",
"symfony/cache": "Required to PSR-6 cache bridge (^4.3.4).",
"symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^1.2).",
"wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)."
},
"config": {

View File

@@ -6,5 +6,58 @@ use Exception;
class AuthorizationException extends Exception
{
//
/**
* The response from the gate.
*
* @var \Illuminate\Auth\Access\Response
*/
protected $response;
/**
* Create a new authorization exception instance.
*
* @param string|null $message
* @param mixed $code
* @param \Exception|null $previous
* @return void
*/
public function __construct($message = null, $code = null, Exception $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;
}
/**
* Create a deny response object from this exception.
*
* @return \Illuminate\Auth\Access\Response
*/
public function toResponse()
{
return Response::deny($this->message, $this->code);
}
}

View File

@@ -3,13 +3,13 @@
namespace Illuminate\Auth\Access;
use Exception;
use ReflectionClass;
use ReflectionFunction;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Arr;
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
{
@@ -144,7 +144,7 @@ class Gate implements GateContract
*
* @param string $name
* @param string $class
* @param array|null $abilities
* @param array|null $abilities
* @return $this
*/
public function resource($name, $class, array $abilities = null)
@@ -274,11 +274,7 @@ class Gate implements GateContract
public function check($abilities, $arguments = [])
{
return collect($abilities)->every(function ($ability) use ($arguments) {
try {
return (bool) $this->raw($ability, $arguments);
} catch (AuthorizationException $e) {
return false;
}
return $this->inspect($ability, $arguments)->allowed();
});
}
@@ -319,13 +315,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();
}
/**
@@ -334,6 +346,8 @@ class Gate implements GateContract
* @param string $ability
* @param array|mixed $arguments
* @return mixed
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function raw($ability, $arguments = [])
{
@@ -365,7 +379,7 @@ class Gate implements GateContract
*
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
* @param \Closure|string|array $class
* @param string|null $method
* @param string|null $method
* @return bool
*/
protected function canBeCalledWithUser($user, $class, $method = null)
@@ -436,7 +450,7 @@ class Gate implements GateContract
*/
protected function parameterAllowsGuests($parameter)
{
return ($parameter->getClass() && $parameter->allowsNull()) ||
return ($parameter->hasType() && $parameter->allowsNull()) ||
($parameter->isDefaultValueAvailable() && is_null($parameter->getDefaultValue()));
}
@@ -530,6 +544,7 @@ class Gate implements GateContract
}
return function () {
//
};
}

View File

@@ -8,23 +8,23 @@ 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);
}
}

View File

@@ -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,17 +20,72 @@ class Response
*/
protected $message;
/**
* The response code.
*
* @var mixed
*/
protected $code;
/**
* 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);
}
/**
* 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.
*
@@ -32,6 +96,47 @@ 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);
}
return $this;
}
/**
* 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.
*

View File

@@ -3,8 +3,8 @@
namespace Illuminate\Auth;
use Closure;
use InvalidArgumentException;
use Illuminate\Contracts\Auth\Factory as FactoryContract;
use InvalidArgumentException;
class AuthManager implements FactoryContract
{
@@ -285,6 +285,16 @@ class AuthManager implements FactoryContract
return $this;
}
/**
* Determines if any guards have already been resolved.
*
* @return bool
*/
public function hasResolvedGuards()
{
return count($this->guards) > 0;
}
/**
* Dynamically call the default driver instance.
*

View File

@@ -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
{
@@ -19,6 +22,7 @@ class AuthServiceProvider extends ServiceProvider
$this->registerAuthenticator();
$this->registerUserResolver();
$this->registerAccessGate();
$this->registerRequirePassword();
$this->registerRequestRebindHandler();
$this->registerEventRebindHandler();
}
@@ -72,6 +76,24 @@ class AuthServiceProvider extends ServiceProvider
});
}
/**
* Register a resolver for the authenticated user.
*
* @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.
*
@@ -98,6 +120,10 @@ class AuthServiceProvider extends ServiceProvider
return;
}
if ($app['auth']->hasResolvedGuards() === false) {
return;
}
if (method_exists($guard = $app['auth']->guard(), 'setDispatcher')) {
$guard->setDispatcher($dispatcher);
}

View File

@@ -1,133 +0,0 @@
<?php
namespace Illuminate\Auth\Console;
use Illuminate\Console\Command;
use Illuminate\Console\DetectsApplicationNamespace;
class AuthMakeCommand 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/verify.stub' => 'auth/verify.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 handle()
{
$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($directory = $this->getViewPath('layouts'))) {
mkdir($directory, 0755, true);
}
if (! is_dir($directory = $this->getViewPath('auth/passwords'))) {
mkdir($directory, 0755, true);
}
}
/**
* Export the authentication views.
*
* @return void
*/
protected function exportViews()
{
foreach ($this->views as $key => $value) {
if (file_exists($view = $this->getViewPath($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,
$view
);
}
}
/**
* Compiles the HomeController stub.
*
* @return string
*/
protected function compileControllerStub()
{
return str_replace(
'{{namespace}}',
$this->getAppNamespace(),
file_get_contents(__DIR__.'/stubs/make/controllers/HomeController.stub')
);
}
/**
* Get full view path relative to the app's configured view path.
*
* @param string $path
* @return string
*/
protected function getViewPath($path)
{
return implode(DIRECTORY_SEPARATOR, [
config('view.paths')[0] ?? resource_path('views'), $path,
]);
}
}

View File

@@ -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\Contracts\Support\Renderable
*/
public function index()
{
return view('home');
}
}

View File

@@ -1,4 +0,0 @@
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');

View File

@@ -1,73 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Login') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('login') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ route('password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,47 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('password.email') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Send Password Reset Link') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,65 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('password.update') }}">
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,77 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Register') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('register') }}">
@csrf
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,24 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Verify Your Email Address') }}</div>
<div class="card-body">
@if (session('resent'))
<div class="alert alert-success" role="alert">
{{ __('A fresh verification link has been sent to your email address.') }}
</div>
@endif
{{ __('Before proceeding, please check your email for a verification link.') }}
{{ __('If you did not receive the email') }}, <a href="{{ route('verification.resend') }}">{{ __('click here to request another') }}</a>.
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,23 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Dashboard</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
You are logged in!
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -66,7 +66,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']);
}

View File

@@ -2,12 +2,12 @@
namespace Illuminate\Auth;
use Illuminate\Support\Str;
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;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Support\Str;
class DatabaseUserProvider implements UserProvider
{

View File

@@ -2,11 +2,11 @@
namespace Illuminate\Auth;
use Illuminate\Support\Str;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
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\Support\Str;
class EloquentUserProvider implements UserProvider
{

View 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;
}
}

View File

@@ -32,7 +32,7 @@ class Login
/**
* Create a new event instance.
*
* @param string $guard
* @param string $guard
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param bool $remember
* @return void

View File

@@ -25,7 +25,7 @@ class Logout
/**
* Create a new event instance.
*
* @param string $guard
* @param string $guard
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return void
*/

View 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;
}
}

View File

@@ -41,9 +41,7 @@ class GenericUser implements UserContract
*/
public function getAuthIdentifier()
{
$name = $this->getAuthIdentifierName();
return $this->attributes[$name];
return $this->attributes[$this->getAuthIdentifierName()];
}
/**

View File

@@ -2,8 +2,8 @@
namespace Illuminate\Auth;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\UserProvider;
/**
* These methods are typically the same across all guards.

View File

@@ -64,6 +64,20 @@ class Authenticate
}
}
$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)
);
@@ -73,7 +87,7 @@ class Authenticate
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string
* @return string|null
*/
protected function redirectTo($request)
{

View File

@@ -3,8 +3,8 @@
namespace Illuminate\Auth\Middleware;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Database\Eloquent\Model;
class Authorize
{
@@ -50,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)
{

View File

@@ -3,8 +3,8 @@
namespace Illuminate\Auth\Middleware;
use Closure;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Redirect;
class EnsureEmailIsVerified
{

View File

@@ -0,0 +1,84 @@
<?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
* @return mixed
*/
public function handle($request, Closure $next, $redirectToRoute = null)
{
if ($this->shouldConfirmPassword($request)) {
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
* @return bool
*/
protected function shouldConfirmPassword($request)
{
$confirmedAt = time() - $request->session()->get('auth.password_confirmed_at', 0);
return $confirmedAt > $this->passwordTimeout;
}
}

View File

@@ -2,6 +2,8 @@
namespace Illuminate\Auth;
use Illuminate\Auth\Notifications\VerifyEmail;
trait MustVerifyEmail
{
/**
@@ -33,6 +35,16 @@ trait MustVerifyEmail
*/
public function sendEmailVerificationNotification()
{
$this->notify(new Notifications\VerifyEmail);
$this->notify(new VerifyEmail);
}
/**
* Get the email address that should be used for verification.
*
* @return string
*/
public function getEmailForVerification()
{
return $this->email;
}
}

View File

@@ -2,9 +2,9 @@
namespace Illuminate\Auth\Notifications;
use Illuminate\Support\Facades\Lang;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Lang;
class ResetPassword extends Notification
{
@@ -57,11 +57,11 @@ class ResetPassword extends Notification
}
return (new MailMessage)
->subject(Lang::getFromJson('Reset Password Notification'))
->line(Lang::getFromJson('You are receiving this email because we received a password reset request for your account.'))
->action(Lang::getFromJson('Reset Password'), url(config('app.url').route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
->line(Lang::getFromJson('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]))
->line(Lang::getFromJson('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(route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
->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.'));
}
/**

View File

@@ -2,12 +2,12 @@
namespace Illuminate\Auth\Notifications;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Config;
use Illuminate\Notifications\Notification;
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
{
@@ -44,10 +44,10 @@ class VerifyEmail extends Notification
}
return (new MailMessage)
->subject(Lang::getFromJson('Verify Email Address'))
->line(Lang::getFromJson('Please click the button below to verify your email address.'))
->action(Lang::getFromJson('Verify Email Address'), $verificationUrl)
->line(Lang::getFromJson('If you did not create an account, no further action is required.'));
->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'), $verificationUrl)
->line(Lang::get('If you did not create an account, no further action is required.'));
}
/**
@@ -61,7 +61,10 @@ class VerifyEmail extends Notification
return URL::temporarySignedRoute(
'verification.verify',
Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
['id' => $notifiable->getKey()]
[
'id' => $notifiable->getKey(),
'hash' => sha1($notifiable->getEmailForVerification()),
]
);
}

View File

@@ -2,11 +2,11 @@
namespace Illuminate\Auth\Passwords;
use Illuminate\Support\Str;
use Illuminate\Support\Carbon;
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.
*

View File

@@ -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;
@@ -63,6 +55,11 @@ class PasswordBroker implements PasswordBrokerContract
return static::INVALID_USER;
}
if (method_exists($this->tokens, 'recentlyCreatedToken') &&
$this->tokens->recentlyCreatedToken($user)) {
return static::RESET_THROTTLED;
}
// 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.
@@ -82,11 +79,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;
}
@@ -115,10 +112,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,55 +119,6 @@ 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)) {
[$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)
{
[$password, $confirm] = [
$credentials['password'],
$credentials['password_confirmation'],
];
return $password === $confirm && mb_strlen($password) >= 8;
}
/**
* Get the user for the given credentials.
*
@@ -199,7 +143,7 @@ class PasswordBroker implements PasswordBrokerContract
/**
* Create a new password reset token for the given user.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @return string
*/
public function createToken(CanResetPasswordContract $user)
@@ -210,7 +154,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 +165,8 @@ class PasswordBroker implements PasswordBrokerContract
/**
* Validate the given password reset token.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $token
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $token
* @return bool
*/
public function tokenExists(CanResetPasswordContract $user, $token)

View File

@@ -2,9 +2,9 @@
namespace Illuminate\Auth\Passwords;
use Illuminate\Contracts\Auth\PasswordBrokerFactory as FactoryContract;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Illuminate\Contracts\Auth\PasswordBrokerFactory as FactoryContract;
/**
* @mixin \Illuminate\Contracts\Auth\PasswordBroker
@@ -95,7 +95,8 @@ class PasswordBrokerManager implements FactoryContract
$this->app['hash'],
$config['table'],
$key,
$config['expire']
$config['expire'],
$config['throttle'] ?? 0
);
}
@@ -135,7 +136,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)

View File

@@ -2,8 +2,8 @@
namespace Illuminate\Auth\Passwords;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
class PasswordResetServiceProvider extends ServiceProvider implements DeferrableProvider
{

View File

@@ -2,10 +2,10 @@
namespace Illuminate\Auth;
use Illuminate\Http\Request;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Traits\Macroable;
class RequestGuard implements Guard
{
@@ -30,7 +30,7 @@ class RequestGuard implements Guard
*
* @param callable $callback
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Contracts\Auth\UserProvider|null $provider
* @param \Illuminate\Contracts\Auth\UserProvider|null $provider
* @return void
*/
public function __construct(callable $callback, Request $request, UserProvider $provider = null)

View File

@@ -2,19 +2,27 @@
namespace Illuminate\Auth;
use RuntimeException;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
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 Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
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\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
use RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
@@ -339,7 +347,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
* 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)
@@ -374,14 +382,20 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
*/
protected function hasValidCredentials($user, $credentials)
{
return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
$validated = ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
if ($validated) {
$this->fireValidatedEvent($user);
}
return $validated;
}
/**
* 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)
@@ -482,17 +496,17 @@ 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) && ! 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($this->name, $user));
$this->events->dispatch(new Logout($this->name, $user));
}
// Once we have fired the logout event we will clear the users out of memory
@@ -531,6 +545,32 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
$this->provider->updateRememberToken($user, $token);
}
/**
* Log the user out of the application on their current device only.
*
* @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
// 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;
}
/**
* Invalidate other sessions for the current user.
*
@@ -583,12 +623,26 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
protected function fireAttemptEvent(array $credentials, $remember = false)
{
if (isset($this->events)) {
$this->events->dispatch(new Events\Attempting(
$this->events->dispatch(new Attempting(
$this->name, $credentials, $remember
));
}
}
/**
* Fires the validated event if the dispatcher is set.
*
* @param $user
*/
protected function fireValidatedEvent($user)
{
if (isset($this->events)) {
$this->events->dispatch(new Validated(
$this->name, $user
));
}
}
/**
* Fire the login event if the dispatcher is set.
*
@@ -599,7 +653,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
protected function fireLoginEvent($user, $remember = false)
{
if (isset($this->events)) {
$this->events->dispatch(new Events\Login(
$this->events->dispatch(new Login(
$this->name, $user, $remember
));
}
@@ -614,7 +668,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
protected function fireAuthenticatedEvent($user)
{
if (isset($this->events)) {
$this->events->dispatch(new Events\Authenticated(
$this->events->dispatch(new Authenticated(
$this->name, $user
));
}
@@ -629,7 +683,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
protected function fireOtherDeviceLogoutEvent($user)
{
if (isset($this->events)) {
$this->events->dispatch(new Events\OtherDeviceLogout(
$this->events->dispatch(new OtherDeviceLogout(
$this->name, $user
));
}
@@ -645,7 +699,7 @@ class SessionGuard implements StatefulGuard, SupportsBasicAuth
protected function fireFailedEvent($user, array $credentials)
{
if (isset($this->events)) {
$this->events->dispatch(new Events\Failed(
$this->events->dispatch(new Failed(
$this->name, $user, $credentials
));
}

View File

@@ -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
{

View File

@@ -14,11 +14,11 @@
}
],
"require": {
"php": "^7.1.3",
"illuminate/contracts": "5.8.*",
"illuminate/http": "5.8.*",
"illuminate/queue": "5.8.*",
"illuminate/support": "5.8.*"
"php": "^7.2.5|^8.0",
"illuminate/contracts": "^6.0",
"illuminate/http": "^6.0",
"illuminate/queue": "^6.0",
"illuminate/support": "^6.0"
},
"autoload": {
"psr-4": {
@@ -27,13 +27,13 @@
},
"extra": {
"branch-alias": {
"dev-master": "5.8-dev"
"dev-master": "6.x-dev"
}
},
"suggest": {
"illuminate/console": "Required to use the auth:clear-resets command (5.8.*).",
"illuminate/queue": "Required to fire login / logout events (5.8.*).",
"illuminate/session": "Required to use the session based guard (5.8.*)."
"illuminate/console": "Required to use the auth:clear-resets command (^6.0).",
"illuminate/queue": "Required to fire login / logout events (^6.0).",
"illuminate/session": "Required to use the session based guard (^6.0)."
},
"config": {
"sort-packages": true

View File

@@ -2,13 +2,13 @@
namespace Illuminate\Broadcasting;
use ReflectionClass;
use ReflectionProperty;
use Illuminate\Support\Arr;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\Broadcaster;
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,20 @@ 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;
/**
* Create a new job handler instance.
*
@@ -30,6 +44,8 @@ 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;
}
/**

View File

@@ -3,15 +3,16 @@
namespace Illuminate\Broadcasting;
use Closure;
use Pusher\Pusher;
use Psr\Log\LoggerInterface;
use InvalidArgumentException;
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\Contracts\Broadcasting\Factory as FactoryContract;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract;
use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Pusher\Pusher;
/**
* @mixin \Illuminate\Contracts\Broadcasting\Broadcaster
@@ -93,7 +94,7 @@ class BroadcastManager implements FactoryContract
* Begin broadcasting an event.
*
* @param mixed|null $event
* @return \Illuminate\Broadcasting\PendingBroadcast|void
* @return \Illuminate\Broadcasting\PendingBroadcast
*/
public function event($event = null)
{
@@ -108,10 +109,8 @@ 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) {
return $this->app->make(BusDispatcherContract::class)->dispatchNow(new BroadcastEvent(clone $event));
}
$queue = null;
@@ -124,7 +123,7 @@ class BroadcastManager implements FactoryContract
$queue = $event->queue;
}
$this->app->make('queue')->connection($connection)->pushOn(
$this->app->make('queue')->connection($event->connection ?? null)->pushOn(
$queue, new BroadcastEvent(clone $event)
);
}
@@ -229,7 +228,8 @@ class BroadcastManager implements FactoryContract
protected function createRedisDriver(array $config)
{
return new RedisBroadcaster(
$this->app->make('redis'), $config['connection'] ?? null
$this->app->make('redis'), $config['connection'] ?? null,
$this->app['config']->get('database.redis.options.prefix', '')
);
}
@@ -296,7 +296,7 @@ class BroadcastManager implements FactoryContract
/**
* Register a custom driver creator Closure.
*
* @param string $driver
* @param string $driver
* @param \Closure $callback
* @return $this
*/
@@ -311,7 +311,7 @@ class BroadcastManager implements FactoryContract
* Dynamically call the default driver instance.
*
* @param string $method
* @param array $parameters
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)

View File

@@ -2,10 +2,10 @@
namespace Illuminate\Broadcasting;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
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 implements DeferrableProvider
{

View File

@@ -3,15 +3,16 @@
namespace Illuminate\Broadcasting\Broadcasters;
use Exception;
use Illuminate\Container\Container;
use Illuminate\Contracts\Broadcasting\Broadcaster as BroadcasterContract;
use Illuminate\Contracts\Routing\BindingRegistrar;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Support\Arr;
use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
use ReflectionClass;
use ReflectionFunction;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Container\Container;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Contracts\Routing\BindingRegistrar;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Illuminate\Contracts\Broadcasting\Broadcaster as BroadcasterContract;
abstract class Broadcaster implements BroadcasterContract
{
@@ -204,9 +205,9 @@ abstract class Broadcaster implements BroadcasterContract
continue;
}
$instance = $parameter->getClass()->newInstance();
$className = Reflector::getParameterClassName($parameter);
if (! $model = $instance->resolveRouteBinding($value)) {
if (is_null($model = (new $className)->resolveRouteBinding($value))) {
throw new AccessDeniedHttpException;
}
@@ -225,8 +226,8 @@ abstract class Broadcaster implements BroadcasterContract
*/
protected function isImplicitlyBindable($key, $parameter)
{
return $parameter->name === $key && $parameter->getClass() &&
$parameter->getClass()->isSubclassOf(UrlRoutable::class);
return $parameter->getName() === $key &&
Reflector::isParameterSubclassOf($parameter, UrlRoutable::class);
}
/**
@@ -261,7 +262,7 @@ abstract class Broadcaster implements BroadcasterContract
* Normalize the given callback into a callable.
*
* @param mixed $callback
* @return callable|\Closure
* @return \Closure|callable
*/
protected function normalizeChannelHandlerToCallable($callback)
{

View File

@@ -2,10 +2,10 @@
namespace Illuminate\Broadcasting\Broadcasters;
use Pusher\Pusher;
use Illuminate\Broadcasting\BroadcastException;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Broadcasting\BroadcastException;
use Pusher\Pusher;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class PusherBroadcaster extends Broadcaster
@@ -102,6 +102,8 @@ class PusherBroadcaster extends Broadcaster
* @param string $event
* @param array $payload
* @return void
*
* @throws \Illuminate\Broadcasting\BroadcastException
*/
public function broadcast(array $channels, $event, array $payload = [])
{
@@ -117,7 +119,9 @@ class PusherBroadcaster extends Broadcaster
}
throw new BroadcastException(
is_bool($response) ? 'Failed to connect to Pusher.' : $response['body']
! empty($response['body'])
? sprintf('Pusher error: %s.', $response['body'])
: 'Failed to connect to Pusher.'
);
}

View File

@@ -2,8 +2,8 @@
namespace Illuminate\Broadcasting\Broadcasters;
use Illuminate\Support\Arr;
use Illuminate\Contracts\Redis\Factory as Redis;
use Illuminate\Support\Arr;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class RedisBroadcaster extends Broadcaster
@@ -24,16 +24,25 @@ class RedisBroadcaster extends Broadcaster
*/
protected $connection;
/**
* The Redis key prefix.
*
* @var string
*/
protected $prefix;
/**
* Create a new broadcaster instance.
*
* @param \Illuminate\Contracts\Redis\Factory $redis
* @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;
}
@@ -47,7 +56,9 @@ class RedisBroadcaster extends Broadcaster
*/
public function auth($request)
{
$channelName = $this->normalizeChannelName($request->channel_name);
$channelName = $this->normalizeChannelName(
str_replace($this->prefix, '', $request->channel_name)
);
if ($this->isGuardedChannel($request->channel_name) &&
! $this->retrieveUser($request, $channelName)) {
@@ -90,6 +101,10 @@ class RedisBroadcaster extends Broadcaster
*/
public function broadcast(array $channels, $event, array $payload = [])
{
if (empty($channels)) {
return;
}
$connection = $this->redis->connection($this->connection);
$payload = json_encode([
@@ -98,8 +113,39 @@ class RedisBroadcaster extends Broadcaster
'socket' => Arr::pull($payload, 'socket'),
]);
foreach ($this->formatChannels($channels) as $channel) {
$connection->publish($channel, $payload);
}
$connection->eval(
$this->broadcastMultipleChannelsScript(),
0, $payload, ...$this->formatChannels($channels)
);
}
/**
* 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));
}
}

View File

@@ -25,10 +25,10 @@ trait UsePusherChannelConventions
*/
public function normalizeChannelName($channel)
{
if ($this->isGuardedChannel($channel)) {
return Str::startsWith($channel, 'private-')
? Str::replaceFirst('private-', '', $channel)
: Str::replaceFirst('presence-', '', $channel);
foreach (['private-encrypted-', 'private-', 'presence-'] as $prefix) {
if (Str::startsWith($channel, $prefix)) {
return Str::replaceFirst($prefix, '', $channel);
}
}
return $channel;

View 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);
}
}

View File

@@ -14,13 +14,13 @@
}
],
"require": {
"php": "^7.1.3",
"php": "^7.2.5|^8.0",
"ext-json": "*",
"psr/log": "^1.0",
"illuminate/bus": "5.8.*",
"illuminate/contracts": "5.8.*",
"illuminate/queue": "5.8.*",
"illuminate/support": "5.8.*"
"illuminate/bus": "^6.0",
"illuminate/contracts": "^6.0",
"illuminate/queue": "^6.0",
"illuminate/support": "^6.0"
},
"autoload": {
"psr-4": {
@@ -29,11 +29,11 @@
},
"extra": {
"branch-alias": {
"dev-master": "5.8-dev"
"dev-master": "6.x-dev"
}
},
"suggest": {
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^3.0)."
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0)."
},
"config": {
"sort-packages": true

View File

@@ -2,11 +2,11 @@
namespace Illuminate\Bus;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
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 implements DeferrableProvider
{

View File

@@ -3,12 +3,12 @@
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\Pipeline\Pipeline;
use RuntimeException;
class Dispatcher implements QueueingDispatcher
{
@@ -140,8 +140,6 @@ class Dispatcher implements QueueingDispatcher
*
* @param mixed $command
* @return mixed
*
* @throws \RuntimeException
*/
public function dispatchToQueue($command)
{
@@ -184,6 +182,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.
*

View File

@@ -2,6 +2,8 @@
namespace Illuminate\Bus;
use Illuminate\Support\Arr;
trait Queueable
{
/**
@@ -39,6 +41,11 @@ trait Queueable
*/
public $delay;
/**
* The middleware the job should be dispatched through.
*/
public $middleware = [];
/**
* The jobs that should run if this job is successful.
*
@@ -113,6 +120,29 @@ trait Queueable
return $this;
}
/**
* Get the middleware the job should be dispatched through.
*
* @return array
*/
public function middleware()
{
return [];
}
/**
* 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.
*

View File

@@ -14,10 +14,10 @@
}
],
"require": {
"php": "^7.1.3",
"illuminate/contracts": "5.8.*",
"illuminate/pipeline": "5.8.*",
"illuminate/support": "5.8.*"
"php": "^7.2.5|^8.0",
"illuminate/contracts": "^6.0",
"illuminate/pipeline": "^6.0",
"illuminate/support": "^6.0"
},
"autoload": {
"psr-4": {
@@ -26,7 +26,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "5.8-dev"
"dev-master": "6.x-dev"
}
},
"config": {

View File

@@ -52,7 +52,7 @@ class ApcStore extends TaggableStore
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -65,7 +65,7 @@ class ApcStore extends TaggableStore
* 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)
@@ -77,7 +77,7 @@ class ApcStore extends TaggableStore
* 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)
@@ -89,7 +89,7 @@ class ApcStore extends TaggableStore
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return bool
*/
public function forever($key, $value)

View File

@@ -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)

View File

@@ -0,0 +1,102 @@
<?php
namespace Illuminate\Cache;
use Carbon\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]);
}
}

View File

@@ -2,9 +2,10 @@
namespace Illuminate\Cache;
use Illuminate\Contracts\Cache\LockProvider;
use Illuminate\Support\InteractsWithTime;
class ArrayStore extends TaggableStore
class ArrayStore extends TaggableStore implements LockProvider
{
use InteractsWithTime, RetrievesMultipleKeys;
@@ -15,6 +16,13 @@ class ArrayStore extends TaggableStore
*/
protected $storage = [];
/**
* The array of locks.
*
* @var array
*/
public $locks = [];
/**
* Retrieve an item from the cache by key.
*
@@ -44,7 +52,7 @@ class ArrayStore extends TaggableStore
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -62,7 +70,7 @@ class ArrayStore extends TaggableStore
* 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)
@@ -82,7 +90,7 @@ class ArrayStore extends TaggableStore
* 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)
@@ -94,7 +102,7 @@ class ArrayStore extends TaggableStore
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return bool
*/
public function forever($key, $value)
@@ -162,4 +170,29 @@ class ArrayStore extends TaggableStore
{
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);
}
}

View File

@@ -2,13 +2,13 @@
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 Aws\DynamoDb\DynamoDbClient;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Contracts\Cache\Factory as FactoryContract;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
/**
* @mixin \Illuminate\Contracts\Cache\Repository
@@ -153,7 +153,7 @@ class CacheManager implements FactoryContract
*/
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));
}
/**
@@ -226,21 +226,11 @@ class CacheManager implements FactoryContract
*/
protected function createDynamodbDriver(array $config)
{
$dynamoConfig = [
'region' => $config['region'],
'version' => 'latest',
'endpoint' => $config['endpoint'] ?? null,
];
if ($config['key'] && $config['secret']) {
$dynamoConfig['credentials'] = Arr::only(
$config, ['key', 'secret', 'token']
);
}
$client = $this->newDynamodbClient($config);
return $this->repository(
new DynamoDbStore(
new DynamoDbClient($dynamoConfig),
$client,
$config['table'],
$config['attributes']['key'] ?? 'key',
$config['attributes']['value'] ?? 'value',
@@ -250,6 +240,28 @@ class CacheManager implements FactoryContract
);
}
/**
* Create new DynamoDb Client instance.
*
* @return DynamoDbClient
*/
protected function newDynamodbClient(array $config)
{
$dynamoConfig = [
'region' => $config['region'],
'version' => 'latest',
'endpoint' => $config['endpoint'] ?? null,
];
if (isset($config['key']) && isset($config['secret'])) {
$dynamoConfig['credentials'] = Arr::only(
$config, ['key', 'secret', 'token']
);
}
return new DynamoDbClient($dynamoConfig);
}
/**
* Create a new cache repository with the given implementation.
*
@@ -258,15 +270,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);
}
/**

View File

@@ -2,8 +2,9 @@
namespace Illuminate\Cache;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\Cache\Adapter\Psr16Adapter;
class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
{
@@ -22,6 +23,10 @@ class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
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;
});
@@ -35,7 +40,7 @@ class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
public function provides()
{
return [
'cache', 'cache.store', 'memcached.connector',
'cache', 'cache.store', 'cache.psr6', 'memcached.connector',
];
}
}

View File

@@ -3,8 +3,8 @@
namespace Illuminate\Cache\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Composer;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Composer;
class CacheTableCommand extends Command
{

View File

@@ -2,11 +2,11 @@
namespace Illuminate\Cache\Console;
use Illuminate\Console\Command;
use Illuminate\Cache\CacheManager;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ClearCommand extends Command
{

View File

@@ -2,8 +2,8 @@
namespace Illuminate\Cache\Console;
use Illuminate\Console\Command;
use Illuminate\Cache\CacheManager;
use Illuminate\Console\Command;
class ForgetCommand extends Command
{

View File

@@ -1,8 +1,8 @@
<?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
{

View File

@@ -4,11 +4,11 @@ namespace Illuminate\Cache;
use Closure;
use Exception;
use Illuminate\Support\Str;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Database\PostgresConnection;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\PostgresConnection;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Support\Str;
class DatabaseStore implements Store
{
@@ -87,7 +87,7 @@ class DatabaseStore implements Store
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -112,7 +112,7 @@ class DatabaseStore implements Store
* 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)
@@ -126,7 +126,7 @@ class DatabaseStore 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)
@@ -197,7 +197,7 @@ class DatabaseStore implements Store
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return bool
*/
public function forever($key, $value)

View File

@@ -42,13 +42,15 @@ class DynamoDbLock extends Lock
/**
* Release the lock.
*
* @return void
* @return bool
*/
public function release()
{
if ($this->isOwnedByCurrentProcess()) {
$this->dynamo->forget($this->name);
return $this->dynamo->forget($this->name);
}
return false;
}
/**

View File

@@ -2,16 +2,16 @@
namespace Illuminate\Cache;
use RuntimeException;
use Illuminate\Support\Str;
use Illuminate\Support\Carbon;
use Aws\DynamoDb\DynamoDbClient;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Contracts\Cache\LockProvider;
use Aws\DynamoDb\Exception\DynamoDbException;
use Illuminate\Contracts\Cache\LockProvider;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Support\Carbon;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Support\Str;
use RuntimeException;
class DynamoDbStore implements Store, LockProvider
class DynamoDbStore implements LockProvider, Store
{
use InteractsWithTime;
@@ -151,6 +151,7 @@ class DynamoDbStore implements Store, LockProvider
$now = Carbon::now();
return array_merge(collect(array_flip($keys))->map(function () {
//
})->all(), collect($response['Responses'][$this->table])->mapWithKeys(function ($response) use ($now) {
if ($this->isExpired($response, $now)) {
$value = null;
@@ -390,7 +391,7 @@ class DynamoDbStore implements Store, LockProvider
*/
public function forever($key, $value)
{
return $this->put($key, $value, now()->addYears(5)->getTimestamp());
return $this->put($key, $value, Carbon::now()->addYears(5)->getTimestamp());
}
/**
@@ -442,6 +443,8 @@ class DynamoDbStore implements Store, LockProvider
* Remove all items from the cache.
*
* @return bool
*
* @throws \RuntimeException
*/
public function flush()
{
@@ -522,4 +525,14 @@ class DynamoDbStore implements Store, LockProvider
{
$this->prefix = ! empty($prefix) ? $prefix.':' : '';
}
/**
* Get the DynamoDb Client instance.
*
* @return DynamoDbClient
*/
public function getClient()
{
return $this->dynamo;
}
}

View File

@@ -25,17 +25,26 @@ class FileStore implements Store
*/
protected $directory;
/**
* Octal representation of the cache file permissions.
*
* @var int|null
*/
protected $filePermission;
/**
* Create a new file cache store instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @param string $directory
* @param int|null $filePermission
* @return void
*/
public function __construct(Filesystem $files, $directory)
public function __construct(Filesystem $files, $directory, $filePermission = null)
{
$this->files = $files;
$this->directory = $directory;
$this->filePermission = $filePermission;
}
/**
@@ -53,7 +62,7 @@ class FileStore implements Store
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -65,7 +74,13 @@ class FileStore implements Store
$path, $this->expiration($seconds).serialize($value), true
);
return $result !== false && $result > 0;
if ($result !== false && $result > 0) {
$this->ensureFileHasCorrectPermissions($path);
return true;
}
return false;
}
/**
@@ -81,11 +96,27 @@ class FileStore implements Store
}
}
/**
* Ensure the cache file has the correct permissions.
*
* @param string $path
* @return void
*/
protected function ensureFileHasCorrectPermissions($path)
{
if (is_null($this->filePermission) ||
intval($this->files->chmod($path), 8) == $this->filePermission) {
return;
}
$this->files->chmod($path, $this->filePermission);
}
/**
* 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)
@@ -101,7 +132,7 @@ class FileStore implements Store
* 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)
@@ -113,7 +144,7 @@ class FileStore implements Store
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return bool
*/
public function forever($key, $value)
@@ -148,7 +179,9 @@ class FileStore implements Store
}
foreach ($this->files->directories($this->directory) as $directory) {
if (! $this->files->deleteDirectory($directory)) {
$deleted = $this->files->deleteDirectory($directory);
if (! $deleted || $this->files->exists($directory)) {
return false;
}
}

View File

@@ -2,10 +2,10 @@
namespace Illuminate\Cache;
use Illuminate\Support\Str;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Contracts\Cache\Lock as LockContract;
use Illuminate\Contracts\Cache\LockTimeoutException;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Support\Str;
abstract class Lock implements LockContract
{
@@ -61,7 +61,7 @@ abstract class Lock implements LockContract
/**
* Release the lock.
*
* @return void
* @return bool
*/
abstract public function release();
@@ -98,7 +98,7 @@ abstract class Lock implements LockContract
*
* @param int $seconds
* @param callable|null $callback
* @return bool
* @return mixed
*
* @throws \Illuminate\Contracts\Cache\LockTimeoutException
*/

View File

@@ -42,13 +42,15 @@ class MemcachedLock extends Lock
/**
* Release the lock.
*
* @return void
* @return bool
*/
public function release()
{
if ($this->isOwnedByCurrentProcess()) {
$this->memcached->delete($this->name);
return $this->memcached->delete($this->name);
}
return false;
}
/**

View File

@@ -2,10 +2,10 @@
namespace Illuminate\Cache;
use Illuminate\Contracts\Cache\LockProvider;
use Illuminate\Support\InteractsWithTime;
use Memcached;
use ReflectionMethod;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Contracts\Cache\LockProvider;
class MemcachedStore extends TaggableStore implements LockProvider
{
@@ -36,7 +36,7 @@ class MemcachedStore extends TaggableStore implements LockProvider
* Create a new Memcached store.
*
* @param \Memcached $memcached
* @param string $prefix
* @param string $prefix
* @return void
*/
public function __construct($memcached, $prefix = '')
@@ -96,7 +96,7 @@ class MemcachedStore extends TaggableStore implements LockProvider
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -131,7 +131,7 @@ class MemcachedStore extends TaggableStore implements LockProvider
* Store an item in the cache if the key doesn't exist.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -146,7 +146,7 @@ class MemcachedStore extends TaggableStore implements LockProvider
* 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)
@@ -158,7 +158,7 @@ class MemcachedStore extends TaggableStore implements LockProvider
* 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)
@@ -170,7 +170,7 @@ class MemcachedStore extends TaggableStore implements LockProvider
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return bool
*/
public function forever($key, $value)
@@ -181,9 +181,9 @@ class MemcachedStore extends TaggableStore implements LockProvider
/**
* Get a lock instance.
*
* @param string $name
* @param int $seconds
* @param string|null $owner
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function lock($name, $seconds = 0, $owner = null)

View File

@@ -6,13 +6,6 @@ class NullStore extends TaggableStore
{
use RetrievesMultipleKeys;
/**
* The array of stored values.
*
* @var array
*/
protected $storage = [];
/**
* Retrieve an item from the cache by key.
*
@@ -21,13 +14,14 @@ class NullStore extends TaggableStore
*/
public function get($key)
{
//
}
/**
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -40,7 +34,7 @@ class NullStore extends TaggableStore
* 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)
@@ -52,7 +46,7 @@ class NullStore extends TaggableStore
* 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)
@@ -64,7 +58,7 @@ class NullStore extends TaggableStore
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return bool
*/
public function forever($key, $value)

View File

@@ -2,8 +2,8 @@
namespace Illuminate\Cache;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Support\InteractsWithTime;
class RateLimiter
{
@@ -36,6 +36,8 @@ class RateLimiter
*/
public function tooManyAttempts($key, $maxAttempts)
{
$key = $this->cleanRateLimiterKey($key);
if ($this->attempts($key) >= $maxAttempts) {
if ($this->cache->has($key.':timer')) {
return true;
@@ -56,6 +58,8 @@ class RateLimiter
*/
public function hit($key, $decaySeconds = 60)
{
$key = $this->cleanRateLimiterKey($key);
$this->cache->add(
$key.':timer', $this->availableAt($decaySeconds), $decaySeconds
);
@@ -79,6 +83,8 @@ class RateLimiter
*/
public function attempts($key)
{
$key = $this->cleanRateLimiterKey($key);
return $this->cache->get($key, 0);
}
@@ -90,6 +96,8 @@ class RateLimiter
*/
public function resetAttempts($key)
{
$key = $this->cleanRateLimiterKey($key);
return $this->cache->forget($key);
}
@@ -102,6 +110,8 @@ class RateLimiter
*/
public function retriesLeft($key, $maxAttempts)
{
$key = $this->cleanRateLimiterKey($key);
$attempts = $this->attempts($key);
return $maxAttempts - $attempts;
@@ -115,6 +125,8 @@ class RateLimiter
*/
public function clear($key)
{
$key = $this->cleanRateLimiterKey($key);
$this->resetAttempts($key);
$this->cache->forget($key.':timer');
@@ -128,6 +140,19 @@ class RateLimiter
*/
public function availableIn($key)
{
$key = $this->cleanRateLimiterKey($key);
return $this->cache->get($key.':timer') - $this->currentTime();
}
/**
* Clean the rate limiter key from unicode characters.
*
* @param string $key
* @return string
*/
public function cleanRateLimiterKey($key)
{
return preg_replace('/&([a-z])[a-z]+;/i', '$1', htmlentities($key));
}
}

View File

@@ -34,23 +34,21 @@ class RedisLock extends Lock
*/
public function acquire()
{
$result = $this->redis->setnx($this->name, $this->owner);
if ($result === 1 && $this->seconds > 0) {
$this->redis->expire($this->name, $this->seconds);
if ($this->seconds > 0) {
return $this->redis->set($this->name, $this->owner, 'EX', $this->seconds, 'NX') == true;
} else {
return $this->redis->setnx($this->name, $this->owner) === 1;
}
return $result === 1;
}
/**
* Release the lock.
*
* @return void
* @return bool
*/
public function release()
{
$this->redis->eval(LuaScripts::releaseLock(), 1, $this->name, $this->owner);
return (bool) $this->redis->eval(LuaScripts::releaseLock(), 1, $this->name, $this->owner);
}
/**

View File

@@ -83,7 +83,7 @@ class RedisStore extends TaggableStore implements LockProvider
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -122,7 +122,7 @@ class RedisStore extends TaggableStore implements LockProvider
* Store an item in the cache if the key doesn't exist.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param int $seconds
* @return bool
*/
@@ -139,7 +139,7 @@ class RedisStore extends TaggableStore implements LockProvider
* 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)
@@ -151,7 +151,7 @@ class RedisStore extends TaggableStore implements LockProvider
* 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)
@@ -163,7 +163,7 @@ class RedisStore extends TaggableStore implements LockProvider
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return bool
*/
public function forever($key, $value)
@@ -174,9 +174,9 @@ class RedisStore extends TaggableStore implements LockProvider
/**
* Get a lock instance.
*
* @param string $name
* @param int $seconds
* @param string|null $owner
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function lock($name, $seconds = 0, $owner = null)
@@ -235,7 +235,7 @@ class RedisStore extends TaggableStore implements LockProvider
/**
* Get the Redis connection instance.
*
* @return \Predis\ClientInterface
* @return \Illuminate\Redis\Connections\Connection
*/
public function connection()
{
@@ -292,7 +292,7 @@ class RedisStore extends TaggableStore implements LockProvider
*/
protected function serialize($value)
{
return is_numeric($value) ? $value : serialize($value);
return is_numeric($value) && ! in_array($value, [INF, -INF]) && ! is_nan($value) ? $value : serialize($value);
}
/**

View File

@@ -21,7 +21,7 @@ class RedisTaggedCache extends TaggedCache
* Store an item in the cache.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @param \DateTimeInterface|\DateInterval|int|null $ttl
* @return bool
*/
@@ -179,7 +179,7 @@ class RedisTaggedCache extends TaggedCache
if (count($values) > 0) {
foreach (array_chunk($values, 1000) as $valuesChunk) {
call_user_func_array([$this->store->connection(), 'del'], $valuesChunk);
$this->store->connection()->del(...$valuesChunk);
}
}
}

View File

@@ -2,25 +2,25 @@
namespace Illuminate\Cache;
use Closure;
use ArrayAccess;
use DateTimeInterface;
use BadMethodCallException;
use Illuminate\Support\Carbon;
use Closure;
use DateTimeInterface;
use Illuminate\Cache\Events\CacheHit;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Cache\Events\KeyWritten;
use Illuminate\Cache\Events\CacheMissed;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Cache\Events\KeyForgotten;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Cache\Events\KeyWritten;
use Illuminate\Contracts\Cache\Repository as CacheContract;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Carbon;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Support\Traits\Macroable;
/**
* @mixin \Illuminate\Contracts\Cache\Store
*/
class Repository implements CacheContract, ArrayAccess
class Repository implements ArrayAccess, CacheContract
{
use InteractsWithTime;
use Macroable {
@@ -504,7 +504,7 @@ class Repository implements CacheContract, ArrayAccess
/**
* Get the default cache time.
*
* @return int
* @return int|null
*/
public function getDefaultCacheTime()
{
@@ -547,6 +547,16 @@ class Repository implements CacheContract, ArrayAccess
}
}
/**
* Get the event dispatcher instance.
*
* @return \Illuminate\Contracts\Events\Dispatcher
*/
public function getEventDispatcher()
{
return $this->events;
}
/**
* Set the event dispatcher instance.
*
@@ -584,7 +594,7 @@ class Repository implements CacheContract, ArrayAccess
* Store an item in the cache for the default time.
*
* @param string $key
* @param mixed $value
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value)

View File

@@ -14,9 +14,9 @@
}
],
"require": {
"php": "^7.1.3",
"illuminate/contracts": "5.8.*",
"illuminate/support": "5.8.*"
"php": "^7.2.5|^8.0",
"illuminate/contracts": "^6.0",
"illuminate/support": "^6.0"
},
"autoload": {
"psr-4": {
@@ -25,13 +25,15 @@
},
"extra": {
"branch-alias": {
"dev-master": "5.8-dev"
"dev-master": "6.x-dev"
}
},
"suggest": {
"illuminate/database": "Required to use the database cache driver (5.8.*).",
"illuminate/filesystem": "Required to use the file cache driver (5.8.*).",
"illuminate/redis": "Required to use the redis cache driver (5.8.*)."
"ext-memcached": "Required to use the memcache cache driver.",
"illuminate/database": "Required to use the database cache driver (^6.0).",
"illuminate/filesystem": "Required to use the file cache driver (^6.0).",
"illuminate/redis": "Required to use the redis cache driver (^6.0).",
"symfony/cache": "Required to PSR-6 cache bridge (^4.3.4)."
},
"config": {
"sort-packages": true

View File

@@ -3,8 +3,8 @@
namespace Illuminate\Config;
use ArrayAccess;
use Illuminate\Support\Arr;
use Illuminate\Contracts\Config\Repository as ConfigContract;
use Illuminate\Support\Arr;
class Repository implements ArrayAccess, ConfigContract
{
@@ -41,7 +41,7 @@ class Repository implements ArrayAccess, ConfigContract
* Get the specified configuration value.
*
* @param array|string $key
* @param mixed $default
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null)
@@ -78,7 +78,7 @@ class Repository implements ArrayAccess, ConfigContract
* Set a given configuration value.
*
* @param array|string $key
* @param mixed $value
* @param mixed $value
* @return void
*/
public function set($key, $value = null)

View File

@@ -14,9 +14,9 @@
}
],
"require": {
"php": "^7.1.3",
"illuminate/contracts": "5.8.*",
"illuminate/support": "5.8.*"
"php": "^7.2.5|^8.0",
"illuminate/contracts": "^6.0",
"illuminate/support": "^6.0"
},
"autoload": {
"psr-4": {
@@ -25,7 +25,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "5.8-dev"
"dev-master": "6.x-dev"
}
},
"config": {

View File

@@ -3,22 +3,25 @@
namespace Illuminate\Console;
use Closure;
use Illuminate\Support\ProcessUtils;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Console\Events\ArtisanStarting;
use Illuminate\Console\Events\CommandFinished;
use Illuminate\Console\Events\CommandStarting;
use Illuminate\Contracts\Console\Application as ApplicationContract;
use Illuminate\Contracts\Container\Container;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\ProcessUtils;
use Symfony\Component\Console\Application as SymfonyApplication;
use Symfony\Component\Console\Command\Command as SymfonyCommand;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Illuminate\Contracts\Console\Application as ApplicationContract;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\PhpExecutableFinder;
class Application extends SymfonyApplication implements ApplicationContract
{
@@ -67,7 +70,7 @@ class Application extends SymfonyApplication implements ApplicationContract
$this->setAutoExit(false);
$this->setCatchExceptions(false);
$this->events->dispatch(new Events\ArtisanStarting($this));
$this->events->dispatch(new ArtisanStarting($this));
$this->bootstrap();
}
@@ -82,7 +85,7 @@ class Application extends SymfonyApplication implements ApplicationContract
);
$this->events->dispatch(
new Events\CommandStarting(
new CommandStarting(
$commandName, $input, $output = $output ?: new ConsoleOutput
)
);
@@ -90,7 +93,7 @@ class Application extends SymfonyApplication implements ApplicationContract
$exitCode = parent::run($input, $output);
$this->events->dispatch(
new Events\CommandFinished($commandName, $input, $output, $exitCode)
new CommandFinished($commandName, $input, $output, $exitCode)
);
return $exitCode;
@@ -113,7 +116,7 @@ class Application extends SymfonyApplication implements ApplicationContract
*/
public static function artisanBinary()
{
return defined('ARTISAN_BINARY') ? ProcessUtils::escapeArgument(ARTISAN_BINARY) : 'artisan';
return ProcessUtils::escapeArgument(defined('ARTISAN_BINARY') ? ARTISAN_BINARY : 'artisan');
}
/**

View File

@@ -2,22 +2,17 @@
namespace Illuminate\Console;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Support\Arrayable;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Command\Command as SymfonyCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Command\Command as SymfonyCommand;
class Command extends SymfonyCommand
{
use Macroable;
use Concerns\CallsCommands,
Concerns\HasParameters,
Concerns\InteractsWithIO,
Macroable;
/**
* The Laravel application instance.
@@ -26,20 +21,6 @@ class Command extends SymfonyCommand
*/
protected $laravel;
/**
* The input interface implementation.
*
* @var \Symfony\Component\Console\Input\InputInterface
*/
protected $input;
/**
* The output interface implementation.
*
* @var \Illuminate\Console\OutputStyle
*/
protected $output;
/**
* The name and signature of the console command.
*
@@ -57,10 +38,17 @@ class Command extends SymfonyCommand
/**
* The console command description.
*
* @var string
* @var string|null
*/
protected $description;
/**
* The console command help text.
*
* @var string|null
*/
protected $help;
/**
* Indicates whether the command should be shown in the Artisan command list.
*
@@ -68,26 +56,6 @@ class Command extends SymfonyCommand
*/
protected $hidden = false;
/**
* The default verbosity of output commands.
*
* @var int
*/
protected $verbosity = OutputInterface::VERBOSITY_NORMAL;
/**
* The mapping between human readable verbosity levels and Symfony's OutputInterface.
*
* @var array
*/
protected $verbosityMap = [
'v' => OutputInterface::VERBOSITY_VERBOSE,
'vv' => OutputInterface::VERBOSITY_VERY_VERBOSE,
'vvv' => OutputInterface::VERBOSITY_DEBUG,
'quiet' => OutputInterface::VERBOSITY_QUIET,
'normal' => OutputInterface::VERBOSITY_NORMAL,
];
/**
* Create a new console command instance.
*
@@ -107,7 +75,9 @@ class Command extends SymfonyCommand
// Once we have constructed the command, we'll set the description and other
// related properties of the command. If a signature wasn't used to build
// the command we'll set the arguments and the options on this command.
$this->setDescription($this->description);
$this->setDescription((string) $this->description);
$this->setHelp((string) $this->help);
$this->setHidden($this->isHidden());
@@ -134,25 +104,6 @@ class Command extends SymfonyCommand
$this->getDefinition()->addOptions($options);
}
/**
* Specify the arguments and options on the command.
*
* @return void
*/
protected function specifyParameters()
{
// We will loop through all of the arguments and options for the command and
// set them all on the base command instance. This specifies what can get
// passed into these commands as "parameters" to control the execution.
foreach ($this->getArguments() as $arguments) {
call_user_func_array([$this, 'addArgument'], $arguments);
}
foreach ($this->getOptions() as $options) {
call_user_func_array([$this, 'addOption'], $options);
}
}
/**
* Run the console command.
*
@@ -184,381 +135,28 @@ class Command extends SymfonyCommand
}
/**
* Call another console command.
* Resolve the console command instance for the given command.
*
* @param string $command
* @param array $arguments
* @return int
* @param \Symfony\Component\Console\Command\Command|string $command
* @return \Symfony\Component\Console\Command\Command
*/
public function call($command, array $arguments = [])
protected function resolveCommand($command)
{
$arguments['command'] = $command;
return $this->getApplication()->find($command)->run(
$this->createInputFromArguments($arguments), $this->output
);
}
/**
* Call another console command silently.
*
* @param string $command
* @param array $arguments
* @return int
*/
public function callSilent($command, array $arguments = [])
{
$arguments['command'] = $command;
return $this->getApplication()->find($command)->run(
$this->createInputFromArguments($arguments), new NullOutput
);
}
/**
* Create an input instance from the given arguments.
*
* @param array $arguments
* @return \Symfony\Component\Console\Input\ArrayInput
*/
protected function createInputFromArguments(array $arguments)
{
return tap(new ArrayInput(array_merge($this->context(), $arguments)), function ($input) {
if ($input->hasParameterOption(['--no-interaction'], true)) {
$input->setInteractive(false);
}
});
}
/**
* Get all of the context passed to the command.
*
* @return array
*/
protected function context()
{
return collect($this->option())->only([
'ansi',
'no-ansi',
'no-interaction',
'quiet',
'verbose',
])->filter()->mapWithKeys(function ($value, $key) {
return ["--{$key}" => $value];
})->all();
}
/**
* Determine if the given argument is present.
*
* @param string|int $name
* @return bool
*/
public function hasArgument($name)
{
return $this->input->hasArgument($name);
}
/**
* Get the value of a command argument.
*
* @param string|null $key
* @return string|array|null
*/
public function argument($key = null)
{
if (is_null($key)) {
return $this->input->getArguments();
if (! class_exists($command)) {
return $this->getApplication()->find($command);
}
return $this->input->getArgument($key);
}
$command = $this->laravel->make($command);
/**
* Get all of the arguments passed to the command.
*
* @return array
*/
public function arguments()
{
return $this->argument();
}
/**
* Determine if the given option is present.
*
* @param string $name
* @return bool
*/
public function hasOption($name)
{
return $this->input->hasOption($name);
}
/**
* Get the value of a command option.
*
* @param string|null $key
* @return string|array|bool|null
*/
public function option($key = null)
{
if (is_null($key)) {
return $this->input->getOptions();
if ($command instanceof SymfonyCommand) {
$command->setApplication($this->getApplication());
}
return $this->input->getOption($key);
}
/**
* Get all of the options passed to the command.
*
* @return array
*/
public function options()
{
return $this->option();
}
/**
* Confirm a question with the user.
*
* @param string $question
* @param bool $default
* @return bool
*/
public function confirm($question, $default = false)
{
return $this->output->confirm($question, $default);
}
/**
* Prompt the user for input.
*
* @param string $question
* @param string|null $default
* @return mixed
*/
public function ask($question, $default = null)
{
return $this->output->ask($question, $default);
}
/**
* Prompt the user for input with auto completion.
*
* @param string $question
* @param array $choices
* @param string|null $default
* @return mixed
*/
public function anticipate($question, array $choices, $default = null)
{
return $this->askWithCompletion($question, $choices, $default);
}
/**
* Prompt the user for input with auto completion.
*
* @param string $question
* @param array $choices
* @param string|null $default
* @return mixed
*/
public function askWithCompletion($question, array $choices, $default = null)
{
$question = new Question($question, $default);
$question->setAutocompleterValues($choices);
return $this->output->askQuestion($question);
}
/**
* Prompt the user for input but hide the answer from the console.
*
* @param string $question
* @param bool $fallback
* @return mixed
*/
public function secret($question, $fallback = true)
{
$question = new Question($question);
$question->setHidden(true)->setHiddenFallback($fallback);
return $this->output->askQuestion($question);
}
/**
* Give the user a single choice from an array of answers.
*
* @param string $question
* @param array $choices
* @param string|null $default
* @param mixed|null $attempts
* @param bool|null $multiple
* @return string
*/
public function choice($question, array $choices, $default = null, $attempts = null, $multiple = null)
{
$question = new ChoiceQuestion($question, $choices, $default);
$question->setMaxAttempts($attempts)->setMultiselect($multiple);
return $this->output->askQuestion($question);
}
/**
* Format input to textual table.
*
* @param array $headers
* @param \Illuminate\Contracts\Support\Arrayable|array $rows
* @param string $tableStyle
* @param array $columnStyles
* @return void
*/
public function table($headers, $rows, $tableStyle = 'default', array $columnStyles = [])
{
$table = new Table($this->output);
if ($rows instanceof Arrayable) {
$rows = $rows->toArray();
if ($command instanceof self) {
$command->setLaravel($this->getLaravel());
}
$table->setHeaders((array) $headers)->setRows($rows)->setStyle($tableStyle);
foreach ($columnStyles as $columnIndex => $columnStyle) {
$table->setColumnStyle($columnIndex, $columnStyle);
}
$table->render();
}
/**
* Write a string as information output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function info($string, $verbosity = null)
{
$this->line($string, 'info', $verbosity);
}
/**
* Write a string as standard output.
*
* @param string $string
* @param string|null $style
* @param int|string|null $verbosity
* @return void
*/
public function line($string, $style = null, $verbosity = null)
{
$styled = $style ? "<$style>$string</$style>" : $string;
$this->output->writeln($styled, $this->parseVerbosity($verbosity));
}
/**
* Write a string as comment output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function comment($string, $verbosity = null)
{
$this->line($string, 'comment', $verbosity);
}
/**
* Write a string as question output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function question($string, $verbosity = null)
{
$this->line($string, 'question', $verbosity);
}
/**
* Write a string as error output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function error($string, $verbosity = null)
{
$this->line($string, 'error', $verbosity);
}
/**
* Write a string as warning output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function warn($string, $verbosity = null)
{
if (! $this->output->getFormatter()->hasStyle('warning')) {
$style = new OutputFormatterStyle('yellow');
$this->output->getFormatter()->setStyle('warning', $style);
}
$this->line($string, 'warning', $verbosity);
}
/**
* Write a string in an alert box.
*
* @param string $string
* @return void
*/
public function alert($string)
{
$length = Str::length(strip_tags($string)) + 12;
$this->comment(str_repeat('*', $length));
$this->comment('* '.$string.' *');
$this->comment(str_repeat('*', $length));
$this->output->newLine();
}
/**
* Set the verbosity level.
*
* @param string|int $level
* @return void
*/
protected function setVerbosity($level)
{
$this->verbosity = $this->parseVerbosity($level);
}
/**
* Get the verbosity level in terms of Symfony's OutputInterface level.
*
* @param string|int|null $level
* @return int
*/
protected function parseVerbosity($level = null)
{
if (isset($this->verbosityMap[$level])) {
$level = $this->verbosityMap[$level];
} elseif (! is_int($level)) {
$level = $this->verbosity;
}
return $level;
return $command;
}
/**
@@ -579,36 +177,6 @@ class Command extends SymfonyCommand
return $this;
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [];
}
/**
* Get the output implementation.
*
* @return \Illuminate\Console\OutputStyle
*/
public function getOutput()
{
return $this->output;
}
/**
* Get the Laravel application instance.
*

View File

@@ -0,0 +1,92 @@
<?php
namespace Illuminate\Console\Concerns;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;
trait CallsCommands
{
/**
* Resolve the console command instance for the given command.
*
* @param \Symfony\Component\Console\Command\Command|string $command
* @return \Symfony\Component\Console\Command\Command
*/
abstract protected function resolveCommand($command);
/**
* Call another console command.
*
* @param \Symfony\Component\Console\Command\Command|string $command
* @param array $arguments
* @return int
*/
public function call($command, array $arguments = [])
{
return $this->runCommand($command, $arguments, $this->output);
}
/**
* Call another console command silently.
*
* @param \Symfony\Component\Console\Command\Command|string $command
* @param array $arguments
* @return int
*/
public function callSilent($command, array $arguments = [])
{
return $this->runCommand($command, $arguments, new NullOutput);
}
/**
* Run the given the console command.
*
* @param \Symfony\Component\Console\Command\Command|string $command
* @param array $arguments
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return int
*/
protected function runCommand($command, array $arguments, OutputInterface $output)
{
$arguments['command'] = $command;
return $this->resolveCommand($command)->run(
$this->createInputFromArguments($arguments), $output
);
}
/**
* Create an input instance from the given arguments.
*
* @param array $arguments
* @return \Symfony\Component\Console\Input\ArrayInput
*/
protected function createInputFromArguments(array $arguments)
{
return tap(new ArrayInput(array_merge($this->context(), $arguments)), function ($input) {
if ($input->getParameterOption('--no-interaction')) {
$input->setInteractive(false);
}
});
}
/**
* Get all of the context passed to the command.
*
* @return array
*/
protected function context()
{
return collect($this->option())->only([
'ansi',
'no-ansi',
'no-interaction',
'quiet',
'verbose',
])->filter()->mapWithKeys(function ($value, $key) {
return ["--{$key}" => $value];
})->all();
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Illuminate\Console\Concerns;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
trait HasParameters
{
/**
* Specify the arguments and options on the command.
*
* @return void
*/
protected function specifyParameters()
{
// We will loop through all of the arguments and options for the command and
// set them all on the base command instance. This specifies what can get
// passed into these commands as "parameters" to control the execution.
foreach ($this->getArguments() as $arguments) {
if ($arguments instanceof InputArgument) {
$this->getDefinition()->addArgument($arguments);
} else {
$this->addArgument(...array_values($arguments));
}
}
foreach ($this->getOptions() as $options) {
if ($options instanceof InputOption) {
$this->getDefinition()->addOption($options);
} else {
$this->addOption(...array_values($options));
}
}
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [];
}
}

View File

@@ -0,0 +1,397 @@
<?php
namespace Illuminate\Console\Concerns;
use Illuminate\Console\OutputStyle;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Str;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
trait InteractsWithIO
{
/**
* The input interface implementation.
*
* @var \Symfony\Component\Console\Input\InputInterface
*/
protected $input;
/**
* The output interface implementation.
*
* @var \Illuminate\Console\OutputStyle
*/
protected $output;
/**
* The default verbosity of output commands.
*
* @var int
*/
protected $verbosity = OutputInterface::VERBOSITY_NORMAL;
/**
* The mapping between human readable verbosity levels and Symfony's OutputInterface.
*
* @var array
*/
protected $verbosityMap = [
'v' => OutputInterface::VERBOSITY_VERBOSE,
'vv' => OutputInterface::VERBOSITY_VERY_VERBOSE,
'vvv' => OutputInterface::VERBOSITY_DEBUG,
'quiet' => OutputInterface::VERBOSITY_QUIET,
'normal' => OutputInterface::VERBOSITY_NORMAL,
];
/**
* Determine if the given argument is present.
*
* @param string|int $name
* @return bool
*/
public function hasArgument($name)
{
return $this->input->hasArgument($name);
}
/**
* Get the value of a command argument.
*
* @param string|null $key
* @return string|array|null
*/
public function argument($key = null)
{
if (is_null($key)) {
return $this->input->getArguments();
}
return $this->input->getArgument($key);
}
/**
* Get all of the arguments passed to the command.
*
* @return array
*/
public function arguments()
{
return $this->argument();
}
/**
* Determine if the given option is present.
*
* @param string $name
* @return bool
*/
public function hasOption($name)
{
return $this->input->hasOption($name);
}
/**
* Get the value of a command option.
*
* @param string|null $key
* @return string|array|bool|null
*/
public function option($key = null)
{
if (is_null($key)) {
return $this->input->getOptions();
}
return $this->input->getOption($key);
}
/**
* Get all of the options passed to the command.
*
* @return array
*/
public function options()
{
return $this->option();
}
/**
* Confirm a question with the user.
*
* @param string $question
* @param bool $default
* @return bool
*/
public function confirm($question, $default = false)
{
return $this->output->confirm($question, $default);
}
/**
* Prompt the user for input.
*
* @param string $question
* @param string|null $default
* @return mixed
*/
public function ask($question, $default = null)
{
return $this->output->ask($question, $default);
}
/**
* Prompt the user for input with auto completion.
*
* @param string $question
* @param array|callable $choices
* @param string|null $default
* @return mixed
*/
public function anticipate($question, $choices, $default = null)
{
return $this->askWithCompletion($question, $choices, $default);
}
/**
* Prompt the user for input with auto completion.
*
* @param string $question
* @param array|callable $choices
* @param string|null $default
* @return mixed
*/
public function askWithCompletion($question, $choices, $default = null)
{
$question = new Question($question, $default);
is_callable($choices)
? $question->setAutocompleterCallback($choices)
: $question->setAutocompleterValues($choices);
return $this->output->askQuestion($question);
}
/**
* Prompt the user for input but hide the answer from the console.
*
* @param string $question
* @param bool $fallback
* @return mixed
*/
public function secret($question, $fallback = true)
{
$question = new Question($question);
$question->setHidden(true)->setHiddenFallback($fallback);
return $this->output->askQuestion($question);
}
/**
* Give the user a single choice from an array of answers.
*
* @param string $question
* @param array $choices
* @param string|null $default
* @param mixed|null $attempts
* @param bool|null $multiple
* @return string
*/
public function choice($question, array $choices, $default = null, $attempts = null, $multiple = null)
{
$question = new ChoiceQuestion($question, $choices, $default);
$question->setMaxAttempts($attempts)->setMultiselect($multiple);
return $this->output->askQuestion($question);
}
/**
* Format input to textual table.
*
* @param array $headers
* @param \Illuminate\Contracts\Support\Arrayable|array $rows
* @param string $tableStyle
* @param array $columnStyles
* @return void
*/
public function table($headers, $rows, $tableStyle = 'default', array $columnStyles = [])
{
$table = new Table($this->output);
if ($rows instanceof Arrayable) {
$rows = $rows->toArray();
}
$table->setHeaders((array) $headers)->setRows($rows)->setStyle($tableStyle);
foreach ($columnStyles as $columnIndex => $columnStyle) {
$table->setColumnStyle($columnIndex, $columnStyle);
}
$table->render();
}
/**
* Write a string as information output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function info($string, $verbosity = null)
{
$this->line($string, 'info', $verbosity);
}
/**
* Write a string as standard output.
*
* @param string $string
* @param string|null $style
* @param int|string|null $verbosity
* @return void
*/
public function line($string, $style = null, $verbosity = null)
{
$styled = $style ? "<$style>$string</$style>" : $string;
$this->output->writeln($styled, $this->parseVerbosity($verbosity));
}
/**
* Write a string as comment output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function comment($string, $verbosity = null)
{
$this->line($string, 'comment', $verbosity);
}
/**
* Write a string as question output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function question($string, $verbosity = null)
{
$this->line($string, 'question', $verbosity);
}
/**
* Write a string as error output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function error($string, $verbosity = null)
{
$this->line($string, 'error', $verbosity);
}
/**
* Write a string as warning output.
*
* @param string $string
* @param int|string|null $verbosity
* @return void
*/
public function warn($string, $verbosity = null)
{
if (! $this->output->getFormatter()->hasStyle('warning')) {
$style = new OutputFormatterStyle('yellow');
$this->output->getFormatter()->setStyle('warning', $style);
}
$this->line($string, 'warning', $verbosity);
}
/**
* Write a string in an alert box.
*
* @param string $string
* @return void
*/
public function alert($string)
{
$length = Str::length(strip_tags($string)) + 12;
$this->comment(str_repeat('*', $length));
$this->comment('* '.$string.' *');
$this->comment(str_repeat('*', $length));
$this->output->newLine();
}
/**
* Set the input interface implementation.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @return void
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
}
/**
* Set the output interface implementation.
*
* @param \Illuminate\Console\OutputStyle $output
* @return void
*/
public function setOutput(OutputStyle $output)
{
$this->output = $output;
}
/**
* Set the verbosity level.
*
* @param string|int $level
* @return void
*/
protected function setVerbosity($level)
{
$this->verbosity = $this->parseVerbosity($level);
}
/**
* Get the verbosity level in terms of Symfony's OutputInterface level.
*
* @param string|int|null $level
* @return int
*/
protected function parseVerbosity($level = null)
{
if (isset($this->verbosityMap[$level])) {
$level = $this->verbosityMap[$level];
} elseif (! is_int($level)) {
$level = $this->verbosity;
}
return $level;
}
/**
* Get the output implementation.
*
* @return \Illuminate\Console\OutputStyle
*/
public function getOutput()
{
return $this->output;
}
}

View File

@@ -2,8 +2,6 @@
namespace Illuminate\Console;
use Closure;
trait ConfirmableTrait
{
/**
@@ -19,7 +17,7 @@ trait ConfirmableTrait
{
$callback = is_null($callback) ? $this->getDefaultConfirmCallback() : $callback;
$shouldConfirm = $callback instanceof Closure ? call_user_func($callback) : $callback;
$shouldConfirm = value($callback);
if ($shouldConfirm) {
if ($this->hasOption('force') && $this->option('force')) {
@@ -31,7 +29,7 @@ trait ConfirmableTrait
$confirmed = $this->confirm('Do you really wish to run this command?');
if (! $confirmed) {
$this->comment('Command Cancelled!');
$this->comment('Command Canceled!');
return false;
}

View File

@@ -4,6 +4,9 @@ namespace Illuminate\Console;
use Illuminate\Container\Container;
/**
* @deprecated Usage of this trait is deprecated and it will be removed in Laravel 7.0.
*/
trait DetectsApplicationNamespace
{
/**

View File

@@ -0,0 +1,35 @@
<?php
namespace Illuminate\Console\Events;
use Illuminate\Console\Scheduling\Event;
class ScheduledTaskFinished
{
/**
* The scheduled event that ran.
*
* @var \Illuminate\Console\Scheduling\Event
*/
public $task;
/**
* The runtime of the scheduled event.
*
* @var float
*/
public $runtime;
/**
* Create a new event instance.
*
* @param \Illuminate\Console\Scheduling\Event $task
* @param float $runtime
* @return void
*/
public function __construct(Event $task, $runtime)
{
$this->task = $task;
$this->runtime = $runtime;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Illuminate\Console\Events;
use Illuminate\Console\Scheduling\Event;
class ScheduledTaskSkipped
{
/**
* The scheduled event being run.
*
* @var \Illuminate\Console\Scheduling\Event
*/
public $task;
/**
* Create a new event instance.
*
* @param \Illuminate\Console\Scheduling\Event $task
* @return void
*/
public function __construct(Event $task)
{
$this->task = $task;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Illuminate\Console\Events;
use Illuminate\Console\Scheduling\Event;
class ScheduledTaskStarting
{
/**
* The scheduled event being run.
*
* @var \Illuminate\Console\Scheduling\Event
*/
public $task;
/**
* Create a new event instance.
*
* @param \Illuminate\Console\Scheduling\Event $task
* @return void
*/
public function __construct(Event $task)
{
$this->task = $task;
}
}

View File

@@ -2,8 +2,8 @@
namespace Illuminate\Console;
use Illuminate\Support\Str;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputArgument;
abstract class GeneratorCommand extends Command
@@ -46,6 +46,7 @@ abstract class GeneratorCommand extends Command
* Execute the console command.
*
* @return bool|null
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function handle()
@@ -70,7 +71,7 @@ abstract class GeneratorCommand extends Command
// stub files so that it gets the correctly formatted namespace and class name.
$this->makeDirectory($path);
$this->files->put($path, $this->buildClass($name));
$this->files->put($path, $this->sortImports($this->buildClass($name)));
$this->info($this->type.' created successfully.');
}
@@ -153,6 +154,7 @@ abstract class GeneratorCommand extends Command
*
* @param string $name
* @return string
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function buildClass($name)
@@ -205,6 +207,25 @@ abstract class GeneratorCommand extends Command
return str_replace('DummyClass', $class, $stub);
}
/**
* Alphabetically sorts the imports for the given stub.
*
* @param string $stub
* @return string
*/
protected function sortImports($stub)
{
if (preg_match('/(?P<imports>(?:use [^;]+;$\n?)+)/m', $stub, $match)) {
$imports = explode("\n", trim($match['imports']));
sort($imports);
return str_replace(trim($match['imports']), implode("\n", $imports), $stub);
}
return $stub;
}
/**
* Get the desired class name from the input.
*
@@ -232,11 +253,11 @@ abstract class GeneratorCommand extends Command
*/
protected function userProviderModel()
{
$guard = config('auth.defaults.guard');
$config = $this->laravel['config'];
$provider = config("auth.guards.{$guard}.provider");
$provider = $config->get('auth.guards.'.$config->get('auth.defaults.guard').'.provider');
return config("auth.providers.{$provider}.model");
return $config->get("auth.providers.{$provider}.model");
}
/**

View File

@@ -2,9 +2,9 @@
namespace Illuminate\Console;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class OutputStyle extends SymfonyStyle
{

View File

@@ -4,8 +4,8 @@ namespace Illuminate\Console;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class Parser
{
@@ -40,10 +40,6 @@ class Parser
*/
protected static function name($expression)
{
if (trim($expression) === '') {
throw new InvalidArgumentException('Console command definition is empty.');
}
if (! preg_match('/[^\s]+/', $expression, $matches)) {
throw new InvalidArgumentException('Unable to determine command name from signature.');
}

View File

@@ -2,9 +2,10 @@
namespace Illuminate\Console\Scheduling;
use LogicException;
use InvalidArgumentException;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Reflector;
use InvalidArgumentException;
use LogicException;
class CallbackEvent extends Event
{
@@ -28,13 +29,14 @@ class CallbackEvent extends Event
* @param \Illuminate\Console\Scheduling\EventMutex $mutex
* @param string $callback
* @param array $parameters
* @param \DateTimeZone|string|null $timezone
* @return void
*
* @throws \InvalidArgumentException
*/
public function __construct(EventMutex $mutex, $callback, array $parameters = [])
public function __construct(EventMutex $mutex, $callback, array $parameters = [], $timezone = null)
{
if (! is_string($callback) && ! is_callable($callback)) {
if (! is_string($callback) && ! Reflector::isCallable($callback)) {
throw new InvalidArgumentException(
'Invalid scheduled callback event. Must be a string or callable.'
);
@@ -43,6 +45,7 @@ class CallbackEvent extends Event
$this->mutex = $mutex;
$this->callback = $callback;
$this->parameters = $parameters;
$this->timezone = $timezone;
}
/**
@@ -161,6 +164,6 @@ class CallbackEvent extends Event
return $this->description;
}
return is_string($this->callback) ? $this->callback : 'Closure';
return is_string($this->callback) ? $this->callback : 'Callback';
}
}

View File

@@ -51,8 +51,12 @@ class CommandBuilder
$finished = Application::formatCommandString('schedule:finish').' "'.$event->mutexName().'"';
if (windows_os()) {
return 'start /b cmd /c "('.$event->command.' & '.$finished.' "%errorlevel%")'.$redirect.$output.' 2>&1"';
}
return $this->ensureCorrectUser($event,
'('.$event->command.$redirect.$output.' 2>&1 '.(windows_os() ? '&' : ';').' '.$finished.') > '
'('.$event->command.$redirect.$output.' 2>&1 ; '.$finished.' "$?") > '
.ProcessUtils::escapeArgument($event->getDefaultOutput()).' 2>&1 &'
);
}

View File

@@ -4,14 +4,17 @@ namespace Illuminate\Console\Scheduling;
use Closure;
use Cron\CronExpression;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use GuzzleHttp\Client as HttpClient;
use Illuminate\Support\Facades\Date;
use Illuminate\Contracts\Mail\Mailer;
use Symfony\Component\Process\Process;
use Illuminate\Support\Traits\Macroable;
use GuzzleHttp\Exception\TransferException;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Reflector;
use Illuminate\Support\Traits\Macroable;
use Psr\Http\Client\ClientExceptionInterface;
use Symfony\Component\Process\Process;
class Event
{
@@ -155,7 +158,7 @@ class Event
*
* @param \Illuminate\Console\Scheduling\EventMutex $mutex
* @param string $command
* @param \DateTimeZone|string|null $timezone
* @param \DateTimeZone|string|null $timezone
* @return void
*/
public function __construct(EventMutex $mutex, $command, $timezone = null)
@@ -259,6 +262,20 @@ class Event
}
}
/**
* Call all of the "after" callbacks for the event.
*
* @param \Illuminate\Contracts\Container\Container $container
* @param int $exitCode
* @return void
*/
public function callAfterCallbacksWithExitCode(Container $container, $exitCode)
{
$this->exitCode = (int) $exitCode;
$this->callAfterCallbacks($container);
}
/**
* Build the command string.
*
@@ -302,10 +319,10 @@ class Event
*/
protected function expressionPasses()
{
$date = Carbon::now();
$date = Date::now();
if ($this->timezone) {
$date->setTimezone($this->timezone);
$date = $date->setTimezone($this->timezone);
}
return CronExpression::factory($this->expression)->isDue($date->toDateTimeString());
@@ -489,9 +506,7 @@ class Event
*/
public function pingBefore($url)
{
return $this->before(function () use ($url) {
(new HttpClient)->get($url);
});
return $this->before($this->pingCallback($url));
}
/**
@@ -514,9 +529,7 @@ class Event
*/
public function thenPing($url)
{
return $this->then(function () use ($url) {
(new HttpClient)->get($url);
});
return $this->then($this->pingCallback($url));
}
/**
@@ -539,9 +552,7 @@ class Event
*/
public function pingOnSuccess($url)
{
return $this->onSuccess(function () use ($url) {
(new HttpClient)->get($url);
});
return $this->onSuccess($this->pingCallback($url));
}
/**
@@ -552,9 +563,24 @@ class Event
*/
public function pingOnFailure($url)
{
return $this->onFailure(function () use ($url) {
(new HttpClient)->get($url);
});
return $this->onFailure($this->pingCallback($url));
}
/**
* Get the callback that pings the given URL.
*
* @param string $url
* @return \Closure
*/
protected function pingCallback($url)
{
return function (Container $container, HttpClient $http) use ($url) {
try {
$http->get($url);
} catch (ClientExceptionInterface|TransferException $e) {
$container->make(ExceptionHandler::class)->report($e);
}
};
}
/**
@@ -646,7 +672,7 @@ class Event
*/
public function when($callback)
{
$this->filters[] = is_callable($callback) ? $callback : function () use ($callback) {
$this->filters[] = Reflector::isCallable($callback) ? $callback : function () use ($callback) {
return $callback;
};
@@ -661,7 +687,7 @@ class Event
*/
public function skip($callback)
{
$this->rejects[] = is_callable($callback) ? $callback : function () use ($callback) {
$this->rejects[] = Reflector::isCallable($callback) ? $callback : function () use ($callback) {
return $callback;
};

View File

@@ -52,12 +52,22 @@ trait ManagesFrequencies
*/
private function inTimeInterval($startTime, $endTime)
{
return function () use ($startTime, $endTime) {
return Carbon::now($this->timezone)->between(
Carbon::parse($startTime, $this->timezone),
Carbon::parse($endTime, $this->timezone),
true
);
[$now, $startTime, $endTime] = [
Carbon::now($this->timezone),
Carbon::parse($startTime, $this->timezone),
Carbon::parse($endTime, $this->timezone),
];
if ($endTime->lessThan($startTime)) {
if ($startTime->greaterThan($now)) {
$startTime->subDay(1);
} else {
$endTime->addDay(1);
}
}
return function () use ($now, $startTime, $endTime) {
return $now->between($startTime, $endTime);
};
}

View File

@@ -2,14 +2,23 @@
namespace Illuminate\Console\Scheduling;
use Closure;
use DateTimeInterface;
use Illuminate\Console\Application;
use Illuminate\Container\Container;
use Illuminate\Support\ProcessUtils;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\CallQueuedClosure;
use Illuminate\Support\ProcessUtils;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
use RuntimeException;
class Schedule
{
use Macroable;
/**
* All of the events on the schedule.
*
@@ -38,6 +47,13 @@ class Schedule
*/
protected $timezone;
/**
* The job dispatcher implementation.
*
* @var \Illuminate\Contracts\Bus\Dispatcher
*/
protected $dispatcher;
/**
* Create a new schedule instance.
*
@@ -48,6 +64,12 @@ class Schedule
{
$this->timezone = $timezone;
if (! class_exists(Container::class)) {
throw new RuntimeException(
'A container implementation is required to use the scheduler. Please install the illuminate/container package.'
);
}
$container = Container::getInstance();
$this->eventMutex = $container->bound(EventMutex::class)
@@ -69,7 +91,7 @@ class Schedule
public function call($callback, array $parameters = [])
{
$this->events[] = $event = new CallbackEvent(
$this->eventMutex, $callback, $parameters
$this->eventMutex, $callback, $parameters, $this->timezone
);
return $event;
@@ -104,18 +126,52 @@ class Schedule
public function job($job, $queue = null, $connection = null)
{
return $this->call(function () use ($job, $queue, $connection) {
$job = is_string($job) ? resolve($job) : $job;
$job = is_string($job) ? Container::getInstance()->make($job) : $job;
if ($job instanceof ShouldQueue) {
dispatch($job)
->onConnection($connection ?? $job->connection)
->onQueue($queue ?? $job->queue);
$this->dispatchToQueue($job, $queue ?? $job->queue, $connection ?? $job->connection);
} else {
dispatch_now($job);
$this->dispatchNow($job);
}
})->name(is_string($job) ? $job : get_class($job));
}
/**
* Dispatch the given job to the queue.
*
* @param object $job
* @param string|null $queue
* @param string|null $connection
* @return void
*/
protected function dispatchToQueue($job, $queue, $connection)
{
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);
}
$this->getDispatcher()->dispatch(
$job->onConnection($connection)->onQueue($queue)
);
}
/**
* Dispatch the given job right now.
*
* @param object $job
* @return void
*/
protected function dispatchNow($job)
{
$this->getDispatcher()->dispatchNow($job);
}
/**
* Add a new command event to the schedule.
*
@@ -144,10 +200,10 @@ class Schedule
{
return collect($parameters)->map(function ($value, $key) {
if (is_array($value)) {
$value = collect($value)->map(function ($value) {
return ProcessUtils::escapeArgument($value);
})->implode(' ');
} elseif (! is_numeric($value) && ! preg_match('/^(-.$|--.*)/i', $value)) {
return $this->compileArrayInput($key, $value);
}
if (! is_numeric($value) && ! preg_match('/^(-.$|--.*)/i', $value)) {
$value = ProcessUtils::escapeArgument($value);
}
@@ -155,6 +211,32 @@ class Schedule
})->implode(' ');
}
/**
* Compile array input for a command.
*
* @param string|int $key
* @param array $value
* @return string
*/
public function compileArrayInput($key, $value)
{
$value = collect($value)->map(function ($value) {
return ProcessUtils::escapeArgument($value);
});
if (Str::startsWith($key, '--')) {
$value = $value->map(function ($value) use ($key) {
return "{$key}={$value}";
});
} elseif (Str::startsWith($key, '-')) {
$value = $value->map(function ($value) use ($key) {
return "{$key} {$value}";
});
}
return $value->implode(' ');
}
/**
* Determine if the server is allowed to run this event.
*
@@ -206,4 +288,25 @@ class Schedule
return $this;
}
/**
* Get the job dispatcher, if available.
*
* @return \Illuminate\Contracts\Bus\Dispatcher
*/
protected function getDispatcher()
{
if ($this->dispatcher === null) {
try {
$this->dispatcher = Container::getInstance()->make(Dispatcher::class);
} catch (BindingResolutionException $e) {
throw new RuntimeException(
'Unable to resolve the dispatcher from the service container. Please bind it or install the illuminate/bus package.',
$e->getCode(), $e
);
}
}
return $this->dispatcher;
}
}

View File

@@ -11,7 +11,7 @@ class ScheduleFinishCommand extends Command
*
* @var string
*/
protected $signature = 'schedule:finish {id}';
protected $signature = 'schedule:finish {id} {code=0}';
/**
* The console command description.
@@ -28,34 +28,15 @@ class ScheduleFinishCommand extends Command
protected $hidden = true;
/**
* The schedule instance.
*
* @var \Illuminate\Console\Scheduling\Schedule
*/
protected $schedule;
/**
* Create a new command instance.
* Execute the console command.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
public function __construct(Schedule $schedule)
public function handle(Schedule $schedule)
{
$this->schedule = $schedule;
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
collect($this->schedule->events())->filter(function ($value) {
collect($schedule->events())->filter(function ($value) {
return $value->mutexName() == $this->argument('id');
})->each->callAfterCallbacks($this->laravel);
})->each->callAfterCallbacksWithExitCode($this->laravel, $this->argument('code'));
}
}

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