(Grav GitSync) Automatic Commit from dan

This commit is contained in:
dan 2024-04-14 02:40:14 +02:00 committed by GitSync
parent 2cdb70496d
commit 90cd548737
222 changed files with 2289 additions and 6168 deletions

View File

@ -1,3 +1,10 @@
# v4.1.0
## 04/09/2024
1. [](#improved)
* Update vendor libraries for Mailer to latest `5.4` versions
* When you send an email you can use `Email::getLastSendMessage()` and `Email::getLastSendDebug()` methods to get information about the email processing.
# v4.0.4
## 07/10/2023

View File

@ -1,7 +1,7 @@
name: Email
slug: email
type: plugin
version: 4.0.4
version: 4.1.0
testing: false
description: Enables the emailing system for Grav
icon: envelope

View File

@ -31,6 +31,9 @@ class Email
protected $log;
protected $message;
protected $debug;
public function __construct()
{
$this->initMailer();
@ -82,35 +85,31 @@ class Email
/**
* Send email.
*
* @param Message $message
* @param Envelope|null $envelope
* @param Message $message
* @param Envelope|null $envelope
* @return int
*/
public function send(Message $message, Envelope $envelope = null): int
{
$status = '🛑 ';
$sent_msg = null;
$debug = null;
try {
$sent_msg = $this->transport->send($message->getEmail(), $envelope);
$return = 1;
$status = '✅';
$debug = $sent_msg->getDebug();
$status = 1;
$this->message = '✅';
$this->debug = $sent_msg->getDebug();
} catch (TransportExceptionInterface $e) {
$return = 0;
$status .= $e->getMessage();
$debug = $e->getDebug();
$status = 0;
$this->message = '🛑 ' . $e->getMessage();
$this->debug = $e->getDebug();
}
if ($this->debug()) {
$log_msg = "Email sent to %s at %s -> %s\n%s";
$to = $this->jsonifyRecipients($message->getEmail()->getTo());
$msg = sprintf($log_msg, $to, date('Y-m-d H:i:s'), $status, $debug);
$this->log->addInfo($msg);
$message = sprintf($log_msg, $to, date('Y-m-d H:i:s'), $this->message, $this->debug);
$this->log->addInfo($message);
}
return $return;
return $status;
}
/**
@ -453,6 +452,24 @@ class Email
return $transport;
}
/**
* Get any message from the last send attempt
* @return string|null
*/
public function getLastSendMessage(): ?string
{
return $this->message;
}
/**
* Get any debug information from the last send attempt
* @return string|null
*/
public function getLastSendDebug(): ?string
{
return $this->debug;
}
/**
* @param array $recipients
* @return string

View File

@ -7,32 +7,81 @@
"content-hash": "af2cff88b1d472f0931ba2c86fcdddc9",
"packages": [
{
"name": "doctrine/lexer",
"version": "1.2.3",
"name": "doctrine/deprecations",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229"
"url": "https://github.com/doctrine/deprecations.git",
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229",
"reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9.0",
"phpstan/phpstan": "^1.3",
"doctrine/coding-standard": "^9",
"phpstan/phpstan": "1.4.10 || 1.10.15",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"vimeo/psalm": "^4.11"
"psalm/plugin-phpunit": "0.18.4",
"psr/log": "^1 || ^2 || ^3",
"vimeo/psalm": "4.30.0 || 5.12.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.3"
},
"time": "2024-01-30T19:34:25+00:00"
},
{
"name": "doctrine/lexer",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6",
"reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9 || ^12",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
"psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^4.11 || ^5.21"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Lexer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -64,7 +113,7 @@
],
"support": {
"issues": "https://github.com/doctrine/lexer/issues",
"source": "https://github.com/doctrine/lexer/tree/1.2.3"
"source": "https://github.com/doctrine/lexer/tree/2.1.1"
},
"funding": [
{
@ -80,29 +129,28 @@
"type": "tidelift"
}
],
"time": "2022-02-28T11:07:21+00:00"
"time": "2024-02-05T11:35:39+00:00"
},
{
"name": "egulias/email-validator",
"version": "3.2.1",
"version": "3.2.6",
"source": {
"type": "git",
"url": "https://github.com/egulias/EmailValidator.git",
"reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715"
"reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/f88dcf4b14af14a98ad96b14b2b317969eab6715",
"reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7",
"reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7",
"shasum": ""
},
"require": {
"doctrine/lexer": "^1.2",
"doctrine/lexer": "^1.2|^2",
"php": ">=7.2",
"symfony/polyfill-intl-idn": "^1.15"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^8.5.8|^9.3.3",
"vimeo/psalm": "^4"
},
@ -140,7 +188,7 @@
],
"support": {
"issues": "https://github.com/egulias/EmailValidator/issues",
"source": "https://github.com/egulias/EmailValidator/tree/3.2.1"
"source": "https://github.com/egulias/EmailValidator/tree/3.2.6"
},
"funding": [
{
@ -148,7 +196,7 @@
"type": "github"
}
],
"time": "2022-06-18T20:57:19+00:00"
"time": "2023-06-01T07:04:22+00:00"
},
{
"name": "psr/container",
@ -300,16 +348,16 @@
},
{
"name": "symfony/amqp-messenger",
"version": "v5.4.13",
"version": "v5.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/amqp-messenger.git",
"reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521"
"reference": "456958ef89fffddc3935f3954a7eac255a5adb21"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/def93f2a7841cfa1a4a1fa487b84054d0d53e521",
"reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521",
"url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/456958ef89fffddc3935f3954a7eac255a5adb21",
"reference": "456958ef89fffddc3935f3954a7eac255a5adb21",
"shasum": ""
},
"require": {
@ -349,7 +397,7 @@
"description": "Symfony AMQP extension Messenger Bridge",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/amqp-messenger/tree/v5.4.13"
"source": "https://github.com/symfony/amqp-messenger/tree/v5.4.36"
},
"funding": [
{
@ -365,20 +413,20 @@
"type": "tidelift"
}
],
"time": "2022-09-11T09:11:59+00:00"
"time": "2024-02-14T16:15:37+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"version": "v2.5.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
"reference": "80d075412b557d41002320b96a096ca65aa2c98d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d",
"reference": "80d075412b557d41002320b96a096ca65aa2c98d",
"shasum": ""
},
"require": {
@ -416,7 +464,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3"
},
"funding": [
{
@ -432,20 +480,20 @@
"type": "tidelift"
}
],
"time": "2022-01-02T09:53:40+00:00"
"time": "2023-01-24T14:02:46+00:00"
},
{
"name": "symfony/doctrine-messenger",
"version": "v5.4.12",
"version": "v5.4.38",
"source": {
"type": "git",
"url": "https://github.com/symfony/doctrine-messenger.git",
"reference": "7649a80e917b47c5072480a2d763c2422da239d2"
"reference": "0118ae0beaebeb5961ddeedc994454e1ac11f759"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/7649a80e917b47c5072480a2d763c2422da239d2",
"reference": "7649a80e917b47c5072480a2d763c2422da239d2",
"url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/0118ae0beaebeb5961ddeedc994454e1ac11f759",
"reference": "0118ae0beaebeb5961ddeedc994454e1ac11f759",
"shasum": ""
},
"require": {
@ -458,7 +506,7 @@
"doctrine/persistence": "<1.3"
},
"require-dev": {
"doctrine/dbal": "^2.13|^3.0",
"doctrine/dbal": "^2.13|^3|^4",
"doctrine/persistence": "^1.3|^2|^3",
"symfony/property-access": "^4.4|^5.0|^6.0",
"symfony/serializer": "^4.4|^5.0|^6.0"
@ -489,7 +537,7 @@
"description": "Symfony Doctrine Messenger Bridge",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/doctrine-messenger/tree/v5.4.12"
"source": "https://github.com/symfony/doctrine-messenger/tree/v5.4.38"
},
"funding": [
{
@ -505,20 +553,20 @@
"type": "tidelift"
}
],
"time": "2022-08-09T12:54:00+00:00"
"time": "2024-03-17T15:02:26+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v5.4.9",
"version": "v5.4.35",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc"
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
"reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"shasum": ""
},
"require": {
@ -574,7 +622,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9"
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.35"
},
"funding": [
{
@ -590,20 +638,20 @@
"type": "tidelift"
}
],
"time": "2022-05-05T16:45:39+00:00"
"time": "2024-01-23T13:51:25+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v2.5.2",
"version": "v2.5.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
"reference": "540f4c73e87fd0c71ca44a6aa305d024ac68cb73"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/540f4c73e87fd0c71ca44a6aa305d024ac68cb73",
"reference": "540f4c73e87fd0c71ca44a6aa305d024ac68cb73",
"shasum": ""
},
"require": {
@ -653,7 +701,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.3"
},
"funding": [
{
@ -669,24 +717,24 @@
"type": "tidelift"
}
],
"time": "2022-01-02T09:53:40+00:00"
"time": "2024-01-23T13:51:25+00:00"
},
{
"name": "symfony/mailer",
"version": "v5.4.13",
"version": "v5.4.38",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11"
"reference": "1d0ef27f1b19b9a0175a0e130d1df3113e5a130e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11",
"reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11",
"url": "https://api.github.com/repos/symfony/mailer/zipball/1d0ef27f1b19b9a0175a0e130d1df3113e5a130e",
"reference": "1d0ef27f1b19b9a0175a0e130d1df3113e5a130e",
"shasum": ""
},
"require": {
"egulias/email-validator": "^2.1.10|^3",
"egulias/email-validator": "^2.1.10|^3|^4",
"php": ">=7.2.5",
"psr/event-dispatcher": "^1",
"psr/log": "^1|^2|^3",
@ -700,7 +748,7 @@
"symfony/http-kernel": "<4.4"
},
"require-dev": {
"symfony/http-client-contracts": "^1.1|^2|^3",
"symfony/http-client": "^4.4|^5.0|^6.0",
"symfony/messenger": "^4.4|^5.0|^6.0"
},
"type": "library",
@ -729,7 +777,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v5.4.13"
"source": "https://github.com/symfony/mailer/tree/v5.4.38"
},
"funding": [
{
@ -745,20 +793,20 @@
"type": "tidelift"
}
],
"time": "2022-08-29T06:47:07+00:00"
"time": "2024-03-19T10:19:25+00:00"
},
{
"name": "symfony/messenger",
"version": "v5.4.13",
"version": "v5.4.38",
"source": {
"type": "git",
"url": "https://github.com/symfony/messenger.git",
"reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4"
"reference": "a69a4d07e20e4f298a5c030623a1a3328145a889"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/messenger/zipball/8f8d3425991e627902f8288088609a8d8f6c6ea4",
"reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4",
"url": "https://api.github.com/repos/symfony/messenger/zipball/a69a4d07e20e4f298a5c030623a1a3328145a889",
"reference": "a69a4d07e20e4f298a5c030623a1a3328145a889",
"shasum": ""
},
"require": {
@ -819,7 +867,7 @@
"description": "Helps applications send and receive messages to/from other applications or via message queues",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/messenger/tree/v5.4.13"
"source": "https://github.com/symfony/messenger/tree/v5.4.38"
},
"funding": [
{
@ -835,20 +883,20 @@
"type": "tidelift"
}
],
"time": "2022-09-17T07:31:22+00:00"
"time": "2024-03-19T10:19:25+00:00"
},
{
"name": "symfony/mime",
"version": "v5.4.13",
"version": "v5.4.38",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd"
"reference": "82fa6be8a0295a3932df871e88fc8c8d77aa71d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd",
"reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd",
"url": "https://api.github.com/repos/symfony/mime/zipball/82fa6be8a0295a3932df871e88fc8c8d77aa71d4",
"reference": "82fa6be8a0295a3932df871e88fc8c8d77aa71d4",
"shasum": ""
},
"require": {
@ -862,15 +910,17 @@
"egulias/email-validator": "~3.0.0",
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/mailer": "<4.4"
"symfony/mailer": "<4.4",
"symfony/serializer": "<5.4.35|>=6,<6.3.12|>=6.4,<6.4.3"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3.1",
"egulias/email-validator": "^2.1.10|^3.1|^4",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/process": "^5.4|^6.4",
"symfony/property-access": "^4.4|^5.1|^6.0",
"symfony/property-info": "^4.4|^5.1|^6.0",
"symfony/serializer": "^5.2|^6.0"
"symfony/serializer": "^5.4.35|~6.3.12|^6.4.3"
},
"type": "library",
"autoload": {
@ -902,7 +952,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v5.4.13"
"source": "https://github.com/symfony/mime/tree/v5.4.38"
},
"funding": [
{
@ -918,20 +968,20 @@
"type": "tidelift"
}
],
"time": "2022-09-01T18:18:29+00:00"
"time": "2024-03-21T07:25:32+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.26.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919",
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919",
"shasum": ""
},
"require": {
@ -944,9 +994,6 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@ -989,7 +1036,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0"
},
"funding": [
{
@ -1005,20 +1052,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.26.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd"
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"shasum": ""
},
"require": {
@ -1029,9 +1076,6 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@ -1073,7 +1117,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
},
"funding": [
{
@ -1089,20 +1133,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.26.0",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"shasum": ""
},
"require": {
@ -1110,9 +1154,6 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@ -1156,7 +1197,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
},
"funding": [
{
@ -1172,20 +1213,20 @@
"type": "tidelift"
}
],
"time": "2022-05-10T07:21:04+00:00"
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/redis-messenger",
"version": "v5.4.13",
"version": "v5.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/redis-messenger.git",
"reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4"
"reference": "54b107003c5abc03cc5077c8847678b432b1e602"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/redis-messenger/zipball/d3028b772de91e9aa0342c92ff71c77b130ac9c4",
"reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4",
"url": "https://api.github.com/repos/symfony/redis-messenger/zipball/54b107003c5abc03cc5077c8847678b432b1e602",
"reference": "54b107003c5abc03cc5077c8847678b432b1e602",
"shasum": ""
},
"require": {
@ -1223,7 +1264,7 @@
"description": "Symfony Redis extension Messenger Bridge",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/redis-messenger/tree/v5.4.13"
"source": "https://github.com/symfony/redis-messenger/tree/v5.4.36"
},
"funding": [
{
@ -1239,20 +1280,20 @@
"type": "tidelift"
}
],
"time": "2022-09-11T09:11:59+00:00"
"time": "2024-02-05T13:56:32+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.5.2",
"version": "v2.5.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
"reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3",
"reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3",
"shasum": ""
},
"require": {
@ -1306,7 +1347,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/service-contracts/tree/v2.5.3"
},
"funding": [
{
@ -1322,7 +1363,7 @@
"type": "tidelift"
}
],
"time": "2022-05-30T19:17:29+00:00"
"time": "2023-04-21T15:04:16+00:00"
}
],
"packages-dev": [],
@ -1338,5 +1379,5 @@
"platform-overrides": {
"php": "7.3.6"
},
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.6.0"
}

View File

@ -3,11 +3,13 @@ namespace Grav\Plugin;
use Composer\Autoload\ClassLoader;
use Grav\Common\Data\Data;
use Grav\Common\Data\ValidationException;
use Grav\Common\Grav;
use Grav\Common\Plugin;
use Grav\Common\Utils;
use Grav\Plugin\Email\Email;
use RocketTheme\Toolbox\Event\Event;
use Symfony\Component\Mailer\Exception\TransportException;
class EmailPlugin extends Plugin
{
@ -110,10 +112,10 @@ class EmailPlugin extends Plugin
$this->grav->fireEvent('onEmailSend', new Event(['params' => &$params, 'vars' => &$vars]));
if (Utils::isAssoc($params)) {
$this->sendFormEmail($form, $params, $vars);
$this->sendFormEmail($form, $params, $vars, $event);
} else {
foreach ($params as $email) {
$this->sendFormEmail($form, $email, $vars);
$this->sendFormEmail($form, $email, $vars, $event);
}
}
@ -121,7 +123,7 @@ class EmailPlugin extends Plugin
}
}
protected function sendFormEmail($form, $params, $vars)
protected function sendFormEmail($form, $params, $vars, $event)
{
// Build message
$message = $this->email->buildMessage($params, $vars);
@ -155,7 +157,17 @@ class EmailPlugin extends Plugin
$this->grav->fireEvent('onEmailMessage', new Event(['message' => $message, 'params' => $params, 'form' => $form]));
// Send e-mail
$this->email->send($message);
$status = $this->email->send($message);
if ($status < 1) {
$this->grav->fireEvent('onFormValidationError', new Event([
'form' => $form,
'message' => $this->email->getLastSendMessage(),
]));
$event->stopPropagation();
return;
}
//fire event after eMail was sent
$this->grav->fireEvent('onEmailSent', new Event(['message' => $message, 'params' => $params, 'form' => $form]));

View File

@ -3,8 +3,21 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
exit(1);
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';

View File

@ -42,35 +42,37 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var ?string */
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
@ -78,8 +80,7 @@ class ClassLoader
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
* @var array<string, string>
*/
private $classMap = array();
@ -87,29 +88,29 @@ class ClassLoader
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
/** @var string|null */
private $apcuPrefix;
/**
* @var self[]
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return string[]
* @return array<string, list<string>>
*/
public function getPrefixes()
{
@ -121,8 +122,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
@ -130,8 +130,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirs()
{
@ -139,8 +138,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
@ -148,8 +146,7 @@ class ClassLoader
}
/**
* @return string[] Array of classname => path
* @psalm-return array<string, string>
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
@ -157,8 +154,7 @@ class ClassLoader
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
@ -175,24 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
$paths
);
}
@ -201,19 +198,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
$paths
);
}
}
@ -222,9 +219,9 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
@ -232,17 +229,18 @@ class ClassLoader
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@ -252,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
$paths
);
}
}
@ -272,8 +270,8 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
@ -290,8 +288,8 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
@ -425,7 +423,8 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
@ -476,9 +475,9 @@ class ClassLoader
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return self[]
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
@ -555,18 +554,26 @@ class ClassLoader
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View File

@ -98,7 +98,7 @@ class InstalledVersions
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
@ -119,7 +119,7 @@ class InstalledVersions
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
@ -328,7 +328,9 @@ class InstalledVersions
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
@ -340,12 +342,17 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
if (self::$installed !== array()) {
$installed[] = self::$installed;
}
return $installed;
}

View File

@ -24,5 +24,6 @@ return array(
'Grav\\Plugin\\Email\\' => array($baseDir . '/classes'),
'Grav\\Plugin\\Console\\' => array($baseDir . '/cli'),
'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'),
'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/src'),
);

View File

@ -33,25 +33,18 @@ class ComposerAutoloaderInit73924571ea6ee98bb12d10ff20aff2ab
$loader->register(true);
$includeFiles = \Composer\Autoload\ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab::$files;
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire73924571ea6ee98bb12d10ff20aff2ab($fileIdentifier, $file);
$filesToLoad = \Composer\Autoload\ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
}
return $loader;
}
}
/**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequire73924571ea6ee98bb12d10ff20aff2ab($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}

View File

@ -46,6 +46,7 @@ class ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab
),
'D' =>
array (
'Doctrine\\Deprecations\\' => 22,
'Doctrine\\Common\\Lexer\\' => 22,
),
);
@ -123,9 +124,13 @@ class ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab
array (
0 => __DIR__ . '/..' . '/egulias/email-validator/src',
),
'Doctrine\\Deprecations\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations',
),
'Doctrine\\Common\\Lexer\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer',
0 => __DIR__ . '/..' . '/doctrine/lexer/src',
),
);

View File

@ -1,35 +1,87 @@
{
"packages": [
{
"name": "doctrine/lexer",
"version": "1.2.3",
"version_normalized": "1.2.3.0",
"name": "doctrine/deprecations",
"version": "1.1.3",
"version_normalized": "1.1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229"
"url": "https://github.com/doctrine/deprecations.git",
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229",
"reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9.0",
"phpstan/phpstan": "^1.3",
"doctrine/coding-standard": "^9",
"phpstan/phpstan": "1.4.10 || 1.10.15",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"vimeo/psalm": "^4.11"
"psalm/plugin-phpunit": "0.18.4",
"psr/log": "^1 || ^2 || ^3",
"vimeo/psalm": "4.30.0 || 5.12.0"
},
"time": "2022-02-28T11:07:21+00:00",
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"time": "2024-01-30T19:34:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.3"
},
"install-path": "../doctrine/deprecations"
},
{
"name": "doctrine/lexer",
"version": "2.1.1",
"version_normalized": "2.1.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6",
"reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9 || ^12",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
"psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^4.11 || ^5.21"
},
"time": "2024-02-05T11:35:39+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Lexer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -61,7 +113,7 @@
],
"support": {
"issues": "https://github.com/doctrine/lexer/issues",
"source": "https://github.com/doctrine/lexer/tree/1.2.3"
"source": "https://github.com/doctrine/lexer/tree/2.1.1"
},
"funding": [
{
@ -81,33 +133,32 @@
},
{
"name": "egulias/email-validator",
"version": "3.2.1",
"version_normalized": "3.2.1.0",
"version": "3.2.6",
"version_normalized": "3.2.6.0",
"source": {
"type": "git",
"url": "https://github.com/egulias/EmailValidator.git",
"reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715"
"reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/f88dcf4b14af14a98ad96b14b2b317969eab6715",
"reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7",
"reference": "e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7",
"shasum": ""
},
"require": {
"doctrine/lexer": "^1.2",
"doctrine/lexer": "^1.2|^2",
"php": ">=7.2",
"symfony/polyfill-intl-idn": "^1.15"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^8.5.8|^9.3.3",
"vimeo/psalm": "^4"
},
"suggest": {
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
},
"time": "2022-06-18T20:57:19+00:00",
"time": "2023-06-01T07:04:22+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -140,7 +191,7 @@
],
"support": {
"issues": "https://github.com/egulias/EmailValidator/issues",
"source": "https://github.com/egulias/EmailValidator/tree/3.2.1"
"source": "https://github.com/egulias/EmailValidator/tree/3.2.6"
},
"funding": [
{
@ -309,17 +360,17 @@
},
{
"name": "symfony/amqp-messenger",
"version": "v5.4.13",
"version_normalized": "5.4.13.0",
"version": "v5.4.36",
"version_normalized": "5.4.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/amqp-messenger.git",
"reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521"
"reference": "456958ef89fffddc3935f3954a7eac255a5adb21"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/def93f2a7841cfa1a4a1fa487b84054d0d53e521",
"reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521",
"url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/456958ef89fffddc3935f3954a7eac255a5adb21",
"reference": "456958ef89fffddc3935f3954a7eac255a5adb21",
"shasum": ""
},
"require": {
@ -333,7 +384,7 @@
"symfony/property-access": "^4.4|^5.0|^6.0",
"symfony/serializer": "^4.4|^5.0|^6.0"
},
"time": "2022-09-11T09:11:59+00:00",
"time": "2024-02-14T16:15:37+00:00",
"type": "symfony-messenger-bridge",
"installation-source": "dist",
"autoload": {
@ -361,7 +412,7 @@
"description": "Symfony AMQP extension Messenger Bridge",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/amqp-messenger/tree/v5.4.13"
"source": "https://github.com/symfony/amqp-messenger/tree/v5.4.36"
},
"funding": [
{
@ -381,23 +432,23 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"version": "v2.5.3",
"version_normalized": "2.5.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
"reference": "80d075412b557d41002320b96a096ca65aa2c98d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d",
"reference": "80d075412b557d41002320b96a096ca65aa2c98d",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"time": "2022-01-02T09:53:40+00:00",
"time": "2023-01-24T14:02:46+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -431,7 +482,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3"
},
"funding": [
{
@ -451,17 +502,17 @@
},
{
"name": "symfony/doctrine-messenger",
"version": "v5.4.12",
"version_normalized": "5.4.12.0",
"version": "v5.4.38",
"version_normalized": "5.4.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/doctrine-messenger.git",
"reference": "7649a80e917b47c5072480a2d763c2422da239d2"
"reference": "0118ae0beaebeb5961ddeedc994454e1ac11f759"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/7649a80e917b47c5072480a2d763c2422da239d2",
"reference": "7649a80e917b47c5072480a2d763c2422da239d2",
"url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/0118ae0beaebeb5961ddeedc994454e1ac11f759",
"reference": "0118ae0beaebeb5961ddeedc994454e1ac11f759",
"shasum": ""
},
"require": {
@ -474,12 +525,12 @@
"doctrine/persistence": "<1.3"
},
"require-dev": {
"doctrine/dbal": "^2.13|^3.0",
"doctrine/dbal": "^2.13|^3|^4",
"doctrine/persistence": "^1.3|^2|^3",
"symfony/property-access": "^4.4|^5.0|^6.0",
"symfony/serializer": "^4.4|^5.0|^6.0"
},
"time": "2022-08-09T12:54:00+00:00",
"time": "2024-03-17T15:02:26+00:00",
"type": "symfony-messenger-bridge",
"installation-source": "dist",
"autoload": {
@ -507,7 +558,7 @@
"description": "Symfony Doctrine Messenger Bridge",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/doctrine-messenger/tree/v5.4.12"
"source": "https://github.com/symfony/doctrine-messenger/tree/v5.4.38"
},
"funding": [
{
@ -527,17 +578,17 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v5.4.9",
"version_normalized": "5.4.9.0",
"version": "v5.4.35",
"version_normalized": "5.4.35.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc"
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
"reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"shasum": ""
},
"require": {
@ -567,7 +618,7 @@
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"time": "2022-05-05T16:45:39+00:00",
"time": "2024-01-23T13:51:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -595,7 +646,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9"
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.35"
},
"funding": [
{
@ -615,17 +666,17 @@
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"version": "v2.5.3",
"version_normalized": "2.5.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
"reference": "540f4c73e87fd0c71ca44a6aa305d024ac68cb73"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/540f4c73e87fd0c71ca44a6aa305d024ac68cb73",
"reference": "540f4c73e87fd0c71ca44a6aa305d024ac68cb73",
"shasum": ""
},
"require": {
@ -635,7 +686,7 @@
"suggest": {
"symfony/event-dispatcher-implementation": ""
},
"time": "2022-01-02T09:53:40+00:00",
"time": "2024-01-23T13:51:25+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -677,7 +728,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.3"
},
"funding": [
{
@ -697,21 +748,21 @@
},
{
"name": "symfony/mailer",
"version": "v5.4.13",
"version_normalized": "5.4.13.0",
"version": "v5.4.38",
"version_normalized": "5.4.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11"
"reference": "1d0ef27f1b19b9a0175a0e130d1df3113e5a130e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11",
"reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11",
"url": "https://api.github.com/repos/symfony/mailer/zipball/1d0ef27f1b19b9a0175a0e130d1df3113e5a130e",
"reference": "1d0ef27f1b19b9a0175a0e130d1df3113e5a130e",
"shasum": ""
},
"require": {
"egulias/email-validator": "^2.1.10|^3",
"egulias/email-validator": "^2.1.10|^3|^4",
"php": ">=7.2.5",
"psr/event-dispatcher": "^1",
"psr/log": "^1|^2|^3",
@ -725,10 +776,10 @@
"symfony/http-kernel": "<4.4"
},
"require-dev": {
"symfony/http-client-contracts": "^1.1|^2|^3",
"symfony/http-client": "^4.4|^5.0|^6.0",
"symfony/messenger": "^4.4|^5.0|^6.0"
},
"time": "2022-08-29T06:47:07+00:00",
"time": "2024-03-19T10:19:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -756,7 +807,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v5.4.13"
"source": "https://github.com/symfony/mailer/tree/v5.4.38"
},
"funding": [
{
@ -776,17 +827,17 @@
},
{
"name": "symfony/messenger",
"version": "v5.4.13",
"version_normalized": "5.4.13.0",
"version": "v5.4.38",
"version_normalized": "5.4.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/messenger.git",
"reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4"
"reference": "a69a4d07e20e4f298a5c030623a1a3328145a889"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/messenger/zipball/8f8d3425991e627902f8288088609a8d8f6c6ea4",
"reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4",
"url": "https://api.github.com/repos/symfony/messenger/zipball/a69a4d07e20e4f298a5c030623a1a3328145a889",
"reference": "a69a4d07e20e4f298a5c030623a1a3328145a889",
"shasum": ""
},
"require": {
@ -821,7 +872,7 @@
"suggest": {
"enqueue/messenger-adapter": "For using the php-enqueue library as a transport."
},
"time": "2022-09-17T07:31:22+00:00",
"time": "2024-03-19T10:19:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -849,7 +900,7 @@
"description": "Helps applications send and receive messages to/from other applications or via message queues",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/messenger/tree/v5.4.13"
"source": "https://github.com/symfony/messenger/tree/v5.4.38"
},
"funding": [
{
@ -869,17 +920,17 @@
},
{
"name": "symfony/mime",
"version": "v5.4.13",
"version_normalized": "5.4.13.0",
"version": "v5.4.38",
"version_normalized": "5.4.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd"
"reference": "82fa6be8a0295a3932df871e88fc8c8d77aa71d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd",
"reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd",
"url": "https://api.github.com/repos/symfony/mime/zipball/82fa6be8a0295a3932df871e88fc8c8d77aa71d4",
"reference": "82fa6be8a0295a3932df871e88fc8c8d77aa71d4",
"shasum": ""
},
"require": {
@ -893,17 +944,19 @@
"egulias/email-validator": "~3.0.0",
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/mailer": "<4.4"
"symfony/mailer": "<4.4",
"symfony/serializer": "<5.4.35|>=6,<6.3.12|>=6.4,<6.4.3"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3.1",
"egulias/email-validator": "^2.1.10|^3.1|^4",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/process": "^5.4|^6.4",
"symfony/property-access": "^4.4|^5.1|^6.0",
"symfony/property-info": "^4.4|^5.1|^6.0",
"symfony/serializer": "^5.2|^6.0"
"symfony/serializer": "^5.4.35|~6.3.12|^6.4.3"
},
"time": "2022-09-01T18:18:29+00:00",
"time": "2024-03-21T07:25:32+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -935,7 +988,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v5.4.13"
"source": "https://github.com/symfony/mime/tree/v5.4.38"
},
"funding": [
{
@ -955,17 +1008,17 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.26.0",
"version_normalized": "1.26.0.0",
"version": "v1.29.0",
"version_normalized": "1.29.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919",
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919",
"shasum": ""
},
"require": {
@ -976,12 +1029,9 @@
"suggest": {
"ext-intl": "For best performance"
},
"time": "2022-05-24T11:49:31+00:00",
"time": "2024-01-29T20:11:03+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@ -1025,7 +1075,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0"
},
"funding": [
{
@ -1045,17 +1095,17 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.26.0",
"version_normalized": "1.26.0.0",
"version": "v1.29.0",
"version_normalized": "1.29.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd"
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"shasum": ""
},
"require": {
@ -1064,12 +1114,9 @@
"suggest": {
"ext-intl": "For best performance"
},
"time": "2022-05-24T11:49:31+00:00",
"time": "2024-01-29T20:11:03+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@ -1112,7 +1159,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
},
"funding": [
{
@ -1132,28 +1179,25 @@
},
{
"name": "symfony/polyfill-php80",
"version": "v1.26.0",
"version_normalized": "1.26.0.0",
"version": "v1.29.0",
"version_normalized": "1.29.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"time": "2022-05-10T07:21:04+00:00",
"time": "2024-01-29T20:11:03+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@ -1198,7 +1242,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
},
"funding": [
{
@ -1218,17 +1262,17 @@
},
{
"name": "symfony/redis-messenger",
"version": "v5.4.13",
"version_normalized": "5.4.13.0",
"version": "v5.4.36",
"version_normalized": "5.4.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/redis-messenger.git",
"reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4"
"reference": "54b107003c5abc03cc5077c8847678b432b1e602"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/redis-messenger/zipball/d3028b772de91e9aa0342c92ff71c77b130ac9c4",
"reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4",
"url": "https://api.github.com/repos/symfony/redis-messenger/zipball/54b107003c5abc03cc5077c8847678b432b1e602",
"reference": "54b107003c5abc03cc5077c8847678b432b1e602",
"shasum": ""
},
"require": {
@ -1240,7 +1284,7 @@
"symfony/property-access": "^4.4|^5.0|^6.0",
"symfony/serializer": "^4.4|^5.0|^6.0"
},
"time": "2022-09-11T09:11:59+00:00",
"time": "2024-02-05T13:56:32+00:00",
"type": "symfony-messenger-bridge",
"installation-source": "dist",
"autoload": {
@ -1268,7 +1312,7 @@
"description": "Symfony Redis extension Messenger Bridge",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/redis-messenger/tree/v5.4.13"
"source": "https://github.com/symfony/redis-messenger/tree/v5.4.36"
},
"funding": [
{
@ -1288,17 +1332,17 @@
},
{
"name": "symfony/service-contracts",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"version": "v2.5.3",
"version_normalized": "2.5.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
"reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3",
"reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3",
"shasum": ""
},
"require": {
@ -1312,7 +1356,7 @@
"suggest": {
"symfony/service-implementation": ""
},
"time": "2022-05-30T19:17:29+00:00",
"time": "2023-04-21T15:04:16+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -1354,7 +1398,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/service-contracts/tree/v2.5.3"
},
"funding": [
{
@ -1373,6 +1417,6 @@
"install-path": "../symfony/service-contracts"
}
],
"dev": true,
"dev": false,
"dev-package-names": []
}

View File

@ -3,26 +3,35 @@
'name' => 'getgrav/grav-plugin-email',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'f6eb15486887c489363e6bf79fa49ea4a3d833c6',
'reference' => '9b38e4e031e87c79320dd30b46960125a0385453',
'type' => 'grav-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
'dev' => false,
),
'versions' => array(
'doctrine/deprecations' => array(
'pretty_version' => '1.1.3',
'version' => '1.1.3.0',
'reference' => 'dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/deprecations',
'aliases' => array(),
'dev_requirement' => false,
),
'doctrine/lexer' => array(
'pretty_version' => '1.2.3',
'version' => '1.2.3.0',
'reference' => 'c268e882d4dbdd85e36e4ad69e02dc284f89d229',
'pretty_version' => '2.1.1',
'version' => '2.1.1.0',
'reference' => '861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/lexer',
'aliases' => array(),
'dev_requirement' => false,
),
'egulias/email-validator' => array(
'pretty_version' => '3.2.1',
'version' => '3.2.1.0',
'reference' => 'f88dcf4b14af14a98ad96b14b2b317969eab6715',
'pretty_version' => '3.2.6',
'version' => '3.2.6.0',
'reference' => 'e5997fa97e8790cdae03a9cbd5e78e45e3c7bda7',
'type' => 'library',
'install_path' => __DIR__ . '/../egulias/email-validator',
'aliases' => array(),
@ -31,7 +40,7 @@
'getgrav/grav-plugin-email' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'f6eb15486887c489363e6bf79fa49ea4a3d833c6',
'reference' => '9b38e4e031e87c79320dd30b46960125a0385453',
'type' => 'grav-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -71,45 +80,45 @@
'dev_requirement' => false,
),
'symfony/amqp-messenger' => array(
'pretty_version' => 'v5.4.13',
'version' => '5.4.13.0',
'reference' => 'def93f2a7841cfa1a4a1fa487b84054d0d53e521',
'pretty_version' => 'v5.4.36',
'version' => '5.4.36.0',
'reference' => '456958ef89fffddc3935f3954a7eac255a5adb21',
'type' => 'symfony-messenger-bridge',
'install_path' => __DIR__ . '/../symfony/amqp-messenger',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
'pretty_version' => 'v2.5.3',
'version' => '2.5.3.0',
'reference' => '80d075412b557d41002320b96a096ca65aa2c98d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/doctrine-messenger' => array(
'pretty_version' => 'v5.4.12',
'version' => '5.4.12.0',
'reference' => '7649a80e917b47c5072480a2d763c2422da239d2',
'pretty_version' => 'v5.4.38',
'version' => '5.4.38.0',
'reference' => '0118ae0beaebeb5961ddeedc994454e1ac11f759',
'type' => 'symfony-messenger-bridge',
'install_path' => __DIR__ . '/../symfony/doctrine-messenger',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/event-dispatcher' => array(
'pretty_version' => 'v5.4.9',
'version' => '5.4.9.0',
'reference' => '8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc',
'pretty_version' => 'v5.4.35',
'version' => '5.4.35.0',
'reference' => '7a69a85c7ea5bdd1e875806a99c51a87d3a74b38',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/event-dispatcher-contracts' => array(
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'reference' => 'f98b54df6ad059855739db6fcbc2d36995283fe1',
'pretty_version' => 'v2.5.3',
'version' => '2.5.3.0',
'reference' => '540f4c73e87fd0c71ca44a6aa305d024ac68cb73',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts',
'aliases' => array(),
@ -122,27 +131,27 @@
),
),
'symfony/mailer' => array(
'pretty_version' => 'v5.4.13',
'version' => '5.4.13.0',
'reference' => '63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11',
'pretty_version' => 'v5.4.38',
'version' => '5.4.38.0',
'reference' => '1d0ef27f1b19b9a0175a0e130d1df3113e5a130e',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mailer',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/messenger' => array(
'pretty_version' => 'v5.4.13',
'version' => '5.4.13.0',
'reference' => '8f8d3425991e627902f8288088609a8d8f6c6ea4',
'pretty_version' => 'v5.4.38',
'version' => '5.4.38.0',
'reference' => 'a69a4d07e20e4f298a5c030623a1a3328145a889',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/messenger',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/mime' => array(
'pretty_version' => 'v5.4.13',
'version' => '5.4.13.0',
'reference' => 'bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd',
'pretty_version' => 'v5.4.38',
'version' => '5.4.38.0',
'reference' => '82fa6be8a0295a3932df871e88fc8c8d77aa71d4',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mime',
'aliases' => array(),
@ -155,18 +164,18 @@
),
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.26.0',
'version' => '1.26.0.0',
'reference' => '59a8d271f00dd0e4c2e518104cc7963f655a1aa8',
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => 'a287ed7475f85bf6f61890146edbc932c0fff919',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.26.0',
'version' => '1.26.0.0',
'reference' => '219aa369ceff116e673852dce47c3a41794c14bd',
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => 'bc45c394692b948b4d383a08d7753968bed9a83d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
@ -185,27 +194,27 @@
),
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.26.0',
'version' => '1.26.0.0',
'reference' => 'cfa0ae98841b9e461207c13ab093d76b0fa7bace',
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => '87b68208d5c1188808dd7839ee1e6c8ec3b02f1b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/redis-messenger' => array(
'pretty_version' => 'v5.4.13',
'version' => '5.4.13.0',
'reference' => 'd3028b772de91e9aa0342c92ff71c77b130ac9c4',
'pretty_version' => 'v5.4.36',
'version' => '5.4.36.0',
'reference' => '54b107003c5abc03cc5077c8847678b432b1e602',
'type' => 'symfony-messenger-bridge',
'install_path' => __DIR__ . '/../symfony/redis-messenger',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/service-contracts' => array(
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c',
'pretty_version' => 'v2.5.3',
'version' => '2.5.3.0',
'reference' => 'a2329596ddc8fd568900e3fc76cba42489ecc7f3',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/service-contracts',
'aliases' => array(),

View File

@ -0,0 +1,19 @@
Copyright (c) 2020-2021 Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,157 @@
# Doctrine Deprecations
A small (side-effect free by default) layer on top of
`trigger_error(E_USER_DEPRECATED)` or PSR-3 logging.
- no side-effects by default, making it a perfect fit for libraries that don't know how the error handler works they operate under
- options to avoid having to rely on error handlers global state by using PSR-3 logging
- deduplicate deprecation messages to avoid excessive triggering and reduce overhead
We recommend to collect Deprecations using a PSR logger instead of relying on
the global error handler.
## Usage from consumer perspective:
Enable Doctrine deprecations to be sent to a PSR3 logger:
```php
\Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
```
Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)`
messages by setting the `DOCTRINE_DEPRECATIONS` environment variable to `trigger`.
Alternatively, call:
```php
\Doctrine\Deprecations\Deprecation::enableWithTriggerError();
```
If you only want to enable deprecation tracking, without logging or calling `trigger_error`
then set the `DOCTRINE_DEPRECATIONS` environment variable to `track`.
Alternatively, call:
```php
\Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
```
Tracking is enabled with all three modes and provides access to all triggered
deprecations and their individual count:
```php
$deprecations = \Doctrine\Deprecations\Deprecation::getTriggeredDeprecations();
foreach ($deprecations as $identifier => $count) {
echo $identifier . " was triggered " . $count . " times\n";
}
```
### Suppressing Specific Deprecations
Disable triggering about specific deprecations:
```php
\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier");
```
Disable all deprecations from a package
```php
\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm");
```
### Other Operations
When used within PHPUnit or other tools that could collect multiple instances of the same deprecations
the deduplication can be disabled:
```php
\Doctrine\Deprecations\Deprecation::withoutDeduplication();
```
Disable deprecation tracking again:
```php
\Doctrine\Deprecations\Deprecation::disable();
```
## Usage from a library/producer perspective:
When you want to unconditionally trigger a deprecation even when called
from the library itself then the `trigger` method is the way to go:
```php
\Doctrine\Deprecations\Deprecation::trigger(
"doctrine/orm",
"https://link/to/deprecations-description",
"message"
);
```
If variable arguments are provided at the end, they are used with `sprintf` on
the message.
```php
\Doctrine\Deprecations\Deprecation::trigger(
"doctrine/orm",
"https://github.com/doctrine/orm/issue/1234",
"message %s %d",
"foo",
1234
);
```
When you want to trigger a deprecation only when it is called by a function
outside of the current package, but not trigger when the package itself is the cause,
then use:
```php
\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside(
"doctrine/orm",
"https://link/to/deprecations-description",
"message"
);
```
Based on the issue link each deprecation message is only triggered once per
request.
A limited stacktrace is included in the deprecation message to find the
offending location.
Note: A producer/library should never call `Deprecation::enableWith` methods
and leave the decision how to handle deprecations to application and
frameworks.
## Usage in PHPUnit tests
There is a `VerifyDeprecations` trait that you can use to make assertions on
the occurrence of deprecations within a test.
```php
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
class MyTest extends TestCase
{
use VerifyDeprecations;
public function testSomethingDeprecation()
{
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
triggerTheCodeWithDeprecation();
}
public function testSomethingDeprecationFixed()
{
$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
triggerTheCodeWithoutDeprecation();
}
}
```
## What is a deprecation identifier?
An identifier for deprecations is just a link to any resource, most often a
Github Issue or Pull Request explaining the deprecation and potentially its
alternative.

View File

@ -0,0 +1,38 @@
{
"name": "doctrine/deprecations",
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"license": "MIT",
"type": "library",
"homepage": "https://www.doctrine-project.org/",
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpstan/phpstan": "1.4.10 || 1.10.15",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psalm/plugin-phpunit": "0.18.4",
"psr/log": "^1 || ^2 || ^3",
"vimeo/psalm": "4.30.0 || 5.12.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"autoload-dev": {
"psr-4": {
"DeprecationTests\\": "test_fixtures/src",
"Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View File

@ -0,0 +1,313 @@
<?php
declare(strict_types=1);
namespace Doctrine\Deprecations;
use Psr\Log\LoggerInterface;
use function array_key_exists;
use function array_reduce;
use function assert;
use function debug_backtrace;
use function sprintf;
use function str_replace;
use function strpos;
use function strrpos;
use function substr;
use function trigger_error;
use const DEBUG_BACKTRACE_IGNORE_ARGS;
use const DIRECTORY_SEPARATOR;
use const E_USER_DEPRECATED;
/**
* Manages Deprecation logging in different ways.
*
* By default triggered exceptions are not logged.
*
* To enable different deprecation logging mechanisms you can call the
* following methods:
*
* - Minimal collection of deprecations via getTriggeredDeprecations()
* \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
*
* - Uses @trigger_error with E_USER_DEPRECATED
* \Doctrine\Deprecations\Deprecation::enableWithTriggerError();
*
* - Sends deprecation messages via a PSR-3 logger
* \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
*
* Packages that trigger deprecations should use the `trigger()` or
* `triggerIfCalledFromOutside()` methods.
*/
class Deprecation
{
private const TYPE_NONE = 0;
private const TYPE_TRACK_DEPRECATIONS = 1;
private const TYPE_TRIGGER_ERROR = 2;
private const TYPE_PSR_LOGGER = 4;
/** @var int-mask-of<self::TYPE_*>|null */
private static $type;
/** @var LoggerInterface|null */
private static $logger;
/** @var array<string,bool> */
private static $ignoredPackages = [];
/** @var array<string,int> */
private static $triggeredDeprecations = [];
/** @var array<string,bool> */
private static $ignoredLinks = [];
/** @var bool */
private static $deduplication = true;
/**
* Trigger a deprecation for the given package and identfier.
*
* The link should point to a Github issue or Wiki entry detailing the
* deprecation. It is additionally used to de-duplicate the trigger of the
* same deprecation during a request.
*
* @param float|int|string $args
*/
public static function trigger(string $package, string $link, string $message, ...$args): void
{
$type = self::$type ?? self::getTypeFromEnv();
if ($type === self::TYPE_NONE) {
return;
}
if (isset(self::$ignoredLinks[$link])) {
return;
}
if (array_key_exists($link, self::$triggeredDeprecations)) {
self::$triggeredDeprecations[$link]++;
} else {
self::$triggeredDeprecations[$link] = 1;
}
if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
return;
}
if (isset(self::$ignoredPackages[$package])) {
return;
}
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$message = sprintf($message, ...$args);
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
}
/**
* Trigger a deprecation for the given package and identifier when called from outside.
*
* "Outside" means we assume that $package is currently installed as a
* dependency and the caller is not a file in that package. When $package
* is installed as a root package then deprecations triggered from the
* tests folder are also considered "outside".
*
* This deprecation method assumes that you are using Composer to install
* the dependency and are using the default /vendor/ folder and not a
* Composer plugin to change the install location. The assumption is also
* that $package is the exact composer packge name.
*
* Compared to {@link trigger()} this method causes some overhead when
* deprecation tracking is enabled even during deduplication, because it
* needs to call {@link debug_backtrace()}
*
* @param float|int|string $args
*/
public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void
{
$type = self::$type ?? self::getTypeFromEnv();
if ($type === self::TYPE_NONE) {
return;
}
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
// first check that the caller is not from a tests folder, in which case we always let deprecations pass
if (isset($backtrace[1]['file'], $backtrace[0]['file']) && strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
$path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $package) . DIRECTORY_SEPARATOR;
if (strpos($backtrace[0]['file'], $path) === false) {
return;
}
if (strpos($backtrace[1]['file'], $path) !== false) {
return;
}
}
if (isset(self::$ignoredLinks[$link])) {
return;
}
if (array_key_exists($link, self::$triggeredDeprecations)) {
self::$triggeredDeprecations[$link]++;
} else {
self::$triggeredDeprecations[$link] = 1;
}
if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
return;
}
if (isset(self::$ignoredPackages[$package])) {
return;
}
$message = sprintf($message, ...$args);
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
}
/**
* @param list<array{function: string, line?: int, file?: string, class?: class-string, type?: string, args?: mixed[], object?: object}> $backtrace
*/
private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void
{
$type = self::$type ?? self::getTypeFromEnv();
if (($type & self::TYPE_PSR_LOGGER) > 0) {
$context = [
'file' => $backtrace[0]['file'] ?? null,
'line' => $backtrace[0]['line'] ?? null,
'package' => $package,
'link' => $link,
];
assert(self::$logger !== null);
self::$logger->notice($message, $context);
}
if (! (($type & self::TYPE_TRIGGER_ERROR) > 0)) {
return;
}
$message .= sprintf(
' (%s:%d called by %s:%d, %s, package %s)',
self::basename($backtrace[0]['file'] ?? 'native code'),
$backtrace[0]['line'] ?? 0,
self::basename($backtrace[1]['file'] ?? 'native code'),
$backtrace[1]['line'] ?? 0,
$link,
$package
);
@trigger_error($message, E_USER_DEPRECATED);
}
/**
* A non-local-aware version of PHPs basename function.
*/
private static function basename(string $filename): string
{
$pos = strrpos($filename, DIRECTORY_SEPARATOR);
if ($pos === false) {
return $filename;
}
return substr($filename, $pos + 1);
}
public static function enableTrackingDeprecations(): void
{
self::$type = self::$type ?? 0;
self::$type |= self::TYPE_TRACK_DEPRECATIONS;
}
public static function enableWithTriggerError(): void
{
self::$type = self::$type ?? 0;
self::$type |= self::TYPE_TRIGGER_ERROR;
}
public static function enableWithPsrLogger(LoggerInterface $logger): void
{
self::$type = self::$type ?? 0;
self::$type |= self::TYPE_PSR_LOGGER;
self::$logger = $logger;
}
public static function withoutDeduplication(): void
{
self::$deduplication = false;
}
public static function disable(): void
{
self::$type = self::TYPE_NONE;
self::$logger = null;
self::$deduplication = true;
self::$ignoredLinks = [];
foreach (self::$triggeredDeprecations as $link => $count) {
self::$triggeredDeprecations[$link] = 0;
}
}
public static function ignorePackage(string $packageName): void
{
self::$ignoredPackages[$packageName] = true;
}
public static function ignoreDeprecations(string ...$links): void
{
foreach ($links as $link) {
self::$ignoredLinks[$link] = true;
}
}
public static function getUniqueTriggeredDeprecationsCount(): int
{
return array_reduce(self::$triggeredDeprecations, static function (int $carry, int $count) {
return $carry + $count;
}, 0);
}
/**
* Returns each triggered deprecation link identifier and the amount of occurrences.
*
* @return array<string,int>
*/
public static function getTriggeredDeprecations(): array
{
return self::$triggeredDeprecations;
}
/**
* @return int-mask-of<self::TYPE_*>
*/
private static function getTypeFromEnv(): int
{
switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) {
case 'trigger':
self::$type = self::TYPE_TRIGGER_ERROR;
break;
case 'track':
self::$type = self::TYPE_TRACK_DEPRECATIONS;
break;
default:
self::$type = self::TYPE_NONE;
break;
}
return self::$type;
}
}

