[Web] Some minor fixes and improvements for PHP 8

master
andryyy 2021-08-08 16:06:55 +02:00
parent eec75690e0
commit cf8fdae277
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
138 changed files with 2398 additions and 2342 deletions

View File

@ -81,7 +81,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
<div class="row"> <div class="row">
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?>:</div> <div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?>:</div>
<div class="col-sm-9 col-xs-7"> <div class="col-sm-9 col-xs-7">
<p id="tfa_pretty"><?=$tfa_data['pretty'];?></p> <p id="tfa_pretty"><?=(isset($tfa_data['pretty'])) ? $tfa_data['pretty'] : '';?></p>
<div id="tfa_keys"> <div id="tfa_keys">
<?php <?php
if (!empty($tfa_data['additional'])) { if (!empty($tfa_data['additional'])) {
@ -133,7 +133,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
?> ?>
<tr> <tr>
<td> <td>
<?=($_SESSION['fido2_cid'] == $key_info['cid']) ? '<i class="bi bi-unlock-fill"></i> ' : NULL; ?><?=(!empty($key_info['fn']))?$key_info['fn']:$key_info['subject'];?> <?=(isset($_SESSION['fido2_cid']) && $_SESSION['fido2_cid'] == $key_info['cid']) ? '<i class="bi bi-unlock-fill"></i> ' : NULL; ?><?=(!empty($key_info['fn']))?$key_info['fn']:$key_info['subject'];?>
</td> </td>
<td style="min-width:240px;text-align: right"> <td style="min-width:240px;text-align: right">
<form style="display:inline;" method="post"> <form style="display:inline;" method="post">
@ -222,13 +222,13 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-3" for="allow_from_ro"><?=$lang['admin']['api_allow_from'];?>:</label> <label class="control-label col-sm-3" for="allow_from_ro"><?=$lang['admin']['api_allow_from'];?>:</label>
<div class="col-sm-9"> <div class="col-sm-9">
<textarea class="form-control textarea-code" rows="7" name="allow_from" id="allow_from_ro" <?=($api_ro['skip_ip_check'] == 1) ? 'disabled' : null;?> required><?=htmlspecialchars($api_ro['allow_from']);?></textarea> <textarea class="form-control textarea-code" rows="7" name="allow_from" id="allow_from_ro" <?=(isset($api_ro['skip_ip_check']) && $api_ro['skip_ip_check'] == 1) ? 'disabled' : null;?> required><?=(isset($api_ro['allow_from'])) ? htmlspecialchars($api_ro['allow_from']) : '';?></textarea>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-9"> <div class="col-sm-offset-3 col-sm-9">
<label> <label>
<input type="checkbox" name="skip_ip_check" id="skip_ip_check_ro" <?=($api_ro['skip_ip_check'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['api_skip_ip_check'];?> <input type="checkbox" name="skip_ip_check" id="skip_ip_check_ro" <?=(isset($api_ro['skip_ip_check']) && $api_ro['skip_ip_check'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['api_skip_ip_check'];?>
</label> </label>
</div> </div>
</div> </div>
@ -241,7 +241,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-9"> <div class="col-sm-offset-3 col-sm-9">
<label> <label>
<input type="checkbox" name="active" <?=($api_ro['active'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['activate_api'];?> <input type="checkbox" name="active" <?=(isset($api_ro['active']) && $api_ro['active'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['activate_api'];?>
</label> </label>
</div> </div>
</div> </div>
@ -1174,15 +1174,17 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
</tr> </tr>
<?php <?php
$app_links = customize('get', 'app_links'); $app_links = customize('get', 'app_links');
foreach ($app_links as $row) { if ($app_links) {
foreach ($row as $key => $val) { foreach ($app_links as $row) {
?> foreach ($row as $key => $val) {
?>
<tr> <tr>
<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required value="<?=$key;?>"></td> <td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required value="<?=$key;?>"></td>
<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required value="<?=$val;?>"></td> <td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required value="<?=$val;?>"></td>
<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td> <td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td>
</tr> </tr>
<?php <?php
}
} }
} }
foreach ($MAILCOW_APPS as $app) { foreach ($MAILCOW_APPS as $app) {
@ -1433,7 +1435,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p><?=$lang['admin']['rspamd_global_filters_info'];?></p> <p><?=$lang['admin']['rspamd_global_filters_info'];?></p>
<div id="confirm_show_rspamd_global_filters" class="<?=($_SESSION['show_rspamd_global_filters'] === true) ? 'hidden' : '';?>"> <div id="confirm_show_rspamd_global_filters" class="<?=(isset($_SESSION['show_rspamd_global_filters']) && $_SESSION['show_rspamd_global_filters'] === true) ? 'hidden' : '';?>">
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<label> <label>
@ -1442,7 +1444,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
</div> </div>
</div> </div>
</div> </div>
<div id="rspamd_global_filters" class="<?=($_SESSION['show_rspamd_global_filters'] !== true) ? 'hidden' : '';?>"> <div id="rspamd_global_filters" class="<?=(isset($_SESSION['show_rspamd_global_filters']) && $_SESSION['show_rspamd_global_filters'] === true) ? 'hidden' : '';?>">
<hr> <hr>
<span class="anchor" id="regexmaps"></span> <span class="anchor" id="regexmaps"></span>
<h4><?=$lang['admin']['regex_maps'];?></h4> <h4><?=$lang['admin']['regex_maps'];?></h4>
@ -1506,7 +1508,7 @@ $js_minifier->add('/web/js/presets/rspamd.js');
$js_minifier->add('/web/js/site/pwgen.js'); $js_minifier->add('/web/js/site/pwgen.js');
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
} else { } else {
header('Location: /'); header('Location: /');
exit(); exit();
} }
?> ?>

View File

@ -14,7 +14,6 @@
width: auto; width: auto;
float: left; float: left;
margin-right: 10px; margin-right: 10px;
margin-top: auto;
} }

View File

@ -76,7 +76,7 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-info" role="progressbar" style="width:<?=round($solr_status['jvm']['memory']['raw']['used%']);?>%"></div> <div class="progress-bar progress-bar-info" role="progressbar" style="width:<?=round($solr_status['jvm']['memory']['raw']['used%']);?>%"></div>
</div> </div>
<p><?=$lang['debug']['jvm_memory_solr'];?>: <?=$solr_status['jvm']['memory']['total'] - $solr_status['jvm']['memory']['free'];?> / <?=$solr_status['jvm']['memory']['total'];?> <p><?=$lang['debug']['jvm_memory_solr'];?>: <?=(int)$solr_status['jvm']['memory']['total'] - (int)$solr_status['jvm']['memory']['free'];?> / <?=$solr_status['jvm']['memory']['total'];?>
(<?=round($solr_status['jvm']['memory']['raw']['used%']);?>%)</p> (<?=round($solr_status['jvm']['memory']['raw']['used%']);?>%)</p>
<hr> <hr>
<p><?=$lang['debug']['uptime'];?>: <?=round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60);?>h</p> <p><?=$lang['debug']['uptime'];?>: <?=round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60);?>h</p>

View File

@ -0,0 +1 @@
asd

File diff suppressed because it is too large Load Diff

View File

@ -110,7 +110,7 @@
<?php foreach ($MAILCOW_APPS as $app) { <?php foreach ($MAILCOW_APPS as $app) {
if (getenv('SKIP_SOGO') == "y" && preg_match('/^\/SOGo/i', $app['link'])) { continue; } if (getenv('SKIP_SOGO') == "y" && preg_match('/^\/SOGo/i', $app['link'])) { continue; }
?> ?>
<li title="<?= htmlspecialchars($app['description']); ?>"><a href="<?= htmlspecialchars($app['link']); ?>"><?= htmlspecialchars($app['name']); ?></a></li> <li title="<?=(isset($app['description'])) ? htmlspecialchars($app['description']) : '';?>"><a href="<?=(isset($app['link'])) ? htmlspecialchars($app['link']) : '';?>"><?=(isset($app['name'])) ? htmlspecialchars($app['name']) : '';?></a></li>
<?php <?php
} }
$app_links = customize('get', 'app_links'); $app_links = customize('get', 'app_links');

View File

@ -3,7 +3,7 @@
"robthree/twofactorauth": "^1.6", "robthree/twofactorauth": "^1.6",
"yubico/u2flib-server": "^1.0", "yubico/u2flib-server": "^1.0",
"phpmailer/phpmailer": "^6.1", "phpmailer/phpmailer": "^6.1",
"php-mime-mail-parser/php-mime-mail-parser": "^5.0.5", "php-mime-mail-parser/php-mime-mail-parser": "^7",
"soundasleep/html2text": "^0.5.0", "soundasleep/html2text": "^0.5.0",
"ddeboer/imap": "^1.5", "ddeboer/imap": "^1.5",
"matthiasmullie/minify": "^1.3", "matthiasmullie/minify": "^1.3",

View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "ffadb60e56b9e032d9a1777a5bf26477", "content-hash": "50acd623ff29bb513cd29819f4537aa0",
"packages": [ "packages": [
{ {
"name": "bshaffer/oauth2-server-php", "name": "bshaffer/oauth2-server-php",
@ -144,16 +144,16 @@
}, },
{ {
"name": "directorytree/ldaprecord", "name": "directorytree/ldaprecord",
"version": "v2.5.0", "version": "v2.6.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/DirectoryTree/LdapRecord.git", "url": "https://github.com/DirectoryTree/LdapRecord.git",
"reference": "ff7a92615fdc3f8b7f3d347c2847ce7ce06db287" "reference": "5c93ec6d1ef458290825a8b0a148946dce7c1e7a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/ff7a92615fdc3f8b7f3d347c2847ce7ce06db287", "url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/5c93ec6d1ef458290825a8b0a148946dce7c1e7a",
"reference": "ff7a92615fdc3f8b7f3d347c2847ce7ce06db287", "reference": "5c93ec6d1ef458290825a8b0a148946dce7c1e7a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -213,20 +213,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-06-06T18:51:41+00:00" "time": "2021-08-05T21:52:43+00:00"
}, },
{ {
"name": "illuminate/contracts", "name": "illuminate/contracts",
"version": "v8.48.0", "version": "v8.53.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/contracts.git", "url": "https://github.com/illuminate/contracts.git",
"reference": "199fcedc161ba4a0b83feaddc4629f395dbf1641" "reference": "504a34286a1b4c5421c43087d6bd4e176138f6fb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/199fcedc161ba4a0b83feaddc4629f395dbf1641", "url": "https://api.github.com/repos/illuminate/contracts/zipball/504a34286a1b4c5421c43087d6bd4e176138f6fb",
"reference": "199fcedc161ba4a0b83feaddc4629f395dbf1641", "reference": "504a34286a1b4c5421c43087d6bd4e176138f6fb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -261,7 +261,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2021-06-01T14:53:38+00:00" "time": "2021-08-03T14:03:47+00:00"
}, },
{ {
"name": "matthiasmullie/minify", "name": "matthiasmullie/minify",
@ -446,22 +446,23 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "2.49.0", "version": "2.51.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee" "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/93d9db91c0235c486875d22f1e08b50bdf3e6eee", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922",
"reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee", "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"php": "^7.1.8 || ^8.0", "php": "^7.1.8 || ^8.0",
"symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16",
"symfony/translation": "^3.4 || ^4.0 || ^5.0" "symfony/translation": "^3.4 || ^4.0 || ^5.0"
}, },
"require-dev": { "require-dev": {
@ -480,8 +481,8 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.x-dev", "dev-3.x": "3.x-dev",
"dev-3.x": "3.x-dev" "dev-master": "2.x-dev"
}, },
"laravel": { "laravel": {
"providers": [ "providers": [
@ -507,15 +508,15 @@
{ {
"name": "Brian Nesbitt", "name": "Brian Nesbitt",
"email": "brian@nesbot.com", "email": "brian@nesbot.com",
"homepage": "http://nesbot.com" "homepage": "https://markido.com"
}, },
{ {
"name": "kylekatarnls", "name": "kylekatarnls",
"homepage": "http://github.com/kylekatarnls" "homepage": "https://github.com/kylekatarnls"
} }
], ],
"description": "An API extension for DateTime that supports 281 different languages.", "description": "An API extension for DateTime that supports 281 different languages.",
"homepage": "http://carbon.nesbot.com", "homepage": "https://carbon.nesbot.com",
"keywords": [ "keywords": [
"date", "date",
"datetime", "datetime",
@ -535,7 +536,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-06-02T07:31:40+00:00" "time": "2021-07-28T13:16:28+00:00"
}, },
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
@ -589,31 +590,30 @@
}, },
{ {
"name": "php-mime-mail-parser/php-mime-mail-parser", "name": "php-mime-mail-parser/php-mime-mail-parser",
"version": "5.0.5", "version": "7.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git", "url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git",
"reference": "27983433aabeccee832573c3c56e6a4855e57745" "reference": "9d09a017f3f103fec8456211a4a538b80e0eca0d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/27983433aabeccee832573c3c56e6a4855e57745", "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/9d09a017f3f103fec8456211a4a538b80e0eca0d",
"reference": "27983433aabeccee832573c3c56e6a4855e57745", "reference": "9d09a017f3f103fec8456211a4a538b80e0eca0d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-mailparse": "*", "ext-mailparse": "*",
"php": "^7.1" "php": "^7.2|^8.0"
}, },
"replace": { "replace": {
"exorus/php-mime-mail-parser": "*", "exorus/php-mime-mail-parser": "*",
"messaged/php-mime-mail-parser": "*" "messaged/php-mime-mail-parser": "*"
}, },
"require-dev": { "require-dev": {
"php-coveralls/php-coveralls": "^2.1", "php-coveralls/php-coveralls": "^2.2",
"phpunit/php-token-stream": "^3.0", "phpunit/phpunit": "^8.0",
"phpunit/phpunit": "^7.0", "squizlabs/php_codesniffer": "^3.5"
"squizlabs/php_codesniffer": "^3.4"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -657,7 +657,7 @@
"role": "Developer" "role": "Developer"
} }
], ],
"description": "A fully tested email parser for PHP 7.1+ (mailparse extension wrapper).", "description": "A fully tested email parser for PHP 7.2+ (mailparse extension wrapper).",
"homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser", "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
"keywords": [ "keywords": [
"MimeMailParser", "MimeMailParser",
@ -669,9 +669,15 @@
], ],
"support": { "support": {
"issues": "https://github.com/php-mime-mail-parser/php-mime-mail-parser/issues", "issues": "https://github.com/php-mime-mail-parser/php-mime-mail-parser/issues",
"source": "https://github.com/php-mime-mail-parser/php-mime-mail-parser/tree/master" "source": "https://github.com/php-mime-mail-parser/php-mime-mail-parser/tree/7.0.0"
}, },
"time": "2019-09-23T11:57:58+00:00" "funding": [
{
"url": "https://github.com/eXorus",
"type": "github"
}
],
"time": "2021-02-25T17:21:57+00:00"
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
@ -1092,16 +1098,16 @@
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.23.0", "version": "v1.23.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1152,7 +1158,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
}, },
"funding": [ "funding": [
{ {
@ -1168,20 +1174,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-05-27T09:27:20+00:00" "time": "2021-05-27T12:26:48+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.23.0", "version": "v1.23.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1235,7 +1241,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
}, },
"funding": [ "funding": [
{ {
@ -1251,27 +1257,27 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-02-19T12:13:01+00:00" "time": "2021-07-28T13:41:28+00:00"
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
"version": "v5.3.2", "version": "v5.3.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation.git", "url": "https://github.com/symfony/translation.git",
"reference": "7e2603bcc598e14804c4d2359d8dc4ee3c40391b" "reference": "d89ad7292932c2699cbe4af98d72c5c6bbc504c1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/7e2603bcc598e14804c4d2359d8dc4ee3c40391b", "url": "https://api.github.com/repos/symfony/translation/zipball/d89ad7292932c2699cbe4af98d72c5c6bbc504c1",
"reference": "7e2603bcc598e14804c4d2359d8dc4ee3c40391b", "reference": "d89ad7292932c2699cbe4af98d72c5c6bbc504c1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1", "symfony/deprecation-contracts": "^2.1",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "^1.15", "symfony/polyfill-php80": "^1.16",
"symfony/translation-contracts": "^2.3" "symfony/translation-contracts": "^2.3"
}, },
"conflict": { "conflict": {
@ -1285,7 +1291,7 @@
"symfony/translation-implementation": "2.3" "symfony/translation-implementation": "2.3"
}, },
"require-dev": { "require-dev": {
"psr/log": "~1.0", "psr/log": "^1|^2|^3",
"symfony/config": "^4.4|^5.0", "symfony/config": "^4.4|^5.0",
"symfony/console": "^4.4|^5.0", "symfony/console": "^4.4|^5.0",
"symfony/dependency-injection": "^5.0", "symfony/dependency-injection": "^5.0",
@ -1330,7 +1336,7 @@
"description": "Provides tools to internationalize your application", "description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/translation/tree/v5.3.2" "source": "https://github.com/symfony/translation/tree/v5.3.4"
}, },
"funding": [ "funding": [
{ {
@ -1346,7 +1352,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-06-06T09:51:56+00:00" "time": "2021-07-25T09:39:16+00:00"
}, },
{ {
"name": "symfony/translation-contracts", "name": "symfony/translation-contracts",
@ -1428,22 +1434,22 @@
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v5.3.2", "version": "v5.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "905a22c68b292ffb6f20d7636c36b220d1fba5ae" "reference": "3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/905a22c68b292ffb6f20d7636c36b220d1fba5ae", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0",
"reference": "905a22c68b292ffb6f20d7636c36b220d1fba5ae", "reference": "3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "^1.15" "symfony/polyfill-php80": "^1.16"
}, },
"conflict": { "conflict": {
"phpunit/phpunit": "<5.4.3", "phpunit/phpunit": "<5.4.3",
@ -1496,7 +1502,7 @@
"dump" "dump"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-dumper/tree/v5.3.2" "source": "https://github.com/symfony/var-dumper/tree/v5.3.6"
}, },
"funding": [ "funding": [
{ {
@ -1512,7 +1518,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-06-06T09:51:56+00:00" "time": "2021-07-27T01:56:02+00:00"
}, },
{ {
"name": "tightenco/collect", "name": "tightenco/collect",
@ -1618,5 +1624,5 @@
"prefer-lowest": false, "prefer-lowest": false,
"platform": [], "platform": [],
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.0.0" "plugin-api-version": "2.1.0"
} }

View File

@ -338,7 +338,7 @@ class ClassLoader
* Loads the given class or interface. * Loads the given class or interface.
* *
* @param string $class The name of the class * @param string $class The name of the class
* @return bool|null True if loaded, null otherwise * @return true|null True if loaded, null otherwise
*/ */
public function loadClass($class) public function loadClass($class)
{ {
@ -347,6 +347,8 @@ class ClassLoader
return true; return true;
} }
return null;
} }
/** /**

View File

@ -1,536 +1,337 @@
<?php <?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer; namespace Composer;
use Composer\Autoload\ClassLoader; use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser; use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require it's presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions class InstalledVersions
{ {
private static $installed = array ( private static $installed;
'root' => private static $canGetVendors;
array ( private static $installedByVendor = array();
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'aliases' =>
array (
),
'reference' => NULL,
'name' => '__root__',
),
'versions' =>
array (
'__root__' =>
array (
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'aliases' =>
array (
),
'reference' => NULL,
),
'bshaffer/oauth2-server-php' =>
array (
'pretty_version' => 'v1.11.1',
'version' => '1.11.1.0',
'aliases' =>
array (
),
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
),
'ddeboer/imap' =>
array (
'pretty_version' => '1.12.1',
'version' => '1.12.1.0',
'aliases' =>
array (
),
'reference' => 'dbed05ca67b93509345a820b2859de10c48948fb',
),
'directorytree/ldaprecord' =>
array (
'pretty_version' => 'v2.5.0',
'version' => '2.5.0.0',
'aliases' =>
array (
),
'reference' => 'ff7a92615fdc3f8b7f3d347c2847ce7ce06db287',
),
'exorus/php-mime-mail-parser' =>
array (
'replaced' =>
array (
0 => '*',
),
),
'illuminate/contracts' =>
array (
'pretty_version' => 'v8.48.0',
'version' => '8.48.0.0',
'aliases' =>
array (
),
'reference' => '199fcedc161ba4a0b83feaddc4629f395dbf1641',
),
'matthiasmullie/minify' =>
array (
'pretty_version' => '1.3.66',
'version' => '1.3.66.0',
'aliases' =>
array (
),
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
),
'matthiasmullie/path-converter' =>
array (
'pretty_version' => '1.1.3',
'version' => '1.1.3.0',
'aliases' =>
array (
),
'reference' => 'e7d13b2c7e2f2268e1424aaed02085518afa02d9',
),
'messaged/php-mime-mail-parser' =>
array (
'replaced' =>
array (
0 => '*',
),
),
'mustangostang/spyc' =>
array (
'pretty_version' => '0.6.3',
'version' => '0.6.3.0',
'aliases' =>
array (
),
'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0',
),
'nesbot/carbon' =>
array (
'pretty_version' => '2.49.0',
'version' => '2.49.0.0',
'aliases' =>
array (
),
'reference' => '93d9db91c0235c486875d22f1e08b50bdf3e6eee',
),
'paragonie/random_compat' =>
array (
'pretty_version' => 'v9.99.100',
'version' => '9.99.100.0',
'aliases' =>
array (
),
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
),
'php-mime-mail-parser/php-mime-mail-parser' =>
array (
'pretty_version' => '5.0.5',
'version' => '5.0.5.0',
'aliases' =>
array (
),
'reference' => '27983433aabeccee832573c3c56e6a4855e57745',
),
'phpmailer/phpmailer' =>
array (
'pretty_version' => 'v6.5.0',
'version' => '6.5.0.0',
'aliases' =>
array (
),
'reference' => 'a5b5c43e50b7fba655f793ad27303cd74c57363c',
),
'psr/container' =>
array (
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'aliases' =>
array (
),
'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf',
),
'psr/log' =>
array (
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'aliases' =>
array (
),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
),
'psr/simple-cache' =>
array (
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'aliases' =>
array (
),
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
),
'robthree/twofactorauth' =>
array (
'pretty_version' => '1.8.0',
'version' => '1.8.0.0',
'aliases' =>
array (
),
'reference' => '30a38627ae1e7c9399dae67e265063cd6ec5276c',
),
'soundasleep/html2text' =>
array (
'pretty_version' => '0.5.0',
'version' => '0.5.0.0',
'aliases' =>
array (
),
'reference' => 'cdb89f6ffa2c4cc78f8ed9ea6ee0594a9133ccad',
),
'symfony/deprecation-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => '5f38c8804a9e97d23e0c8d63341088cd8a22d627',
),
'symfony/polyfill-mbstring' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '2df51500adbaebdc4c38dea4c89a2e131c45c8a1',
),
'symfony/polyfill-php80' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => 'eca0bf41ed421bed1b57c4958bab16aa86b757d0',
),
'symfony/translation' =>
array (
'pretty_version' => 'v5.3.2',
'version' => '5.3.2.0',
'aliases' =>
array (
),
'reference' => '7e2603bcc598e14804c4d2359d8dc4ee3c40391b',
),
'symfony/translation-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => '95c812666f3e91db75385749fe219c5e494c7f95',
),
'symfony/translation-implementation' =>
array (
'provided' =>
array (
0 => '2.3',
),
),
'symfony/var-dumper' =>
array (
'pretty_version' => 'v5.3.2',
'version' => '5.3.2.0',
'aliases' =>
array (
),
'reference' => '905a22c68b292ffb6f20d7636c36b220d1fba5ae',
),
'tightenco/collect' =>
array (
'pretty_version' => 'v8.34.0',
'version' => '8.34.0.0',
'aliases' =>
array (
),
'reference' => 'b069783ab0c547bb894ebcf8e7f6024bb401f9d2',
),
'yubico/u2flib-server' =>
array (
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'aliases' =>
array (
),
'reference' => '55d813acf68212ad2cadecde07551600d6971939',
),
),
);
private static $canGetVendors;
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
public static function getInstalledPackages() /**
{ * Checks whether the given package is installed
$packages = array(); *
foreach (self::getInstalled() as $installed) { * This also returns true if the package name is provided or replaced by another package
$packages[] = array_keys($installed['versions']); *
} * @param string $packageName
* @param bool $includeDevRequirements
if (1 === \count($packages)) { * @return bool
return $packages[0]; */
} public static function isInstalled($packageName, $includeDevRequirements = true)
{
return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); foreach (self::getInstalled() as $installed) {
} if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
public static function isInstalled($packageName) *
{ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
foreach (self::getInstalled() as $installed) { *
if (isset($installed['versions'][$packageName])) { * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
return true; *
} * @param VersionParser $parser Install composer/semver to have access to this class and functionality
} * @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
return false; * @return bool
} */
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
public static function satisfies(VersionParser $parser, $packageName, $constraint) * @param string $packageName
{ * @return string Version constraint usable with composer/semver
$constraint = $parser->parseConstraints($constraint); */
$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); public static function getVersionRanges($packageName)
{
return $provided->matches($constraint); foreach (self::getInstalled() as $installed) {
} if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
public static function getVersionRanges($packageName) if (array_key_exists('replaced', $installed['versions'][$packageName])) {
{ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
foreach (self::getInstalled() as $installed) { }
if (!isset($installed['versions'][$packageName])) { if (array_key_exists('provided', $installed['versions'][$packageName])) {
continue; $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
} }
$ranges = array(); return implode(' || ', $ranges);
if (isset($installed['versions'][$packageName]['pretty_version'])) { }
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
} throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
if (array_key_exists('aliases', $installed['versions'][$packageName])) { }
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
} /**
if (array_key_exists('replaced', $installed['versions'][$packageName])) { * @param string $packageName
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
} */
if (array_key_exists('provided', $installed['versions'][$packageName])) { public static function getVersion($packageName)
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); {
} foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
return implode(' || ', $ranges); continue;
} }
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); if (!isset($installed['versions'][$packageName]['version'])) {
} return null;
}
return $installed['versions'][$packageName]['version'];
}
public static function getVersion($packageName) throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
{ }
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) { /**
continue; * @param string $packageName
} * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
if (!isset($installed['versions'][$packageName]['version'])) { public static function getPrettyVersion($packageName)
return null; {
} foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
return $installed['versions'][$packageName]['version']; continue;
} }
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); if (!isset($installed['versions'][$packageName]['pretty_version'])) {
} return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
public static function getPrettyVersion($packageName) throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
{ }
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) { /**
continue; * @param string $packageName
} * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
if (!isset($installed['versions'][$packageName]['pretty_version'])) { public static function getReference($packageName)
return null; {
} foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
return $installed['versions'][$packageName]['pretty_version']; continue;
} }
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); if (!isset($installed['versions'][$packageName]['reference'])) {
} return null;
}
return $installed['versions'][$packageName]['reference'];
}
public static function getReference($packageName) throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
{ }
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) { /**
continue; * @param string $packageName
} * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
if (!isset($installed['versions'][$packageName]['reference'])) { public static function getInstallPath($packageName)
return null; {
} foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
return $installed['versions'][$packageName]['reference']; continue;
} }
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
} }
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
public static function getRootPackage() * @return array
{ * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
$installed = self::getInstalled(); */
public static function getRootPackage()
return $installed[0]['root']; {
} $installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
public static function getRawData() * @return array[]
{ * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); */
public static function getRawData()
return self::$installed; {
} @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// 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 = include __DIR__ . '/installed.php';
} else {
public static function getAllRawData() self::$installed = array();
{ }
return self::getInstalled(); }
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
public static function reload($data) * and wants to ensure both projects have access to their version of installed.php.
{ *
self::$installed = $data; * A typical case would be PHPUnit, where it would need to make sure it reads all
self::$installedByVendor = array(); * the data it needs from this class, then call reload() with
} * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
private static function getInstalled() *
{ * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
if (null === self::$canGetVendors) { */
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); public static function reload($data)
} {
self::$installed = $data;
$installed = array(); self::$installedByVendor = array();
}
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { /**
if (isset(self::$installedByVendor[$vendorDir])) { * @return array[]
$installed[] = self::$installedByVendor[$vendorDir]; * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
} elseif (is_file($vendorDir.'/composer/installed.php')) { */
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; private static function getInstalled()
} {
} if (null === self::$canGetVendors) {
} self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed[] = self::$installed;
$installed = array();
return $installed;
} if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
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';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// 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';
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
return $installed;
}
} }