View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Doctrine\Deprecations\PHPUnit;
use Doctrine\Deprecations\Deprecation;
use function sprintf;
trait VerifyDeprecations
{
/** @var array<string,int> */
private $doctrineDeprecationsExpectations = [];
/** @var array<string,int> */
private $doctrineNoDeprecationsExpectations = [];
public function expectDeprecationWithIdentifier(string $identifier): void
{
$this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
}
public function expectNoDeprecationWithIdentifier(string $identifier): void
{
$this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
}
/**
* @before
*/
public function enableDeprecationTracking(): void
{
Deprecation::enableTrackingDeprecations();
}
/**
* @after
*/
public function verifyDeprecationsAreTriggered(): void
{
foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) {
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
$this->assertTrue(
$actualCount > $expectation,
sprintf(
"Expected deprecation with identifier '%s' was not triggered by code executed in test.",
$identifier
)
);
}
foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) {
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
$this->assertTrue(
$actualCount === $expectation,
sprintf(
"Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.",
$identifier
)
);
}
}
}

View File

@ -0,0 +1,14 @@
Note about upgrading: Doctrine uses static and runtime mechanisms to raise
awareness about deprecated code.
- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or
Static Analysis tools (like Psalm, phpstan)
- Use of our low-overhead runtime deprecation API, details:
https://github.com/doctrine/deprecations/
# Upgrade to 2.0.0
`AbstractLexer::glimpse()` and `AbstractLexer::peek()` now return
instances of `Doctrine\Common\Lexer\Token`, which is an array-like class
Using it as an array is deprecated in favor of using properties of that class.
Using `count()` on it is deprecated with no replacement.

View File

@ -1,7 +1,8 @@
{
"name": "doctrine/lexer",
"type": "library",
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"license": "MIT",
"type": "library",
"keywords": [
"php",
"parser",
@ -9,27 +10,41 @@
"annotations",
"docblock"
],
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"require": {
"php": "^7.1 || ^8.0"
"php": "^7.1 || ^8.0",
"doctrine/deprecations": "^1.0"
},
"require-dev": {
"doctrine/coding-standard": "^9.0",
"doctrine/coding-standard": "^9 || ^12",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"vimeo/psalm": "^4.11"
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
"psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^4.11 || ^5.21"
},
"autoload": {
"psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" }
"psr-4": {
"Doctrine\\Common\\Lexer\\": "src"
}
},
"autoload-dev": {
"psr-4": { "Doctrine\\Tests\\": "tests/Doctrine" }
"psr-4": {
"Doctrine\\Tests\\Common\\Lexer\\": "tests"
}
},
"config": {
"allow-plugins": {

View File

@ -1,15 +0,0 @@
<?xml version="1.0"?>
<psalm
errorLevel="5"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="lib/Doctrine/Common/Lexer" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>

View File

@ -5,9 +5,10 @@ declare(strict_types=1);
namespace Doctrine\Common\Lexer;
use ReflectionClass;
use UnitEnum;
use function get_class;
use function implode;
use function in_array;
use function preg_split;
use function sprintf;
use function substr;
@ -19,7 +20,8 @@ use const PREG_SPLIT_OFFSET_CAPTURE;
/**
* Base class for writing simple lexers, i.e. for creating small DSLs.
*
* @psalm-type Token = array{value: int|string, type:string|int|null, position:int}
* @template T of UnitEnum|string|int
* @template V of string|int
*/
abstract class AbstractLexer
{
@ -33,14 +35,7 @@ abstract class AbstractLexer
/**
* Array of scanned tokens.
*
* Each token is an associative array containing three items:
* - 'value' : the string value of the token in the input string
* - 'type' : the type of the token (identifier, numeric, string, input
* parameter, none)
* - 'position' : the position of the token in the input string
*
* @var mixed[][]
* @psalm-var list<Token>
* @var list<Token<T, V>>
*/
private $tokens = [];
@ -61,23 +56,21 @@ abstract class AbstractLexer
/**
* The next token in the input.
*
* @var mixed[]|null
* @psalm-var Token|null
* @var Token<T, V>|null
*/
public $lookahead;
/**
* The last matched/seen token.
*
* @var mixed[]|null
* @psalm-var Token|null
* @var Token<T, V>|null
*/
public $token;
/**
* Composed regex for input parsing.
*
* @var string|null
* @var non-empty-string|null
*/
private $regex;
@ -150,31 +143,37 @@ abstract class AbstractLexer
/**
* Checks whether a given token matches the current lookahead.
*
* @param int|string $type
* @param T $type
*
* @return bool
*
* @psalm-assert-if-true !=null $this->lookahead
*/
public function isNextToken($type)
{
return $this->lookahead !== null && $this->lookahead['type'] === $type;
return $this->lookahead !== null && $this->lookahead->isA($type);
}
/**
* Checks whether any of the given tokens matches the current lookahead.
*
* @param list<int|string> $types
* @param list<T> $types
*
* @return bool
*
* @psalm-assert-if-true !=null $this->lookahead
*/
public function isNextTokenAny(array $types)
{
return $this->lookahead !== null && in_array($this->lookahead['type'], $types, true);
return $this->lookahead !== null && $this->lookahead->isA(...$types);
}
/**
* Moves to the next token in the input string.
*
* @return bool
*
* @psalm-assert-if-true !null $this->lookahead
*/
public function moveNext()
{
@ -189,13 +188,13 @@ abstract class AbstractLexer
/**
* Tells the lexer to skip input tokens until it sees a token with the given value.
*
* @param string $type The token type to skip until.
* @param T $type The token type to skip until.
*
* @return void
*/
public function skipUntil($type)
{
while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
while ($this->lookahead !== null && ! $this->lookahead->isA($type)) {
$this->moveNext();
}
}
@ -203,7 +202,7 @@ abstract class AbstractLexer
/**
* Checks if given value is identical to the given token.
*
* @param mixed $value
* @param string $value
* @param int|string $token
*
* @return bool
@ -216,8 +215,7 @@ abstract class AbstractLexer
/**
* Moves the lookahead token forward.
*
* @return mixed[]|null The next token or NULL if there are no more tokens ahead.
* @psalm-return Token|null
* @return Token<T, V>|null The next token or NULL if there are no more tokens ahead.
*/
public function peek()
{
@ -231,8 +229,7 @@ abstract class AbstractLexer
/**
* Peeks at the next token, returns it and immediately resets the peek.
*
* @return mixed[]|null The next token or NULL if there are no more tokens ahead.
* @psalm-return Token|null
* @return Token<T, V>|null The next token or NULL if there are no more tokens ahead.
*/
public function glimpse()
{
@ -270,26 +267,32 @@ abstract class AbstractLexer
foreach ($matches as $match) {
// Must remain before 'value' assignment since it can change content
$type = $this->getType($match[0]);
$firstMatch = $match[0];
$type = $this->getType($firstMatch);
$this->tokens[] = [
'value' => $match[0],
'type' => $type,
'position' => $match[1],
];
$this->tokens[] = new Token(
$firstMatch,
$type,
$match[1]
);
}
}
/**
* Gets the literal for a given token.
*
* @param int|string $token
* @param T $token
*
* @return int|string
*/
public function getLiteral($token)
{
if ($token instanceof UnitEnum) {
return get_class($token) . '::' . $token->name;
}
$className = static::class;
$reflClass = new ReflectionClass($className);
$constants = $reflClass->getConstants();
@ -331,7 +334,9 @@ abstract class AbstractLexer
*
* @param string $value
*
* @return int|string|null
* @return T|null
*
* @param-out V $value
*/
abstract protected function getType(&$value);
}

View File

@ -0,0 +1,145 @@
<?php
declare(strict_types=1);
namespace Doctrine\Common\Lexer;
use ArrayAccess;
use Doctrine\Deprecations\Deprecation;
use ReturnTypeWillChange;
use UnitEnum;
use function in_array;
/**
* @template T of UnitEnum|string|int
* @template V of string|int
* @implements ArrayAccess<string,mixed>
*/
final class Token implements ArrayAccess
{
/**
* The string value of the token in the input string
*
* @readonly
* @var V
*/
public $value;
/**
* The type of the token (identifier, numeric, string, input parameter, none)
*
* @readonly
* @var T|null
*/
public $type;
/**
* The position of the token in the input string
*
* @readonly
* @var int
*/
public $position;
/**
* @param V $value
* @param T|null $type
*/
public function __construct($value, $type, int $position)
{
$this->value = $value;
$this->type = $type;
$this->position = $position;
}
/** @param T ...$types */
public function isA(...$types): bool
{
return in_array($this->type, $types, true);
}
/**
* @deprecated Use the value, type or position property instead
* {@inheritDoc}
*/
public function offsetExists($offset): bool
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead',
self::class
);
return in_array($offset, ['value', 'type', 'position'], true);
}
/**
* @deprecated Use the value, type or position property instead
* {@inheritDoc}
*
* @param O $offset
*
* @return mixed
* @psalm-return (
* O is 'value'
* ? V
* : (
* O is 'type'
* ? T|null
* : (
* O is 'position'
* ? int
* : mixed
* )
* )
* )
*
* @template O of array-key
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead',
self::class
);
return $this->$offset;
}
/**
* @deprecated no replacement planned
* {@inheritDoc}
*/
public function offsetSet($offset, $value): void
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Setting %s properties via ArrayAccess is deprecated',
self::class
);
$this->$offset = $value;
}
/**
* @deprecated no replacement planned
* {@inheritDoc}
*/
public function offsetUnset($offset): void
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Setting %s properties via ArrayAccess is deprecated',
self::class
);
$this->$offset = null;
}
}