View File

@ -6,8 +6,8 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',

View File

@ -7,8 +7,8 @@ namespace Composer\Autoload;
class ComposerStaticInit873464e4bd965a3168f133248b1b218b class ComposerStaticInit873464e4bd965a3168f133248b1b218b
{ {
public static $files = array ( public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',

View File

@ -140,17 +140,17 @@
}, },
{ {
"name": "directorytree/ldaprecord", "name": "directorytree/ldaprecord",
"version": "v2.5.0", "version": "v2.6.3",
"version_normalized": "2.5.0.0", "version_normalized": "2.6.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/DirectoryTree/LdapRecord.git", "url": "https://github.com/DirectoryTree/LdapRecord.git",
"reference": "ff7a92615fdc3f8b7f3d347c2847ce7ce06db287" "reference": "5c93ec6d1ef458290825a8b0a148946dce7c1e7a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/ff7a92615fdc3f8b7f3d347c2847ce7ce06db287", "url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/5c93ec6d1ef458290825a8b0a148946dce7c1e7a",
"reference": "ff7a92615fdc3f8b7f3d347c2847ce7ce06db287", "reference": "5c93ec6d1ef458290825a8b0a148946dce7c1e7a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -168,7 +168,7 @@
"phpunit/phpunit": "^8.0", "phpunit/phpunit": "^8.0",
"spatie/ray": "^1.24" "spatie/ray": "^1.24"
}, },
"time": "2021-06-06T18:51:41+00:00", "time": "2021-08-05T21:52:43+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -216,17 +216,17 @@
}, },
{ {
"name": "illuminate/contracts", "name": "illuminate/contracts",
"version": "v8.48.0", "version": "v8.53.1",
"version_normalized": "8.48.0.0", "version_normalized": "8.53.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/contracts.git", "url": "https://github.com/illuminate/contracts.git",
"reference": "199fcedc161ba4a0b83feaddc4629f395dbf1641" "reference": "504a34286a1b4c5421c43087d6bd4e176138f6fb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/199fcedc161ba4a0b83feaddc4629f395dbf1641", "url": "https://api.github.com/repos/illuminate/contracts/zipball/504a34286a1b4c5421c43087d6bd4e176138f6fb",
"reference": "199fcedc161ba4a0b83feaddc4629f395dbf1641", "reference": "504a34286a1b4c5421c43087d6bd4e176138f6fb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -234,7 +234,7 @@
"psr/container": "^1.0", "psr/container": "^1.0",
"psr/simple-cache": "^1.0" "psr/simple-cache": "^1.0"
}, },
"time": "2021-06-01T14:53:38+00:00", "time": "2021-08-03T14:03:47+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -453,23 +453,24 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "2.49.0", "version": "2.51.1",
"version_normalized": "2.49.0.0", "version_normalized": "2.51.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee" "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/93d9db91c0235c486875d22f1e08b50bdf3e6eee", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922",
"reference": "93d9db91c0235c486875d22f1e08b50bdf3e6eee", "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"php": "^7.1.8 || ^8.0", "php": "^7.1.8 || ^8.0",
"symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16",
"symfony/translation": "^3.4 || ^4.0 || ^5.0" "symfony/translation": "^3.4 || ^4.0 || ^5.0"
}, },
"require-dev": { "require-dev": {
@ -482,15 +483,15 @@
"phpunit/phpunit": "^7.5.20 || ^8.5.14", "phpunit/phpunit": "^7.5.20 || ^8.5.14",
"squizlabs/php_codesniffer": "^3.4" "squizlabs/php_codesniffer": "^3.4"
}, },
"time": "2021-06-02T07:31:40+00:00", "time": "2021-07-28T13:16:28+00:00",
"bin": [ "bin": [
"bin/carbon" "bin/carbon"
], ],
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.x-dev", "dev-3.x": "3.x-dev",
"dev-3.x": "3.x-dev" "dev-master": "2.x-dev"
}, },
"laravel": { "laravel": {
"providers": [ "providers": [
@ -517,15 +518,15 @@
{ {
"name": "Brian Nesbitt", "name": "Brian Nesbitt",
"email": "brian@nesbot.com", "email": "brian@nesbot.com",
"homepage": "http://nesbot.com" "homepage": "https://markido.com"
}, },
{ {
"name": "kylekatarnls", "name": "kylekatarnls",
"homepage": "http://github.com/kylekatarnls" "homepage": "https://github.com/kylekatarnls"
} }
], ],
"description": "An API extension for DateTime that supports 281 different languages.", "description": "An API extension for DateTime that supports 281 different languages.",
"homepage": "http://carbon.nesbot.com", "homepage": "https://carbon.nesbot.com",
"keywords": [ "keywords": [
"date", "date",
"datetime", "datetime",
@ -602,34 +603,33 @@
}, },
{ {
"name": "php-mime-mail-parser/php-mime-mail-parser", "name": "php-mime-mail-parser/php-mime-mail-parser",
"version": "5.0.5", "version": "7.0.0",
"version_normalized": "5.0.5.0", "version_normalized": "7.0.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git", "url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git",
"reference": "27983433aabeccee832573c3c56e6a4855e57745" "reference": "9d09a017f3f103fec8456211a4a538b80e0eca0d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/27983433aabeccee832573c3c56e6a4855e57745", "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/9d09a017f3f103fec8456211a4a538b80e0eca0d",
"reference": "27983433aabeccee832573c3c56e6a4855e57745", "reference": "9d09a017f3f103fec8456211a4a538b80e0eca0d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-mailparse": "*", "ext-mailparse": "*",
"php": "^7.1" "php": "^7.2|^8.0"
}, },
"replace": { "replace": {
"exorus/php-mime-mail-parser": "*", "exorus/php-mime-mail-parser": "*",
"messaged/php-mime-mail-parser": "*" "messaged/php-mime-mail-parser": "*"
}, },
"require-dev": { "require-dev": {
"php-coveralls/php-coveralls": "^2.1", "php-coveralls/php-coveralls": "^2.2",
"phpunit/php-token-stream": "^3.0", "phpunit/phpunit": "^8.0",
"phpunit/phpunit": "^7.0", "squizlabs/php_codesniffer": "^3.5"
"squizlabs/php_codesniffer": "^3.4"
}, },
"time": "2019-09-23T11:57:58+00:00", "time": "2021-02-25T17:21:57+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -673,7 +673,7 @@
"role": "Developer" "role": "Developer"
} }
], ],
"description": "A fully tested email parser for PHP 7.1+ (mailparse extension wrapper).", "description": "A fully tested email parser for PHP 7.2+ (mailparse extension wrapper).",
"homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser", "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
"keywords": [ "keywords": [
"MimeMailParser", "MimeMailParser",
@ -683,6 +683,16 @@
"parser", "parser",
"php" "php"
], ],
"support": {
"issues": "https://github.com/php-mime-mail-parser/php-mime-mail-parser/issues",
"source": "https://github.com/php-mime-mail-parser/php-mime-mail-parser/tree/7.0.0"
},
"funding": [
{
"url": "https://github.com/eXorus",
"type": "github"
}
],
"install-path": "../php-mime-mail-parser/php-mime-mail-parser" "install-path": "../php-mime-mail-parser/php-mime-mail-parser"
}, },
{ {
@ -1120,17 +1130,17 @@
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.23.0", "version": "v1.23.1",
"version_normalized": "1.23.0.0", "version_normalized": "1.23.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1139,7 +1149,7 @@
"suggest": { "suggest": {
"ext-mbstring": "For best performance" "ext-mbstring": "For best performance"
}, },
"time": "2021-05-27T09:27:20+00:00", "time": "2021-05-27T12:26:48+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -1183,7 +1193,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
}, },
"funding": [ "funding": [
{ {
@ -1203,23 +1213,23 @@
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.23.0", "version": "v1.23.1",
"version_normalized": "1.23.0.0", "version_normalized": "1.23.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.1" "php": ">=7.1"
}, },
"time": "2021-02-19T12:13:01+00:00", "time": "2021-07-28T13:41:28+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -1269,7 +1279,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
}, },
"funding": [ "funding": [
{ {
@ -1289,24 +1299,24 @@
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
"version": "v5.3.2", "version": "v5.3.4",
"version_normalized": "5.3.2.0", "version_normalized": "5.3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation.git", "url": "https://github.com/symfony/translation.git",
"reference": "7e2603bcc598e14804c4d2359d8dc4ee3c40391b" "reference": "d89ad7292932c2699cbe4af98d72c5c6bbc504c1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/7e2603bcc598e14804c4d2359d8dc4ee3c40391b", "url": "https://api.github.com/repos/symfony/translation/zipball/d89ad7292932c2699cbe4af98d72c5c6bbc504c1",
"reference": "7e2603bcc598e14804c4d2359d8dc4ee3c40391b", "reference": "d89ad7292932c2699cbe4af98d72c5c6bbc504c1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1", "symfony/deprecation-contracts": "^2.1",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "^1.15", "symfony/polyfill-php80": "^1.16",
"symfony/translation-contracts": "^2.3" "symfony/translation-contracts": "^2.3"
}, },
"conflict": { "conflict": {
@ -1320,7 +1330,7 @@
"symfony/translation-implementation": "2.3" "symfony/translation-implementation": "2.3"
}, },
"require-dev": { "require-dev": {
"psr/log": "~1.0", "psr/log": "^1|^2|^3",
"symfony/config": "^4.4|^5.0", "symfony/config": "^4.4|^5.0",
"symfony/console": "^4.4|^5.0", "symfony/console": "^4.4|^5.0",
"symfony/dependency-injection": "^5.0", "symfony/dependency-injection": "^5.0",
@ -1336,7 +1346,7 @@
"symfony/config": "", "symfony/config": "",
"symfony/yaml": "" "symfony/yaml": ""
}, },
"time": "2021-06-06T09:51:56+00:00", "time": "2021-07-25T09:39:16+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -1367,7 +1377,7 @@
"description": "Provides tools to internationalize your application", "description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/translation/tree/v5.3.2" "source": "https://github.com/symfony/translation/tree/v5.3.4"
}, },
"funding": [ "funding": [
{ {
@ -1468,23 +1478,23 @@
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v5.3.2", "version": "v5.3.6",
"version_normalized": "5.3.2.0", "version_normalized": "5.3.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "905a22c68b292ffb6f20d7636c36b220d1fba5ae" "reference": "3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/905a22c68b292ffb6f20d7636c36b220d1fba5ae", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0",
"reference": "905a22c68b292ffb6f20d7636c36b220d1fba5ae", "reference": "3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "^1.15" "symfony/polyfill-php80": "^1.16"
}, },
"conflict": { "conflict": {
"phpunit/phpunit": "<5.4.3", "phpunit/phpunit": "<5.4.3",
@ -1501,7 +1511,7 @@
"ext-intl": "To show region name in time zone dump", "ext-intl": "To show region name in time zone dump",
"symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
}, },
"time": "2021-06-06T09:51:56+00:00", "time": "2021-07-27T01:56:02+00:00",
"bin": [ "bin": [
"Resources/bin/var-dump-server" "Resources/bin/var-dump-server"
], ],
@ -1539,7 +1549,7 @@
"dump" "dump"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-dumper/tree/v5.3.2" "source": "https://github.com/symfony/var-dumper/tree/v5.3.6"
}, },
"funding": [ "funding": [
{ {

View File

@ -1,261 +1,257 @@
<?php return array ( <?php return array(
'root' => 'root' => array(
array ( 'pretty_version' => '1.0.0+no-version-set',
'pretty_version' => '1.0.0+no-version-set', 'version' => '1.0.0.0',
'version' => '1.0.0.0', 'type' => 'library',
'aliases' => 'install_path' => __DIR__ . '/../../',
array ( 'aliases' => array(),
'reference' => NULL,
'name' => '__root__',
'dev' => true,
), ),
'reference' => NULL, 'versions' => array(
'name' => '__root__', '__root__' => array(
), 'pretty_version' => '1.0.0+no-version-set',
'versions' => 'version' => '1.0.0.0',
array ( 'type' => 'library',
'__root__' => 'install_path' => __DIR__ . '/../../',
array ( 'aliases' => array(),
'pretty_version' => '1.0.0+no-version-set', 'reference' => NULL,
'version' => '1.0.0.0', 'dev_requirement' => false,
'aliases' => ),
array ( 'bshaffer/oauth2-server-php' => array(
), 'pretty_version' => 'v1.11.1',
'reference' => NULL, 'version' => '1.11.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../bshaffer/oauth2-server-php',
'aliases' => array(),
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
'dev_requirement' => false,
),
'ddeboer/imap' => array(
'pretty_version' => '1.12.1',
'version' => '1.12.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../ddeboer/imap',
'aliases' => array(),
'reference' => 'dbed05ca67b93509345a820b2859de10c48948fb',
'dev_requirement' => false,
),
'directorytree/ldaprecord' => array(
'pretty_version' => 'v2.6.3',
'version' => '2.6.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../directorytree/ldaprecord',
'aliases' => array(),
'reference' => '5c93ec6d1ef458290825a8b0a148946dce7c1e7a',
'dev_requirement' => false,
),
'exorus/php-mime-mail-parser' => array(
'dev_requirement' => false,
'replaced' => array(
0 => '*',
),
),
'illuminate/contracts' => array(
'pretty_version' => 'v8.53.1',
'version' => '8.53.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/contracts',
'aliases' => array(),
'reference' => '504a34286a1b4c5421c43087d6bd4e176138f6fb',
'dev_requirement' => false,
),
'matthiasmullie/minify' => array(
'pretty_version' => '1.3.66',
'version' => '1.3.66.0',
'type' => 'library',
'install_path' => __DIR__ . '/../matthiasmullie/minify',
'aliases' => array(),
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
'dev_requirement' => false,
),
'matthiasmullie/path-converter' => array(
'pretty_version' => '1.1.3',
'version' => '1.1.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../matthiasmullie/path-converter',
'aliases' => array(),
'reference' => 'e7d13b2c7e2f2268e1424aaed02085518afa02d9',
'dev_requirement' => false,
),
'messaged/php-mime-mail-parser' => array(
'dev_requirement' => false,
'replaced' => array(
0 => '*',
),
),
'mustangostang/spyc' => array(
'pretty_version' => '0.6.3',
'version' => '0.6.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../mustangostang/spyc',
'aliases' => array(),
'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0',
'dev_requirement' => false,
),
'nesbot/carbon' => array(
'pretty_version' => '2.51.1',
'version' => '2.51.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../nesbot/carbon',
'aliases' => array(),
'reference' => '8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922',
'dev_requirement' => false,
),
'paragonie/random_compat' => array(
'pretty_version' => 'v9.99.100',
'version' => '9.99.100.0',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/random_compat',
'aliases' => array(),
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
'dev_requirement' => false,
),
'php-mime-mail-parser/php-mime-mail-parser' => array(
'pretty_version' => '7.0.0',
'version' => '7.0.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../php-mime-mail-parser/php-mime-mail-parser',
'aliases' => array(),
'reference' => '9d09a017f3f103fec8456211a4a538b80e0eca0d',
'dev_requirement' => false,
),
'phpmailer/phpmailer' => array(
'pretty_version' => 'v6.5.0',
'version' => '6.5.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
'aliases' => array(),
'reference' => 'a5b5c43e50b7fba655f793ad27303cd74c57363c',
'dev_requirement' => false,
),
'psr/container' => array(
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf',
'dev_requirement' => false,
),
'psr/log' => array(
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
'dev_requirement' => false,
),
'psr/simple-cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/simple-cache',
'aliases' => array(),
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'dev_requirement' => false,
),
'robthree/twofactorauth' => array(
'pretty_version' => '1.8.0',
'version' => '1.8.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../robthree/twofactorauth',
'aliases' => array(),
'reference' => '30a38627ae1e7c9399dae67e265063cd6ec5276c',
'dev_requirement' => false,
),
'soundasleep/html2text' => array(
'pretty_version' => '0.5.0',
'version' => '0.5.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../soundasleep/html2text',
'aliases' => array(),
'reference' => 'cdb89f6ffa2c4cc78f8ed9ea6ee0594a9133ccad',
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'reference' => '5f38c8804a9e97d23e0c8d63341088cd8a22d627',
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6',
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be',
'dev_requirement' => false,
),
'symfony/translation' => array(
'pretty_version' => 'v5.3.4',
'version' => '5.3.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation',
'aliases' => array(),
'reference' => 'd89ad7292932c2699cbe4af98d72c5c6bbc504c1',
'dev_requirement' => false,
),
'symfony/translation-contracts' => array(
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(),
'reference' => '95c812666f3e91db75385749fe219c5e494c7f95',
'dev_requirement' => false,
),
'symfony/translation-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '2.3',
),
),
'symfony/var-dumper' => array(
'pretty_version' => 'v5.3.6',
'version' => '5.3.6.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'reference' => '3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0',
'dev_requirement' => false,
),
'tightenco/collect' => array(
'pretty_version' => 'v8.34.0',
'version' => '8.34.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../tightenco/collect',
'aliases' => array(),
'reference' => 'b069783ab0c547bb894ebcf8e7f6024bb401f9d2',
'dev_requirement' => false,
),
'yubico/u2flib-server' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../yubico/u2flib-server',
'aliases' => array(),
'reference' => '55d813acf68212ad2cadecde07551600d6971939',
'dev_requirement' => false,
),
), ),
'bshaffer/oauth2-server-php' =>
array (
'pretty_version' => 'v1.11.1',
'version' => '1.11.1.0',
'aliases' =>
array (
),
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
),
'ddeboer/imap' =>
array (
'pretty_version' => '1.12.1',
'version' => '1.12.1.0',
'aliases' =>
array (
),
'reference' => 'dbed05ca67b93509345a820b2859de10c48948fb',
),
'directorytree/ldaprecord' =>
array (
'pretty_version' => 'v2.5.0',
'version' => '2.5.0.0',
'aliases' =>
array (
),
'reference' => 'ff7a92615fdc3f8b7f3d347c2847ce7ce06db287',
),
'exorus/php-mime-mail-parser' =>
array (
'replaced' =>
array (
0 => '*',
),
),
'illuminate/contracts' =>
array (
'pretty_version' => 'v8.48.0',
'version' => '8.48.0.0',
'aliases' =>
array (
),
'reference' => '199fcedc161ba4a0b83feaddc4629f395dbf1641',
),
'matthiasmullie/minify' =>
array (
'pretty_version' => '1.3.66',
'version' => '1.3.66.0',
'aliases' =>
array (
),
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
),
'matthiasmullie/path-converter' =>
array (
'pretty_version' => '1.1.3',
'version' => '1.1.3.0',
'aliases' =>
array (
),
'reference' => 'e7d13b2c7e2f2268e1424aaed02085518afa02d9',
),
'messaged/php-mime-mail-parser' =>
array (
'replaced' =>
array (
0 => '*',
),
),
'mustangostang/spyc' =>
array (
'pretty_version' => '0.6.3',
'version' => '0.6.3.0',
'aliases' =>
array (
),
'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0',
),
'nesbot/carbon' =>
array (
'pretty_version' => '2.49.0',
'version' => '2.49.0.0',
'aliases' =>
array (
),
'reference' => '93d9db91c0235c486875d22f1e08b50bdf3e6eee',
),
'paragonie/random_compat' =>
array (
'pretty_version' => 'v9.99.100',
'version' => '9.99.100.0',
'aliases' =>
array (
),
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
),
'php-mime-mail-parser/php-mime-mail-parser' =>
array (
'pretty_version' => '5.0.5',
'version' => '5.0.5.0',
'aliases' =>
array (
),
'reference' => '27983433aabeccee832573c3c56e6a4855e57745',
),
'phpmailer/phpmailer' =>
array (
'pretty_version' => 'v6.5.0',
'version' => '6.5.0.0',
'aliases' =>
array (
),
'reference' => 'a5b5c43e50b7fba655f793ad27303cd74c57363c',
),
'psr/container' =>
array (
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'aliases' =>
array (
),
'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf',
),
'psr/log' =>
array (
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'aliases' =>
array (
),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
),
'psr/simple-cache' =>
array (
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'aliases' =>
array (
),
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
),
'robthree/twofactorauth' =>
array (
'pretty_version' => '1.8.0',
'version' => '1.8.0.0',
'aliases' =>
array (
),
'reference' => '30a38627ae1e7c9399dae67e265063cd6ec5276c',
),
'soundasleep/html2text' =>
array (
'pretty_version' => '0.5.0',
'version' => '0.5.0.0',
'aliases' =>
array (
),
'reference' => 'cdb89f6ffa2c4cc78f8ed9ea6ee0594a9133ccad',
),
'symfony/deprecation-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => '5f38c8804a9e97d23e0c8d63341088cd8a22d627',
),
'symfony/polyfill-mbstring' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '2df51500adbaebdc4c38dea4c89a2e131c45c8a1',
),
'symfony/polyfill-php80' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => 'eca0bf41ed421bed1b57c4958bab16aa86b757d0',
),
'symfony/translation' =>
array (
'pretty_version' => 'v5.3.2',
'version' => '5.3.2.0',
'aliases' =>
array (
),
'reference' => '7e2603bcc598e14804c4d2359d8dc4ee3c40391b',
),
'symfony/translation-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => '95c812666f3e91db75385749fe219c5e494c7f95',
),
'symfony/translation-implementation' =>
array (
'provided' =>
array (
0 => '2.3',
),
),
'symfony/var-dumper' =>
array (
'pretty_version' => 'v5.3.2',
'version' => '5.3.2.0',
'aliases' =>
array (
),
'reference' => '905a22c68b292ffb6f20d7636c36b220d1fba5ae',
),
'tightenco/collect' =>
array (
'pretty_version' => 'v8.34.0',
'version' => '8.34.0.0',
'aliases' =>
array (
),
'reference' => 'b069783ab0c547bb894ebcf8e7f6024bb401f9d2',
),
'yubico/u2flib-server' =>
array (
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'aliases' =>
array (
),
'reference' => '55d813acf68212ad2cadecde07551600d6971939',
),
),
); );

View File