View File

@ -5,7 +5,7 @@
* Access to local part and domain part from EmailParser
* Validations outside of the scope of the RFC will be considered "extra" validations, thus opening the door for adding new; will live in their own folder "extra" (as requested in #248, #195, #183).
## Breacking changes
## Breaking changes
* PHP version upgraded to match Symfony's (as of 12/2020).
* DNSCheckValidation now fails for missing MX records. While the RFC argues that the existence of only A records to be valid, starting in v3 they will be considered invalid.

View File

@ -1,4 +1,4 @@
Copyright (c) 2013-2021 Eduardo Gulias Davis
Copyright (c) 2013-2022 Eduardo Gulias Davis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -14,11 +14,10 @@
},
"require": {
"php": ">=7.2",
"doctrine/lexer": "^1.2",
"doctrine/lexer": "^1.2|^2",
"symfony/polyfill-intl-idn": "^1.15"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^8.5.8|^9.3.3",
"vimeo/psalm": "^4"
},

File diff suppressed because it is too large Load Diff

View File

@ -3,58 +3,62 @@
namespace Egulias\EmailValidator;
use Doctrine\Common\Lexer\AbstractLexer;
use Doctrine\Common\Lexer\Token;
/**
* @extends AbstractLexer<int, string>
*/
class EmailLexer extends AbstractLexer
{
//ASCII values
const S_EMPTY = null;
const C_NUL = 0;
const S_HTAB = 9;
const S_LF = 10;
const S_CR = 13;
const S_SP = 32;
const EXCLAMATION = 33;
const S_DQUOTE = 34;
const NUMBER_SIGN = 35;
const DOLLAR = 36;
const PERCENTAGE = 37;
const AMPERSAND = 38;
const S_SQUOTE = 39;
const S_OPENPARENTHESIS = 40;
const S_CLOSEPARENTHESIS = 41;
const ASTERISK = 42;
const S_PLUS = 43;
const S_COMMA = 44;
const S_HYPHEN = 45;
const S_DOT = 46;
const S_SLASH = 47;
const S_COLON = 58;
const S_SEMICOLON = 59;
const S_LOWERTHAN = 60;
const S_EQUAL = 61;
const S_GREATERTHAN = 62;
const QUESTIONMARK = 63;
const S_AT = 64;
const S_OPENBRACKET = 91;
const S_BACKSLASH = 92;
const S_CLOSEBRACKET = 93;
const CARET = 94;
const S_UNDERSCORE = 95;
const S_BACKTICK = 96;
const S_OPENCURLYBRACES = 123;
const S_PIPE = 124;
const S_CLOSECURLYBRACES = 125;
const S_TILDE = 126;
const C_DEL = 127;
const INVERT_QUESTIONMARK= 168;
const INVERT_EXCLAMATION = 173;
const GENERIC = 300;
const S_IPV6TAG = 301;
const INVALID = 302;
const CRLF = 1310;
const S_DOUBLECOLON = 5858;
const ASCII_INVALID_FROM = 127;
const ASCII_INVALID_TO = 199;
public const S_EMPTY = null;
public const C_NUL = 0;
public const S_HTAB = 9;
public const S_LF = 10;
public const S_CR = 13;
public const S_SP = 32;
public const EXCLAMATION = 33;
public const S_DQUOTE = 34;
public const NUMBER_SIGN = 35;
public const DOLLAR = 36;
public const PERCENTAGE = 37;
public const AMPERSAND = 38;
public const S_SQUOTE = 39;
public const S_OPENPARENTHESIS = 40;
public const S_CLOSEPARENTHESIS = 41;
public const ASTERISK = 42;
public const S_PLUS = 43;
public const S_COMMA = 44;
public const S_HYPHEN = 45;
public const S_DOT = 46;
public const S_SLASH = 47;
public const S_COLON = 58;
public const S_SEMICOLON = 59;
public const S_LOWERTHAN = 60;
public const S_EQUAL = 61;
public const S_GREATERTHAN = 62;
public const QUESTIONMARK = 63;
public const S_AT = 64;
public const S_OPENBRACKET = 91;
public const S_BACKSLASH = 92;
public const S_CLOSEBRACKET = 93;
public const CARET = 94;
public const S_UNDERSCORE = 95;
public const S_BACKTICK = 96;
public const S_OPENCURLYBRACES = 123;
public const S_PIPE = 124;
public const S_CLOSECURLYBRACES = 125;
public const S_TILDE = 126;
public const C_DEL = 127;
public const INVERT_QUESTIONMARK= 168;
public const INVERT_EXCLAMATION = 173;
public const GENERIC = 300;
public const S_IPV6TAG = 301;
public const INVALID = 302;
public const CRLF = 1310;
public const S_DOUBLECOLON = 5858;
public const ASCII_INVALID_FROM = 127;
public const ASCII_INVALID_TO = 199;
/**
* US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3)
@ -107,11 +111,11 @@ class EmailLexer extends AbstractLexer
'¡' => self::INVERT_EXCLAMATION,
];
const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu";
public const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu";
const VALID_UTF8_REGEX = '/\p{Cc}+/u';
public const VALID_UTF8_REGEX = '/\p{Cc}+/u';
const CATCHABLE_PATTERNS = [
public const CATCHABLE_PATTERNS = [
'[a-zA-Z]+[46]?', //ASCII and domain literal
'[^\x00-\x7F]', //UTF-8
'[0-9]+',
@ -121,11 +125,11 @@ class EmailLexer extends AbstractLexer
'.',
];
const NON_CATCHABLE_PATTERNS = [
public const NON_CATCHABLE_PATTERNS = [
'[\xA0-\xff]+',
];
const MODIFIERS = 'iu';
public const MODIFIERS = 'iu';
/** @var bool */
protected $hasInvalidTokens = false;
@ -140,18 +144,20 @@ class EmailLexer extends AbstractLexer
/**
* The last matched/seen token.
*
* @var array
* @var array|Token
*
* @psalm-suppress NonInvariantDocblockPropertyType
* @psalm-var array{value:string, type:null|int, position:int}
* @psalm-suppress NonInvariantDocblockPropertyType
* @psalm-var array{value:string, type:null|int, position:int}|Token<int, string>
*/
public $token;
/**
* The next token in the input.
*
* @var array{position: int, type: int|null|string, value: int|string}|null
* @var array|Token|null
*
* @psalm-suppress NonInvariantDocblockPropertyType
* @psalm-var array{position: int, type: int|null|string, value: int|string}|Token<int, string>|null
*/
public $lookahead;
@ -207,11 +213,11 @@ class EmailLexer extends AbstractLexer
public function moveNext() : bool
{
if ($this->hasToRecord && $this->previous === self::$nullToken) {
$this->accumulator .= $this->token['value'];
$this->accumulator .= ((array) $this->token)['value'];
}
$this->previous = $this->token;
$this->previous = (array) $this->token;
if($this->lookahead === null) {
$this->lookahead = self::$nullToken;
}
@ -219,7 +225,7 @@ class EmailLexer extends AbstractLexer
$hasNext = parent::moveNext();
if ($this->hasToRecord) {
$this->accumulator .= $this->token['value'];
$this->accumulator .= ((array) $this->token)['value'];
}
return $hasNext;

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\LocalPart;
use Egulias\EmailValidator\Parser\DomainPart;
@ -13,7 +12,7 @@ use Egulias\EmailValidator\Result\Reason\NoLocalPart;
class EmailParser extends Parser
{
const EMAIL_MAX_LENGTH = 254;
public const EMAIL_MAX_LENGTH = 254;
/**
* @var string

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\IDLeftPart;
use Egulias\EmailValidator\Parser\IDRightPart;
@ -14,7 +13,7 @@ use Egulias\EmailValidator\Result\Reason\NoLocalPart;
class MessageIDParser extends Parser
{
const EMAILID_MAX_LENGTH = 254;
public const EMAILID_MAX_LENGTH = 254;
/**
* @var string
@ -89,4 +88,4 @@ class MessageIDParser extends Parser
$this->warnings[EmailTooLong::CODE] = new EmailTooLong();
}
}
}
}

View File

@ -29,7 +29,7 @@ abstract class Parser
public function __construct(EmailLexer $lexer)
{
$this->lexer = $lexer;
$this->lexer = $lexer;
}
public function parse(string $str) : Result
@ -51,7 +51,7 @@ abstract class Parser
return $localPartResult;
}
$domainPartResult = $this->parseRightFromAt();
$domainPartResult = $this->parseRightFromAt();
if ($domainPartResult->isInvalid()) {
return $domainPartResult;
@ -73,6 +73,6 @@ abstract class Parser
$this->lexer->moveNext();
$this->lexer->moveNext();
return $this->lexer->token['type'] !== EmailLexer::S_AT;
return ((array) $this->lexer->token)['type'] !== EmailLexer::S_AT;
}
}

View File

@ -31,15 +31,15 @@ class Comment extends PartParser
public function parse() : Result
{
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->openedParenthesis++;
if($this->noClosingParenthesis()) {
return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']);
return new InvalidEmail(new UnclosedComment(), ((array) $this->lexer->token)['value']);
}
}
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
return new InvalidEmail(new UnOpenedComment(), ((array) $this->lexer->token)['value']);
}
$this->warnings[WarningComment::CODE] = new WarningComment();
@ -58,9 +58,10 @@ class Comment extends PartParser
}
if($this->openedParenthesis >= 1) {
return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']);
} else if ($this->openedParenthesis < 0) {
return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']);
return new InvalidEmail(new UnclosedComment(), ((array) $this->lexer->token)['value']);
}
if ($this->openedParenthesis < 0) {
return new InvalidEmail(new UnOpenedComment(), ((array) $this->lexer->token)['value']);
}
$finalValidations = $this->commentStrategy->endOfLoopValidations($this->lexer);
@ -77,7 +78,7 @@ class Comment extends PartParser
private function warnEscaping() : bool
{
//Backslash found
if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
if (((array) $this->lexer->token)['type'] !== EmailLexer::S_BACKSLASH) {
return false;
}
@ -86,12 +87,12 @@ class Comment extends PartParser
}
$this->warnings[QuotedPart::CODE] =
new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
new QuotedPart($this->lexer->getPrevious()['type'], ((array) $this->lexer->token)['type']);
return true;
}
private function noClosingParenthesis() : bool
private function noClosingParenthesis() : bool
{
try {
$this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS);
@ -100,4 +101,4 @@ class Comment extends PartParser
return true;
}
}
}
}

View File

@ -15,4 +15,4 @@ interface CommentStrategy
public function endOfLoopValidations(EmailLexer $lexer) : Result;
public function getWarnings() : array;
}
}

View File

@ -23,7 +23,7 @@ class DomainComment implements CommentStrategy
{
//test for end of string
if (!$lexer->isNextToken(EmailLexer::S_DOT)) {
return new InvalidEmail(new ExpectingATEXT('DOT not found near CLOSEPARENTHESIS'), $lexer->token['value']);
return new InvalidEmail(new ExpectingATEXT('DOT not found near CLOSEPARENTHESIS'), ((array) $lexer->token)['value']);
}
//add warning
//Address is valid within the message but cannot be used unmodified for the envelope
@ -34,4 +34,4 @@ class DomainComment implements CommentStrategy
{
return [];
}
}
}

View File

@ -24,7 +24,7 @@ class LocalComment implements CommentStrategy
public function endOfLoopValidations(EmailLexer $lexer) : Result
{
if (!$lexer->isNextToken(EmailLexer::S_AT)) {
return new InvalidEmail(new ExpectingATEXT('ATEX is not expected after closing comments'), $lexer->token['value']);
return new InvalidEmail(new ExpectingATEXT('ATEX is not expected after closing comments'), ((array) $lexer->token)['value']);
}
$this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
return new ValidEmail();
@ -34,4 +34,4 @@ class LocalComment implements CommentStrategy
{
return $this->warnings;
}
}
}

View File

@ -22,9 +22,9 @@ use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
class DomainLiteral extends PartParser
{
const IPV4_REGEX = '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/';
public const IPV4_REGEX = '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/';
const OBSOLETE_WARNINGS = [
public const OBSOLETE_WARNINGS = [
EmailLexer::INVALID,
EmailLexer::C_DEL,
EmailLexer::S_LF,
@ -39,14 +39,14 @@ class DomainLiteral extends PartParser
$addressLiteral = '';
do {
if ($this->lexer->token['type'] === EmailLexer::C_NUL) {
return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::C_NUL) {
return new InvalidEmail(new ExpectingDTEXT(), ((array) $this->lexer->token)['value']);
}
$this->addObsoleteWarnings();
if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) {
return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
return new InvalidEmail(new ExpectingDTEXT(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->isNextTokenAny(
@ -57,21 +57,21 @@ class DomainLiteral extends PartParser
}
if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']);
return new InvalidEmail(new CRNoLF(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) {
return new InvalidEmail(new UnusualElements($this->lexer->token['value']), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_BACKSLASH) {
return new InvalidEmail(new UnusualElements(((array) $this->lexer->token)['value']), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_IPV6TAG) {
$IPv6TAG = true;
}
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_CLOSEBRACKET) {
break;
}
$addressLiteral .= $this->lexer->token['value'];
$addressLiteral .= ((array) $this->lexer->token)['value'];
} while ($this->lexer->moveNext());
@ -144,7 +144,7 @@ class DomainLiteral extends PartParser
$this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated();
}
}
public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string
{
$matchesIP = [];
@ -189,7 +189,7 @@ class DomainLiteral extends PartParser
private function addObsoleteWarnings() : void
{
if(in_array($this->lexer->token['type'], self::OBSOLETE_WARNINGS)) {
if(in_array(((array) $this->lexer->token)['type'], self::OBSOLETE_WARNINGS)) {
$this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
}
}
@ -208,4 +208,4 @@ class DomainLiteral extends PartParser
}
}
}
}

View File

@ -2,6 +2,7 @@
namespace Egulias\EmailValidator\Parser;
use Doctrine\Common\Lexer\Token;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Warning\TLD;
use Egulias\EmailValidator\Result\Result;
@ -24,8 +25,8 @@ use Egulias\EmailValidator\Parser\DomainLiteral as DomainLiteralParser;
class DomainPart extends PartParser
{
const DOMAIN_MAX_LENGTH = 253;
const LABEL_MAX_LENGTH = 63;
public const DOMAIN_MAX_LENGTH = 253;
public const LABEL_MAX_LENGTH = 63;
/**
* @var string
@ -49,8 +50,8 @@ class DomainPart extends PartParser
return $domainChecks;
}
if ($this->lexer->token['type'] === EmailLexer::S_AT) {
return new InvalidEmail(new ConsecutiveAt(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_AT) {
return new InvalidEmail(new ConsecutiveAt(), ((array) $this->lexer->token)['value']);
}
$result = $this->doParseDomainPart();
@ -68,7 +69,7 @@ class DomainPart extends PartParser
$length = strlen($this->domainPart);
if ($length > self::DOMAIN_MAX_LENGTH) {
return new InvalidEmail(new DomainTooLong(), $this->lexer->token['value']);
return new InvalidEmail(new DomainTooLong(), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
@ -78,13 +79,13 @@ class DomainPart extends PartParser
{
$prev = $this->lexer->getPrevious();
if ($prev['type'] === EmailLexer::S_DOT) {
return new InvalidEmail(new DotAtEnd(), $this->lexer->token['value']);
return new InvalidEmail(new DotAtEnd(), ((array) $this->lexer->token)['value']);
}
if ($prev['type'] === EmailLexer::S_HYPHEN) {
return new InvalidEmail(new DomainHyphened('Hypen found at the end of the domain'), $prev['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_SP) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_SP) {
return new InvalidEmail(new CRLFAtTheEnd(), $prev['value']);
}
return new ValidEmail();
@ -97,13 +98,13 @@ class DomainPart extends PartParser
if ($invalidTokens->isInvalid()) {
return $invalidTokens;
}
$missingDomain = $this->checkEmptyDomain();
if ($missingDomain->isInvalid()) {
return $missingDomain;
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->warnings[DeprecatedComment::CODE] = new DeprecatedComment();
}
return new ValidEmail();
@ -111,12 +112,12 @@ class DomainPart extends PartParser
private function checkEmptyDomain() : Result
{
$thereIsNoDomain = $this->lexer->token['type'] === EmailLexer::S_EMPTY ||
($this->lexer->token['type'] === EmailLexer::S_SP &&
$thereIsNoDomain = ((array) $this->lexer->token)['type'] === EmailLexer::S_EMPTY ||
(((array) $this->lexer->token)['type'] === EmailLexer::S_SP &&
!$this->lexer->isNextToken(EmailLexer::GENERIC));
if ($thereIsNoDomain) {
return new InvalidEmail(new NoDomainPart(), $this->lexer->token['value']);
return new InvalidEmail(new NoDomainPart(), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
@ -124,11 +125,11 @@ class DomainPart extends PartParser
private function checkInvalidTokensAfterAT() : Result
{
if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
return new InvalidEmail(new DotAtStart(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT) {
return new InvalidEmail(new DotAtStart(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
return new InvalidEmail(new DomainHyphened('After AT'), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_HYPHEN) {
return new InvalidEmail(new DomainHyphened('After AT'), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
}
@ -155,8 +156,8 @@ class DomainPart extends PartParser
return $notAllowedChars;
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS ||
$this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS ) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENPARENTHESIS ||
((array) $this->lexer->token)['type'] === EmailLexer::S_CLOSEPARENTHESIS ) {
$hasComments = true;
$commentsResult = $this->parseComments();
@ -171,7 +172,7 @@ class DomainPart extends PartParser
return $dotsResult;
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENBRACKET) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENBRACKET) {
$literalResult = $this->parseDomainLiteral();
$this->addTLDWarnings($tldMissing);
@ -188,9 +189,9 @@ class DomainPart extends PartParser
return $FwsResult;
}
$domain .= $this->lexer->token['value'];
$domain .= ((array) $this->lexer->token)['value'];
if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::GENERIC)) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::GENERIC)) {
$tldMissing = false;
}
@ -200,7 +201,7 @@ class DomainPart extends PartParser
}
$this->lexer->moveNext();
} while (null !== $this->lexer->token['type']);
} while (null !== ((array) $this->lexer->token)['type']);
$labelCheck = $this->checkLabelLength(true);
if ($labelCheck->isInvalid()) {
@ -212,11 +213,14 @@ class DomainPart extends PartParser
return new ValidEmail();
}
private function checkNotAllowedChars(array $token) : Result
/**
* @psalm-param array|Token<int, string> $token
*/
private function checkNotAllowedChars($token) : Result
{
$notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true];
if (isset($notAllowed[$token['type']])) {
return new InvalidEmail(new CharNotAllowed(), $token['value']);
if (isset($notAllowed[((array) $token)['type']])) {
return new InvalidEmail(new CharNotAllowed(), ((array) $token)['value']);
}
return new ValidEmail();
}
@ -229,7 +233,7 @@ class DomainPart extends PartParser
try {
$this->lexer->find(EmailLexer::S_CLOSEBRACKET);
} catch (\RuntimeException $e) {
return new InvalidEmail(new ExpectingDomainLiteralClose(), $this->lexer->token['value']);
return new InvalidEmail(new ExpectingDomainLiteralClose(), ((array) $this->lexer->token)['value']);
}
$domainLiteralParser = new DomainLiteralParser($this->lexer);
@ -240,17 +244,17 @@ class DomainPart extends PartParser
protected function checkDomainPartExceptions(array $prev, bool $hasComments) : Result
{
if ($this->lexer->token['type'] === EmailLexer::S_OPENBRACKET && $prev['type'] !== EmailLexer::S_AT) {
return new InvalidEmail(new ExpectingATEXT('OPENBRACKET not after AT'), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENBRACKET && $prev['type'] !== EmailLexer::S_AT) {
return new InvalidEmail(new ExpectingATEXT('OPENBRACKET not after AT'), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
return new InvalidEmail(new DomainHyphened('Hypen found near DOT'), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
return new InvalidEmail(new DomainHyphened('Hypen found near DOT'), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH
if (((array) $this->lexer->token)['type'] === EmailLexer::S_BACKSLASH
&& $this->lexer->isNextToken(EmailLexer::GENERIC)) {
return new InvalidEmail(new ExpectingATEXT('Escaping following "ATOM"'), $this->lexer->token['value']);
return new InvalidEmail(new ExpectingATEXT('Escaping following "ATOM"'), ((array) $this->lexer->token)['value']);
}
return $this->validateTokens($hasComments);
@ -269,8 +273,8 @@ class DomainPart extends PartParser
$validDomainTokens[EmailLexer::S_CLOSEPARENTHESIS] = true;
}
if (!isset($validDomainTokens[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']);
if (!isset($validDomainTokens[((array) $this->lexer->token)['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . ((array) $this->lexer->token)['value']), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
@ -278,13 +282,13 @@ class DomainPart extends PartParser
private function checkLabelLength(bool $isEndOfDomain = false) : Result
{
if ($this->lexer->token['type'] === EmailLexer::S_DOT || $isEndOfDomain) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT || $isEndOfDomain) {
if ($this->isLabelTooLong($this->label)) {
return new InvalidEmail(new LabelTooLong(), $this->lexer->token['value']);
return new InvalidEmail(new LabelTooLong(), ((array) $this->lexer->token)['value']);
}
$this->label = '';
}
$this->label .= $this->lexer->token['value'];
$this->label .= ((array) $this->lexer->token)['value'];
return new ValidEmail();
}

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Parser\Parser;
use Egulias\EmailValidator\Result\ValidEmail;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Warning\CFWSWithFWS;
@ -31,24 +30,24 @@ class DoubleQuote extends PartParser
EmailLexer::S_CR => true,
EmailLexer::S_LF => true
];
$setSpecialsWarning = true;
$this->lexer->moveNext();
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) {
if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
while (((array) $this->lexer->token)['type'] !== EmailLexer::S_DQUOTE && null !== ((array) $this->lexer->token)['type']) {
if (isset($special[((array) $this->lexer->token)['type']]) && $setSpecialsWarning) {
$this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
$setSpecialsWarning = false;
}
if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) {
$this->lexer->moveNext();
}
$this->lexer->moveNext();
if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->token['value']);
if (!$this->escaped() && isset($invalid[((array) $this->lexer->token)['type']])) {
return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), ((array) $this->lexer->token)['value']);
}
}
@ -60,7 +59,7 @@ class DoubleQuote extends PartParser
}
if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) {
return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->token['value']);
return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
@ -72,17 +71,17 @@ class DoubleQuote extends PartParser
if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
$description = 'https://tools.ietf.org/html/rfc5322#section-3.2.4 - quoted string should be a unit';
return new InvalidEmail(new ExpectingATEXT($description), $this->lexer->token['value']);
return new InvalidEmail(new ExpectingATEXT($description), ((array) $this->lexer->token)['value']);
}
try {
$this->lexer->find(EmailLexer::S_DQUOTE);
} catch (\Exception $e) {
return new InvalidEmail(new UnclosedQuotedString(), $this->lexer->token['value']);
return new InvalidEmail(new UnclosedQuotedString(), ((array) $this->lexer->token)['value']);
}
$this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']);
$this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], ((array) $this->lexer->token)['value']);
return new ValidEmail();
}
}
}

View File

@ -15,7 +15,7 @@ use Egulias\EmailValidator\Result\ValidEmail;
class FoldingWhiteSpace extends PartParser
{
const FWS_TYPES = [
public const FWS_TYPES = [
EmailLexer::S_SP,
EmailLexer::S_HTAB,
EmailLexer::S_CR,
@ -36,16 +36,16 @@ class FoldingWhiteSpace extends PartParser
return $resultCRLF;
}
if ($this->lexer->token['type'] === EmailLexer::S_CR) {
return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_CR) {
return new InvalidEmail(new CRNoLF(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] !== EmailLexer::S_AT) {
return new InvalidEmail(new AtextAfterCFWS(), $this->lexer->token['value']);
return new InvalidEmail(new AtextAfterCFWS(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) {
return new InvalidEmail(new ExpectingCTEXT(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_LF || ((array) $this->lexer->token)['type'] === EmailLexer::C_NUL) {
return new InvalidEmail(new ExpectingCTEXT(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type'] === EmailLexer::S_AT) {
@ -59,28 +59,28 @@ class FoldingWhiteSpace extends PartParser
protected function checkCRLFInFWS() : Result
{
if ($this->lexer->token['type'] !== EmailLexer::CRLF) {
if (((array) $this->lexer->token)['type'] !== EmailLexer::CRLF) {
return new ValidEmail();
}
if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
return new InvalidEmail(new CRLFX2(), $this->lexer->token['value']);
return new InvalidEmail(new CRLFX2(), ((array) $this->lexer->token)['value']);
}
//this has no coverage. Condition is repeated from above one
if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
return new InvalidEmail(new CRLFAtTheEnd(), $this->lexer->token['value']);
return new InvalidEmail(new CRLFAtTheEnd(), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
}
protected function isFWS() : bool
{
if ($this->escaped()) {
return false;
}
return in_array($this->lexer->token['type'], self::FWS_TYPES);
return in_array(((array) $this->lexer->token)['type'], self::FWS_TYPES);
}
}
}

View File

@ -3,7 +3,6 @@
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\LocalPart;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\CommentsInIDRight;
@ -11,6 +10,6 @@ class IDLeftPart extends LocalPart
{
protected function parseComments(): Result
{
return new InvalidEmail(new CommentsInIDRight(), $this->lexer->token['value']);
return new InvalidEmail(new CommentsInIDRight(), ((array) $this->lexer->token)['value']);
}
}
}

View File

@ -20,10 +20,10 @@ class IDRightPart extends DomainPart
EmailLexer::S_GREATERTHAN => true,
EmailLexer::S_LOWERTHAN => true,
];
if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']);
if (isset($invalidDomainTokens[((array) $this->lexer->token)['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . ((array) $this->lexer->token)['value']), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
}
}
}

View File

@ -15,7 +15,7 @@ use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment;
class LocalPart extends PartParser
{
const INVALID_TOKENS = [
public const INVALID_TOKENS = [
EmailLexer::S_COMMA => EmailLexer::S_COMMA,
EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,
@ -36,12 +36,12 @@ class LocalPart extends PartParser
{
$this->lexer->startRecording();
while ($this->lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) {
while (((array) $this->lexer->token)['type'] !== EmailLexer::S_AT && null !== ((array) $this->lexer->token)['type']) {
if ($this->hasDotAtStart()) {
return new InvalidEmail(new DotAtStart(), $this->lexer->token['value']);
return new InvalidEmail(new DotAtStart(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_DQUOTE) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_DQUOTE) {
$dquoteParsingResult = $this->parseDoubleQuote();
//Invalid double quote parsing
@ -50,8 +50,8 @@ class LocalPart extends PartParser
}
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS ||
$this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS ) {
if (((array) $this->lexer->token)['type'] === EmailLexer::S_OPENPARENTHESIS ||
((array) $this->lexer->token)['type'] === EmailLexer::S_CLOSEPARENTHESIS ) {
$commentsResult = $this->parseComments();
//Invalid comment parsing
@ -60,14 +60,14 @@ class LocalPart extends PartParser
}
}
if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
return new InvalidEmail(new ConsecutiveDot(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
return new InvalidEmail(new ConsecutiveDot(), ((array) $this->lexer->token)['value']);
}
if ($this->lexer->token['type'] === EmailLexer::S_DOT &&
if (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT &&
$this->lexer->isNextToken(EmailLexer::S_AT)
) {
return new InvalidEmail(new DotAtEnd(), $this->lexer->token['value']);
return new InvalidEmail(new DotAtEnd(), ((array) $this->lexer->token)['value']);
}
$resultEscaping = $this->validateEscaping();
@ -99,8 +99,8 @@ class LocalPart extends PartParser
protected function validateTokens(bool $hasComments) : Result
{
if (isset(self::INVALID_TOKENS[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']);
if (isset(self::INVALID_TOKENS[((array) $this->lexer->token)['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token found'), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
}
@ -110,7 +110,7 @@ class LocalPart extends PartParser
return $this->localPart;
}
private function parseLocalFWS() : Result
private function parseLocalFWS() : Result
{
$foldingWS = new FoldingWhiteSpace($this->lexer);
$resultFWS = $foldingWS->parse();
@ -122,7 +122,7 @@ class LocalPart extends PartParser
private function hasDotAtStart() : bool
{
return $this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type'];
return ((array) $this->lexer->token)['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type'];
}
private function parseDoubleQuote() : Result
@ -148,12 +148,12 @@ class LocalPart extends PartParser
private function validateEscaping() : Result
{
//Backslash found
if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
if (((array) $this->lexer->token)['type'] !== EmailLexer::S_BACKSLASH) {
return new ValidEmail();
}
if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->token['value']);
return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), ((array) $this->lexer->token)['value']);
}
if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
@ -162,4 +162,4 @@ class LocalPart extends PartParser
return new ValidEmail();
}
}
}

View File

@ -45,8 +45,8 @@ abstract class PartParser
protected function checkConsecutiveDots() : Result
{
if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
return new InvalidEmail(new ConsecutiveDot(), $this->lexer->token['value']);
if (((array) $this->lexer->token)['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
return new InvalidEmail(new ConsecutiveDot(), ((array) $this->lexer->token)['value']);
}
return new ValidEmail();
@ -58,6 +58,6 @@ abstract class PartParser
return $previous && $previous['type'] === EmailLexer::S_BACKSLASH
&&
$this->lexer->token['type'] !== EmailLexer::GENERIC;
((array) $this->lexer->token)['type'] !== EmailLexer::GENERIC;
}
}
}

View File

@ -6,7 +6,7 @@ use Egulias\EmailValidator\Result\Reason\Reason;
class InvalidEmail implements Result
{
private $token;
private $token;
/**
* @var Reason
*/
@ -43,4 +43,4 @@ class InvalidEmail implements Result
return $this->reason;
}
}
}

View File

@ -13,4 +13,4 @@ class AtextAfterCFWS implements Reason
{
return 'ATEXT found after CFWS';
}
}
}

View File

@ -4,8 +4,8 @@ namespace Egulias\EmailValidator\Result\Reason;
class CRLFAtTheEnd implements Reason
{
const CODE = 149;
const REASON = "CRLF at the end";
public const CODE = 149;
public const REASON = "CRLF at the end";
public function code() : int
{

View File

@ -13,4 +13,4 @@ class CharNotAllowed implements Reason
{
return "Character not allowed";
}
}
}

View File

@ -13,4 +13,4 @@ class CommaInDomain implements Reason
{
return "Comma ',' is not allowed in domain part";
}
}
}

View File

@ -13,4 +13,4 @@ class CommentsInIDRight implements Reason
{
return 'Comments are not allowed in IDRight for message-id';
}
}
}

View File

@ -10,4 +10,4 @@ abstract class DetailedReason implements Reason
{
$this->detailedDescription = $details;
}
}
}

View File

@ -13,4 +13,4 @@ class DomainAcceptsNoMail implements Reason
{
return 'Domain accepts no mail (Null MX, RFC7505)';
}
}
}

View File

@ -23,4 +23,4 @@ class ExceptionFound implements Reason
{
return $this->exception->getMessage();
}
}
}

View File

@ -13,4 +13,4 @@ class ExpectingDomainLiteralClose implements Reason
{
return "Closing bracket ']' for domain literal not found";
}
}
}

View File

@ -13,4 +13,4 @@ class LocalOrReservedDomain implements Reason
{
return 'Local, mDNS or reserved domain (RFC2606, RFC6762)';
}
}
}

View File

@ -13,4 +13,4 @@ class NoDNSRecord implements Reason
{
return 'No MX or A DSN record was found for this email';
}
}
}

View File

@ -13,4 +13,4 @@ interface Reason
* Short description of the result, human readable.
*/
public function description() : string;
}
}

View File

@ -13,4 +13,4 @@ class UnOpenedComment implements Reason
{
return 'Missing opening comment parentheses - https://tools.ietf.org/html/rfc5322#section-3.2.2';
}
}
}

View File

@ -23,4 +23,4 @@ class UnusualElements implements Reason
{
return 'Unusual element found, wourld render invalid in majority of cases. Element found: ' . $this->element;
}
}
}

View File

@ -24,4 +24,4 @@ interface Result
* Code for user land to act upon.
*/
public function code() : int;
}
}

View File

@ -1,7 +1,6 @@
<?php
namespace Egulias\EmailValidator\Result;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\SpoofEmail as ReasonSpoofEmail;
class SpoofEmail extends InvalidEmail
@ -11,4 +10,4 @@ class SpoofEmail extends InvalidEmail
$this->reason = new ReasonSpoofEmail();
parent::__construct($this->reason, '');
}
}
}