@ -7,8 +7,9 @@ assignees: ''
--- ---
**Environment (please complete the following information):** <!-- Please update the below information with your environment. -->
**Environment:**
- LDAP Server Type: [e.g. ActiveDirectory / OpenLDAP / FreeIPA] - LDAP Server Type: [e.g. ActiveDirectory / OpenLDAP / FreeIPA]
- PHP Version: [e.g. 7.2 / 7.3 / 7.4] - PHP Version: [e.g. 7.3 / 7.4 / 8.0]
**Describe the bug:** **Describe the bug:**

View File

@ -10,3 +10,8 @@ assignees: ''
<!-- ISSUE WILL BE CLOSED WITHOUT SPONSORSHIP: --> <!-- ISSUE WILL BE CLOSED WITHOUT SPONSORSHIP: -->
<!-- https://github.com/sponsors/stevebauman --> <!-- https://github.com/sponsors/stevebauman -->
<!-- Thank you for your understanding. --> <!-- Thank you for your understanding. -->
<!-- Please update the below information with your environment. -->
**Environment:**
- LDAP Server Type: [e.g. ActiveDirectory / OpenLDAP / FreeIPA]
- PHP Version: [e.g. 7.3 / 7.4 / 8.0]

View File

@ -8,13 +8,14 @@ on:
jobs: jobs:
run-tests: run-tests:
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest]
php: [8.0, 7.4, 7.3] php: [8.0, 7.4, 7.3]
name: P${{ matrix.php }} name: ${{ matrix.os }} - P${{ matrix.php }}
steps: steps:
- name: Checkout code - name: Checkout code
@ -34,7 +35,7 @@ jobs:
coverage: none coverage: none
- name: Install dependencies - name: Install dependencies
run: composer update --prefer-dist --no-interaction --no-suggest run: composer update --prefer-dist --no-interaction
- name: Execute tests - name: Execute tests
run: vendor/bin/phpunit run: vendor/bin/phpunit

View File

@ -2,19 +2,20 @@
namespace LdapRecord\Configuration\Validators; namespace LdapRecord\Configuration\Validators;
use LdapRecord\Configuration\ConfigurationException;
class ArrayValidator extends Validator class ArrayValidator extends Validator
{ {
/**
* The validation exception message.
*
* @var string
*/
protected $message = 'Option [:option] must be an array.';
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function validate() public function passes()
{ {
if (! is_array($this->value)) { return is_array($this->value);
throw new ConfigurationException("Option {$this->key} must be an array.");
}
return true;
} }
} }

View File

@ -2,19 +2,20 @@
namespace LdapRecord\Configuration\Validators; namespace LdapRecord\Configuration\Validators;
use LdapRecord\Configuration\ConfigurationException;
class BooleanValidator extends Validator class BooleanValidator extends Validator
{ {
/**
* The validation exception message.
*
* @var string
*/
protected $message = 'Option [:option] must be a boolean.';
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function validate() public function passes()
{ {
if (! is_bool($this->value)) { return is_bool($this->value);
throw new ConfigurationException("Option {$this->key} must be a boolean.");
}
return true;
} }
} }

View File

@ -2,19 +2,20 @@
namespace LdapRecord\Configuration\Validators; namespace LdapRecord\Configuration\Validators;
use LdapRecord\Configuration\ConfigurationException;
class IntegerValidator extends Validator class IntegerValidator extends Validator
{ {
/**
* The validation exception message.
*
* @var string
*/
protected $message = 'Option [:option] must be an integer.';
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function validate() public function passes()
{ {
if (! is_numeric($this->value)) { return is_numeric($this->value);
throw new ConfigurationException("Option {$this->key} must be an integer.");
}
return true;
} }
} }

View File

@ -2,19 +2,20 @@
namespace LdapRecord\Configuration\Validators; namespace LdapRecord\Configuration\Validators;
use LdapRecord\Configuration\ConfigurationException;
class StringOrNullValidator extends Validator class StringOrNullValidator extends Validator
{ {
/**
* The validation exception message.
*
* @var string
*/
protected $message = 'Option [:option] must be a string or null.';
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function validate() public function passes()
{ {
if (is_string($this->value) || is_null($this->value)) { return is_string($this->value) || is_null($this->value);
return true;
}
throw new ConfigurationException("Option {$this->key} must be a string or null.");
} }
} }

View File

@ -2,6 +2,8 @@
namespace LdapRecord\Configuration\Validators; namespace LdapRecord\Configuration\Validators;
use LdapRecord\Configuration\ConfigurationException;
abstract class Validator abstract class Validator
{ {
/** /**
@ -18,6 +20,13 @@ abstract class Validator
*/ */
protected $value; protected $value;
/**
* The validation exception message.
*
* @var string
*/
protected $message;
/** /**
* Constructor. * Constructor.
* *
@ -31,11 +40,39 @@ abstract class Validator
} }
/** /**
* Validates the configuration value. * Determine if the validation rule passes.
*
* @throws \LdapRecord\Configuration\ConfigurationException When the value given fails validation.
* *
* @return bool * @return bool
*/ */
abstract public function validate(); abstract public function passes();
/**
* Validate the configuration value.
*
* @throws ConfigurationException
*
* @return bool
*/
public function validate()
{
if (! $this->passes()) {
$this->fail();
}
return true;
}
/**
* Throw a configuration exception.
*
* @throws ConfigurationException
*
* @return void
*/
protected function fail()
{
throw new ConfigurationException(
str_replace(':option', $this->key, $this->message)
);
}
} }

View File

@ -74,7 +74,7 @@ class Connection
/** /**
* The authentication guard resolver. * The authentication guard resolver.
* *
* @var \Closure * @var Closure
*/ */
protected $authGuardResolver; protected $authGuardResolver;

View File