View File

@ -24,4 +24,4 @@ class ValidEmail implements Result
return 0;
}
}
}

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\Validation\DNSGetRecordWrapper;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\DomainAcceptsNoMail;
@ -22,7 +21,7 @@ class DNSCheckValidation implements EmailValidation
* Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2),
* mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G)
*/
const RESERVED_DNS_TOP_LEVEL_NAMES = [
public const RESERVED_DNS_TOP_LEVEL_NAMES = [
// Reserved Top Level DNS Names
'test',
'example',
@ -61,7 +60,7 @@ class DNSCheckValidation implements EmailValidation
*/
private $dnsGetRecord;
public function __construct(DNSGetRecordWrapper $dnsGetRecord = null)
public function __construct(?DNSGetRecordWrapper $dnsGetRecord = null)
{
if (!function_exists('idn_to_ascii')) {
throw new \LogicException(sprintf('The %s class requires the Intl extension.', __CLASS__));
@ -189,4 +188,4 @@ class DNSCheckValidation implements EmailValidation
return true;
}
}
}

View File

@ -25,4 +25,4 @@ class DNSGetRecordWrapper
restore_error_handler();
}
}
}
}

View File

@ -32,4 +32,4 @@ class DNSRecords
}
}
}

View File

@ -9,7 +9,7 @@ class EmptyValidationList extends \InvalidArgumentException
/**
* @param int $code
*/
public function __construct($code = 0, Exception $previous = null)
public function __construct($code = 0, ?Exception $previous = null)
{
parent::__construct("Empty validation list is not allowed", $code, $previous);
}

View File

@ -13,13 +13,13 @@ class MultipleValidationWithAnd implements EmailValidation
* If one of validations fails, the remaining validations will be skipped.
* This means MultipleErrors will only contain a single error, the first found.
*/
const STOP_ON_ERROR = 0;
public const STOP_ON_ERROR = 0;
/**
* All of validations will be invoked even if one of them got failure.
* So MultipleErrors will contain all causes.
*/
const ALLOW_ALL_ERRORS = 1;
public const ALLOW_ALL_ERRORS = 1;
/**
* @var EmailValidation[]

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class AddressLiteral extends Warning
{
const CODE = 12;
public const CODE = 12;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class CFWSNearAt extends Warning
{
const CODE = 49;
public const CODE = 49;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class CFWSWithFWS extends Warning
{
const CODE = 18;
public const CODE = 18;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class Comment extends Warning
{
const CODE = 17;
public const CODE = 17;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class DeprecatedComment extends Warning
{
const CODE = 37;
public const CODE = 37;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class DomainLiteral extends Warning
{
const CODE = 70;
public const CODE = 70;
public function __construct()
{

View File

@ -6,7 +6,7 @@ use Egulias\EmailValidator\EmailParser;
class EmailTooLong extends Warning
{
const CODE = 66;
public const CODE = 66;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6BadChar extends Warning
{
const CODE = 74;
public const CODE = 74;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6ColonEnd extends Warning
{
const CODE = 77;
public const CODE = 77;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6ColonStart extends Warning
{
const CODE = 76;
public const CODE = 76;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6Deprecated extends Warning
{
const CODE = 13;
public const CODE = 13;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6DoubleColon extends Warning
{
const CODE = 73;
public const CODE = 73;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6GroupCount extends Warning
{
const CODE = 72;
public const CODE = 72;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6MaxGroups extends Warning
{
const CODE = 75;
public const CODE = 75;
public function __construct()
{

View File

@ -4,8 +4,8 @@ namespace Egulias\EmailValidator\Warning;
class LocalTooLong extends Warning
{
const CODE = 64;
const LOCAL_PART_LENGTH = 64;
public const CODE = 64;
public const LOCAL_PART_LENGTH = 64;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class NoDNSMXRecord extends Warning
{
const CODE = 6;
public const CODE = 6;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class ObsoleteDTEXT extends Warning
{
const CODE = 71;
public const CODE = 71;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class QuotedPart extends Warning
{
const CODE = 36;
public const CODE = 36;
/**
* @param scalar $prevToken

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class QuotedString extends Warning
{
const CODE = 11;
public const CODE = 11;
/**
* @param scalar $prevToken

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class TLD extends Warning
{
const CODE = 9;
public const CODE = 9;
public function __construct()
{

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
abstract class Warning
{
const CODE = 0;
public const CODE = 0;
/**
* @var string

View File

@ -1,4 +1,4 @@
Copyright (c) 2018-2022 Fabien Potencier
Copyright (c) 2018-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -30,7 +30,7 @@ class AmqpReceiver implements QueueReceiverInterface, MessageCountAwareInterface
private $serializer;
private $connection;
public function __construct(Connection $connection, SerializerInterface $serializer = null)
public function __construct(Connection $connection, ?SerializerInterface $serializer = null)
{
$this->connection = $connection;
$this->serializer = $serializer ?? new PhpSerializer();

View File

@ -29,7 +29,7 @@ class AmqpSender implements SenderInterface
private $serializer;
private $connection;
public function __construct(Connection $connection, SerializerInterface $serializer = null)
public function __construct(Connection $connection, ?SerializerInterface $serializer = null)
{
$this->connection = $connection;
$this->serializer = $serializer ?? new PhpSerializer();

View File

@ -24,7 +24,7 @@ final class AmqpStamp implements NonSendableStampInterface
private $attributes;
private $isRetryAttempt = false;
public function __construct(string $routingKey = null, int $flags = \AMQP_NOPARAM, array $attributes = [])
public function __construct(?string $routingKey = null, int $flags = \AMQP_NOPARAM, array $attributes = [])
{
$this->routingKey = $routingKey;
$this->flags = $flags;
@ -46,7 +46,7 @@ final class AmqpStamp implements NonSendableStampInterface
return $this->attributes;
}
public static function createFromAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, self $previousStamp = null, string $retryRoutingKey = null): self
public static function createFromAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, ?self $previousStamp = null, ?string $retryRoutingKey = null): self
{
$attr = $previousStamp->attributes ?? [];
@ -79,7 +79,7 @@ final class AmqpStamp implements NonSendableStampInterface
return $this->isRetryAttempt;
}
public static function createWithAttributes(array $attributes, self $previousStamp = null): self
public static function createWithAttributes(array $attributes, ?self $previousStamp = null): self
{
return new self(
$previousStamp->routingKey ?? null,

View File

@ -29,7 +29,7 @@ class AmqpTransport implements QueueReceiverInterface, TransportInterface, Setup
private $receiver;
private $sender;
public function __construct(Connection $connection, SerializerInterface $serializer = null)
public function __construct(Connection $connection, ?SerializerInterface $serializer = null)
{
$this->connection = $connection;
$this->serializer = $serializer ?? new PhpSerializer();

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Messenger\Bridge\Amqp\Transport;
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
use Symfony\Component\Messenger\Exception\LogicException;
use Symfony\Component\Messenger\Exception\TransportException;
/**
* An AMQP connection.
@ -32,6 +33,9 @@ class Connection
'x-message-ttl',
];
/**
* @see https://github.com/php-amqp/php-amqp/blob/master/amqp_connection_resource.h
*/
private const AVAILABLE_OPTIONS = [
'host',
'port',
@ -53,6 +57,7 @@ class Connection
'write_timeout',
'confirm_timeout',
'connect_timeout',
'rpc_timeout',
'cacert',
'cert',
'key',
@ -102,7 +107,12 @@ class Connection
*/
private $amqpDelayExchange;
public function __construct(array $connectionOptions, array $exchangeOptions, array $queuesOptions, AmqpFactory $amqpFactory = null)
/**
* @var int
*/
private $lastActivityTime = 0;
public function __construct(array $connectionOptions, array $exchangeOptions, array $queuesOptions, ?AmqpFactory $amqpFactory = null)
{
if (!\extension_loaded('amqp')) {
throw new LogicException(sprintf('You cannot use the "%s" as the "amqp" extension is not installed.', __CLASS__));
@ -166,26 +176,26 @@ class Connection
* * verify: Enable or disable peer verification. If peer verification is enabled then the common name in the
* server certificate must match the server name. Peer verification is enabled by default.
*/
public static function fromDsn(string $dsn, array $options = [], AmqpFactory $amqpFactory = null): self
public static function fromDsn(string $dsn, array $options = [], ?AmqpFactory $amqpFactory = null): self
{
if (false === $parsedUrl = parse_url($dsn)) {
if (false === $params = parse_url($dsn)) {
// this is a valid URI that parse_url cannot handle when you want to pass all parameters as options
if (!\in_array($dsn, ['amqp://', 'amqps://'])) {
throw new InvalidArgumentException(sprintf('The given AMQP DSN "%s" is invalid.', $dsn));
throw new InvalidArgumentException('The given AMQP DSN is invalid.');
}
$parsedUrl = [];
$params = [];
}
$useAmqps = 0 === strpos($dsn, 'amqps://');
$pathParts = isset($parsedUrl['path']) ? explode('/', trim($parsedUrl['path'], '/')) : [];
$pathParts = isset($params['path']) ? explode('/', trim($params['path'], '/')) : [];
$exchangeName = $pathParts[1] ?? 'messages';
parse_str($parsedUrl['query'] ?? '', $parsedQuery);
parse_str($params['query'] ?? '', $parsedQuery);
$port = $useAmqps ? 5671 : 5672;
$amqpOptions = array_replace_recursive([
'host' => $parsedUrl['host'] ?? 'localhost',
'port' => $parsedUrl['port'] ?? $port,
'host' => $params['host'] ?? 'localhost',
'port' => $params['port'] ?? $port,
'vhost' => isset($pathParts[0]) ? urldecode($pathParts[0]) : '/',
'exchange' => [
'name' => $exchangeName,
@ -194,12 +204,12 @@ class Connection
self::validateOptions($amqpOptions);
if (isset($parsedUrl['user'])) {
$amqpOptions['login'] = urldecode($parsedUrl['user']);
if (isset($params['user'])) {
$amqpOptions['login'] = rawurldecode($params['user']);
}
if (isset($parsedUrl['pass'])) {
$amqpOptions['password'] = urldecode($parsedUrl['pass']);
if (isset($params['pass'])) {
$amqpOptions['password'] = rawurldecode($params['pass']);
}
if (!isset($amqpOptions['queues'])) {
@ -288,7 +298,7 @@ class Connection
/**
* @throws \AMQPException
*/
public function publish(string $body, array $headers = [], int $delayInMs = 0, AmqpStamp $amqpStamp = null): void
public function publish(string $body, array $headers = [], int $delayInMs = 0, ?AmqpStamp $amqpStamp = null): void
{
$this->clearWhenDisconnected();
@ -324,7 +334,7 @@ class Connection
/**
* @throws \AMQPException
*/
private function publishWithDelay(string $body, array $headers, int $delay, AmqpStamp $amqpStamp = null)
private function publishWithDelay(string $body, array $headers, int $delay, ?AmqpStamp $amqpStamp = null)
{
$routingKey = $this->getRoutingKeyForMessage($amqpStamp);
$isRetryAttempt = $amqpStamp ? $amqpStamp->isRetryAttempt() : false;
@ -340,13 +350,15 @@ class Connection
);
}
private function publishOnExchange(\AMQPExchange $exchange, string $body, string $routingKey = null, array $headers = [], AmqpStamp $amqpStamp = null)
private function publishOnExchange(\AMQPExchange $exchange, string $body, ?string $routingKey = null, array $headers = [], ?AmqpStamp $amqpStamp = null)
{
$attributes = $amqpStamp ? $amqpStamp->getAttributes() : [];
$attributes['headers'] = array_merge($attributes['headers'] ?? [], $headers);
$attributes['delivery_mode'] = $attributes['delivery_mode'] ?? 2;
$attributes['timestamp'] = $attributes['timestamp'] ?? time();
$this->lastActivityTime = time();
$exchange->publish(
$body,
$routingKey,
@ -401,7 +413,7 @@ class Connection
// delete the delay queue 10 seconds after the message expires
// publishing another message redeclares the queue which renews the lease
'x-expires' => $delay + 10000,
// message should be broadcasted to all consumers during delay, but to only one queue during retry
// message should be broadcast to all consumers during delay, but to only one queue during retry
// empty name is default direct exchange
'x-dead-letter-exchange' => $isRetryAttempt ? '' : $this->exchangeOptions['name'],
// after being released from to DLX, make sure the original routing key will be used
@ -445,12 +457,12 @@ class Connection
public function ack(\AMQPEnvelope $message, string $queueName): bool
{
return $this->queue($queueName)->ack($message->getDeliveryTag());
return $this->queue($queueName)->ack($message->getDeliveryTag()) ?? true;
}
public function nack(\AMQPEnvelope $message, string $queueName, int $flags = \AMQP_NOPARAM): bool
{
return $this->queue($queueName)->nack($message->getDeliveryTag(), $flags);
return $this->queue($queueName)->nack($message->getDeliveryTag(), $flags) ?? true;
}
public function setup(): void
@ -505,11 +517,16 @@ class Connection
static function (): bool {
return false;
},
static function (): bool {
return false;
static function () {
throw new TransportException('Message publication failed due to a negative acknowledgment (nack) from the broker.');
}
);
}
$this->lastActivityTime = time();
} elseif (0 < ($this->connectionOptions['heartbeat'] ?? 0) && time() > $this->lastActivityTime + 2 * $this->connectionOptions['heartbeat']) {
$disconnectMethod = 'true' === ($this->connectionOptions['persistent'] ?? 'false') ? 'pdisconnect' : 'disconnect';
$this->amqpChannel->getConnection()->{$disconnectMethod}();
}
return $this->amqpChannel;
@ -518,7 +535,7 @@ class Connection
public function queue(string $queueName): \AMQPQueue
{
if (!isset($this->amqpQueues[$queueName])) {
$queueConfig = $this->queuesOptions[$queueName];
$queueConfig = $this->queuesOptions[$queueName] ?? [];
$amqpQueue = $this->amqpFactory->createQueue($this->channel());
$amqpQueue->setName($queueName);

View File

@ -1,4 +1,4 @@
Copyright (c) 2020-2022 Fabien Potencier
Copyright (c) 2020-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,4 +1,4 @@
Copyright (c) 2018-2022 Fabien Potencier
Copyright (c) 2018-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -66,7 +66,7 @@ class Connection implements ResetInterface
private $schemaSynchronizer;
private $autoSetup;
public function __construct(array $configuration, DBALConnection $driverConnection, SchemaSynchronizer $schemaSynchronizer = null)
public function __construct(array $configuration, DBALConnection $driverConnection, ?SchemaSynchronizer $schemaSynchronizer = null)
{
$this->configuration = array_replace_recursive(static::DEFAULT_OPTIONS, $configuration);
$this->driverConnection = $driverConnection;
@ -86,16 +86,16 @@ class Connection implements ResetInterface
public static function buildConfiguration(string $dsn, array $options = []): array
{
if (false === $components = parse_url($dsn)) {
throw new InvalidArgumentException(sprintf('The given Doctrine Messenger DSN "%s" is invalid.', $dsn));
if (false === $params = parse_url($dsn)) {
throw new InvalidArgumentException('The given Doctrine Messenger DSN is invalid.');
}
$query = [];
if (isset($components['query'])) {
parse_str($components['query'], $query);
if (isset($params['query'])) {
parse_str($params['query'], $query);
}
$configuration = ['connection' => $components['host']];
$configuration = ['connection' => $params['host']];
$configuration += $query + $options + static::DEFAULT_OPTIONS;
$configuration['auto_setup'] = filter_var($configuration['auto_setup'], \FILTER_VALIDATE_BOOLEAN);
@ -125,7 +125,7 @@ class Connection implements ResetInterface
public function send(string $body, array $headers, int $delay = 0): string
{
$now = new \DateTime();
$availableAt = (clone $now)->modify(sprintf('+%d seconds', $delay / 1000));
$availableAt = (clone $now)->modify(sprintf('%+d seconds', $delay / 1000));
$queryBuilder = $this->driverConnection->createQueryBuilder()
->insert($this->configuration['table_name'])
@ -144,9 +144,9 @@ class Connection implements ResetInterface
$now,
$availableAt,
], [
null,
null,
null,
Types::STRING,
Types::STRING,
Types::STRING,
Types::DATETIME_MUTABLE,
Types::DATETIME_MUTABLE,
]);
@ -161,6 +161,10 @@ class Connection implements ResetInterface
$this->driverConnection->delete($this->configuration['table_name'], ['delivered_at' => '9999-12-31 23:59:59']);
} catch (DriverException $e) {
// Ignore the exception
} catch (TableNotFoundException $e) {
if ($this->autoSetup) {
$this->setup();
}
}
}
@ -171,13 +175,32 @@ class Connection implements ResetInterface
->orderBy('available_at', 'ASC')
->setMaxResults(1);
if ($this->driverConnection->getDatabasePlatform() instanceof OraclePlatform) {
$query->select('m.id');
}
// Append pessimistic write lock to FROM clause if db platform supports it
$sql = $query->getSQL();
if (($fromPart = $query->getQueryPart('from')) &&
($table = $fromPart[0]['table'] ?? null) &&
($alias = $fromPart[0]['alias'] ?? null)
) {
$fromClause = sprintf('%s %s', $table, $alias);
// Wrap the rownum query in a sub-query to allow writelocks without ORA-02014 error
if ($this->driverConnection->getDatabasePlatform() instanceof OraclePlatform) {
$query = $this->createQueryBuilder('w')
->where('w.id IN ('.str_replace('SELECT a.* FROM', 'SELECT a.id FROM', $sql).')')
->setParameters($query->getParameters(), $query->getParameterTypes());
if (method_exists(QueryBuilder::class, 'forUpdate')) {
$query->forUpdate();
}
$sql = $query->getSQL();
} elseif (method_exists(QueryBuilder::class, 'forUpdate')) {
$query->forUpdate();
try {
$sql = $query->getSQL();
} catch (DBALException $e) {
}
} elseif (preg_match('/FROM (.+) WHERE/', (string) $sql, $matches)) {
$fromClause = $matches[1];
$sql = str_replace(
sprintf('FROM %s WHERE', $fromClause),
sprintf('FROM %s WHERE', $this->driverConnection->getDatabasePlatform()->appendLockHint($fromClause, LockMode::PESSIMISTIC_WRITE)),
@ -185,25 +208,13 @@ class Connection implements ResetInterface
);
}
// Wrap the rownum query in a sub-query to allow writelocks without ORA-02014 error
if ($this->driverConnection->getDatabasePlatform() instanceof OraclePlatform) {
$sql = str_replace('SELECT a.* FROM', 'SELECT a.id FROM', $sql);
$wrappedQuery = $this->driverConnection->createQueryBuilder()
->select(
'w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", '.
'w.created_at AS "created_at", w.available_at AS "available_at", '.
'w.delivered_at AS "delivered_at"'
)
->from($this->configuration['table_name'], 'w')
->where('w.id IN('.$sql.')');
$sql = $wrappedQuery->getSQL();
// use SELECT ... FOR UPDATE to lock table
if (!method_exists(QueryBuilder::class, 'forUpdate')) {
$sql .= ' '.$this->driverConnection->getDatabasePlatform()->getWriteLockSQL();
}
// use SELECT ... FOR UPDATE to lock table
$stmt = $this->executeQuery(
$sql.' '.$this->driverConnection->getDatabasePlatform()->getWriteLockSQL(),
$sql,
$query->getParameters(),
$query->getParameterTypes()
);
@ -278,7 +289,7 @@ class Connection implements ResetInterface
{
$configuration = $this->driverConnection->getConfiguration();
$assetFilter = $configuration->getSchemaAssetsFilter();
$configuration->setSchemaAssetsFilter(null);
$configuration->setSchemaAssetsFilter(static function () { return true; });
$this->updateSchema();
$configuration->setSchemaAssetsFilter($assetFilter);
$this->autoSetup = false;
@ -287,7 +298,7 @@ class Connection implements ResetInterface
public function getMessageCount(): int
{
$queryBuilder = $this->createAvailableMessagesQueryBuilder()
->select('COUNT(m.id) as message_count')
->select('COUNT(m.id) AS message_count')
->setMaxResults(1);
$stmt = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes());
@ -295,9 +306,10 @@ class Connection implements ResetInterface
return $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchOne() : $stmt->fetchColumn();
}
public function findAll(int $limit = null): array
public function findAll(?int $limit = null): array
{
$queryBuilder = $this->createAvailableMessagesQueryBuilder();
if (null !== $limit) {
$queryBuilder->setMaxResults($limit);
}
@ -352,24 +364,39 @@ class Connection implements ResetInterface
$redeliverLimit = (clone $now)->modify(sprintf('-%d seconds', $this->configuration['redeliver_timeout']));
return $this->createQueryBuilder()
->where('m.delivered_at is null OR m.delivered_at < ?')
->where('m.queue_name = ?')
->andWhere('m.delivered_at is null OR m.delivered_at < ?')
->andWhere('m.available_at <= ?')
->andWhere('m.queue_name = ?')
->setParameters([
$this->configuration['queue_name'],
$redeliverLimit,
$now,
$this->configuration['queue_name'],
], [
Types::STRING,
Types::DATETIME_MUTABLE,
Types::DATETIME_MUTABLE,
]);
}
private function createQueryBuilder(): QueryBuilder
private function createQueryBuilder(string $alias = 'm'): QueryBuilder
{
return $this->driverConnection->createQueryBuilder()
->select('m.*')
->from($this->configuration['table_name'], 'm');
$queryBuilder = $this->driverConnection->createQueryBuilder()
->from($this->configuration['table_name'], $alias);
$alias .= '.';
if (!$this->driverConnection->getDatabasePlatform() instanceof OraclePlatform) {
return $queryBuilder->select($alias.'*');
}
// Oracle databases use UPPER CASE on tables and column identifiers.
// Column alias is added to force the result to be lowercase even when the actual field is all caps.
return $queryBuilder->select(str_replace(', ', ', '.$alias,
$alias.'id AS "id", body AS "body", headers AS "headers", queue_name AS "queue_name", '.
'created_at AS "created_at", available_at AS "available_at", '.
'delivered_at AS "delivered_at"'
));
}
private function executeQuery(string $sql, array $parameters = [], array $types = [])
@ -470,13 +497,41 @@ class Connection implements ResetInterface
$schemaManager = $this->createSchemaManager();
$comparator = $this->createComparator($schemaManager);
$schemaDiff = $this->compareSchemas($comparator, $schemaManager->createSchema(), $this->getSchema());
$schemaDiff = $this->compareSchemas($comparator, method_exists($schemaManager, 'introspectSchema') ? $schemaManager->introspectSchema() : $schemaManager->createSchema(), $this->getSchema());
$platform = $this->driverConnection->getDatabasePlatform();
$exec = method_exists($this->driverConnection, 'executeStatement') ? 'executeStatement' : 'exec';
foreach ($schemaDiff->toSaveSql($this->driverConnection->getDatabasePlatform()) as $sql) {
if (method_exists($this->driverConnection, 'executeStatement')) {
$this->driverConnection->executeStatement($sql);
} else {
$this->driverConnection->exec($sql);
if (!method_exists(SchemaDiff::class, 'getCreatedSchemas')) {
foreach ($schemaDiff->toSaveSql($platform) as $sql) {
$this->driverConnection->$exec($sql);
}
return;
}
if ($platform->supportsSchemas()) {
foreach ($schemaDiff->getCreatedSchemas() as $schema) {
$this->driverConnection->$exec($platform->getCreateSchemaSQL($schema));
}
}
if ($platform->supportsSequences()) {
foreach ($schemaDiff->getAlteredSequences() as $sequence) {
$this->driverConnection->$exec($platform->getAlterSequenceSQL($sequence));
}
foreach ($schemaDiff->getCreatedSequences() as $sequence) {
$this->driverConnection->$exec($platform->getCreateSequenceSQL($sequence));
}
}
foreach ($platform->getCreateTablesSQL($schemaDiff->getCreatedTables()) as $sql) {
$this->driverConnection->$exec($sql);
}
foreach ($schemaDiff->getAlteredTables() as $tableDiff) {
foreach ($platform->getAlterTableSQL($tableDiff) as $sql) {
$this->driverConnection->$exec($sql);
}
}
}
@ -497,7 +552,7 @@ class Connection implements ResetInterface
private function compareSchemas(Comparator $comparator, Schema $from, Schema $to): SchemaDiff
{
return method_exists($comparator, 'compareSchemas')
return method_exists($comparator, 'compareSchemas') || method_exists($comparator, 'doCompareSchemas')
? $comparator->compareSchemas($from, $to)
: $comparator->compare($from, $to);
}

View File

@ -33,7 +33,7 @@ class DoctrineReceiver implements ListableReceiverInterface, MessageCountAwareIn
private $connection;
private $serializer;
public function __construct(Connection $connection, SerializerInterface $serializer = null)
public function __construct(Connection $connection, ?SerializerInterface $serializer = null)
{
$this->connection = $connection;
$this->serializer = $serializer ?? new PhpSerializer();
@ -107,7 +107,7 @@ class DoctrineReceiver implements ListableReceiverInterface, MessageCountAwareIn
/**
* {@inheritdoc}
*/
public function all(int $limit = null): iterable
public function all(?int $limit = null): iterable
{
try {
$doctrineEnvelopes = $this->connection->findAll($limit);

View File

@ -28,7 +28,7 @@ class DoctrineSender implements SenderInterface
private $connection;
private $serializer;
public function __construct(Connection $connection, SerializerInterface $serializer = null)
public function __construct(Connection $connection, ?SerializerInterface $serializer = null)
{
$this->connection = $connection;
$this->serializer = $serializer ?? new PhpSerializer();

View File

@ -72,7 +72,7 @@ class DoctrineTransport implements TransportInterface, SetupableTransportInterfa
/**
* {@inheritdoc}
*/
public function all(int $limit = null): iterable
public function all(?int $limit = null): iterable
{
return ($this->receiver ?? $this->getReceiver())->all($limit);
}

View File

@ -35,6 +35,9 @@ class DoctrineTransportFactory implements TransportFactoryInterface
$this->registry = $registry;
}
/**
* @param array $options You can set 'use_notify' to false to not use LISTEN/NOTIFY with postgresql
*/
public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface
{
$useNotify = ($options['use_notify'] ?? true);
@ -45,7 +48,7 @@ class DoctrineTransportFactory implements TransportFactoryInterface
try {
$driverConnection = $this->registry->getConnection($configuration['connection']);
} catch (\InvalidArgumentException $e) {
throw new TransportException(sprintf('Could not find Doctrine connection from Messenger DSN "%s".', $dsn), 0, $e);
throw new TransportException('Could not find Doctrine connection from Messenger DSN.', 0, $e);
}
if ($useNotify && $driverConnection->getDatabasePlatform() instanceof PostgreSQLPlatform) {

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