@ -0,0 +1,320 @@
<?php
namespace LdapRecord;
use BadMethodCallException;
use LdapRecord\Events\Dispatcher;
use LdapRecord\Events\DispatcherInterface;
use LdapRecord\Events\Logger;
use Psr\Log\LoggerInterface;
class ConnectionManager
{
/**
* The logger instance.
*
* @var LoggerInterface|null
*/
protected $logger;
/**
* The event dispatcher instance.
*
* @var DispatcherInterface|null
*/
protected $dispatcher;
/**
* The added LDAP connections.
*
* @var Connection[]
*/
protected $connections = [];
/**
* The name of the default connection.
*
* @var string
*/
protected $default = 'default';
/**
* The events to register listeners for during initialization.
*
* @var array
*/
protected $listen = [
'LdapRecord\Auth\Events\*',
'LdapRecord\Query\Events\*',
'LdapRecord\Models\Events\*',
];
/**
* The method calls to proxy for compatibility.
*
* To be removed in the next major version.
*
* @var array
*/
protected $proxy = [
'reset' => 'flush',
'addConnection' => 'add',
'getConnection' => 'get',
'allConnections' => 'all',
'removeConnection' => 'remove',
'getDefaultConnection' => 'getDefault',
'setDefaultConnection' => 'setDefault',
'getEventDispatcher' => 'dispatcher',
'setEventDispatcher' => 'setDispatcher',
];
/**
* Constructor.
*
* @return void
*/
public function __construct()
{
$this->dispatcher = new Dispatcher();
}
/**
* Forward missing method calls onto the instance.
*
* @param string $method
* @param mixed $args
*
* @return mixed
*/
public function __call($method, $args)
{
$method = $this->proxy[$method] ?? $method;
if (! method_exists($this, $method)) {
throw new BadMethodCallException(sprintf(
'Call to undefined method %s::%s()',
static::class,
$method
));
}
return $this->{$method}(...$args);
}
/**
* Add a new connection.
*
* @param Connection $connection
* @param string|null $name
*
* @return $this
*/
public function add(Connection $connection, $name = null)
{
$this->connections[$name ?? $this->default] = $connection;
if ($this->dispatcher) {
$connection->setDispatcher($this->dispatcher);
}
return $this;
}
/**
* Remove a connection.
*
* @param $name
*
* @return $this
*/
public function remove($name)
{
unset($this->connections[$name]);
return $this;
}
/**
* Get all of the connections.
*
* @return Connection[]
*/
public function all()
{
return $this->connections;
}
/**
* Get a connection by name or return the default.
*
* @param string|null $name
*
* @throws ContainerException If the given connection does not exist.
*
* @return Connection
*/
public function get($name = null)
{
if ($this->exists($name = $name ?? $this->default)) {
return $this->connections[$name];
}
throw new ContainerException("The LDAP connection [$name] does not exist.");
}
/**
* Return the default connection.
*
* @return Connection
*/
public function getDefault()
{
return $this->get($this->default);
}
/**
* Get the default connection name.
*
* @return string
*/
public function getDefaultConnectionName()
{
return $this->default;
}
/**
* Checks if the connection exists.
*
* @param string $name
*
* @return bool
*/
public function exists($name)
{
return array_key_exists($name, $this->connections);
}
/**
* Set the default connection name.
*
* @param string $name
*
* @return $this
*/
public function setDefault($name = null)
{
$this->default = $name;
return $this;
}
/**
* Flush the manager of all instances and connections.
*
* @return $this
*/
public function flush()
{
$this->logger = null;
$this->connections = [];
$this->dispatcher = new Dispatcher();
return $this;
}
/**
* Get the logger instance.
*
* @return LoggerInterface|null
*/
public function getLogger()
{
return $this->logger;
}
/**
* Set the event logger to use.
*
* @param LoggerInterface $logger
*
* @return void
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
$this->initEventLogger();
}
/**
* Initialize the event logger.
*
* @return void
*/
public function initEventLogger()
{
$logger = $this->newEventLogger();
foreach ($this->listen as $event) {
$this->dispatcher->listen($event, function ($eventName, $events) use ($logger) {
foreach ($events as $event) {
$logger->log($event);
}
});
}
}
/**
* Make a new event logger instance.
*
* @return Logger
*/
protected function newEventLogger()
{
return new Logger($this->logger);
}
/**
* Unset the logger instance.
*
* @return void
*/
public function unsetLogger()
{
$this->logger = null;
}
/**
* Get the event dispatcher.
*
* @return DispatcherInterface|null
*/
public function dispatcher()
{
return $this->dispatcher;
}
/**
* Set the event dispatcher.
*
* @param DispatcherInterface $dispatcher
*
* @return void
*/
public function setDispatcher(DispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Unset the event dispatcher.
*
* @return void
*/
public function unsetEventDispatcher()
{
$this->dispatcher = null;
}
}

View File

@ -2,11 +2,21 @@
namespace LdapRecord; namespace LdapRecord;
use LdapRecord\Events\Dispatcher; /**
use LdapRecord\Events\DispatcherInterface; * @method static $this reset()
use LdapRecord\Events\Logger; * @method static Connection[] all()
use Psr\Log\LoggerInterface; * @method static Connection[] allConnections()
* @method static Connection getDefaultConnection()
* @method static Connection get(string|null $name = null)
* @method static Connection getConnection(string|null $name = null)
* @method static bool exists(string $name)
* @method static $this remove(string|null $name = null)
* @method static $this removeConnection(string|null $name = null)
* @method static $this setDefault(string|null $name = null)
* @method static $this setDefaultConnection(string|null $name = null)
* @method static $this add(Connection $connection, string|null $name = null)
* @method static $this addConnection(Connection $connection, string|null $name = null)
*/
class Container class Container
{ {
/** /**
@ -17,44 +27,37 @@ class Container
protected static $instance; protected static $instance;
/** /**
* The logger instance. * The connection manager instance.
* *
* @var LoggerInterface|null * @var ConnectionManager
*/ */
protected $logger; protected $manager;
/** /**
* The event dispatcher instance. * The methods to passthru, for compatibility.
*
* @var DispatcherInterface|null
*/
protected $dispatcher;
/**
* The added connections in the container instance.
*
* @var Connection[]
*/
protected $connections = [];
/**
* The name of the default connection.
*
* @var string
*/
protected $default = 'default';
/**
* The events to register listeners for during initialization.
* *
* @var array * @var array
*/ */
protected $listen = [ protected $passthru = [
'LdapRecord\Auth\Events\*', 'reset', 'flush',
'LdapRecord\Query\Events\*', 'add', 'addConnection',
'LdapRecord\Models\Events\*', 'remove', 'removeConnection',
'setDefault', 'setDefaultConnection',
]; ];
/**
* Forward missing static calls onto the current instance.
*
* @param string $method
* @param mixed $args
*
* @return mixed
*/
public static function __callStatic($method, $args)
{
return static::getInstance()->{$method}(...$args);
}
/** /**
* Get or set the current instance of the container. * Get or set the current instance of the container.
* *
@ -88,320 +91,37 @@ class Container
} }
/** /**
* Add a connection to the container. * Constructor.
*
* @param Connection $connection
* @param string|null $name
*
* @return static
*/
public static function addConnection(Connection $connection, $name = null)
{
return static::getInstance()->add($connection, $name);
}
/**
* Remove a connection from the container.
*
* @param string $name
* *
* @return void * @return void
*/ */
public static function removeConnection($name) public function __construct()
{ {
static::getInstance()->remove($name); $this->manager = new ConnectionManager();
} }
/** /**
* Get a connection by name or return the default. * Forward missing method calls onto the connection manager.
* *
* @param string|null $name * @param string $method
* @param mixed $args
* *
* @throws ContainerException If the given connection does not exist. * @return mixed
*
* @return Connection
*/ */
public static function getConnection($name = null) public function __call($method, $args)
{ {
return static::getInstance()->get($name); $value = $this->manager->{$method}(...$args);
return in_array($method, $this->passthru) ? $this : $value;
} }
/** /**
* Set the default connection name. * Get the connection manager.
* *
* @param string|null $name * @return ConnectionManager
*
* @return static
*/ */
public static function setDefaultConnection($name = null) public function manager()
{ {
return static::getInstance()->setDefault($name); return $this->manager;
}
/**
* Get the default connection.
*
* @return Connection
*/
public static function getDefaultConnection()
{
return static::getInstance()->getDefault();
}
/**
* Flush all of the added connections and reset the container.
*
* @return $this
*/
public static function reset()
{
return static::getInstance()->flush();
}
/**
* Get the container dispatcher instance.
*
* @return DispatcherInterface
*/
public static function getEventDispatcher()
{
$instance = static::getInstance();
if (! ($dispatcher = $instance->dispatcher())) {
$instance->setDispatcher($dispatcher = new Dispatcher());
}
return $dispatcher;
}
/**
* Set the container dispatcher instance.
*
* @param DispatcherInterface $dispatcher
*
* @return void
*/
public static function setEventDispatcher(DispatcherInterface $dispatcher)
{
static::getInstance()->setDispatcher($dispatcher);
}
/**
* Get the container dispatcher instance.
*
* @return DispatcherInterface|null
*/
public function dispatcher()
{
return $this->dispatcher;
}
/**
* Set the container dispatcher instance.
*
* @param DispatcherInterface $dispatcher
*
* @return void
*/
public function setDispatcher(DispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Unset the event dispatcher instance.
*
* @return void
*/
public function unsetEventDispatcher()
{
$this->dispatcher = null;
}
/**
* Get the logger instance.
*
* @return LoggerInterface|null
*/
public function getLogger()
{
return $this->logger;
}
/**
* Set the event logger to use.
*
* @param LoggerInterface $logger
*
* @return void
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
$this->initEventLogger();
}
/**
* Initializes the event logger.
*
* @return void
*/
public function initEventLogger()
{
$dispatcher = $this->getEventDispatcher();
$logger = $this->newEventLogger();
foreach ($this->listen as $event) {
$dispatcher->listen($event, function ($eventName, $events) use ($logger) {
foreach ($events as $event) {
$logger->log($event);
}
});
}
}
/**
* Returns a new event logger instance.
*
* @return Logger
*/
protected function newEventLogger()
{
return new Logger($this->logger);
}
/**
* Unset the logger instance.
*
* @return void
*/
public function unsetLogger()
{
$this->logger = null;
}
/**
* Add a new connection into the container.
*
* @param Connection $connection
* @param string|null $name
*
* @return $this
*/
public function add(Connection $connection, $name = null)
{
$this->connections[$name ?? $this->default] = $connection;
if ($this->dispatcher) {
$connection->setDispatcher($this->dispatcher);
}
return $this;
}
/**
* Remove a connection from the container.
*
* @param $name
*
* @return $this
*/
public function remove($name)
{
if ($this->exists($name)) {
unset($this->connections[$name]);
}
return $this;
}
/**
* Return all of the connections from the container.
*
* @return Connection[]
*/
public function all()
{
return $this->connections;
}
/**
* Get a connection by name or return the default.
*
* @param string|null $name
*
* @throws ContainerException If the given connection does not exist.
*
* @return Connection
*/
public function get($name = null)
{
if ($this->exists($name = $name ?? $this->default)) {
return $this->connections[$name];
}
throw new ContainerException("The LDAP connection [$name] does not exist.");
}
/**
* Return the default connection.
*
* @return Connection
*/
public function getDefault()
{
return $this->get($this->default);
}
/**
* Get the default connection name.
*
* @return string
*/
public function getDefaultConnectionName()
{
return $this->default;
}
/**
* Checks if the connection exists.
*
* @param $name
*
* @return bool
*/
public function exists($name)
{
return array_key_exists($name, $this->connections);
}
/**
* Set the default connection name.
*
* @param string $name
*
* @return $this
*/
public function setDefault($name = null)
{
$this->default = $name;
return $this;
}
/**
* Flush the container of all instances and connections.
*
* @return $this
*/
public function flush()
{
$this->connections = [];
$this->dispatcher = null;
$this->logger = null;
return $this;
} }
} }

View File

@ -118,7 +118,7 @@ class Logger
$message = "LDAP ({$connection->getHost()})" $message = "LDAP ({$connection->getHost()})"
." - Operation: {$this->getOperationName($event)}" ." - Operation: {$this->getOperationName($event)}"
." - Base DN: {$query->getDn()}" ." - Base DN: {$query->getBaseDn()}"
." - Filter: {$query->getQuery()}" ." - Filter: {$query->getQuery()}"
." - Selected: ({$selected})" ." - Selected: ({$selected})"
." - Time Elapsed: {$event->getTime()}"; ." - Time Elapsed: {$event->getTime()}";

View File

@ -6,10 +6,8 @@ use Closure;
use ErrorException; use ErrorException;
use Exception; use Exception;
abstract class LdapBase implements LdapInterface trait HandlesConnection
{ {
use DetectsErrors;
/** /**
* The LDAP host that is currently connected. * The LDAP host that is currently connected.
* *
@ -136,7 +134,7 @@ abstract class LdapBase implements LdapInterface
*/ */
public function getProtocol() public function getProtocol()
{ {
return $this->isUsingSSL() ? $this::PROTOCOL_SSL : $this::PROTOCOL; return $this->isUsingSSL() ? LdapInterface::PROTOCOL_SSL : LdapInterface::PROTOCOL;
} }
/** /**
@ -214,7 +212,7 @@ abstract class LdapBase implements LdapInterface
/** /**
* Determine if the current PHP version supports server controls. * Determine if the current PHP version supports server controls.
* *
* @deprecated * @deprecated since v2.5.0
* *
* @return bool * @return bool
*/ */
@ -236,8 +234,8 @@ abstract class LdapBase implements LdapInterface
// If an attempt to connect via SSL protocol is being performed, // If an attempt to connect via SSL protocol is being performed,
// and we are still using the default port, we will swap it // and we are still using the default port, we will swap it
// for the default SSL port, for developer convenience. // for the default SSL port, for developer convenience.
if ($this->isUsingSSL() && $port == static::PORT) { if ($this->isUsingSSL() && $port == LdapInterface::PORT) {
$port = static::PORT_SSL; $port = LdapInterface::PORT_SSL;
} }
// The blank space here is intentional. PHP's LDAP extension // The blank space here is intentional. PHP's LDAP extension

View File

@ -2,8 +2,10 @@
namespace LdapRecord; namespace LdapRecord;
class Ldap extends LdapBase class Ldap implements LdapInterface
{ {
use HandlesConnection, DetectsErrors;
/** /**
* @inheritdoc * @inheritdoc
*/ */
@ -17,9 +19,9 @@ class Ldap extends LdapBase
/** /**
* Retrieves the first entry from a search result. * Retrieves the first entry from a search result.
* *
* @link http://php.net/manual/en/function.ldap-first-entry.php * @see http://php.net/manual/en/function.ldap-first-entry.php
* *
* @param resource $searchResult * @param resource $searchResults
* *
* @return resource * @return resource
*/ */
@ -33,7 +35,7 @@ class Ldap extends LdapBase
/** /**
* Retrieves the next entry from a search result. * Retrieves the next entry from a search result.
* *
* @link http://php.net/manual/en/function.ldap-next-entry.php * @see http://php.net/manual/en/function.ldap-next-entry.php
* *
* @param resource $entry * @param resource $entry
* *
@ -49,7 +51,7 @@ class Ldap extends LdapBase
/** /**
* Retrieves the ldap entry's attributes. * Retrieves the ldap entry's attributes.
* *
* @link http://php.net/manual/en/function.ldap-get-attributes.php * @see http://php.net/manual/en/function.ldap-get-attributes.php
* *
* @param resource $entry * @param resource $entry
* *
@ -65,9 +67,9 @@ class Ldap extends LdapBase
/** /**
* Returns the number of entries from a search result. * Returns the number of entries from a search result.
* *
* @link http://php.net/manual/en/function.ldap-count-entries.php * @see http://php.net/manual/en/function.ldap-count-entries.php
* *
* @param resource $searchResult * @param resource $searchResults
* *
* @return int * @return int
*/ */
@ -81,7 +83,7 @@ class Ldap extends LdapBase
/** /**
* Compare value of attribute found in entry specified with DN. * Compare value of attribute found in entry specified with DN.
* *
* @link http://php.net/manual/en/function.ldap-compare.php * @see http://php.net/manual/en/function.ldap-compare.php
* *
* @param string $dn * @param string $dn
* @param string $attribute * @param string $attribute
@ -125,7 +127,7 @@ class Ldap extends LdapBase
/** /**
* Get all binary values from the specified result entry. * Get all binary values from the specified result entry.
* *
* @link http://php.net/manual/en/function.ldap-get-values-len.php * @see http://php.net/manual/en/function.ldap-get-values-len.php
* *
* @param $entry * @param $entry
* @param $attribute * @param $attribute
@ -160,7 +162,7 @@ class Ldap extends LdapBase
/** /**
* Set a callback function to do re-binds on referral chasing. * Set a callback function to do re-binds on referral chasing.
* *
* @link http://php.net/manual/en/function.ldap-set-rebind-proc.php * @see http://php.net/manual/en/function.ldap-set-rebind-proc.php
* *
* @param callable $callback * @param callable $callback
* *
@ -224,9 +226,9 @@ class Ldap extends LdapBase
$deref, $deref,
$serverControls $serverControls
) { ) {
return $this->supportsServerControlsInMethods() && ! empty($serverControls) return empty($serverControls)
? ldap_search($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls) ? ldap_search($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref)
: ldap_search($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref); : ldap_search($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls);
}); });
} }
@ -245,9 +247,9 @@ class Ldap extends LdapBase
$deref, $deref,
$serverControls $serverControls
) { ) {
return $this->supportsServerControlsInMethods() && ! empty($serverControls) return empty($serverControls)
? ldap_list($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls) ? ldap_list($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref)
: ldap_list($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref); : ldap_list($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls);
}); });
} }
@ -266,9 +268,9 @@ class Ldap extends LdapBase
$deref, $deref,
$serverControls $serverControls
) { ) {
return $this->supportsServerControlsInMethods() && ! empty($serverControls) return empty($serverControls)
? ldap_read($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls) ? ldap_read($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref)
: ldap_read($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref); : ldap_read($this->connection, $dn, $filter, $fields, $onlyAttributes, $size, $time, $deref, $serverControls);
}); });
} }
@ -285,9 +287,9 @@ class Ldap extends LdapBase
&$referrals, &$referrals,
&$serverControls &$serverControls
) { ) {
return $this->supportsServerControlsInMethods() && ! empty($serverControls) return empty($serverControls)
? ldap_parse_result($this->connection, $result, $errorCode, $dn, $errorMessage, $referrals, $serverControls) ? ldap_parse_result($this->connection, $result, $errorCode, $dn, $errorMessage, $referrals)
: ldap_parse_result($this->connection, $result, $errorCode, $dn, $errorMessage, $referrals); : ldap_parse_result($this->connection, $result, $errorCode, $dn, $errorMessage, $referrals, $serverControls);
}); });
} }
@ -419,9 +421,7 @@ class Ldap extends LdapBase
*/ */
public function errNo() public function errNo()
{ {
return $this->connection return $this->connection ? ldap_errno($this->connection) : null;
? ldap_errno($this->connection)
: null;
} }
/** /**

View File

@ -136,9 +136,9 @@ interface LdapInterface
/** /**
* Retrieve the entries from a search result. * Retrieve the entries from a search result.
* *
* @link http://php.net/manual/en/function.ldap-get-entries.php * @see http://php.net/manual/en/function.ldap-get-entries.php
* *
* @param resource $searchResult * @param resource $searchResults
* *
* @return array * @return array
*/ */
@ -147,7 +147,7 @@ interface LdapInterface
/** /**
* Retrieve the last error on the current connection. * Retrieve the last error on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-error.php * @see http://php.net/manual/en/function.ldap-error.php
* *
* @return string|null * @return string|null
*/ */
@ -167,7 +167,7 @@ interface LdapInterface
/** /**
* Set an option on the current connection. * Set an option on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-set-option.php * @see http://php.net/manual/en/function.ldap-set-option.php
* *
* @param int $option * @param int $option
* @param mixed $value * @param mixed $value
@ -188,7 +188,7 @@ interface LdapInterface
/** /**
* Get the value for the LDAP option. * Get the value for the LDAP option.
* *
* @link https://www.php.net/manual/en/function.ldap-get-option.php * @see https://www.php.net/manual/en/function.ldap-get-option.php
* *
* @param int $option * @param int $option
* @param mixed $value * @param mixed $value
@ -200,7 +200,7 @@ interface LdapInterface
/** /**
* Starts a connection using TLS. * Starts a connection using TLS.
* *
* @link http://php.net/manual/en/function.ldap-start-tls.php * @see http://php.net/manual/en/function.ldap-start-tls.php
* *
* @throws LdapRecordException * @throws LdapRecordException
* *
@ -211,7 +211,7 @@ interface LdapInterface
/** /**
* Connects to the specified hostname using the specified port. * Connects to the specified hostname using the specified port.
* *
* @link http://php.net/manual/en/function.ldap-start-tls.php * @see http://php.net/manual/en/function.ldap-start-tls.php
* *
* @param string|array $hosts * @param string|array $hosts
* @param int $port * @param int $port
@ -225,7 +225,7 @@ interface LdapInterface
* *
* Returns false if no connection is present. * Returns false if no connection is present.
* *
* @link http://php.net/manual/en/function.ldap-close.php * @see http://php.net/manual/en/function.ldap-close.php
* *
* @return bool * @return bool
*/ */
@ -234,7 +234,7 @@ interface LdapInterface
/** /**
* Performs a search on the current connection. * Performs a search on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-search.php * @see http://php.net/manual/en/function.ldap-search.php
* *
* @param string $dn * @param string $dn
* @param string $filter * @param string $filter
@ -252,11 +252,11 @@ interface LdapInterface
/** /**
* Performs a single level search on the current connection. * Performs a single level search on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-list.php * @see http://php.net/manual/en/function.ldap-list.php
* *
* @param string $dn * @param string $dn
* @param string $filter * @param string $filter
* @param array $attributes * @param array $fields
* @param bool $onlyAttributes * @param bool $onlyAttributes
* @param int $size * @param int $size
* @param int $time * @param int $time
@ -270,7 +270,7 @@ interface LdapInterface
/** /**
* Reads an entry on the current connection. * Reads an entry on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-read.php * @see http://php.net/manual/en/function.ldap-read.php
* *
* @param string $dn * @param string $dn
* @param string $filter * @param string $filter
@ -288,7 +288,7 @@ interface LdapInterface
/** /**
* Extract information from an LDAP result. * Extract information from an LDAP result.
* *
* @link https://www.php.net/manual/en/function.ldap-parse-result.php * @see https://www.php.net/manual/en/function.ldap-parse-result.php
* *
* @param resource $result * @param resource $result
* @param int $errorCode * @param int $errorCode
@ -305,7 +305,7 @@ interface LdapInterface
* Binds to the current connection using the specified username and password. * Binds to the current connection using the specified username and password.
* If sasl is true, the current connection is bound using SASL. * If sasl is true, the current connection is bound using SASL.
* *
* @link http://php.net/manual/en/function.ldap-bind.php * @see http://php.net/manual/en/function.ldap-bind.php
* *
* @param string $username * @param string $username
* @param string $password * @param string $password
@ -319,7 +319,7 @@ interface LdapInterface
/** /**
* Adds an entry to the current connection. * Adds an entry to the current connection.
* *
* @link http://php.net/manual/en/function.ldap-add.php * @see http://php.net/manual/en/function.ldap-add.php
* *
* @param string $dn * @param string $dn
* @param array $entry * @param array $entry
@ -333,7 +333,7 @@ interface LdapInterface
/** /**
* Deletes an entry on the current connection. * Deletes an entry on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-delete.php * @see http://php.net/manual/en/function.ldap-delete.php
* *
* @param string $dn * @param string $dn
* *
@ -346,7 +346,7 @@ interface LdapInterface
/** /**
* Modify the name of an entry on the current connection. * Modify the name of an entry on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-rename.php * @see http://php.net/manual/en/function.ldap-rename.php
* *
* @param string $dn * @param string $dn
* @param string $newRdn * @param string $newRdn
@ -362,7 +362,7 @@ interface LdapInterface
/** /**
* Modifies an existing entry on the current connection. * Modifies an existing entry on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-modify.php * @see http://php.net/manual/en/function.ldap-modify.php
* *
* @param string $dn * @param string $dn
* @param array $entry * @param array $entry
@ -376,7 +376,7 @@ interface LdapInterface
/** /**
* Batch modifies an existing entry on the current connection. * Batch modifies an existing entry on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-modify-batch.php * @see http://php.net/manual/en/function.ldap-modify-batch.php
* *
* @param string $dn * @param string $dn
* @param array $values * @param array $values
@ -390,7 +390,7 @@ interface LdapInterface
/** /**
* Add attribute values to current attributes. * Add attribute values to current attributes.
* *
* @link http://php.net/manual/en/function.ldap-mod-add.php * @see http://php.net/manual/en/function.ldap-mod-add.php
* *
* @param string $dn * @param string $dn
* @param array $entry * @param array $entry
@ -404,7 +404,7 @@ interface LdapInterface
/** /**
* Replaces attribute values with new ones. * Replaces attribute values with new ones.
* *
* @link http://php.net/manual/en/function.ldap-mod-replace.php * @see http://php.net/manual/en/function.ldap-mod-replace.php
* *
* @param string $dn * @param string $dn
* @param array $entry * @param array $entry
@ -418,7 +418,7 @@ interface LdapInterface
/** /**
* Delete attribute values from current attributes. * Delete attribute values from current attributes.
* *
* @link http://php.net/manual/en/function.ldap-mod-del.php * @see http://php.net/manual/en/function.ldap-mod-del.php
* *
* @param string $dn * @param string $dn
* @param array $entry * @param array $entry
@ -432,7 +432,7 @@ interface LdapInterface
/** /**
* Send LDAP pagination control. * Send LDAP pagination control.
* *
* @link http://php.net/manual/en/function.ldap-control-paged-result.php * @see http://php.net/manual/en/function.ldap-control-paged-result.php
* *
* @param int $pageSize * @param int $pageSize
* @param bool $isCritical * @param bool $isCritical
@ -445,7 +445,7 @@ interface LdapInterface
/** /**
* Retrieve the LDAP pagination cookie. * Retrieve the LDAP pagination cookie.
* *
* @link http://php.net/manual/en/function.ldap-control-paged-result-response.php * @see http://php.net/manual/en/function.ldap-control-paged-result-response.php
* *
* @param resource $result * @param resource $result
* @param string $cookie * @param string $cookie
@ -457,7 +457,7 @@ interface LdapInterface
/** /**
* Frees up the memory allocated internally to store the result. * Frees up the memory allocated internally to store the result.
* *
* @link https://www.php.net/manual/en/function.ldap-free-result.php * @see https://www.php.net/manual/en/function.ldap-free-result.php
* *
* @param resource $result * @param resource $result
* *
@ -466,10 +466,9 @@ interface LdapInterface
public function freeResult($result); public function freeResult($result);
/** /**
* Returns the error number of the last command * Returns the error number of the last command executed.
* executed on the current connection.
* *
* @link http://php.net/manual/en/function.ldap-errno.php * @see http://php.net/manual/en/function.ldap-errno.php
* *
* @return int|null * @return int|null
*/ */
@ -478,7 +477,7 @@ interface LdapInterface
/** /**
* Returns the error string of the specified error number. * Returns the error string of the specified error number.
* *
* @link http://php.net/manual/en/function.ldap-err2str.php * @see http://php.net/manual/en/function.ldap-err2str.php
* *
* @param int $number * @param int $number
* *
@ -510,6 +509,8 @@ interface LdapInterface
/** /**
* Determine if the current PHP version supports server controls. * Determine if the current PHP version supports server controls.
* *
* @deprecated since v2.5.0
*
* @return bool * @return bool
*/ */
public function supportsServerControlsInMethods(); public function supportsServerControlsInMethods();

View File

@ -326,7 +326,7 @@ class AccountControl
* *
* For information about how to programmatically set this permission, visit the following link: * For information about how to programmatically set this permission, visit the following link:
* *
* @link http://msdn2.microsoft.com/en-us/library/aa746398.aspx * @see http://msdn2.microsoft.com/en-us/library/aa746398.aspx
* *
* @return $this * @return $this
*/ */

View File

@ -3,6 +3,7 @@
namespace LdapRecord\Models\Attributes; namespace LdapRecord\Models\Attributes;
use LdapRecord\EscapesValues; use LdapRecord\EscapesValues;
use LdapRecord\Support\Arr;
class DistinguishedName class DistinguishedName
{ {
@ -60,7 +61,7 @@ class DistinguishedName
} }
/** /**
* Make a new Distinguished Name instance. * Make a new distinguished name instance.
* *
* @param string|null $value * @param string|null $value
* *
@ -158,19 +159,15 @@ class DistinguishedName
} }
/** /**
* Get the Distinguished Name values without attributes. * Get the distinguished name values without attributes.
* *
* @return array * @return array
*/ */
public function values() public function values()
{ {
$components = $this->components();
$values = []; $values = [];
foreach ($components as $rdn) { foreach ($this->multi() as [, $value]) {
[,$value] = static::explodeRdn($rdn);
$values[] = static::unescape($value); $values[] = static::unescape($value);
} }
@ -178,35 +175,45 @@ class DistinguishedName
} }
/** /**
* Get the Distinguished Name components with attributes. * Get the distinguished name attributes without values.
*
* @return array
*/
public function attributes()
{
$attributes = [];
foreach ($this->multi() as [$attribute]) {
$attributes[] = $attribute;
}
return $attributes;
}
/**
* Get the distinguished name components with attributes.
* *
* @return array * @return array
*/ */
public function components() public function components()
{ {
$rdns = static::explode($this->value);
$components = []; $components = [];
foreach ($rdns as $rdn) { foreach ($this->multi() as [$attribute, $value]) {
[$attribute, $value] = static::explodeRdn($rdn); // When a distinguished name is exploded, the values are automatically
// When a Distinguished Name is exploded, the values are automatically
// escaped. This cannot be opted out of. Here we will unescape // escaped. This cannot be opted out of. Here we will unescape
// the attribute value, then re-escape it to its original // the attribute value, then re-escape it to its original
// representation from the server using the "dn" flag. // representation from the server using the "dn" flag.
$value = $this->escape(static::unescape($value))->dn(); $value = $this->escape(static::unescape($value))->dn();
$components[] = static::makeRdn([ $components[] = static::makeRdn([$attribute, $value]);
$attribute, $value,
]);
} }
return $components; return $components;
} }
/** /**
* Convert the DN into an associative array. * Convert the distinguished name into an associative array.
* *
* @return array * @return array
*/ */
@ -214,9 +221,7 @@ class DistinguishedName
{ {
$map = []; $map = [];
foreach ($this->components() as $rdn) { foreach ($this->multi() as [$attribute, $value]) {
[$attribute, $value] = static::explodeRdn($rdn);
$attribute = $this->normalize($attribute); $attribute = $this->normalize($attribute);
array_key_exists($attribute, $map) array_key_exists($attribute, $map)
@ -228,31 +233,71 @@ class DistinguishedName
} }
/** /**
* Get the name value. * Split the RDNs into a multi-dimensional array.
*
* @return array
*/
public function multi()
{
return array_map(function ($rdn) {
return static::explodeRdn($rdn);
}, $this->rdns());
}
/**
* Split the distinguished name into an array of unescaped RDN's.
*
* @return array
*/
public function rdns()
{
return static::explode($this->value);
}
/**
* Get the first RDNs value.
* *
* @return string|null * @return string|null
*/ */
public function name() public function name()
{ {
$values = $this->values(); return Arr::first($this->values());
return reset($values) ?: null;
} }
/** /**
* Get the relative Distinguished name. * Get the first RDNs attribute.
*
* @return string|null
*/
public function head()
{
return Arr::first($this->attributes());
}
/**
* Get the relative distinguished name.
* *
* @return string|null * @return string|null
*/ */
public function relative() public function relative()
{ {
$components = $this->components(); return Arr::first($this->components());
return reset($components) ?: null;
} }
/** /**
* Get the parent Distinguished name. * Alias of relative().
*
* Get the first RDN from the distinguished name.
*
* @return string|null
*/
public function first()
{
return $this->relative();
}
/**
* Get the parent distinguished name.
* *
* @return string|null * @return string|null
*/ */
@ -266,7 +311,7 @@ class DistinguishedName
} }
/** /**
* Determine if the current Distinguished Name is a parent of the given child. * Determine if the current distinguished name is a parent of the given child.
* *
* @param DistinguishedName $child * @param DistinguishedName $child
* *
@ -278,7 +323,7 @@ class DistinguishedName
} }
/** /**
* Determine if the current Distinguished Name is a child of the given parent. * Determine if the current distinguished name is a child of the given parent.
* *
* @param DistinguishedName $parent * @param DistinguishedName $parent
* *
@ -299,7 +344,7 @@ class DistinguishedName
} }
/** /**
* Determine if the current Distinguished Name is an ancestor of the descendant. * Determine if the current distinguished name is an ancestor of the descendant.
* *
* @param DistinguishedName $descendant * @param DistinguishedName $descendant
* *
@ -311,7 +356,7 @@ class DistinguishedName
} }
/** /**
* Determine if the current Distinguished Name is a descendant of the ancestor. * Determine if the current distinguished name is a descendant of the ancestor.
* *
* @param DistinguishedName $ancestor * @param DistinguishedName $ancestor
* *
@ -336,7 +381,7 @@ class DistinguishedName
} }
/** /**
* Compare whether the two Distinguished Name values are equal. * Compare whether the two distinguished name values are equal.
* *
* @param array $values * @param array $values
* @param array $other * @param array $other

View File

@ -45,7 +45,7 @@ class DistinguishedNameBuilder
*/ */
public function __call($method, $args) public function __call($method, $args)
{ {
return $this->get()->{$method}($args); return $this->get()->{$method}(...$args);
} }
/** /**

View File

@ -19,7 +19,7 @@ class Guid
* *
* @author Chad Sikorra <Chad.Sikorra@gmail.com> * @author Chad Sikorra <Chad.Sikorra@gmail.com>
* *
* @link https://github.com/ldaptools/ldaptools * @see https://github.com/ldaptools/ldaptools
* *
* @var array * @var array
*/ */
@ -36,7 +36,7 @@ class Guid
* *
* @author Chad Sikorra <Chad.Sikorra@gmail.com> * @author Chad Sikorra <Chad.Sikorra@gmail.com>
* *
* @link https://github.com/ldaptools/ldaptools * @see https://github.com/ldaptools/ldaptools
* *
* @var array * @var array
*/ */
@ -142,7 +142,7 @@ class Guid
* *
* @author Chad Sikorra <Chad.Sikorra@gmail.com> * @author Chad Sikorra <Chad.Sikorra@gmail.com>
* *
* @link https://github.com/ldaptools/ldaptools * @see https://github.com/ldaptools/ldaptools
* *
* @param string $hex The full hex string. * @param string $hex The full hex string.
* @param array $sections An array of start and length (unless octet is true, then length is always 2). * @param array $sections An array of start and length (unless octet is true, then length is always 2).

View File

@ -185,7 +185,15 @@ trait HasPassword
*/ */
protected function validateSecureConnection() protected function validateSecureConnection()
{ {
if (! $this->getConnection()->getLdapConnection()->canChangePasswords()) { $connection = $this->getConnection();
if ($connection->isConnected()) {
$secure = $connection->getLdapConnection()->canChangePasswords();
} else {
$secure = $connection->getConfiguration()->get('use_ssl') || $connection->getConfiguration()->get('use_tls');
}
if (! $secure) {
throw new ConnectionException( throw new ConnectionException(
'You must be connected to your LDAP server with TLS or SSL to perform this operation.' 'You must be connected to your LDAP server with TLS or SSL to perform this operation.'
); );

View File

@ -5,7 +5,7 @@ namespace LdapRecord\Models\Concerns;
/** /**
* @author Taylor Otwell * @author Taylor Otwell
* *
* @link https://laravel.com * @see https://laravel.com
*/ */
trait HidesAttributes trait HidesAttributes
{ {

View File

@ -767,6 +767,18 @@ abstract class Model implements ArrayAccess, JsonSerializable
return $this->newDn($dn ?? $this->dn)->name(); return $this->newDn($dn ?? $this->dn)->name();
} }
/**
* Get the head attribute of the model, or the given DN.
*
* @param string|null $dn
*
* @return string|null
*/
public function getHead($dn = null)
{
return $this->newDn($dn ?? $this->dn)->head();
}
/** /**
* Get the RDN of the model, of the given DN. * Get the RDN of the model, of the given DN.
* *
@ -803,10 +815,20 @@ abstract class Model implements ArrayAccess, JsonSerializable
return new DistinguishedName($dn); return new DistinguishedName($dn);
} }
/**
* Get the model's object GUID key.
*
* @return void
*/
public function getObjectGuidKey()
{
return $this->guidKey;
}
/** /**
* Get the model's binary object GUID. * Get the model's binary object GUID.
* *
* @link https://msdn.microsoft.com/en-us/library/ms679021(v=vs.85).aspx * @see https://msdn.microsoft.com/en-us/library/ms679021(v=vs.85).aspx
* *
* @return string|null * @return string|null
*/ */
@ -952,8 +974,8 @@ abstract class Model implements ArrayAccess, JsonSerializable
protected function performInsert() protected function performInsert()
{ {
// Here we will populate the models object classes if it // Here we will populate the models object classes if it
// does not already have any. An LDAP object cannot // does not already have any set. An LDAP object cannot
// be successfully created without them set. // be successfully created in the server without them.
if (! $this->hasAttribute('objectclass')) { if (! $this->hasAttribute('objectclass')) {
$this->setAttribute('objectclass', static::$objectClasses); $this->setAttribute('objectclass', static::$objectClasses);
} }
@ -961,17 +983,18 @@ abstract class Model implements ArrayAccess, JsonSerializable
$query = $this->newQuery(); $query = $this->newQuery();
// If the model does not currently have a distinguished // If the model does not currently have a distinguished
// name, we will attempt to create one automatically // name, we will attempt to generate one automatically
// using the current query builders DN as a base. // using the current query builder's DN as the base.
if (empty($this->getDn())) { if (empty($this->getDn())) {
$this->setDn($this->getCreatableDn()); $this->setDn($this->getCreatableDn());
} }
$this->fireModelEvent(new Events\Creating($this)); $this->fireModelEvent(new Events\Creating($this));
// Here we perform the insert of the object in the directory. // Here we perform the insert of new object in the directory,
// We will also filter out any empty attribute values here, // but filter out any empty attributes before sending them
// otherwise the LDAP server will return an error message. // to the server. LDAP servers will throw an exception if
// attributes have been given empty or null values.
$query->insert($this->getDn(), array_filter($this->getAttributes())); $query->insert($this->getDn(), array_filter($this->getAttributes()));
$this->fireModelEvent(new Events\Created($this)); $this->fireModelEvent(new Events\Created($this));

View File

@ -2,6 +2,7 @@
namespace LdapRecord\Models\Relations; namespace LdapRecord\Models\Relations;
use Closure;
use LdapRecord\DetectsErrors; use LdapRecord\DetectsErrors;
use LdapRecord\LdapRecordException; use LdapRecord\LdapRecordException;
use LdapRecord\Models\Model; use LdapRecord\Models\Model;
@ -107,6 +108,21 @@ class HasMany extends OneToMany
return $result; return $result;
} }
/**
* Chunk the relation results using the given callback.
*
* @param int $pageSize
* @param Closure $callback
*
* @return void
*/
public function chunk($pageSize, Closure $callback)
{
$this->getRelationQuery()->chunk($pageSize, function ($entries) use ($callback) {
$callback($this->transformResults($entries));
});
}
/** /**
* Get the relationships results. * Get the relationships results.
* *

View File

@ -89,7 +89,7 @@ abstract class OneToMany extends Relation
public function getResults() public function getResults()
{ {
$results = $this->recursive $results = $this->recursive
? $this->getRecursiveResults($this->getRelationResults()) ? $this->getRecursiveResults()
: $this->getRelationResults(); : $this->getRelationResults();
return $results->merge( return $results->merge(
@ -142,46 +142,45 @@ abstract class OneToMany extends Relation
/** /**
* Get the results for the models relation recursively. * Get the results for the models relation recursively.
* *
* @param Collection $models The models to retrieve nested relation results from * @param string[] $loaded The distinguished names of models already loaded
* @param string[] $loaded The distinguished names of models already loaded
* *
* @return Collection * @return Collection
*/ */
protected function getRecursiveResults(Collection $models, array &$loaded = []) protected function getRecursiveResults(array $loaded = [])
{ {
return $models->unless(empty($loaded), function ($models) use ($loaded) { $results = $this->getRelationResults()->reject(function (Model $model) use ($loaded) {
// Here we will exclude the models that we have already // Here we will exclude the models that we have already
// gathered the recursive results for so we don't run // loaded the recursive results for so we don't run
// into issues with circular relations in LDAP. // into issues with circular relations in LDAP.
return $models->reject(function (Model $model) use ($loaded) { return in_array($model->getDn(), $loaded);
return in_array($model->getDn(), $loaded); });
});
})->each(function (Model $model) use (&$loaded, $models) { foreach ($results as $model) {
$loaded[] = $model->getDn(); $loaded[] = $model->getDn();
// Next, we will call the same relation method on each // Finally, we will fetch the related models relations,
// returned model to retrieve its related models and // passing along our loaded models, to ensure we do
// merge them into our final resulting collection. // not attempt fetching already loaded relations.
$this->getRecursiveResults( $results = $results->merge(
$this->getRecursiveRelationResults($model), $this->getRecursiveRelationResults($model, $loaded)
$loaded );
)->each(function (Model $related) use ($models) { }
$models->add($related);
}); return $results;
});
} }
/** /**
* Get the recursive relation results for given model. * Get the recursive relation results for given model.
* *
* @param Model $model * @param Model $model
* @param array $loaded
* *
* @return Collection * @return Collection
*/ */
protected function getRecursiveRelationResults(Model $model) protected function getRecursiveRelationResults(Model $model, array $loaded)
{ {
return method_exists($model, $this->relationName) return method_exists($model, $this->relationName)
? $model->{$this->relationName}()->recursive()->get() ? $model->{$this->relationName}()->getRecursiveResults($loaded)
: $model->newCollection(); : $model->newCollection();
} }
} }

View File

@ -14,7 +14,7 @@ interface ActiveDirectory extends TypeInterface
/** /**
* Returns the model's hex object SID. * Returns the model's hex object SID.
* *
* @link https://msdn.microsoft.com/en-us/library/ms679024(v=vs.85).aspx * @see https://msdn.microsoft.com/en-us/library/ms679024(v=vs.85).aspx
* *
* @return string * @return string
*/ */

View File

@ -44,12 +44,36 @@ class ArrayCacheStore implements CacheInterface
{ {
$this->storage[$key] = [ $this->storage[$key] = [
'value' => $value, 'value' => $value,
'expiresAt' => $this->parseDateInterval($ttl), 'expiresAt' => $this->calculateExpiration($ttl),
]; ];
return true; return true;
} }
/**
* Get the expiration time of the key.
*
* @param int $seconds
*
* @return int
*/
protected function calculateExpiration($seconds)
{
return $this->toTimestamp($seconds);
}
/**
* Get the UNIX timestamp for the given number of seconds.
*
* @param int $seconds
*
* @return int
*/
protected function toTimestamp($seconds)
{
return $seconds > 0 ? $this->availableAt($seconds) : 0;
}
/** /**
* @inheritdoc * @inheritdoc
*/ */

View File

@ -51,7 +51,13 @@ class Cache
*/ */
public function put($key, $value, $ttl = null) public function put($key, $value, $ttl = null)
{ {
return $this->store->set($key, $value, $this->expiresAt($ttl)); $seconds = $this->secondsUntil($ttl);
if ($seconds <= 0) {
return $this->delete($key);
}
return $this->store->set($key, $value, $seconds);
} }
/** /**

View File

@ -9,18 +9,34 @@ use DateTimeInterface;
/** /**
* @author Taylor Otwell * @author Taylor Otwell
* *
* @link https://laravel.com * @see https://laravel.com
*/ */
trait InteractsWithTime trait InteractsWithTime
{ {
/** /**
* Get the "expires at" UNIX timestamp. * Get the number of seconds until the given DateTime.
* *
* @param DateTimeInterface|DateInterval|int $delay * @param DateTimeInterface|DateInterval|int $delay
* *
* @return int * @return int
*/ */
protected function expiresAt($delay = 0) protected function secondsUntil($delay)
{
$delay = $this->parseDateInterval($delay);
return $delay instanceof DateTimeInterface
? max(0, $delay->getTimestamp() - $this->currentTime())
: (int) $delay;
}
/**
* Get the "available at" UNIX timestamp.
*
* @param DateTimeInterface|DateInterval|int $delay
*
* @return int
*/
protected function availableAt($delay = 0)
{ {
$delay = $this->parseDateInterval($delay); $delay = $this->parseDateInterval($delay);

View File

@ -5,7 +5,7 @@ namespace LdapRecord\Query\Pagination;
use LdapRecord\LdapInterface; use LdapRecord\LdapInterface;
/** /**
* @deprecated * @deprecated since v2.5.0
*/ */
class DeprecatedPaginator extends AbstractPaginator class DeprecatedPaginator extends AbstractPaginator
{ {

View File

@ -32,7 +32,11 @@ class ConnectionFake extends Connection
*/ */
public static function make(array $config = [], $ldap = LdapFake::class) public static function make(array $config = [], $ldap = LdapFake::class)
{ {
return new static($config, new $ldap()); $connection = new static($config, new $ldap());
$connection->configure();
return $connection;
} }
/** /**

View File

@ -207,7 +207,7 @@ class LdapExpectation
public function getMethod() public function getMethod()
{ {
if (is_null($this->method)) { if (is_null($this->method)) {
throw new UnexpectedValueException('The [$method] property cannot be null.'); throw new UnexpectedValueException('An expectation must have a method.');
} }
return $this->method; return $this->method;
@ -226,7 +226,7 @@ class LdapExpectation
/** /**
* Get the expected arguments. * Get the expected arguments.
* *
* @return array * @return Constraint[]
*/ */
public function getExpectedArgs() public function getExpectedArgs()
{ {

View File

@ -4,13 +4,17 @@ namespace LdapRecord\Testing;
use Exception; use Exception;
use LdapRecord\DetailedError; use LdapRecord\DetailedError;
use LdapRecord\LdapBase; use LdapRecord\DetectsErrors;
use LdapRecord\HandlesConnection;
use LdapRecord\LdapInterface;
use LdapRecord\Support\Arr; use LdapRecord\Support\Arr;
use PHPUnit\Framework\Assert as PHPUnit; use PHPUnit\Framework\Assert as PHPUnit;
use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\Constraint\Constraint;
class LdapFake extends LdapBase class LdapFake implements LdapInterface
{ {
use HandlesConnection, DetectsErrors;
/** /**
* The expectations of the LDAP fake. * The expectations of the LDAP fake.
* *
@ -101,7 +105,7 @@ class LdapFake extends LdapBase
* *
* @return bool * @return bool
*/ */
protected function hasExpectations($method) public function hasExpectations($method)
{ {
return count($this->getExpectations($method)) > 0; return count($this->getExpectations($method)) > 0;
} }
@ -113,7 +117,7 @@ class LdapFake extends LdapBase
* *
* @return LdapExpectation[]|mixed * @return LdapExpectation[]|mixed
*/ */
protected function getExpectations($method) public function getExpectations($method)
{ {
return $this->expectations[$method] ?? []; return $this->expectations[$method] ?? [];
} }
@ -126,7 +130,7 @@ class LdapFake extends LdapBase
* *
* @return void * @return void
*/ */
protected function removeExpectation($method, $key) public function removeExpectation($method, $key)
{ {
unset($this->expectations[$method][$key]); unset($this->expectations[$method][$key]);
} }
@ -230,7 +234,7 @@ class LdapFake extends LdapBase
{ {
return $this->hasExpectations('isUsingSSL') return $this->hasExpectations('isUsingSSL')
? $this->resolveExpectation('isUsingSSL') ? $this->resolveExpectation('isUsingSSL')
: parent::isUsingSSL(); : $this->useSSL;
} }
/** /**
@ -240,7 +244,7 @@ class LdapFake extends LdapBase
{ {
return $this->hasExpectations('isUsingTLS') return $this->hasExpectations('isUsingTLS')
? $this->resolveExpectation('isUsingTLS') ? $this->resolveExpectation('isUsingTLS')
: parent::isUsingTLS(); : $this->useTLS;
} }
/** /**
@ -250,7 +254,7 @@ class LdapFake extends LdapBase
{ {
return $this->hasExpectations('isBound') return $this->hasExpectations('isBound')
? $this->resolveExpectation('isBound') ? $this->resolveExpectation('isBound')
: parent::isBound(); : $this->bound;
} }
/** /**
@ -453,7 +457,7 @@ class LdapFake extends LdapBase
* *
* @return mixed * @return mixed
*/ */
protected function resolveExpectation($method, $args = []) protected function resolveExpectation($method, array $args = [])
{ {
foreach ($this->getExpectations($method) as $key => $expectation) { foreach ($this->getExpectations($method) as $key => $expectation) {
$this->assertMethodArgumentsMatch($method, $expectation->getExpectedArgs(), $args); $this->assertMethodArgumentsMatch($method, $expectation->getExpectedArgs(), $args);
@ -501,7 +505,7 @@ class LdapFake extends LdapBase
* *
* @return void * @return void
*/ */
protected function assertMethodArgumentsMatch($method, $expectedArgs = [], $methodArgs = []) protected function assertMethodArgumentsMatch($method, array $expectedArgs = [], array $methodArgs = [])
{ {
foreach ($expectedArgs as $key => $constraint) { foreach ($expectedArgs as $key => $constraint) {
$argNumber = $key + 1; $argNumber = $key + 1;

View File

@ -55,8 +55,8 @@ class Utilities
* *
* @author Chad Sikorra * @author Chad Sikorra
* *
* @link https://github.com/ChadSikorra * @see https://github.com/ChadSikorra
* @link https://stackoverflow.com/questions/39533560/php-ldap-get-user-sid * @see https://stackoverflow.com/questions/39533560/php-ldap-get-user-sid
* *
* @param string $value The Binary SID * @param string $value The Binary SID
* *

View File

@ -2,7 +2,9 @@
namespace Illuminate\Contracts\Support; namespace Illuminate\Contracts\Support;
interface MessageBag extends Arrayable use Countable;
interface MessageBag extends Arrayable, Countable
{ {
/** /**
* Get the keys present in the message bag. * Get the keys present in the message bag.
@ -97,11 +99,4 @@ interface MessageBag extends Arrayable
* @return bool * @return bool
*/ */
public function isNotEmpty(); public function isNotEmpty();
/**
* Get the number of messages in the container.
*
* @return int
*/
public function count();
} }

View File

@ -7,30 +7,24 @@
"time", "time",
"DateTime" "DateTime"
], ],
"homepage": "http://carbon.nesbot.com", "homepage": "https://carbon.nesbot.com",
"support": {
"issues": "https://github.com/briannesbitt/Carbon/issues",
"source": "https://github.com/briannesbitt/Carbon"
},
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
{ {
"name": "Brian Nesbitt", "name": "Brian Nesbitt",
"email": "brian@nesbot.com", "email": "brian@nesbot.com",
"homepage": "http://nesbot.com" "homepage": "https://markido.com"
}, },
{ {
"name": "kylekatarnls", "name": "kylekatarnls",
"homepage": "http://github.com/kylekatarnls" "homepage": "https://github.com/kylekatarnls"
} }
], ],
"prefer-stable": true,
"minimum-stability": "dev",
"bin": ["bin/carbon"],
"require": { "require": {
"php": "^7.1.8 || ^8.0", "php": "^7.1.8 || ^8.0",
"ext-json": "*", "ext-json": "*",
"symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16",
"symfony/translation": "^3.4 || ^4.0 || ^5.0" "symfony/translation": "^3.4 || ^4.0 || ^5.0"
}, },
"require-dev": { "require-dev": {
@ -43,43 +37,14 @@
"phpunit/phpunit": "^7.5.20 || ^8.5.14", "phpunit/phpunit": "^7.5.20 || ^8.5.14",
"squizlabs/php_codesniffer": "^3.4" "squizlabs/php_codesniffer": "^3.4"
}, },
"autoload": {
"psr-4": {
"Carbon\\": "src/Carbon/"
}
},
"autoload-dev": {
"files": [
"tests/Laravel/ServiceProvider.php"
],
"psr-4": {
"Tests\\": "tests/"
}
},
"config": { "config": {
"process-timeout": 0, "process-timeout": 0,
"sort-packages": true "sort-packages": true
}, },
"scripts": {
"test": [
"@phpunit",
"@style-check"
],
"style-check": [
"@phpcs",
"@phpstan",
"@phpmd"
],
"phpunit": "phpunit --verbose",
"phpcs": "php-cs-fixer fix -v --diff --dry-run",
"phpstan": "phpstan analyse --configuration phpstan.neon",
"phpmd": "phpmd src text /phpmd.xml",
"phpdoc": "php phpdoc.php"
},
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.x-dev", "dev-3.x": "3.x-dev",
"dev-3.x": "3.x-dev" "dev-master": "2.x-dev"
}, },
"laravel": { "laravel": {
"providers": [ "providers": [
@ -91,5 +56,43 @@
"extension.neon" "extension.neon"
] ]
} }
},
"autoload": {
"psr-4": {
"Carbon\\": "src/Carbon/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
},
"files": [
"tests/Laravel/ServiceProvider.php"
]
},
"minimum-stability": "dev",
"prefer-stable": true,
"bin": [
"bin/carbon"
],
"scripts": {
"phpcs": "php-cs-fixer fix -v --diff --dry-run",
"phpdoc": "php phpdoc.php",
"phpmd": "phpmd src text /phpmd.xml",
"phpstan": "phpstan analyse --configuration phpstan.neon",
"phpunit": "phpunit --verbose",
"style-check": [
"@phpcs",
"@phpstan",
"@phpmd"
],
"test": [
"@phpunit",
"@style-check"
]
},
"support": {
"issues": "https://github.com/briannesbitt/Carbon/issues",
"source": "https://github.com/briannesbitt/Carbon"
} }
} }

View File

@ -1,154 +0,0 @@
# Contributing to Carbon
## Issue Contributions
Please report any security issue using [Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.
Please don't disclose security bugs publicly until they have been handled by us.
For any other bug or issue, please click this link and follow the template:
[Create new issue](https://github.com/briannesbitt/Carbon/issues/new)
You may think this template does not apply to your case but please think again. A long description will never be as
clear as a code chunk with the output you expect from it (for either bug report or new features).
## Code Contributions
### Where to begin
We use the label **good first issue** to tag issues that could be a good fit for new contributors, see if there are such issues now following this link:
https://github.com/briannesbitt/Carbon/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
Else, check the roadmap to see what we plan to do in next releases:
https://github.com/briannesbitt/Carbon/issues/1681
### Develop locally, then submit changes
Fork the [GitHub project](https://github.com/briannesbitt/Carbon) and download it locally:
```shell
git clone https://github.com/<username>/Carbon.git
cd Carbon
git remote add upstream https://github.com/briannesbitt/Carbon.git
```
Replace `<username>` with your GitHub username.
Then, you can work on the master or create a specific branch for your development:
```shell
git checkout -b my-feature-branch -t origin/master
```
You can now edit the "Carbon" directory contents.
Before committing, please set your name and your e-mail (use the same e-mail address as in your GitHub account):
```shell
git config --global user.name "Your Name"
git config --global user.email "your.email.address@example.com"
```
The ```--global``` argument will apply this setting for all your git repositories, remove it to set only your Carbon
fork with those settings.
Now you can commit your modifications as you usually do with git:
```shell
git add --all
git commit -m "The commit message log"
```
If your patch fixes an open issue, please insert ```#``` immediately followed by the issue number:
```shell
git commit -m "#21 Fix this or that"
```
Use git rebase (not git merge) to sync your work from time to time:
```shell
git fetch origin
git rebase origin/master
```
Please add some tests for bug fixes and features (so it will ensure next developments will not break your code),
then check all is right with phpunit:
Install PHP if you haven't yet, then install composer:
https://getcomposer.org/download/
Update dependencies:
```
./composer.phar update
```
Or if you installed composer globally:
```
composer update
```
Then call phpunit:
```
./vendor/bin/phpunit
```
Make sure all tests succeed before submitting your pull-request, else we will not be able to merge it.
Push your work on your remote GitHub fork with:
```
git push origin my-feature-branch
```
Go to https://github.com/yourusername/Carbon and select your feature branch. Click the 'Pull Request' button and fill
out the form.
We will review it within a few days. And we thank you in advance for your help.
## Versioning
### Note about Semantic Versioning and breaking changes
As a developer, you must understand every change is a breaking change. What is a bug for someone
is expected in someone else's workflow. The consequence of a change strongly depends on the usage.
[Semantic Versioning](https://semver.org/) relies to public API. In PHP, the public API of a class is its public
methods. However, if you extend a class, you can access protected methods, then if you use reflexion, you can
access private methods. So anything can become a public API if you force it to be. That doesn't mean we should handle
any possible usage, else we would have to publish a major release for each change and it would no longer make sense.
So before any complain about a breaking change, be warned, we do not guarantee a strict Semantic Versioning as you
may expect, we're following a pragmatic interpretation of Semantic Versioning that allows the software to evolve in a
reliable way with reasonable maintenance effort.
Concretely, we consider a change as breaking if it makes fail one of our unit test. We will do our best to avoid
incompatibilities with libraries that extends Carbon classes (such as Laravel that is continuously tested thanks to
Travis CI, [see the compatibility matrix](https://github.com/kylekatarnls/carbon-laravel/tree/master#carbon-1-dev-version-1next)).
If you're the owner of a library that strongly depends on Carbon, we recommend you to run unit tests daily requiring
`"nesbot/carbon": "dev-master"` (for `^2`) or `"nesbot/carbon": "dev-version-1.next"` (for `^1`), this way you can
detect incompatibilities earlier and report it to us before we tag a release. We'll pay attention and try to fix it to
make update to next minor releases as soft as possible.
We reserve the right to publish emergency patches within 24 hours after a release if a tag that does not respect
this pattern would have been released despite our vigilance. In this very rare and particular case, we would mark the
tag as broken on GitHub and backward compatibility would be based on previous stable tag.
Last, you must understand that Carbon extends PHP natives classes, that means Carbon can be impacted by any change
that occurs in the date/time API of PHP. We watch new PHP versions and handle those changes as quickly as possible
when detected, but as PHP does not follow the semantic versioning pattern, it basically means any releases (including
patches) can have unexpected consequences on Carbon methods results.
### Long term support
To benefit the better support, require Carbon using major version range (`^1` or `^2`). By requiring `1.26.*`,
`~1.26.0` or limited range such as `>=1.20 <1.33`, you fall to low priority support (only security and critical issues
will be fixed), our prior support goes to next minor releases of each major version. It applies to bug fixes and
low-cost features. Other new features will only be added in the last stable release. At the opposite, we recommend you
to restrain to a major number, as there is no compatibility guarantee from a major version to the next. It means
requiring `>=2`, as it allows any newer version, will probably leads to errors on releasing our next major version.
Open milestones can be patched if a minor bug is detected while if you're on a closed milestone, we'll more likely
ask you to update first to an open one. See currently open milestones:
https://github.com/briannesbitt/Carbon/milestones

View File

@ -1,46 +0,0 @@
<?xml version="1.0"?>
<ruleset name="Mess detection rules for Carbon"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
Mess detection rules for Carbon
</description>
<rule ref="rulesets/codesize.xml">
<exclude name="CyclomaticComplexity" />
<exclude name="NPathComplexity" />
<exclude name="ExcessiveMethodLength" />
<exclude name="ExcessiveClassLength" />
<exclude name="ExcessivePublicCount" />
<exclude name="TooManyMethods" />
<exclude name="TooManyPublicMethods" />
<exclude name="ExcessiveClassComplexity" />
</rule>
<rule ref="rulesets/cleancode.xml">
<exclude name="BooleanArgumentFlag" />
<exclude name="StaticAccess" />
<exclude name="IfStatementAssignment" />
<exclude name="UndefinedVariable" />
<exclude name="ErrorControlOperator" />
</rule>
<rule ref="rulesets/controversial.xml" />
<rule ref="rulesets/design.xml">
<exclude name="EvalExpression" />
<exclude name="CouplingBetweenObjects" />
<exclude name="CountInLoopExpression" />
</rule>
<rule ref="rulesets/design.xml/CouplingBetweenObjects">
<properties>
<property name="maximum" value="25" />
</properties>
</rule>
<rule ref="rulesets/naming.xml/ShortVariable">
<properties>
<property name="exceptions" value="ci,id,to,tz" />
</properties>
</rule>
<rule ref="rulesets/unusedcode.xml" />
</ruleset>

View File

@ -8,7 +8,7 @@
[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-44CC11.svg?longCache=true&style=flat-square)](https://github.com/phpstan/phpstan) [![PHPStan](https://img.shields.io/badge/PHPStan-enabled-44CC11.svg?longCache=true&style=flat-square)](https://github.com/phpstan/phpstan)
[![Tidelift](https://tidelift.com/badges/github/briannesbitt/Carbon)](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme) [![Tidelift](https://tidelift.com/badges/github/briannesbitt/Carbon)](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme)
An international PHP extension for DateTime. [http://carbon.nesbot.com](http://carbon.nesbot.com) An international PHP extension for DateTime. [https://carbon.nesbot.com](https://carbon.nesbot.com)
```php ```php
<?php <?php
@ -84,7 +84,7 @@ printf("Now: %s", Carbon::now());
### Without Composer ### Without Composer
Why are you not using [composer](http://getcomposer.org/)? Download the Carbon [latest release](https://github.com/briannesbitt/Carbon/releases) and put the contents of the ZIP archive into a directory in your project. Then require the file `autoload.php` to get all classes and dependencies loaded on need. Why are you not using [composer](https://getcomposer.org/)? Download the Carbon [latest release](https://github.com/briannesbitt/Carbon/releases) and put the contents of the ZIP archive into a directory in your project. Then require the file `autoload.php` to get all classes and dependencies loaded on need.
```php ```php
<?php <?php
@ -97,7 +97,7 @@ printf("Now: %s", Carbon::now());
## Docs ## Docs
[http://carbon.nesbot.com/docs](http://carbon.nesbot.com/docs) [https://carbon.nesbot.com/docs](https://carbon.nesbot.com/docs)
## Security contact information ## Security contact information
@ -122,7 +122,7 @@ This project exists thanks to all the people who contribute.
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. Support this project by becoming a sponsor. Your logo will show up here with a link to your website.
<a href="https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme" target="_blank"><img src="https://carbon.nesbot.com/tidelift-brand.png" width="256" height="64"></a> <a href="https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme" target="_blank"><img src="https://carbon.nesbot.com/tidelift-brand.png" width="256" height="64"></a>
<a href="https://onlinecasinohex.ca/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/0/avatar.svg" width="192" height="64"></a> <a href="https://onlinecasinohex.ca/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img src="https://images.opencollective.com/hexcasinoca/2da3af2/logo/256.png" width="85" height="64"></a>
<a href="https://opencollective.com/Carbon/sponsor/0/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/Carbon/sponsor/0/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/Carbon/sponsor/1/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/Carbon/sponsor/1/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/Carbon/sponsor/2/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/Carbon/sponsor/2/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/2/avatar.svg"></a>

View File

@ -555,6 +555,11 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface
return 145261681241552; return 145261681241552;
} }
// Remove if https://bugs.php.net/bug.php?id=81107 is fixed
if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) {
return 1118290769066902787;
}
return PHP_INT_MAX; return PHP_INT_MAX;
} }
@ -567,6 +572,11 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface
return -135908816449551; return -135908816449551;
} }
// Remove if https://bugs.php.net/bug.php?id=81107 is fixed
if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) {
return -1118290769066898816;
}
return max(PHP_INT_MIN, -9223372036854773760); return max(PHP_INT_MIN, -9223372036854773760);
} }
} }

View File

@ -26,6 +26,7 @@ use DateTimeInterface;
use DateTimeZone; use DateTimeZone;
use JsonSerializable; use JsonSerializable;
use ReflectionException; use ReflectionException;
use ReturnTypeWillChange;
use Throwable; use Throwable;
/** /**
@ -721,6 +722,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public static function __set_state($dump); public static function __set_state($dump);
/** /**
@ -755,6 +757,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public function add($unit, $value = 1, $overflow = null); public function add($unit, $value = 1, $overflow = null);
/** /**
@ -830,6 +833,16 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*/ */
public function average($date = null); public function average($date = null);
/**
* Clone the current instance if it's mutable.
*
* This method is convenient to ensure you don't mutate the initial object
* but avoid to make a useless copy of it if it's already immutable.
*
* @return static
*/
public function avoidMutation();
/** /**
* Determines if the instance is between two others. * Determines if the instance is between two others.
* *
@ -1066,6 +1079,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static|false * @return static|false
*/ */
#[ReturnTypeWillChange]
public static function createFromFormat($format, $time, $tz = null); public static function createFromFormat($format, $time, $tz = null);
/** /**
@ -1946,7 +1960,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
/** /**
* Format the instance with the current locale. You can set the current * Format the instance with the current locale. You can set the current
* locale using setlocale() http://php.net/setlocale. * locale using setlocale() https://php.net/setlocale.
* *
* @param string $format * @param string $format
* *
@ -2135,6 +2149,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
#[ReturnTypeWillChange]
public static function getLastErrors(); public static function getLastErrors();
/** /**
@ -3007,6 +3022,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return array|string * @return array|string
*/ */
#[ReturnTypeWillChange]
public function jsonSerialize(); public function jsonSerialize();
/** /**
@ -3317,6 +3333,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @see https://php.net/manual/en/datetime.modify.php * @see https://php.net/manual/en/datetime.modify.php
*/ */
#[ReturnTypeWillChange]
public function modify($modify); public function modify($modify);
/** /**
@ -3700,6 +3717,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public function setDate($year, $month, $day); public function setDate($year, $month, $day);
/** /**
@ -3764,6 +3782,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public function setISODate($year, $week, $day = 1); public function setISODate($year, $week, $day = 1);
/** /**
@ -3834,6 +3853,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public function setTime($hour, $minute, $second = 0, $microseconds = 0); public function setTime($hour, $minute, $second = 0, $microseconds = 0);
/** /**
@ -3863,6 +3883,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public function setTimestamp($unixTimestamp); public function setTimestamp($unixTimestamp);
/** /**
@ -3872,6 +3893,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public function setTimezone($value); public function setTimezone($value);
/** /**
@ -4213,6 +4235,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @return static * @return static
*/ */
#[ReturnTypeWillChange]
public function sub($unit, $value = 1, $overflow = null); public function sub($unit, $value = 1, $overflow = null);
public function subRealUnit($unit, $value = 1); public function subRealUnit($unit, $value = 1);
@ -4751,7 +4774,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @param string $key * @param string $key
* @param array $parameters * @param array $parameters
* @param null $number * @param string|int|float|null $number
* @param \Symfony\Component\Translation\TranslatorInterface $translator * @param \Symfony\Component\Translation\TranslatorInterface $translator
* *
* @return string * @return string
@ -4808,7 +4831,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
public static function translateWith(\Symfony\Component\Translation\TranslatorInterface $translator, string $key, array $parameters = [], $number = null): string; public static function translateWith(\Symfony\Component\Translation\TranslatorInterface $translator, string $key, array $parameters = [], $number = null): string;
/** /**
* Format as ->format() do (using date replacements patterns from http://php.net/manual/fr/function.date.php) * Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php)
* but translate words whenever possible (months, day names, etc.) using the current locale. * but translate words whenever possible (months, day names, etc.) using the current locale.
* *
* @param string $format * @param string $format
@ -4991,6 +5014,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
* *
* @param Closure|static|string|false|null $testNow real or mock Carbon instance * @param Closure|static|string|false|null $testNow real or mock Carbon instance
* @param Closure|null $callback * @param Closure|null $callback
*
* @return mixed
*/ */
public static function withTestNow($testNow = null, $callback = null); public static function withTestNow($testNow = null, $callback = null);

View File

@ -353,7 +353,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
$spec = $years; $spec = $years;
if (!\is_string($spec) || \floatval($years) || preg_match('/^[0-9.]/', $years)) { if (!\is_string($spec) || (float) $years || preg_match('/^[0-9.]/', $years)) {
$spec = static::PERIOD_PREFIX; $spec = static::PERIOD_PREFIX;
$spec .= $years > 0 ? $years.static::PERIOD_YEARS : ''; $spec .= $years > 0 ? $years.static::PERIOD_YEARS : '';
@ -380,7 +380,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
parent::__construct($spec); parent::__construct($spec);
if (!\is_null($microseconds)) { if ($microseconds !== null) {
$this->f = $microseconds / Carbon::MICROSECONDS_PER_SECOND; $this->f = $microseconds / Carbon::MICROSECONDS_PER_SECOND;
} }
} }
@ -536,7 +536,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
} }
$interval = mb_substr($interval, mb_strlen($match[0])); $interval = mb_substr($interval, mb_strlen($match[0]));
$instance->$unit += \intval($match[0]); $instance->$unit += (int) ($match[0]);
continue; continue;
} }
@ -546,7 +546,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
"'$expected'", "'$expected'",
$nextCharacter, $nextCharacter,
'Allowed substitutes for interval formats are '.implode(', ', array_keys(static::$formats))."\n". 'Allowed substitutes for interval formats are '.implode(', ', array_keys(static::$formats))."\n".
'See https://www.php.net/manual/en/function.date.php for their meaning' 'See https://php.net/manual/en/function.date.php for their meaning'
); );
} }
@ -679,8 +679,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
preg_match_all($pattern, $intervalDefinition, $parts, PREG_SET_ORDER); preg_match_all($pattern, $intervalDefinition, $parts, PREG_SET_ORDER);
while ([$part, $value, $unit] = array_shift($parts)) { while ([$part, $value, $unit] = array_shift($parts)) {
$intValue = \intval($value); $intValue = (int) $value;
$fraction = \floatval($value) - $intValue; $fraction = (float) $value - $intValue;
// Fix calculation precision // Fix calculation precision
switch (round($fraction, 6)) { switch (round($fraction, 6)) {
@ -964,7 +964,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
* *
* @return static * @return static
* *
* @link http://php.net/manual/en/dateinterval.createfromdatestring.php * @link https://php.net/manual/en/dateinterval.createfromdatestring.php
*/ */
#[ReturnTypeWillChange] #[ReturnTypeWillChange]
public static function createFromDateString($time) public static function createFromDateString($time)
@ -996,7 +996,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
*/ */
public function get($name) public function get($name)
{ {
if (substr($name, 0, 5) === 'total') { if (str_starts_with($name, 'total')) {
return $this->total(substr($name, 5)); return $this->total(substr($name, 5));
} }
@ -1360,7 +1360,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
$minimumUnit = 's'; $minimumUnit = 's';
extract($this->getForHumansInitialVariables($syntax, $short)); extract($this->getForHumansInitialVariables($syntax, $short));
if (\is_null($syntax)) { if ($syntax === null) {
$syntax = CarbonInterface::DIFF_ABSOLUTE; $syntax = CarbonInterface::DIFF_ABSOLUTE;
} }
@ -1368,7 +1368,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
$parts = INF; $parts = INF;
} }
if (\is_null($options)) { if ($options === null) {
$options = static::getHumanDiffOptions(); $options = static::getHumanDiffOptions();
} }
@ -1860,7 +1860,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
[$value, $unit] = [$unit, $value]; [$value, $unit] = [$unit, $value];
} }
return $this->add($unit, -\floatval($value)); return $this->add($unit, -(float) $value);
} }
/** /**
@ -2104,7 +2104,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
public static function compareDateIntervals(DateInterval $first, DateInterval $second) public static function compareDateIntervals(DateInterval $first, DateInterval $second)
{ {
$current = Carbon::now(); $current = Carbon::now();
$passed = $current->copy()->add($second); $passed = $current->avoidMutation()->add($second);
$current->add($first); $current->add($first);
if ($current < $passed) { if ($current < $passed) {
@ -2242,12 +2242,12 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
'years' => $this->years, 'years' => $this->years,
'months' => $this->months, 'months' => $this->months,
'weeks' => (int) ($this->d / $daysPerWeek), 'weeks' => (int) ($this->d / $daysPerWeek),
'dayz' => (int) ($this->d % $daysPerWeek), 'dayz' => $this->d % $daysPerWeek,
'hours' => $this->hours, 'hours' => $this->hours,
'minutes' => $this->minutes, 'minutes' => $this->minutes,
'seconds' => $this->seconds, 'seconds' => $this->seconds,
'milliseconds' => (int) ($this->microseconds / Carbon::MICROSECONDS_PER_MILLISECOND), 'milliseconds' => (int) ($this->microseconds / Carbon::MICROSECONDS_PER_MILLISECOND),
'microseconds' => (int) ($this->microseconds % Carbon::MICROSECONDS_PER_MILLISECOND), 'microseconds' => $this->microseconds % Carbon::MICROSECONDS_PER_MILLISECOND,
]; ];
if (isset($factors['dayz']) && $factors['dayz'][0] !== 'weeks') { if (isset($factors['dayz']) && $factors['dayz'][0] !== 'weeks') {

View File

@ -32,6 +32,7 @@ use InvalidArgumentException;
use Iterator; use Iterator;
use JsonSerializable; use JsonSerializable;
use ReflectionException; use ReflectionException;
use ReturnTypeWillChange;
use RuntimeException; use RuntimeException;
/** /**
@ -875,7 +876,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/ */
public function setOptions($options) public function setOptions($options)
{ {
if (!\is_int($options) && !\is_null($options)) { if (!\is_int($options) && $options !== null) {
throw new InvalidPeriodParameterException('Invalid options.'); throw new InvalidPeriodParameterException('Invalid options.');
} }
@ -962,7 +963,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/ */
public function getStartDate(string $rounding = null) public function getStartDate(string $rounding = null)
{ {
$date = $this->startDate->copy(); $date = $this->startDate->avoidMutation();
return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date; return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date;
} }
@ -980,7 +981,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
return null; return null;
} }
$date = $this->endDate->copy(); $date = $this->endDate->avoidMutation();
return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date; return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date;
} }
@ -1220,7 +1221,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/ */
public function setRecurrences($recurrences) public function setRecurrences($recurrences)
{ {
if (!is_numeric($recurrences) && !\is_null($recurrences) || $recurrences < 0) { if (!is_numeric($recurrences) && $recurrences !== null || $recurrences < 0) {
throw new InvalidPeriodParameterException('Invalid number of recurrences.'); throw new InvalidPeriodParameterException('Invalid number of recurrences.');
} }
@ -1276,7 +1277,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/ */
public function setEndDate($date, $inclusive = null) public function setEndDate($date, $inclusive = null)
{ {
if (!\is_null($date) && !$date = ([$this->dateClass, 'make'])($date)) { if ($date !== null && !$date = ([$this->dateClass, 'make'])($date)) {
throw new InvalidPeriodDateException('Invalid end date.'); throw new InvalidPeriodDateException('Invalid end date.');
} }
@ -1523,7 +1524,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
{ {
$state = [ $state = [
$this->key, $this->key,
$this->current ? $this->current->copy() : null, $this->current ? $this->current->avoidMutation() : null,
$this->validationResult, $this->validationResult,
]; ];
@ -1722,7 +1723,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
$date = $this->getEndFromRecurrences() ?? $this->iterateUntilEnd(); $date = $this->getEndFromRecurrences() ?? $this->iterateUntilEnd();
if ($date && $rounding) { if ($date && $rounding) {
$date = $date->copy()->round($this->getDateInterval(), $rounding); $date = $date->avoidMutation()->round($this->getDateInterval(), $rounding);
} }
return $date; return $date;
@ -1743,13 +1744,13 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
if ($this->recurrences === INF) { if ($this->recurrences === INF) {
$start = $this->getStartDate(); $start = $this->getStartDate();
return $start < $start->copy()->add($this->getDateInterval()) return $start < $start->avoidMutation()->add($this->getDateInterval())
? CarbonImmutable::endOfTime() ? CarbonImmutable::endOfTime()
: CarbonImmutable::startOfTime(); : CarbonImmutable::startOfTime();
} }
if ($this->filters === [[static::RECURRENCES_FILTER, null]]) { if ($this->filters === [[static::RECURRENCES_FILTER, null]]) {
return $this->getStartDate()->copy()->add( return $this->getStartDate()->avoidMutation()->add(
$this->getDateInterval()->times( $this->getDateInterval()->times(
$this->recurrences - ($this->isStartExcluded() ? 0 : 1) $this->recurrences - ($this->isStartExcluded() ? 0 : 1)
) )
@ -1795,13 +1796,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
$range = static::create($range); $range = static::create($range);
} }
$thisDates = [$this->getStartDate(), $this->calculateEnd()]; [$start, $end] = $this->orderCouple($this->getStartDate(), $this->calculateEnd());
sort($thisDates); [$rangeStart, $rangeEnd] = $this->orderCouple($range->getStartDate(), $range->calculateEnd());
[$start, $end] = $thisDates;
$rangeDates = [$range->getStartDate(), $range->calculateEnd()];
sort($rangeDates);
[$rangeStart, $rangeEnd] = $rangeDates;
return $end > $rangeStart && $rangeEnd > $start; return $end > $rangeStart && $rangeEnd > $start;
} }
@ -2168,6 +2164,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
* *
* @return CarbonInterface[] * @return CarbonInterface[]
*/ */
#[ReturnTypeWillChange]
public function jsonSerialize() public function jsonSerialize()
{ {
return $this->toArray(); return $this->toArray();
@ -2283,7 +2280,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/ */
protected function isCarbonPredicateMethod($callable) protected function isCarbonPredicateMethod($callable)
{ {
return \is_string($callable) && substr($callable, 0, 2) === 'is' && return \is_string($callable) && str_starts_with($callable, 'is') &&
(method_exists($this->dateClass, $callable) || ([$this->dateClass, 'hasMacro'])($callable)); (method_exists($this->dateClass, $callable) || ([$this->dateClass, 'hasMacro'])($callable));
} }
@ -2384,7 +2381,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
foreach ($this->filters as $tuple) { foreach ($this->filters as $tuple) {
$result = \call_user_func( $result = \call_user_func(
$tuple[0], $tuple[0],
$current->copy(), $current->avoidMutation(),
$this->key, $this->key,
$this $this
); );
@ -2493,4 +2490,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
? static::instance($period) ? static::instance($period)
: static::create($period, ...$arguments); : static::create($period, ...$arguments);
} }
private function orderCouple($first, $second): array
{
return $first > $second ? [$second, $first] : [$first, $second];
}
} }

View File

@ -33,7 +33,7 @@ class CarbonTimeZone extends DateTimeZone
protected static function getDateTimeZoneNameFromMixed($timezone) protected static function getDateTimeZoneNameFromMixed($timezone)
{ {
if (\is_null($timezone)) { if ($timezone === null) {
return date_default_timezone_get(); return date_default_timezone_get();
} }

View File

@ -37,7 +37,7 @@ trait CarbonTypeConverter
return $type; return $type;
} }
if (strpos($type, '(') !== false) { if (str_contains($type, '(')) {
return preg_replace('/\(\d+\)/', "($precision)", $type); return preg_replace('/\(\d+\)/', "($precision)", $type);
} }
@ -95,7 +95,7 @@ trait CarbonTypeConverter
return $value; return $value;
} }
if ($value instanceof DateTimeInterface || $value instanceof CarbonInterface) { if ($value instanceof DateTimeInterface) {
return $value->format('Y-m-d H:i:s.u'); return $value->format('Y-m-d H:i:s.u');
} }

View File

@ -215,7 +215,7 @@ use ReflectionMethod;
* You should rather use the ->settings() method. * You should rather use the ->settings() method.
* Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants
* are available for quarters, years, decade, centuries, millennia (singular and plural forms). * are available for quarters, years, decade, centuries, millennia (singular and plural forms).
* @method Carbon withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback. * @method mixed withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback.
* Using setTestNow to set the date, executing the callback, then * Using setTestNow to set the date, executing the callback, then
* clearing the test instance. * clearing the test instance.
* /!\ Use this method for unit tests only. * /!\ Use this method for unit tests only.
@ -229,7 +229,7 @@ class Factory
protected $settings = []; protected $settings = [];
public function __construct(array $settings = [], string $className = null) public function __construct(array $settings = [], ?string $className = null)
{ {
if ($className) { if ($className) {
$this->className = $className; $this->className = $className;

View File

@ -214,7 +214,7 @@ use Closure;
* You should rather use the ->settings() method. * You should rather use the ->settings() method.
* Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants
* are available for quarters, years, decade, centuries, millennia (singular and plural forms). * are available for quarters, years, decade, centuries, millennia (singular and plural forms).
* @method CarbonImmutable withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback. * @method mixed withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback.
* Using setTestNow to set the date, executing the callback, then * Using setTestNow to set the date, executing the callback, then
* clearing the test instance. * clearing the test instance.
* /!\ Use this method for unit tests only. * /!\ Use this method for unit tests only.

View File

@ -11,7 +11,7 @@
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
if (class_exists('Symfony\\Component\\Translation\\PluralizationRules')) { if (class_exists('Symfony\\Component\\Translation\\PluralizationRules')) {
\Symfony\Component\Translation\PluralizationRules::set(function ($number) { \Symfony\Component\Translation\PluralizationRules::set(function ($number) {
return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
}, 'be'); }, 'be');
} }
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -11,7 +11,7 @@
/* /*
* Authors: * Authors:
* - Ankur Group, http://www.ankurbangla.org, http://www.bengalinux.org Taneem Ahmed, Jamil Ahmed taneem@bengalinux.org, jamil@bengalinux.org * - Ankur Group, Taneem Ahmed, Jamil Ahmed
*/ */
return array_replace_recursive(require __DIR__.'/bn.php', [ return array_replace_recursive(require __DIR__.'/bn.php', [
'formats' => [ 'formats' => [

View File

@ -41,7 +41,7 @@ return [
's' => ':count seg.', 's' => ':count seg.',
'ago' => 'hai :time', 'ago' => 'hai :time',
'from_now' => function ($time) { 'from_now' => function ($time) {
if (substr($time, 0, 2) === 'un') { if (str_starts_with($time, 'un')) {
return "n$time"; return "n$time";
} }

View File

@ -169,8 +169,8 @@ return [
return $number.'-ე'; return $number.'-ე';
}, },
'months' => ['იანვარს', 'თებერვალს', 'მარტს', 'აპრილის', 'მაისს', 'ივნისს', 'ივლისს', 'აგვისტს', 'სექტემბერს', 'ოქტომბერს', 'ნოემბერს', 'დეკემბერს'], 'months' => ['იანვარი', 'თებერვალი', 'მარტი', 'აპრილი', 'მაისი', 'ივნისი', 'ივლისი', 'აგვისტო', 'სექტემბერი', 'ოქტომბერი', 'ნოემბერი', 'დეკემბერი'],
'months_standalone' => ['იანვარი', 'თებერვალი', 'მარტი', 'აპრილი', 'მაისი', 'ივნისი', 'ივლისი', 'აგვისტო', 'სექტემბერი', 'ოქტომბერი', 'ნოემბერი', 'დეკემბერი'], 'months_standalone' => ['იანვარს', 'თებერვალს', 'მარტს', 'აპრილს', 'მაისს', 'ივნისს', 'ივლისს', 'აგვისტოს', 'სექტემბერს', 'ოქტომბერს', 'ნოემბერს', 'დეკემბერს'],
'months_short' => ['იან', 'თებ', 'მარ', 'აპრ', 'მაი', 'ივნ', 'ივლ', 'აგვ', 'სექ', 'ოქტ', 'ნოე', 'დეკ'], 'months_short' => ['იან', 'თებ', 'მარ', 'აპრ', 'მაი', 'ივნ', 'ივლ', 'აგვ', 'სექ', 'ოქტ', 'ნოე', 'დეკ'],
'months_regexp' => '/(D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|L{2,4}|l{2,4})/', 'months_regexp' => '/(D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|L{2,4}|l{2,4})/',
'weekdays' => ['კვირას', 'ორშაბათს', 'სამშაბათს', 'ოთხშაბათს', 'ხუთშაბათს', 'პარასკევს', 'შაბათს'], 'weekdays' => ['კვირას', 'ორშაბათს', 'სამშაბათს', 'ოთხშაბათს', 'ხუთშაბათს', 'პარასკევს', 'შაბათს'],

View File

@ -69,7 +69,7 @@ return [
'diff_after_tomorrow' => 'overmorgen', 'diff_after_tomorrow' => 'overmorgen',
'diff_before_yesterday' => 'eergisteren', 'diff_before_yesterday' => 'eergisteren',
'period_recurrences' => ':count keer', 'period_recurrences' => ':count keer',
'period_interval' => function ($interval) { 'period_interval' => function (string $interval = '') {
/** @var string $output */ /** @var string $output */
$output = preg_replace('/^(een|één|1)\s+/', '', $interval); $output = preg_replace('/^(een|één|1)\s+/', '', $interval);

View File

@ -82,7 +82,7 @@ return [
'weekdays' => ['dimenge', 'diluns', 'dimars', 'dimècres', 'dijòus', 'divendres', 'dissabte'], 'weekdays' => ['dimenge', 'diluns', 'dimars', 'dimècres', 'dijòus', 'divendres', 'dissabte'],
'weekdays_short' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'], 'weekdays_short' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'],
'weekdays_min' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'], 'weekdays_min' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'],
'ordinal' => function ($number, $period) { 'ordinal' => function ($number, string $period = '') {
$ordinal = [1 => 'èr', 2 => 'nd'][(int) $number] ?? 'en'; $ordinal = [1 => 'èr', 2 => 'nd'][(int) $number] ?? 'en';
// feminine for year, week, hour, minute, second // feminine for year, week, hour, minute, second

View File

@ -29,7 +29,7 @@
return [ return [
'year' => ':count rok|:count lata|:count lat', 'year' => ':count rok|:count lata|:count lat',
'a_year' => 'rok|:count lata|:count lat', 'a_year' => 'rok|:count lata|:count lat',
'y' => ':count r|:count l', 'y' => ':count r|:count l|:count l',
'month' => ':count miesiąc|:count miesiące|:count miesięcy', 'month' => ':count miesiąc|:count miesiące|:count miesięcy',
'a_month' => 'miesiąc|:count miesiące|:count miesięcy', 'a_month' => 'miesiąc|:count miesiące|:count miesięcy',
'm' => ':count mies.', 'm' => ':count mies.',

View File

@ -11,7 +11,7 @@
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
if (class_exists('Symfony\\Component\\Translation\\PluralizationRules')) { if (class_exists('Symfony\\Component\\Translation\\PluralizationRules')) {
\Symfony\Component\Translation\PluralizationRules::set(function ($number) { \Symfony\Component\Translation\PluralizationRules::set(function ($number) {
return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
}, 'sh'); }, 'sh');
} }
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -11,7 +11,7 @@
/* /*
* Authors: * Authors:
* - ubuntu Myanmar LoCo Team http://www.ubuntu-mm.net Bone Pyae Sone bone.burma@mail.com * - ubuntu Myanmar LoCo Team https://ubuntu-mm.net Bone Pyae Sone bone.burma@mail.com
*/ */
return array_replace_recursive(require __DIR__.'/en.php', [ return array_replace_recursive(require __DIR__.'/en.php', [
'formats' => [ 'formats' => [

View File

@ -11,6 +11,7 @@
namespace Carbon; namespace Carbon;
use JsonSerializable; use JsonSerializable;
use ReturnTypeWillChange;
class Language implements JsonSerializable class Language implements JsonSerializable
{ {
@ -332,6 +333,7 @@ class Language implements JsonSerializable
* *
* @return string * @return string
*/ */
#[ReturnTypeWillChange]
public function jsonSerialize() public function jsonSerialize()
{ {
return $this->getIsoDescription(); return $this->getIsoDescription();

View File

@ -622,7 +622,7 @@ trait Comparison
if (!isset($units[$unit])) { if (!isset($units[$unit])) {
if (isset($this->$unit)) { if (isset($this->$unit)) {
return $this->$unit === $this->resolveCarbon($date)->$unit; return $this->resolveCarbon($date)->$unit === $this->$unit;
} }
if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) { if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {
@ -949,7 +949,7 @@ trait Comparison
$tester = trim($tester); $tester = trim($tester);
if (preg_match('/^\d+$/', $tester)) { if (preg_match('/^\d+$/', $tester)) {
return $this->year === \intval($tester); return $this->year === (int) $tester;
} }
if (preg_match('/^\d{3,}-\d{1,2}$/', $tester)) { if (preg_match('/^\d{3,}-\d{1,2}$/', $tester)) {
@ -964,9 +964,9 @@ trait Comparison
/* @var CarbonInterface $max */ /* @var CarbonInterface $max */
$median = static::parse('5555-06-15 12:30:30.555555')->modify($modifier); $median = static::parse('5555-06-15 12:30:30.555555')->modify($modifier);
$current = $this->copy(); $current = $this->avoidMutation();
/* @var CarbonInterface $other */ /* @var CarbonInterface $other */
$other = $this->copy()->modify($modifier); $other = $this->avoidMutation()->modify($modifier);
if ($current->eq($other)) { if ($current->eq($other)) {
return true; return true;
@ -1001,7 +1001,7 @@ trait Comparison
]; ];
foreach ($units as $unit => [$minimum, $startUnit]) { foreach ($units as $unit => [$minimum, $startUnit]) {
if ($median->$unit === $minimum) { if ($minimum === $median->$unit) {
$current = $current->startOf($startUnit); $current = $current->startOf($startUnit);
break; break;

View File

@ -38,7 +38,7 @@ trait Converter
* *
* @var string|Closure|null * @var string|Closure|null
*/ */
protected static $toStringFormat = null; protected static $toStringFormat;
/** /**
* Reset the format used to the default when type juggling a Carbon instance to a string * Reset the format used to the default when type juggling a Carbon instance to a string
@ -324,7 +324,9 @@ trait Converter
*/ */
public function toIso8601ZuluString($unitPrecision = 'second') public function toIso8601ZuluString($unitPrecision = 'second')
{ {
return $this->copy()->utc()->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision).'\Z'); return $this->avoidMutation()
->utc()
->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision).'\Z');
} }
/** /**
@ -452,7 +454,7 @@ trait Converter
*/ */
public function toRfc7231String() public function toRfc7231String()
{ {
return $this->copy() return $this->avoidMutation()
->setTimezone('GMT') ->setTimezone('GMT')
->rawFormat(\defined('static::RFC7231_FORMAT') ? static::RFC7231_FORMAT : CarbonInterface::RFC7231_FORMAT); ->rawFormat(\defined('static::RFC7231_FORMAT') ? static::RFC7231_FORMAT : CarbonInterface::RFC7231_FORMAT);
} }
@ -512,7 +514,7 @@ trait Converter
*/ */
public function toString() public function toString()
{ {
return $this->copy()->locale('en')->isoFormat('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); return $this->avoidMutation()->locale('en')->isoFormat('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
} }
/** /**
@ -537,7 +539,7 @@ trait Converter
$yearFormat = $this->year < 0 || $this->year > 9999 ? 'YYYYYY' : 'YYYY'; $yearFormat = $this->year < 0 || $this->year > 9999 ? 'YYYYYY' : 'YYYY';
$tzFormat = $keepOffset ? 'Z' : '[Z]'; $tzFormat = $keepOffset ? 'Z' : '[Z]';
$date = $keepOffset ? $this : $this->copy()->utc(); $date = $keepOffset ? $this : $this->avoidMutation()->utc();
return $date->isoFormat("$yearFormat-MM-DD[T]HH:mm:ss.SSSSSS$tzFormat"); return $date->isoFormat("$yearFormat-MM-DD[T]HH:mm:ss.SSSSSS$tzFormat");
} }

View File

@ -77,7 +77,7 @@ trait Creator
} }
// Work-around for PHP bug https://bugs.php.net/bug.php?id=67127 // Work-around for PHP bug https://bugs.php.net/bug.php?id=67127
if (strpos((string) .1, '.') === false) { if (!str_contains((string) .1, '.')) {
$locale = setlocale(LC_NUMERIC, '0'); $locale = setlocale(LC_NUMERIC, '0');
setlocale(LC_NUMERIC, 'C'); setlocale(LC_NUMERIC, 'C');
} }
@ -592,7 +592,7 @@ trait Creator
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
if ($originalTz === null) { if ($originalTz === null) {
return parent::createFromFormat($format, "$time"); return parent::createFromFormat($format, (string) $time);
} }
$tz = \is_int($originalTz) $tz = \is_int($originalTz)
@ -605,7 +605,7 @@ trait Creator
return false; return false;
} }
return parent::createFromFormat($format, "$time", $tz); return parent::createFromFormat($format, (string) $time, $tz);
} }
/** /**

View File

@ -27,6 +27,7 @@ use Closure;
use DateInterval; use DateInterval;
use DatePeriod; use DatePeriod;
use DateTime; use DateTime;
use DateTimeImmutable;
use DateTimeInterface; use DateTimeInterface;
use DateTimeZone; use DateTimeZone;
use InvalidArgumentException; use InvalidArgumentException;
@ -630,7 +631,7 @@ trait Date
* *
* @return CarbonTimeZone * @return CarbonTimeZone
* *
* @link http://php.net/manual/en/datetime.gettimezone.php * @link https://php.net/manual/en/datetime.gettimezone.php
*/ */
#[ReturnTypeWillChange] #[ReturnTypeWillChange]
public function getTimezone() public function getTimezone()
@ -683,6 +684,23 @@ trait Date
return clone $this; return clone $this;
} }
/**
* Clone the current instance if it's mutable.
*
* This method is convenient to ensure you don't mutate the initial object
* but avoid to make a useless copy of it if it's already immutable.
*
* @return static
*/
public function avoidMutation(): self
{
if ($this instanceof DateTimeImmutable) {
return $this;
}
return clone $this;
}
/** /**
* Returns a present instance in the same timezone. * Returns a present instance in the same timezone.
* *
@ -774,7 +792,7 @@ trait Date
public function carbonize($date = null) public function carbonize($date = null)
{ {
if ($date instanceof DateInterval) { if ($date instanceof DateInterval) {
return $this->copy()->add($date); return $this->avoidMutation()->add($date);
} }
if ($date instanceof DatePeriod || $date instanceof CarbonPeriod) { if ($date instanceof DatePeriod || $date instanceof CarbonPeriod) {
@ -872,7 +890,7 @@ trait Date
switch (true) { switch (true) {
case isset($formats[$name]): case isset($formats[$name]):
$format = $formats[$name]; $format = $formats[$name];
$method = substr($format, 0, 1) === '%' ? 'formatLocalized' : 'rawFormat'; $method = str_starts_with($format, '%') ? 'formatLocalized' : 'rawFormat';
$value = $this->$method($format); $value = $this->$method($format);
return is_numeric($value) ? (int) $value : $value; return is_numeric($value) ? (int) $value : $value;
@ -927,11 +945,11 @@ trait Date
// @property-read int 51 through 53 // @property-read int 51 through 53
case $name === 'weeksInYear': case $name === 'weeksInYear':
return (int) $this->weeksInYear(); return $this->weeksInYear();
// @property-read int 51 through 53 // @property-read int 51 through 53
case $name === 'isoWeeksInYear': case $name === 'isoWeeksInYear':
return (int) $this->isoWeeksInYear(); return $this->isoWeeksInYear();
// @property-read int 1 through 5 // @property-read int 1 through 5
case $name === 'weekOfMonth': case $name === 'weekOfMonth':
@ -939,7 +957,7 @@ trait Date
// @property-read int 1 through 5 // @property-read int 1 through 5
case $name === 'weekNumberInMonth': case $name === 'weekNumberInMonth':
return (int) ceil(($this->day + $this->copy()->startOfMonth()->dayOfWeekIso - 1) / static::DAYS_PER_WEEK); return (int) ceil(($this->day + $this->avoidMutation()->startOfMonth()->dayOfWeekIso - 1) / static::DAYS_PER_WEEK);
// @property-read int 0 through 6 // @property-read int 0 through 6
case $name === 'firstWeekDay': case $name === 'firstWeekDay':
@ -951,7 +969,7 @@ trait Date
// @property int 1 through 366 // @property int 1 through 366
case $name === 'dayOfYear': case $name === 'dayOfYear':
return 1 + \intval($this->rawFormat('z')); return 1 + (int) ($this->rawFormat('z'));
// @property-read int 365 or 366 // @property-read int 365 or 366
case $name === 'daysInYear': case $name === 'daysInYear':
@ -1013,7 +1031,7 @@ trait Date
// @property-read bool checks if the timezone is local, true if local, false otherwise // @property-read bool checks if the timezone is local, true if local, false otherwise
case $name === 'local': case $name === 'local':
return $this->getOffset() === $this->copy()->setTimezone(date_default_timezone_get())->getOffset(); return $this->getOffset() === $this->avoidMutation()->setTimezone(date_default_timezone_get())->getOffset();
// @property-read bool checks if the timezone is UTC, true if UTC, false otherwise // @property-read bool checks if the timezone is UTC, true if UTC, false otherwise
case $name === 'utc': case $name === 'utc':
@ -1114,7 +1132,7 @@ trait Date
case 'microseconds': case 'microseconds':
case 'microsecond': case 'microsecond':
case 'micro': case 'micro':
if (substr($name, 0, 5) === 'milli') { if (str_starts_with($name, 'milli')) {
$value *= 1000; $value *= 1000;
} }
@ -1309,7 +1327,7 @@ trait Date
{ {
$dayOfYear = $this->dayOfYear; $dayOfYear = $this->dayOfYear;
return \is_null($value) ? $dayOfYear : $this->addDays($value - $dayOfYear); return $value === null ? $dayOfYear : $this->addDays($value - $dayOfYear);
} }
/** /**
@ -1321,9 +1339,9 @@ trait Date
*/ */
public function weekday($value = null) public function weekday($value = null)
{ {
$dayOfWeek = ($this->dayOfWeek + 7 - \intval($this->getTranslationMessage('first_day_of_week') ?? 0)) % 7; $dayOfWeek = ($this->dayOfWeek + 7 - (int) ($this->getTranslationMessage('first_day_of_week') ?? 0)) % 7;
return \is_null($value) ? $dayOfWeek : $this->addDays($value - $dayOfWeek); return $value === null ? $dayOfWeek : $this->addDays($value - $dayOfWeek);
} }
/** /**
@ -1337,7 +1355,7 @@ trait Date
{ {
$dayOfWeekIso = $this->dayOfWeekIso; $dayOfWeekIso = $this->dayOfWeekIso;
return \is_null($value) ? $dayOfWeekIso : $this->addDays($value - $dayOfWeekIso); return $value === null ? $dayOfWeekIso : $this->addDays($value - $dayOfWeekIso);
} }
/** /**
@ -1352,11 +1370,11 @@ trait Date
public function setUnitNoOverflow($valueUnit, $value, $overflowUnit) public function setUnitNoOverflow($valueUnit, $value, $overflowUnit)
{ {
try { try {
$original = $this->copy(); $original = $this->avoidMutation();
/** @var static $date */ /** @var static $date */
$date = $this->$valueUnit($value); $date = $this->$valueUnit($value);
$end = $original->copy()->endOf($overflowUnit); $end = $original->avoidMutation()->endOf($overflowUnit);
$start = $original->copy()->startOf($overflowUnit); $start = $original->avoidMutation()->startOf($overflowUnit);
if ($date < $start) { if ($date < $start) {
$date = $date->setDateTimeFrom($start); $date = $date->setDateTimeFrom($start);
} elseif ($date > $end) { } elseif ($date > $end) {
@ -1509,7 +1527,7 @@ trait Date
*/ */
public function setTimeFromTimeString($time) public function setTimeFromTimeString($time)
{ {
if (strpos($time, ':') === false) { if (!str_contains($time, ':')) {
$time .= ':0'; $time .= ':0';
} }
@ -1791,7 +1809,7 @@ trait Date
/** /**
* Format the instance with the current locale. You can set the current * Format the instance with the current locale. You can set the current
* locale using setlocale() http://php.net/setlocale. * locale using setlocale() https://php.net/setlocale.
* *
* @param string $format * @param string $format
* *
@ -1900,7 +1918,7 @@ trait Date
's' => 'second', 's' => 'second',
'ss' => ['getPaddedUnit', ['second']], 'ss' => ['getPaddedUnit', ['second']],
'S' => function (CarbonInterface $date) { 'S' => function (CarbonInterface $date) {
return \strval((string) floor($date->micro / 100000)); return (string) floor($date->micro / 100000);
}, },
'SS' => function (CarbonInterface $date) { 'SS' => function (CarbonInterface $date) {
return str_pad((string) floor($date->micro / 10000), 2, '0', STR_PAD_LEFT); return str_pad((string) floor($date->micro / 10000), 2, '0', STR_PAD_LEFT);
@ -1999,15 +2017,15 @@ trait Date
* *
* @return string * @return string
*/ */
public function ordinal(string $key, string $period = null): string public function ordinal(string $key, ?string $period = null): string
{ {
$number = $this->$key; $number = $this->$key;
$result = $this->translate('ordinal', [ $result = $this->translate('ordinal', [
':number' => $number, ':number' => $number,
':period' => $period, ':period' => (string) $period,
]); ]);
return \strval($result === 'ordinal' ? $number : $result); return (string) ($result === 'ordinal' ? $number : $result);
} }
/** /**
@ -2070,7 +2088,7 @@ trait Date
* *
* @return string * @return string
*/ */
public function isoFormat(string $format, string $originalFormat = null): string public function isoFormat(string $format, ?string $originalFormat = null): string
{ {
$result = ''; $result = '';
$length = mb_strlen($format); $length = mb_strlen($format);
@ -2149,7 +2167,7 @@ trait Date
} }
$format = mb_substr($format, 0, $i).$sequence.mb_substr($format, $i + mb_strlen($code)); $format = mb_substr($format, 0, $i).$sequence.mb_substr($format, $i + mb_strlen($code));
$i += mb_strlen("$sequence") - 1; $i += mb_strlen((string) $sequence) - 1;
$length = mb_strlen($format); $length = mb_strlen($format);
$char = $sequence; $char = $sequence;
} }
@ -2179,7 +2197,7 @@ trait Date
'S' => function ($date) { 'S' => function ($date) {
$day = $date->rawFormat('j'); $day = $date->rawFormat('j');
return str_replace("$day", '', $date->isoFormat('Do')); return str_replace((string) $day, '', $date->isoFormat('Do'));
}, },
'w' => true, 'w' => true,
'z' => true, 'z' => true,
@ -2219,7 +2237,7 @@ trait Date
} }
/** /**
* Format as ->format() do (using date replacements patterns from http://php.net/manual/fr/function.date.php) * Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php)
* but translate words whenever possible (months, day names, etc.) using the current locale. * but translate words whenever possible (months, day names, etc.) using the current locale.
* *
* @param string $format * @param string $format
@ -2519,7 +2537,7 @@ trait Date
$unit = rtrim($method, 's'); $unit = rtrim($method, 's');
if (substr($unit, 0, 2) === 'is') { if (str_starts_with($unit, 'is')) {
$word = substr($unit, 2); $word = substr($unit, 2);
if (\in_array($word, static::$days)) { if (\in_array($word, static::$days)) {
@ -2557,7 +2575,7 @@ trait Date
if ($action === 'add' || $action === 'sub') { if ($action === 'add' || $action === 'sub') {
$unit = substr($unit, 3); $unit = substr($unit, 3);
if (substr($unit, 0, 4) === 'Real') { if (str_starts_with($unit, 'Real')) {
$unit = static::singularUnit(substr($unit, 4)); $unit = static::singularUnit(substr($unit, 4));
return $this->{"${action}RealUnit"}($unit, ...$parameters); return $this->{"${action}RealUnit"}($unit, ...$parameters);
@ -2599,7 +2617,7 @@ trait Date
} }
} }
if (substr($unit, 0, 9) === 'isCurrent') { if (str_starts_with($unit, 'isCurrent')) {
try { try {
return $this->isCurrentUnit(strtolower(substr($unit, 9))); return $this->isCurrentUnit(strtolower(substr($unit, 9)));
} catch (BadComparisonUnitException | BadMethodCallException $exception) { } catch (BadComparisonUnitException | BadMethodCallException $exception) {
@ -2607,7 +2625,7 @@ trait Date
} }
} }
if (substr($method, -5) === 'Until') { if (str_ends_with($method, 'Until')) {
try { try {
$unit = static::singularUnit(substr($method, 0, -5)); $unit = static::singularUnit(substr($method, 0, -5));

View File

@ -121,7 +121,17 @@ trait Difference
#[ReturnTypeWillChange] #[ReturnTypeWillChange]
public function diff($date = null, $absolute = false) public function diff($date = null, $absolute = false)
{ {
return parent::diff($this->resolveCarbon($date), (bool) $absolute); $other = $this->resolveCarbon($date);
// Can be removed if https://github.com/derickr/timelib/pull/110
// is merged
// @codeCoverageIgnoreStart
if (version_compare(PHP_VERSION, '8.1.0-dev', '>=') && $other->tz !== $this->tz) {
$other = $other->avoidMutation()->tz($this->tz);
}
// @codeCoverageIgnoreEnd
return parent::diff($other, (bool) $absolute);
} }
/** /**
@ -540,14 +550,14 @@ trait Difference
} }
$monthsDiff = $start->diffInMonths($end); $monthsDiff = $start->diffInMonths($end);
/** @var Carbon|CarbonImmutable $floorEnd */ /** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addMonths($monthsDiff); $floorEnd = $start->avoidMutation()->addMonths($monthsDiff);
if ($floorEnd >= $end) { if ($floorEnd >= $end) {
return $sign * $monthsDiff; return $sign * $monthsDiff;
} }
/** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */ /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
$startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth(); $startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth();
if ($startOfMonthAfterFloorEnd > $end) { if ($startOfMonthAfterFloorEnd > $end) {
return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInMonth); return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInMonth);
@ -575,14 +585,14 @@ trait Difference
} }
$yearsDiff = $start->diffInYears($end); $yearsDiff = $start->diffInYears($end);
/** @var Carbon|CarbonImmutable $floorEnd */ /** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addYears($yearsDiff); $floorEnd = $start->avoidMutation()->addYears($yearsDiff);
if ($floorEnd >= $end) { if ($floorEnd >= $end) {
return $sign * $yearsDiff; return $sign * $yearsDiff;
} }
/** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */ /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
$startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear(); $startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear();
if ($startOfYearAfterFloorEnd > $end) { if ($startOfYearAfterFloorEnd > $end) {
return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInYear); return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInYear);
@ -641,7 +651,7 @@ trait Difference
public function floatDiffInRealDays($date = null, $absolute = true) public function floatDiffInRealDays($date = null, $absolute = true)
{ {
$date = $this->resolveUTC($date); $date = $this->resolveUTC($date);
$utc = $this->copy()->utc(); $utc = $this->avoidMutation()->utc();
$hoursDiff = $utc->floatDiffInRealHours($date, $absolute); $hoursDiff = $utc->floatDiffInRealHours($date, $absolute);
return ($hoursDiff < 0 ? -1 : 1) * $utc->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY; return ($hoursDiff < 0 ? -1 : 1) * $utc->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;
@ -679,14 +689,14 @@ trait Difference
} }
$monthsDiff = $start->diffInMonths($end); $monthsDiff = $start->diffInMonths($end);
/** @var Carbon|CarbonImmutable $floorEnd */ /** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addMonths($monthsDiff); $floorEnd = $start->avoidMutation()->addMonths($monthsDiff);
if ($floorEnd >= $end) { if ($floorEnd >= $end) {
return $sign * $monthsDiff; return $sign * $monthsDiff;
} }
/** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */ /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
$startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth(); $startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth();
if ($startOfMonthAfterFloorEnd > $end) { if ($startOfMonthAfterFloorEnd > $end) {
return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInMonth); return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInMonth);
@ -714,14 +724,14 @@ trait Difference
} }
$yearsDiff = $start->diffInYears($end); $yearsDiff = $start->diffInYears($end);
/** @var Carbon|CarbonImmutable $floorEnd */ /** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addYears($yearsDiff); $floorEnd = $start->avoidMutation()->addYears($yearsDiff);
if ($floorEnd >= $end) { if ($floorEnd >= $end) {
return $sign * $yearsDiff; return $sign * $yearsDiff;
} }
/** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */ /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
$startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear(); $startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear();
if ($startOfYearAfterFloorEnd > $end) { if ($startOfYearAfterFloorEnd > $end) {
return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInYear); return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInYear);
@ -737,7 +747,7 @@ trait Difference
*/ */
public function secondsSinceMidnight() public function secondsSinceMidnight()
{ {
return $this->diffInSeconds($this->copy()->startOfDay()); return $this->diffInSeconds($this->avoidMutation()->startOfDay());
} }
/** /**
@ -747,7 +757,7 @@ trait Difference
*/ */
public function secondsUntilEndOfDay() public function secondsUntilEndOfDay()
{ {
return $this->diffInSeconds($this->copy()->endOfDay()); return $this->diffInSeconds($this->avoidMutation()->endOfDay());
} }
/** /**
@ -1106,9 +1116,9 @@ trait Difference
public function calendar($referenceTime = null, array $formats = []) public function calendar($referenceTime = null, array $formats = [])
{ {
/** @var CarbonInterface $current */ /** @var CarbonInterface $current */
$current = $this->copy()->startOfDay(); $current = $this->avoidMutation()->startOfDay();
/** @var CarbonInterface $other */ /** @var CarbonInterface $other */
$other = $this->resolveCarbon($referenceTime)->copy()->setTimezone($this->getTimezone())->startOfDay(); $other = $this->resolveCarbon($referenceTime)->avoidMutation()->setTimezone($this->getTimezone())->startOfDay();
$diff = $other->diffInDays($current, false); $diff = $other->diffInDays($current, false);
$format = $diff < -6 ? 'sameElse' : ( $format = $diff < -6 ? 'sameElse' : (
$diff < -1 ? 'lastWeek' : ( $diff < -1 ? 'lastWeek' : (
@ -1126,6 +1136,6 @@ trait Difference
$format = $format($current, $other) ?? ''; $format = $format($current, $other) ?? '';
} }
return $this->isoFormat(\strval($format)); return $this->isoFormat((string) $format);
} }
} }

View File

@ -64,7 +64,7 @@ trait IntervalStep
$carbonDate = $dateTime instanceof CarbonInterface ? $dateTime : $this->resolveCarbon($dateTime); $carbonDate = $dateTime instanceof CarbonInterface ? $dateTime : $this->resolveCarbon($dateTime);
if ($this->step) { if ($this->step) {
return $carbonDate->setDateTimeFrom(($this->step)($carbonDate->copy(), $negated)); return $carbonDate->setDateTimeFrom(($this->step)($carbonDate->avoidMutation(), $negated));
} }
if ($negated) { if ($negated) {

View File

@ -168,7 +168,7 @@ trait Localization
* *
* @return string * @return string
*/ */
public static function getTranslationMessageWith($translator, string $key, string $locale = null, string $default = null) public static function getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null)
{ {
if (!($translator instanceof TranslatorBagInterface && $translator instanceof TranslatorInterface)) { if (!($translator instanceof TranslatorBagInterface && $translator instanceof TranslatorInterface)) {
throw new InvalidTypeException( throw new InvalidTypeException(
@ -196,7 +196,7 @@ trait Localization
* *
* @return string * @return string
*/ */
public function getTranslationMessage(string $key, string $locale = null, string $default = null, $translator = null) public function getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null)
{ {
return static::getTranslationMessageWith($translator ?: $this->getLocalTranslator(), $key, $locale, $default); return static::getTranslationMessageWith($translator ?: $this->getLocalTranslator(), $key, $locale, $default);
} }
@ -239,12 +239,12 @@ trait Localization
* *
* @param string $key * @param string $key
* @param array $parameters * @param array $parameters
* @param null $number * @param string|int|float|null $number
* @param \Symfony\Component\Translation\TranslatorInterface $translator * @param \Symfony\Component\Translation\TranslatorInterface $translator
* *
* @return string * @return string
*/ */
public function translate(string $key, array $parameters = [], $number = null, TranslatorInterface $translator = null, bool $altNumbers = false): string public function translate(string $key, array $parameters = [], $number = null, ?TranslatorInterface $translator = null, bool $altNumbers = false): string
{ {
$translation = static::translateWith($translator ?: $this->getLocalTranslator(), $key, $parameters, $number); $translation = static::translateWith($translator ?: $this->getLocalTranslator(), $key, $parameters, $number);
@ -302,7 +302,7 @@ trait Localization
return $result; return $result;
} }
return "$number"; return (string) $number;
} }
/** /**

View File

@ -224,11 +224,11 @@ trait Modifiers
*/ */
public function nthOfMonth($nth, $dayOfWeek) public function nthOfMonth($nth, $dayOfWeek)
{ {
$date = $this->copy()->firstOfMonth(); $date = $this->avoidMutation()->firstOfMonth();
$check = $date->rawFormat('Y-m'); $check = $date->rawFormat('Y-m');
$date = $date->modify('+'.$nth.' '.static::$days[$dayOfWeek]); $date = $date->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
return $date->rawFormat('Y-m') === $check ? $this->modify("$date") : false; return $date->rawFormat('Y-m') === $check ? $this->modify((string) $date) : false;
} }
/** /**
@ -274,12 +274,12 @@ trait Modifiers
*/ */
public function nthOfQuarter($nth, $dayOfWeek) public function nthOfQuarter($nth, $dayOfWeek)
{ {
$date = $this->copy()->day(1)->month($this->quarter * static::MONTHS_PER_QUARTER); $date = $this->avoidMutation()->day(1)->month($this->quarter * static::MONTHS_PER_QUARTER);
$lastMonth = $date->month; $lastMonth = $date->month;
$year = $date->year; $year = $date->year;
$date = $date->firstOfQuarter()->modify('+'.$nth.' '.static::$days[$dayOfWeek]); $date = $date->firstOfQuarter()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
return ($lastMonth < $date->month || $year !== $date->year) ? false : $this->modify("$date"); return ($lastMonth < $date->month || $year !== $date->year) ? false : $this->modify((string) $date);
} }
/** /**
@ -325,9 +325,9 @@ trait Modifiers
*/ */
public function nthOfYear($nth, $dayOfWeek) public function nthOfYear($nth, $dayOfWeek)
{ {
$date = $this->copy()->firstOfYear()->modify('+'.$nth.' '.static::$days[$dayOfWeek]); $date = $this->avoidMutation()->firstOfYear()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
return $this->year === $date->year ? $this->modify("$date") : false; return $this->year === $date->year ? $this->modify((string) $date) : false;
} }
/** /**
@ -454,7 +454,7 @@ trait Modifiers
{ {
return $this->modify(preg_replace_callback('/^(next|previous|last)\s+(\d{1,2}(h|am|pm|:\d{1,2}(:\d{1,2})?))$/i', function ($match) { return $this->modify(preg_replace_callback('/^(next|previous|last)\s+(\d{1,2}(h|am|pm|:\d{1,2}(:\d{1,2})?))$/i', function ($match) {
$match[2] = str_replace('h', ':00', $match[2]); $match[2] = str_replace('h', ':00', $match[2]);
$test = $this->copy()->modify($match[2]); $test = $this->avoidMutation()->modify($match[2]);
$method = $match[1] === 'next' ? 'lt' : 'gt'; $method = $match[1] === 'next' ? 'lt' : 'gt';
$match[1] = $test->$method($this) ? $match[1].' day' : 'today'; $match[1] = $test->$method($this) ? $match[1].' day' : 'today';

View File

@ -17,5 +17,5 @@ trait ObjectInitialisation
* *
* @var string * @var string
*/ */
protected $constructedObjectId = null; protected $constructedObjectId;
} }

View File

@ -151,21 +151,21 @@ trait Options
* *
* @var string|callable|null * @var string|callable|null
*/ */
protected static $formatFunction = null; protected static $formatFunction;
/** /**
* Function to call instead of createFromFormat. * Function to call instead of createFromFormat.
* *
* @var string|callable|null * @var string|callable|null
*/ */
protected static $createFromFormatFunction = null; protected static $createFromFormatFunction;
/** /**
* Function to call instead of parse. * Function to call instead of parse.
* *
* @var string|callable|null * @var string|callable|null
*/ */
protected static $parseFunction = null; protected static $parseFunction;
/** /**
* Indicates if months should be calculated with overflow. * Indicates if months should be calculated with overflow.
@ -173,7 +173,7 @@ trait Options
* *
* @var bool|null * @var bool|null
*/ */
protected $localMonthsOverflow = null; protected $localMonthsOverflow;
/** /**
* Indicates if years should be calculated with overflow. * Indicates if years should be calculated with overflow.
@ -181,7 +181,7 @@ trait Options
* *
* @var bool|null * @var bool|null
*/ */
protected $localYearsOverflow = null; protected $localYearsOverflow;
/** /**
* Indicates if the strict mode is in use. * Indicates if the strict mode is in use.
@ -189,49 +189,49 @@ trait Options
* *
* @var bool|null * @var bool|null
*/ */
protected $localStrictModeEnabled = null; protected $localStrictModeEnabled;
/** /**
* Options for diffForHumans and forHumans methods. * Options for diffForHumans and forHumans methods.
* *
* @var bool|null * @var bool|null
*/ */
protected $localHumanDiffOptions = null; protected $localHumanDiffOptions;
/** /**
* Format to use on string cast. * Format to use on string cast.
* *
* @var string|null * @var string|null
*/ */
protected $localToStringFormat = null; protected $localToStringFormat;
/** /**
* Format to use on JSON serialization. * Format to use on JSON serialization.
* *
* @var string|null * @var string|null
*/ */
protected $localSerializer = null; protected $localSerializer;
/** /**
* Instance-specific macros. * Instance-specific macros.
* *
* @var array|null * @var array|null
*/ */
protected $localMacros = null; protected $localMacros;
/** /**
* Instance-specific generic macros. * Instance-specific generic macros.
* *
* @var array|null * @var array|null
*/ */
protected $localGenericMacros = null; protected $localGenericMacros;
/** /**
* Function to call instead of format. * Function to call instead of format.
* *
* @var string|callable|null * @var string|callable|null
*/ */
protected $localFormatFunction = null; protected $localFormatFunction;
/** /**
* @deprecated To avoid conflict between different third-party libraries, static setters should not be used. * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
@ -449,7 +449,7 @@ trait Options
protected function addExtraDebugInfos(&$infos): void protected function addExtraDebugInfos(&$infos): void
{ {
if ($this instanceof CarbonInterface || $this instanceof DateTimeInterface) { if ($this instanceof DateTimeInterface) {
try { try {
if (!isset($infos['date'])) { if (!isset($infos['date'])) {
$infos['date'] = $this->format(CarbonInterface::MOCK_DATETIME_FORMAT); $infos['date'] = $this->format(CarbonInterface::MOCK_DATETIME_FORMAT);

View File

@ -194,7 +194,10 @@ trait Rounding
*/ */
public function roundWeek($weekStartsAt = null) public function roundWeek($weekStartsAt = null)
{ {
return $this->closest($this->copy()->floorWeek($weekStartsAt), $this->copy()->ceilWeek($weekStartsAt)); return $this->closest(
$this->avoidMutation()->floorWeek($weekStartsAt),
$this->avoidMutation()->ceilWeek($weekStartsAt)
);
} }
/** /**
@ -219,7 +222,7 @@ trait Rounding
public function ceilWeek($weekStartsAt = null) public function ceilWeek($weekStartsAt = null)
{ {
if ($this->isMutable()) { if ($this->isMutable()) {
$startOfWeek = $this->copy()->startOfWeek($weekStartsAt); $startOfWeek = $this->avoidMutation()->startOfWeek($weekStartsAt);
return $startOfWeek != $this ? return $startOfWeek != $this ?
$this->startOfWeek($weekStartsAt)->addWeek() : $this->startOfWeek($weekStartsAt)->addWeek() :
@ -230,6 +233,6 @@ trait Rounding
return $startOfWeek != $this ? return $startOfWeek != $this ?
$startOfWeek->addWeek() : $startOfWeek->addWeek() :
$this->copy(); $this->avoidMutation();
} }
} }

View File

@ -12,6 +12,7 @@ namespace Carbon\Traits;
use Carbon\Exceptions\InvalidFormatException; use Carbon\Exceptions\InvalidFormatException;
use ReturnTypeWillChange; use ReturnTypeWillChange;
use Throwable;
/** /**
* Trait Serialization. * Trait Serialization.
@ -53,7 +54,15 @@ trait Serialization
* *
* @var string|null * @var string|null
*/ */
protected $dumpLocale = null; protected $dumpLocale;
/**
* Embed date properties to dump in a dedicated variables so it won't overlap native
* DateTime ones.
*
* @var array|null
*/
protected $dumpDateProperties;
/** /**
* Return a serialized string of the instance. * Return a serialized string of the instance.
@ -76,7 +85,7 @@ trait Serialization
*/ */
public static function fromSerialized($value) public static function fromSerialized($value)
{ {
$instance = @unserialize("$value"); $instance = @unserialize((string) $value);
if (!$instance instanceof static) { if (!$instance instanceof static) {
throw new InvalidFormatException("Invalid serialized value: $value"); throw new InvalidFormatException("Invalid serialized value: $value");
@ -114,7 +123,7 @@ trait Serialization
*/ */
public function __sleep() public function __sleep()
{ {
$properties = $this->dumpProperties; $properties = $this->getSleepProperties();
if ($this->localTranslator ?? null) { if ($this->localTranslator ?? null) {
$properties[] = 'dumpLocale'; $properties[] = 'dumpLocale';
@ -131,7 +140,15 @@ trait Serialization
public function __wakeup() public function __wakeup()
{ {
if (get_parent_class() && method_exists(parent::class, '__wakeup')) { if (get_parent_class() && method_exists(parent::class, '__wakeup')) {
parent::__wakeup(); // @codeCoverageIgnoreStart
try {
parent::__wakeup();
} catch (Throwable $exception) {
// FatalError occurs when calling msgpack_unpack() in PHP 7.4 or later.
['date' => $date, 'timezone' => $timezone] = $this->dumpDateProperties;
parent::__construct($date, unserialize($timezone));
}
// @codeCoverageIgnoreEnd
} }
$this->constructedObjectId = spl_object_hash($this); $this->constructedObjectId = spl_object_hash($this);
@ -149,6 +166,7 @@ trait Serialization
* *
* @return array|string * @return array|string
*/ */
#[ReturnTypeWillChange]
public function jsonSerialize() public function jsonSerialize()
{ {
$serializer = $this->localSerializer ?? static::$serializer; $serializer = $this->localSerializer ?? static::$serializer;
@ -194,4 +212,26 @@ trait Serialization
return $this; return $this;
} }
private function getSleepProperties(): array
{
$properties = $this->dumpProperties;
// @codeCoverageIgnoreStart
if (!\extension_loaded('msgpack')) {
return $properties;
}
if (isset($this->constructedObjectId)) {
$this->dumpDateProperties = [
'date' => $this->format('Y-m-d H:i:s.u'),
'timezone' => serialize($this->timezone ?? null),
];
$properties[] = 'dumpDateProperties';
}
return $properties;
// @codeCoverageIgnoreEnd
}
} }

View File

@ -63,12 +63,16 @@ trait Test
* *
* @param Closure|static|string|false|null $testNow real or mock Carbon instance * @param Closure|static|string|false|null $testNow real or mock Carbon instance
* @param Closure|null $callback * @param Closure|null $callback
*
* @return mixed
*/ */
public static function withTestNow($testNow = null, $callback = null) public static function withTestNow($testNow = null, $callback = null)
{ {
static::setTestNow($testNow); static::setTestNow($testNow);
$callback(); $result = $callback();
static::setTestNow(); static::setTestNow();
return $result;
} }
/** /**

View File

@ -45,6 +45,7 @@ trait Timestamp
$delta = floor($decimal / static::MICROSECONDS_PER_SECOND); $delta = floor($decimal / static::MICROSECONDS_PER_SECOND);
$integer += $delta; $integer += $delta;
$decimal -= $delta * static::MICROSECONDS_PER_SECOND; $decimal -= $delta * static::MICROSECONDS_PER_SECOND;
$decimal = str_pad((string) $decimal, 6, '0', STR_PAD_LEFT);
return static::rawCreateFromFormat('U u', "$integer $decimal"); return static::rawCreateFromFormat('U u', "$integer $decimal");
} }
@ -136,6 +137,16 @@ trait Timestamp
return $this->getPreciseTimestamp(3); return $this->getPreciseTimestamp(3);
} }
/**
* Returns the timestamp with millisecond precision.
*
* @return int
*/
public function getTimestampMs()
{
return (int) $this->getPreciseTimestamp(3);
}
/** /**
* @alias getTimestamp * @alias getTimestamp
* *
@ -166,15 +177,15 @@ trait Timestamp
$numbers = number_format($numbers, $decimals, '.', ''); $numbers = number_format($numbers, $decimals, '.', '');
} }
$sign = substr($numbers, 0, 1) === '-' ? -1 : 1; $sign = str_starts_with($numbers, '-') ? -1 : 1;
$integer = 0; $integer = 0;
$decimal = 0; $decimal = 0;
foreach (preg_split('`[^0-9.]+`', $numbers) as $chunk) { foreach (preg_split('`[^0-9.]+`', $numbers) as $chunk) {
[$integerPart, $decimalPart] = explode('.', "$chunk."); [$integerPart, $decimalPart] = explode('.', "$chunk.");
$integer += \intval($integerPart); $integer += (int) $integerPart;
$decimal += \floatval("0.$decimalPart"); $decimal += (float) ("0.$decimalPart");
} }
$overflow = floor($decimal); $overflow = floor($decimal);

View File

@ -48,7 +48,7 @@ trait Units
$seconds = (int) floor($diff / static::MICROSECONDS_PER_SECOND); $seconds = (int) floor($diff / static::MICROSECONDS_PER_SECOND);
$time += $seconds; $time += $seconds;
$diff -= $seconds * static::MICROSECONDS_PER_SECOND; $diff -= $seconds * static::MICROSECONDS_PER_SECOND;
$microtime = str_pad("$diff", 6, '0', STR_PAD_LEFT); $microtime = str_pad((string) $diff, 6, '0', STR_PAD_LEFT);
$tz = $this->tz; $tz = $this->tz;
return $this->tz('UTC')->modify("@$time.$microtime")->tz($tz); return $this->tz('UTC')->modify("@$time.$microtime")->tz($tz);
@ -201,6 +201,21 @@ trait Units
$unit = CarbonInterval::make($unit); $unit = CarbonInterval::make($unit);
} }
// Can be removed if https://bugs.php.net/bug.php?id=81106
// is fixed
// @codeCoverageIgnoreStart
if (
$unit instanceof DateInterval &&
version_compare(PHP_VERSION, '8.1.0-dev', '>=') &&
($unit->f < 0 || $unit->f >= 1)
) {
$unit = clone $unit;
$seconds = floor($unit->f);
$unit->f -= $seconds;
$unit->s += (int) $seconds;
}
// @codeCoverageIgnoreEnd
if ($unit instanceof CarbonConverterInterface) { if ($unit instanceof CarbonConverterInterface) {
return $this->resolveCarbon($unit->convertDate($this, false)); return $this->resolveCarbon($unit->convertDate($this, false));
} }
@ -233,8 +248,8 @@ trait Units
{ {
$date = $this; $date = $this;
if (!is_numeric($value) || !\floatval($value)) { if (!is_numeric($value) || !(float) $value) {
return $date->isMutable() ? $date : $date->copy(); return $date->isMutable() ? $date : $date->avoidMutation();
} }
$metaUnits = [ $metaUnits = [
@ -377,7 +392,7 @@ trait Units
[$value, $unit] = [$unit, $value]; [$value, $unit] = [$unit, $value];
} }
return $this->addUnit($unit, -\floatval($value), $overflow); return $this->addUnit($unit, -(float) $value, $overflow);
} }
/** /**

View File

@ -27,7 +27,7 @@ namespace Carbon\Traits;
* @method static addWeeks(int $weeks = 1) * @method static addWeeks(int $weeks = 1)
* @method static copy() * @method static copy()
* @method static dayOfYear(int $dayOfYear) * @method static dayOfYear(int $dayOfYear)
* @method string getTranslationMessage(string $key, string $locale = null, string $default = null, $translator = null) * @method string getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null)
* @method static next(int|string $day = null) * @method static next(int|string $day = null)
* @method static startOfWeek(int $day = 1) * @method static startOfWeek(int $day = 1)
* @method static subWeeks(int $weeks = 1) * @method static subWeeks(int $weeks = 1)
@ -75,7 +75,7 @@ trait Week
$year = (int) round($year); $year = (int) round($year);
if ($this->weekYear(null, $dayOfWeek, $dayOfYear) === $year) { if ($this->weekYear(null, $dayOfWeek, $dayOfYear) === $year) {
return $this->copy(); return $this->avoidMutation();
} }
$week = $this->week(null, $dayOfWeek, $dayOfYear); $week = $this->week(null, $dayOfWeek, $dayOfYear);
@ -103,13 +103,13 @@ trait Week
$year = $this->year; $year = $this->year;
$day = $this->dayOfYear; $day = $this->dayOfYear;
$date = $this->copy()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); $date = $this->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
if ($date->year === $year && $day < $date->dayOfYear) { if ($date->year === $year && $day < $date->dayOfYear) {
return $year - 1; return $year - 1;
} }
$date = $this->copy()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); $date = $this->avoidMutation()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
if ($date->year === $year && $day >= $date->dayOfYear) { if ($date->year === $year && $day >= $date->dayOfYear) {
return $year + 1; return $year + 1;
@ -151,12 +151,12 @@ trait Week
$dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0; $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0;
$dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1; $dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1;
$year = $this->year; $year = $this->year;
$start = $this->copy()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); $start = $this->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$startDay = $start->dayOfYear; $startDay = $start->dayOfYear;
if ($start->year !== $year) { if ($start->year !== $year) {
$startDay -= $start->daysInYear; $startDay -= $start->daysInYear;
} }
$end = $this->copy()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); $end = $this->avoidMutation()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$endDay = $end->dayOfYear; $endDay = $end->dayOfYear;
if ($end->year !== $year) { if ($end->year !== $year) {
$endDay += $this->daysInYear; $endDay += $this->daysInYear;
@ -186,8 +186,8 @@ trait Week
return $date->addWeeks(round($week) - $this->week(null, $dayOfWeek, $dayOfYear)); return $date->addWeeks(round($week) - $this->week(null, $dayOfWeek, $dayOfYear));
} }
$start = $date->copy()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); $start = $date->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$end = $date->copy()->startOfWeek($dayOfWeek); $end = $date->avoidMutation()->startOfWeek($dayOfWeek);
if ($start > $end) { if ($start > $end) {
$start = $start->subWeeks(26)->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); $start = $start->subWeeks(26)->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
} }

View File

@ -148,7 +148,7 @@ class Translator extends Translation\Translator
*/ */
public function trans($id, array $parameters = [], $domain = null, $locale = null) public function trans($id, array $parameters = [], $domain = null, $locale = null)
{ {
if (null === $domain) { if ($domain === null) {
$domain = 'messages'; $domain = 'messages';
} }
@ -326,7 +326,7 @@ class Translator extends Translation\Translator
$previousLocale = $this->getLocale(); $previousLocale = $this->getLocale();
if ($previousLocale === $locale) { if ($previousLocale === $locale && isset($this->messages[$locale])) {
return true; return true;
} }
@ -355,7 +355,7 @@ class Translator extends Translation\Translator
} }
// If subtag (ex: en_CA) first load the macro (ex: en) to have a fallback // If subtag (ex: en_CA) first load the macro (ex: en) to have a fallback
if (strpos($locale, '_') !== false && if (str_contains($locale, '_') &&
$this->loadMessagesFromFile($macroLocale = preg_replace('/^([^_]+).*$/', '$1', $locale)) $this->loadMessagesFromFile($macroLocale = preg_replace('/^([^_]+).*$/', '$1', $locale))
) { ) {
parent::setLocale($macroLocale); parent::setLocale($macroLocale);

View File

@ -0,0 +1,60 @@
name: CI
on: [push]
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php: [7.2, 7.3, 7.4, 8.0]
dependency-version: [prefer-lowest, prefer-stable]
steps:
- name: Checkout code
uses: actions/checkout@v1
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mailparse
coverage: none
- name: Install dependencies
run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest --no-progress
- name: Execute tests
run: vendor/bin/phpunit
php-cs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v1
- name: Install dependencies
run: composer update --no-progress --ignore-platform-reqs
- name: Execute phpcs
run: vendor/bin/phpcs src tests --standard=psr2
coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v1
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
extensions: mailparse
- name: Install dependencies
run: composer update --prefer-dist --no-interaction --no-suggest --no-progress
- name: Execute code coverage
run: |
vendor/bin/phpunit --coverage-clover=coverage.xml --whitelist src
bash <(curl -s https://codecov.io/bash) -t ${{ secrets.COVERALLS_REPO_TOKEN }}

View File

@ -1,6 +1,6 @@
# php-mime-mail-parser # php-mime-mail-parser
A fully tested email parser for PHP 7.1+ (mailparse extension wrapper). A fully tested email parser for PHP 7.2+ (mailparse extension wrapper).
It's the most effective php email parser around in terms of performance, foreign character encoding, attachment handling, and ease of use. It's the most effective php email parser around in terms of performance, foreign character encoding, attachment handling, and ease of use.
Internet Message Format RFC [822](https://tools.ietf.org/html/rfc822), [2822](https://tools.ietf.org/html/rfc2822), [5322](https://tools.ietf.org/html/rfc5322). Internet Message Format RFC [822](https://tools.ietf.org/html/rfc822), [2822](https://tools.ietf.org/html/rfc2822), [5322](https://tools.ietf.org/html/rfc5322).
@ -23,7 +23,7 @@ Yes. All known issues have been reproduced, fixed and tested.
We use GitHub Actions, Codecov, Codacy to help ensure code quality. You can see real-time statistics below: We use GitHub Actions, Codecov, Codacy to help ensure code quality. You can see real-time statistics below:
[![Actions Status](https://wdp9fww0r9.execute-api.us-west-2.amazonaws.com/production/badge/php-mime-mail-parser/php-mime-mail-parser?style=flat-square)](https://wdp9fww0r9.execute-api.us-west-2.amazonaws.com/production/results/php-mime-mail-parser/php-mime-mail-parser) [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fphp-mime-mail-parser%2Fphp-mime-mail-parser%2Fbadge%3Fref%3Dmaster&style=flat-square)](https://actions-badge.atrox.dev/php-mime-mail-parser/php-mime-mail-parser/goto?ref=master)
[![Coverage](https://img.shields.io/codecov/c/gh/php-mime-mail-parser/php-mime-mail-parser?style=flat-square)](https://codecov.io/gh/php-mime-mail-parser/php-mime-mail-parser) [![Coverage](https://img.shields.io/codecov/c/gh/php-mime-mail-parser/php-mime-mail-parser?style=flat-square)](https://codecov.io/gh/php-mime-mail-parser/php-mime-mail-parser)
[![Code Quality](https://img.shields.io/codacy/grade/4e0e44fee21147ddbdd18ff976251875?style=flat-square)](https://app.codacy.com/app/php-mime-mail-parser/php-mime-mail-parser) [![Code Quality](https://img.shields.io/codacy/grade/4e0e44fee21147ddbdd18ff976251875?style=flat-square)](https://app.codacy.com/app/php-mime-mail-parser/php-mime-mail-parser)
@ -40,19 +40,20 @@ To install the latest version of PHP MIME Mail Parser, run the command below:
The following versions of PHP are supported: The following versions of PHP are supported:
* PHP 7.1
* PHP 7.2 * PHP 7.2
* PHP 7.3 * PHP 7.3
* PHP 7.4
Previous Versions: Previous Versions:
| PHP Compatibility | Version | | PHP Compatibility | Version |
| ------------- | ------------- | | ------------- | ------------- |
| HHVM | php-mime-mail-parser 2.11.1 | | HHVM | php-mime-mail-parser 2.11.1 |
| PHP 5.4 | php-mime-mail-parser 2.11.1 | | PHP 5.4 | php-mime-mail-parser 2.11.1 |
| PHP 5.5 | php-mime-mail-parser 2.11.1 | | PHP 5.5 | php-mime-mail-parser 2.11.1 |
| PHP 5.6 | php-mime-mail-parser 3.0.4 | | PHP 5.6 | php-mime-mail-parser 3.0.4 |
| PHP 7.0 | php-mime-mail-parser 3.0.4 | | PHP 7.0 | php-mime-mail-parser 3.0.4 |
| PHP 7.1 | php-mime-mail-parser 5.0.5 |
Make sure you have the mailparse extension (http://php.net/manual/en/book.mailparse.php) properly installed. The command line `php -m | grep mailparse` need to return "mailparse". Make sure you have the mailparse extension (http://php.net/manual/en/book.mailparse.php) properly installed. The command line `php -m | grep mailparse` need to return "mailparse".

View File

@ -1,7 +1,7 @@
{ {
"name": "php-mime-mail-parser/php-mime-mail-parser", "name": "php-mime-mail-parser/php-mime-mail-parser",
"type": "library", "type": "library",
"description": "A fully tested email parser for PHP 7.1+ (mailparse extension wrapper).", "description": "A fully tested email parser for PHP 7.2+ (mailparse extension wrapper).",
"keywords": ["mime", "mail", "mailparse", "MimeMailParser", "parser", "php"], "keywords": ["mime", "mail", "mailparse", "MimeMailParser", "parser", "php"],
"homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser", "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
"license": "MIT", "license": "MIT",
@ -42,14 +42,13 @@
"url":"https://github.com/php-mime-mail-parser/php-mime-mail-parser.git" "url":"https://github.com/php-mime-mail-parser/php-mime-mail-parser.git"
}, },
"require": { "require": {
"php": "^7.1", "php": "^7.2|^8.0",
"ext-mailparse": "*" "ext-mailparse": "*"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7.0", "phpunit/phpunit": "^8.0",
"phpunit/php-token-stream": "^3.0", "php-coveralls/php-coveralls": "^2.2",
"php-coveralls/php-coveralls": "^2.1", "squizlabs/php_codesniffer": "^3.5"
"squizlabs/php_codesniffer": "^3.4"
}, },
"replace": { "replace": {
"exorus/php-mime-mail-parser": "*", "exorus/php-mime-mail-parser": "*",

View File

@ -69,14 +69,15 @@ final class Mbstring
{ {
public const MB_CASE_FOLD = \PHP_INT_MAX; public const MB_CASE_FOLD = \PHP_INT_MAX;
private static $encodingList = ['ASCII', 'UTF-8']; private const CASE_FOLD = [
private static $language = 'neutral';
private static $internalEncoding = 'UTF-8';
private static $caseFold = [
['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
]; ];
private static $encodingList = ['ASCII', 'UTF-8'];
private static $language = 'neutral';
private static $internalEncoding = 'UTF-8';
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
{ {
if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) { if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
@ -300,7 +301,7 @@ final class Mbstring
$map = $upper; $map = $upper;
} else { } else {
if (self::MB_CASE_FOLD === $mode) { if (self::MB_CASE_FOLD === $mode) {
$s = str_replace(self::$caseFold[0], self::$caseFold[1], $s); $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
} }
static $lower = null; static $lower = null;

View File

@ -16,7 +16,7 @@ This component provides features added to PHP 8.0 core:
- [`get_resource_id`](https://php.net/get_resource_id) - [`get_resource_id`](https://php.net/get_resource_id)
More information can be found in the More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). [main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License License
======= =======

View File

@ -26,13 +26,13 @@ if (!function_exists('preg_last_error_msg')) {
function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
} }
if (!function_exists('str_contains')) { if (!function_exists('str_contains')) {
function str_contains(string $haystack, string $needle): bool { return p\Php80::str_contains($haystack, $needle); } function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
} }
if (!function_exists('str_starts_with')) { if (!function_exists('str_starts_with')) {
function str_starts_with(string $haystack, string $needle): bool { return p\Php80::str_starts_with($haystack, $needle); } function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
} }
if (!function_exists('str_ends_with')) { if (!function_exists('str_ends_with')) {
function str_ends_with(string $haystack, string $needle): bool { return p\Php80::str_ends_with($haystack, $needle); } function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
} }
if (!function_exists('get_debug_type')) { if (!function_exists('get_debug_type')) {
function get_debug_type($value): string { return p\Php80::get_debug_type($value); } function get_debug_type($value): string { return p\Php80::get_debug_type($value); }

View File

@ -94,13 +94,13 @@ EOF
*/ */
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$provider = $this->providers->get($input->getArgument('provider'));
if (!$this->enabledLocales) { if (!$this->enabledLocales) {
throw new InvalidArgumentException('You must define "framework.translator.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.'); throw new InvalidArgumentException(sprintf('You must define "framework.translator.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME)));
} }
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
$provider = $this->providers->get($input->getArgument('provider'));
$domains = $input->getOption('domains'); $domains = $input->getOption('domains');
$locales = $input->getOption('locales'); $locales = $input->getOption('locales');
$force = $input->getOption('force'); $force = $input->getOption('force');

View File

@ -64,6 +64,9 @@ class TranslatorPathsPass extends AbstractRecursivePass
foreach ($this->paths as $class => $_) { foreach ($this->paths as $class => $_) {
if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) { if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) {
$paths[] = $r->getFileName(); $paths[] = $r->getFileName();
foreach ($r->getTraits() as $trait) {
$paths[] = $trait->getFileName();
}
} }
} }
if ($paths) { if ($paths) {

View File

@ -141,8 +141,8 @@ class XliffFileDumper extends FileDumper
$xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale())); $xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale()));
$xliffFile = $xliff->appendChild($dom->createElement('file')); $xliffFile = $xliff->appendChild($dom->createElement('file'));
if (MessageCatalogue::INTL_DOMAIN_SUFFIX === substr($domain, -($suffixLength = \strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)))) { if (str_ends_with($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX)) {
$xliffFile->setAttribute('id', substr($domain, 0, -$suffixLength).'.'.$messages->getLocale()); $xliffFile->setAttribute('id', substr($domain, 0, -\strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)).'.'.$messages->getLocale());
} else { } else {
$xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale()); $xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());
} }
@ -198,6 +198,6 @@ class XliffFileDumper extends FileDumper
private function hasMetadataArrayInfo(string $key, array $metadata = null): bool private function hasMetadataArrayInfo(string $key, array $metadata = null): bool
{ {
return null !== $metadata && \array_key_exists($key, $metadata) && ($metadata[$key] instanceof \Traversable || \is_array($metadata[$key])); return is_iterable($metadata[$key] ?? null);
} }
} }

View File

@ -13,7 +13,7 @@ namespace Symfony\Component\Translation\Exception;
class IncompleteDsnException extends InvalidArgumentException class IncompleteDsnException extends InvalidArgumentException
{ {
public function __construct(string $message, string $dsn = null, ?\Throwable $previous = null) public function __construct(string $message, string $dsn = null, \Throwable $previous = null)
{ {
if ($dsn) { if ($dsn) {
$message = sprintf('Invalid "%s" provider DSN: ', $dsn).$message; $message = sprintf('Invalid "%s" provider DSN: ', $dsn).$message;

View File

@ -16,7 +16,7 @@ namespace Symfony\Component\Translation\Exception;
*/ */
class MissingRequiredOptionException extends IncompleteDsnException class MissingRequiredOptionException extends IncompleteDsnException
{ {
public function __construct(string $option, string $dsn = null, ?\Throwable $previous = null) public function __construct(string $option, string $dsn = null, \Throwable $previous = null)
{ {
$message = sprintf('The option "%s" is required but missing.', $option); $message = sprintf('The option "%s" is required but missing.', $option);

View File

@ -29,8 +29,6 @@ class ChainExtractor implements ExtractorInterface
/** /**
* Adds a loader to the translation extractor. * Adds a loader to the translation extractor.
*
* @param string $format The format of the loader
*/ */
public function addExtractor(string $format, ExtractorInterface $extractor) public function addExtractor(string $format, ExtractorInterface $extractor)
{ {

View File

@ -24,14 +24,12 @@ interface ExtractorInterface
/** /**
* Extracts translation messages from files, a file or a directory to the catalogue. * Extracts translation messages from files, a file or a directory to the catalogue.
* *
* @param string|string[] $resource Files, a file or a directory * @param string|iterable<string> $resource Files, a file or a directory
*/ */
public function extract($resource, MessageCatalogue $catalogue); public function extract($resource, MessageCatalogue $catalogue);
/** /**
* Sets the prefix that should be used for new found messages. * Sets the prefix that should be used for new found messages.
*
* @param string $prefix The prefix
*/ */
public function setPrefix(string $prefix); public function setPrefix(string $prefix);
} }

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