mirror of
https://github.com/itflow-org/itflow
synced 2026-08-16 04:25:13 +00:00
Mail Parser: Completely remove Webklex IMAP and all dependcies
This commit is contained in:
7
plugins/vendor/nesbot/carbon/SECURITY.md
vendored
Normal file
7
plugins/vendor/nesbot/carbon/SECURITY.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report a security vulnerability, please use the
|
||||
[Tidelift security contact](https://tidelift.com/security).
|
||||
Tidelift will coordinate the fix and disclosure.
|
||||
4
plugins/vendor/nesbot/carbon/composer.json
vendored
4
plugins/vendor/nesbot/carbon/composer.json
vendored
@@ -109,8 +109,8 @@
|
||||
"phpdoc": "php phpdoc.php",
|
||||
"phpmd": "phpmd src text /phpmd.xml",
|
||||
"phpmd-test": "phpmd tests text /tests/phpmd-test.xml",
|
||||
"phpstan": "phpstan analyse --configuration phpstan.neon",
|
||||
"phpunit": "phpunit --verbose",
|
||||
"phpstan": "phpstan analyse --configuration phpstan.neon --memory-limit 1024M",
|
||||
"phpunit": "phpunit",
|
||||
"style-check": [
|
||||
"@phpcs",
|
||||
"@phpstan",
|
||||
|
||||
153
plugins/vendor/nesbot/carbon/readme.md
vendored
153
plugins/vendor/nesbot/carbon/readme.md
vendored
@@ -127,63 +127,102 @@ 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.
|
||||
|
||||
<!-- <open-collective-sponsors> -->
|
||||
<a title="Нова українська букмекерська контора" href="https://betking.com.ua/sports-book/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Ставки на спорт" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/c56d2fe2-f9fb-4d63-947c-77575f4b15c6/stavki.jpg" width="96" height="96"></a>
|
||||
<a title="Онлайн казино 777 Україна" href="https://777.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Онлайн казино 777" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/7e572d50-1ce8-4d69-ae12-86cc80371373/ok-ua-777.png" width="96" height="96"></a>
|
||||
<a title="Non GamStop Bookies UK" href="https://netto.co.uk/betting-sites-not-on-gamstop/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Non GamStop Bookies UK" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/51bfaa05-02b3-4cd9-b1a4-9d0d8f34cbae/%D0%97%D0%BD%D1%96%D0%BC%D0%BE%D0%BA%20%D0%B5%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202025-07-04%20%D0%BE%2015.21.16%20(1)%20(1)%20(1).jpg" width="126" height="96"></a>
|
||||
<a title="Trusted last mile route planning and route optimization" href="https://route4me.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Route4Me Route Planner" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/237386c3-48a2-47c6-97ac-5f888cdb4cda/Route4MeIconLogo.png" width="96" height="96"></a>
|
||||
<a title="Bei Releaf erhalten Sie schnell und diskret Ihr Cannabis Rezept online. Unsere Ärzte prüfen Ihre Angaben und stellen bei Eignung das Rezept aus. Anschließend können Sie legal und sicher medizinisches Cannabis über unsere Partnerapotheken kaufen." href="https://releaf.com/de?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Releaf – Medizinischer Cannabis Shop" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/b686d646-5029-4b4c-8cab-9645ab2679de/9da596d1-f48a-41ec-947d-a64dd8e7529c.png" width="96" height="96"></a>
|
||||
<a title="Buitenlandse Online Casino" href="https://nl.trustpilot.com/review/buitenlandsecasino.vip?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Buitenlandse Online Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/9465308a-8e44-4606-af5d-5a81a3c6567b/ChatGPT%20Image%20Nov%2015%2C%202025%2C%2002_53_25%20PM.png" width="96" height="96"></a>
|
||||
<a title="Online Casino Zonder Registratie" href="https://nl.trustpilot.com/review/zonderregistratiecasinos.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Online Casino Zonder Registratie" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/cf382ddc-627b-4bd9-8870-43ee28d2a628/casino-zonder-registratie.png" width="127.5" height="96"></a>
|
||||
<a title="Mi misión es la educación y transparencia en el mundo de los casinos online" href="https://www.educatransparencia.cl/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Transparencia en Casinos Online" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/c034fdcb-1d17-4c83-8105-f3cfa4f874d6/educalogocito.png" width="192" height="96"></a>
|
||||
<a title="Wildflower" href="https://www.trustpilot.com/review/wildflower.uno?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Wildflower" src="https://images.opencollective.com/wildflower_cases/avatar/256.png" width="96" height="96"></a>
|
||||
<a title="Best non Gamstop sites in the UK" href="https://www.pieria.co.uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Best non Gamstop sites in the UK" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/34e340b8-e1de-4932-8a76-1b3ce2ec7ee8/logo_white%20bg%20(8).png" width="96" height="96"></a>
|
||||
<a title="gaia-wines.gr" href="https://www.gaia-wines.gr/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="gaia-wines.gr" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/a9b971ee-db5f-4400-8c4b-76cf9bc35015/IMAGE%202024-06-14%2013%3A54%3A14.jpg" width="96" height="96"></a>
|
||||
<a title="#1 Guide To Online Gambling In Canada" href="https://casinohex.org/canada/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="CasinoHex Canada" src="https://opencollective-production.s3.us-west-1.amazonaws.com/79fdbcc0-a997-11eb-abbc-25e48b63c6dc.jpg" width="127.5" height="96"></a>
|
||||
<a title="We specialize in the online gambling industry, helping players access reliable and verified information about the best online casinos and pokies in Australia. Our team tests casinos and games, collects user reviews from Trustpilot, and organizes them in o" href="https://au.trustpilot.com/review/bestpayidpokies.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="PayID Pokies" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/985a0ae7-54c3-4680-8816-bc8d656f7562/payidpokies.png" width="64" height="64"></a>
|
||||
<a title="TopRating.casino ➢ Гід по онлайн-казино в Україні" href="https://toprating.casino/ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Top Rating casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/fec14fc4-85b1-4fdc-971e-e8aabfc60926/toprating%20logo.jpg" width="64" height="64"></a>
|
||||
<a title="iDealeCasinos" href="https://idealecasinos.nl/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="iDealeCasinos" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/907841d3-435e-44b4-9684-c33fd8635ece/ideale-casinos-square-white-logo-300.png" width="64" height="64"></a>
|
||||
<a title="Find the best Interac online casinos in Canada with secure payments, exclusive bonuses, and fast withdrawals." href="https://interac-casino.com/en-ca/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Interac-casino.com - Canada" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/865d9613-74db-45b6-9f33-3ba992682259/2025-09-10%2019.33.08.jpg" width="64" height="64"></a>
|
||||
<a title="Porównanie kasyn online w Polsce. Darmowe automaty online." href="https://onlinekasyno-polis.pl/" target="_blank"><img alt="Online Kasyno Polis" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/12fe53d4-b2e4-4601-b9ea-7b652c414a38/274px%20274px-2.png" width="64" height="64"></a><details><summary>See more</summary>
|
||||
<a title="OnlineCasinosSpelen" href="https://onlinecasinosspelen.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="OnlineCasinosSpelen" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/47e87426-6a55-4f69-9fb5-4e5032dc35a8/5d10dd22-320e-47d4-84e6-d144874f1f5f.png" width="64" height="64"></a>
|
||||
<a title="Betwinner is an online bookmaker offering sports betting, casino games, and more." href="https://guidebook.betwinner.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Guidebook.BetWinner" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/82cab29a-7002-4924-83bf-2eecb03d07c4/0x0.png" width="64" height="64"></a>
|
||||
<a title="Discover the Top 10 Online Casino Australia sites for fast payouts, big bonuses, and top real money pokies" href="https://au.trustpilot.com/review/top-10-online-casino-australia.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Top 10 Casino Australia" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/cd3f2230-ca38-41e1-9f31-f3069b910be3/top-10-online-casino-aus.jpg" width="64" height="64"></a>
|
||||
<a title="We test dozens of casinos every month and select the coolest ones for Australian players." href="https://au.trustpilot.com/review/payid-casino.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="PayID Pokies Sites" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/ecd8a5f4-fd86-4903-a512-cbfaff35e7ef/payidpokiessites.png" width="69" height="64"></a>
|
||||
<a title="We collect all reviews about the best online pokies." href="https://au.trustpilot.com/review/aussiepokies.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Online Pokies in Australia" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/44d84116-8762-4167-9433-a9e5da542e29/pokies.png" width="64" height="64"></a>
|
||||
<a title="Plinko Game" href="https://www.trustpilot.com/review/plinkoplay.top?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Plinko Game" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/5e953df9-1876-45b6-9ffc-f2009804935b/plinkoo.png" width="64" height="64"></a>
|
||||
<a title="Онлайн казино casino.ua" href="https://casino.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Онлайн казино casino.ua" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/32790ee6-245b-45bd-acf7-7a661fe2cf9f/logo.png" width="64" height="64"></a>
|
||||
<a title="Real Money Pokies" href="https://onlinecasinoskiwi.co.nz/real-money-pokies/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Real Money Pokies" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/d0f7382e-32ea-4425-a8c4-3019f9ed501c/NZ_logo%20(6)%20(2).jpg" width="64" height="64"></a>
|
||||
<a title="Uudet Nettikasinot" href="https://fi.parhaatuudetkasinot.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="parhaatuudetkasinot.com" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/09e109d6-8ad2-4ade-ab24-4427028c8e38/260bfa9d-6a5c-494d-9ec0-a624327429ae.png" width="64" height="64"></a>
|
||||
<a title="matej_j" href="https://matej.jurancic.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="matej_j" src="https://www.gravatar.com/avatar/a145a33757bfa7be46eb0b449485f13c?default=404" width="64" height="64"></a>
|
||||
<a title="New Casino Bonuses" href="https://newcasinobonuses.gb.net/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="New Casino Bonuses" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/38e356d8-3597-406a-a263-1c348723aa17/new_casino_bonuses_logo.png" width="64" height="64"></a>
|
||||
<a title="Best online sports betting and casino company." href="https://global.fun88.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Fun88" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/1688ebca-4984-4b9b-a24d-8fdd1233892f/fun88-logo.png" width="64" height="64"></a>
|
||||
<a title="Top 50 Online Casinos UK" href="https://eastvillafc.co.uk?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="East Villa FC" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/2560f1b5-20d6-4cf4-83cd-2457bf111fc3/trophy-fav-blue.png" width="64" height="64"></a>
|
||||
<a title="Instant withdrawal casino" href="https://au.trustpilot.com/review/quickcashoutcasinos.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Instant withdrawal casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/e4be26b6-a57a-4758-ad56-bd31c759465e/quickcashoutcasinos2.png" width="75" height="64"></a>
|
||||
<a title="บริษัทรับแทงบอลออนไลน์ที่ดีที่สุดในประเทศไทย" href="https://www.fun88thh.com/th/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Fun88" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/bbf7174c-fc01-4ce6-86b5-f621e350969d/fun88-logo.png" width="64" height="64"></a>
|
||||
<a title="Nhà cái cá cược thể thao trực tuyến tốt nhất tại Việt Nam" href="https://www.fun88vnu.com/vn/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Fun88" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/ed704e1d-3894-48bb-83e3-6094b2c68a5c/fun88-logo.png" width="64" height="64"></a>
|
||||
<a title="Casino ohne oasis" href="https://de.trustpilot.com/review/onlinecasinoohneoasis.me?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino ohne oasis" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/f59e1e3a-6378-4aa7-91f5-6934a58bc21d/oasis.png" width="64" height="64"></a>
|
||||
<a title="Najlepsi Bukmacherzy" href="https://najlepsibukmacherzy.pl/ranking-legalnych-bukmacherow/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Najlepsi Bukmacherzy" src="https://opencollective-production.s3.us-west-1.amazonaws.com/81588eb0-608a-11eb-ad1c-b119533ac7bb.png" width="64" height="64"></a>
|
||||
<a title="Paysafecard Casino" href="https://de.trustpilot.com/review/onlinecasinospaysafecard.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Paysafecard Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/641d34bb-f65f-4df5-a6ec-ad5ab35df1e0/paysafe.png" width="64" height="64"></a>
|
||||
<a title="Offshore bookmakers review site." href="https://www.sportsbookreviewsonline.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Sportsbook Reviews Online" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/6d499f24-d669-4fc6-bb5f-b87184aa7963/sportsbookreviewsonline_com.png" width="42" height="42"></a>
|
||||
<a title="Get professional support for Carbon" href="https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=docs" target="_blank"><img alt="Tidelift" src="https://carbonphp.github.io/carbon/sponsors/tidelift-brand.png" width="84" height="42"></a>
|
||||
<a title="Ставки на спорт Favbet" href="https://www.favbet.ua/uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Ставки на спорт Favbet" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/d86d313e-7b17-42fa-8b76-3f17fbf681a2/favbet-logo.jpg" width="42" height="42"></a>
|
||||
<a title="Casino-portugal.pt" href="https://casino-portugal.pt/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino-portugal.pt" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/870b4bd0-b6aa-4129-9827-e8ac02cfde56/167bdc1d-0a19-414d-a288-cfc3278b388f.png" width="42" height="42"></a>
|
||||
<a title="Best Casinos not on Gamstop in the UK 2025" href="https://www.vso.org.uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="best non Gamstop casinos" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/3f48874e-f2f6-4062-a2a2-1500677ee3d9/125%D1%85125%20(1).jpg" width="42" height="42"></a>
|
||||
<a title="https://play-fortune.pl/kasyno/z-minimalnym-depozytem/" href="https://play-fortune.pl/kasyno/z-minimalnym-depozytem/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="https://play-fortune.pl/kasyno/z-minimalnym-depozytem/" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/cbeea308-5148-4f6c-ac6e-dbfa029aadd1/PL.png" width="42" height="42"></a>
|
||||
<a title="Playfortune.net.br" href="https://playfortune.net.br/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Playfortune.net.br" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/bf7ba31d-648c-470f-bf7e-2293c5ca0509/62a0353e-3858-41f1-bbb3-597449949e66.png" width="42" height="42"></a>
|
||||
<a title="Znajdź najlepsze zakłady bukmacherskie w Polsce w 2023 roku. Probukmacher.pl to Twoje kompendium wiedzy na temat bukmacherów!" href="https://www.probukmacher.pl?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Probukmacher" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/caf50271-4560-4ffe-a434-ea15239168db/Screenshot_1.png" width="58" height="42"></a>
|
||||
<a title="Онлайн казино та БК (ставки на спорт) в Україні" href="https://betking.com.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="betking онлайн казино" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/08587758-582c-4136-aba5-2519230960d3/betking.jpg" width="42" height="42"></a>
|
||||
<a title="BetPokies NZ features top fast payout casinos where winnings are processed within hours. The speed depends on the casino and payment method, with the platform highlighting the best options for smooth, reliable play." href="https://betpokies.co.nz/casinos/fast-payout?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Fastest Payout Online Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/37cba042-a941-4bfd-87c4-b4f4c1a98641/7912b3ee-3c62-4ebd-b435-6a9a88b2228b.png" width="42" height="42"></a>
|
||||
<a title="inkedin" href="https://inkedin.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="inkedin" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/6cb31863-b725-49c5-820c-2c2be7d54adf/cc930e12-04de-4574-9cca-171e07d277c3.png" width="42" height="42"></a>
|
||||
<a title="Best PayID Pokies in Australia" href="https://ausgambler.net/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="AusGambler" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/b120ff74-a4cc-4e25-a96f-2b040d60de14/payidgambler.png" width="42" height="42"></a>
|
||||
<a title="Актуальний та повносправний рейтинг онлайн казино України, ґрунтований на відгуках реальних гравців." href="https://uk.onlinecasino.in.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Онлайн казино України" src="https://opencollective-production.s3.us-west-1.amazonaws.com/c0b4b090-eef8-11ec-9cb7-0527a205b226.png" width="42" height="42"></a>
|
||||
<a title="Post-production resource scheduling app" href="https://freispace.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="freispace" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/7d553b00-78ff-4442-91dd-33c220e82ac4/freispace-icon-inverted.png" width="42" height="42"></a>
|
||||
<a title="bestecasinozondercruks" href="https://nl.trustpilot.com/review/bestecasinozondercruks.online?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="bestecasinozondercruks" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/4948eca9-abd5-49ea-bb70-1ea6053f8663/ChatGPT%20Image%20Dec%2027%2C%202025%2C%2010_22_47%20PM-min.png" width="42" height="42"></a>
|
||||
<a title="Run Weekly" href="https://www.runweekly.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Run Weekly" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/4d7e1fad-f160-4b64-ab41-d493023f9369/2de8e56c-e9fa-497c-8882-3736ec946664.png" width="42" height="42"></a>
|
||||
<a title="Are you looking for the latest online casino sites to play in the UK? How about ones that actually deliver on their promises? Every year new online casinos pops up, but are they worth your time? Check out https://helpdirect.org.uk" href="https://helpdirect.org.uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="New Casino Sites UK (2025) Help Direct" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/d5e8c98f-7df3-40e8-bfe1-3c1583222eab/help-direct-logo-white-trans.png" width="42" height="42"></a>
|
||||
<a title="UnAIMyText" href="https://unaimytext.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="UnAIMyText" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/fa5b36d5-69e6-44a4-bbdf-b5d264399365/icon_resized.png" width="42" height="42"></a>
|
||||
<a title="Online Casino utan Svensk licens" href="https://se.trustpilot.com/review/casino-utan-svensk-licens-se.se?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Online Casino utan Svensk licens" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/64a7a6b0-e843-4cc2-a04e-0e829ccade58/logose.png" width="42" height="42"></a>
|
||||
<a title="Slots City® ➢ Лучшее лицензионно казино онлайн и оффлайн на гривны в Украине. 【 Более1500 игровых автоматов и слотов】✅ Официально и Безопасно" href="https://slotscity.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Slots City" src="https://opencollective-production.s3.us-west-1.amazonaws.com/d7e298c0-7abe-11ed-8553-230872f5e54d.png" width="59" height="42"></a>
|
||||
<a title="ssddanbrown" href="https://github.com/ssddanbrown" target="_blank"><img alt="ssddanbrown" src="https://avatars.githubusercontent.com/u/8343178?s=128&v=4" width="42" height="42"></a></details><!-- </open-collective-sponsors> -->
|
||||
<table>
|
||||
<tr>
|
||||
<td><a title="Онлайн казино 777 Україна" href="https://777.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Онлайн казино 777" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/7e572d50-1ce8-4d69-ae12-86cc80371373/ok-ua-777.png" width="96" height="96"></a></td>
|
||||
<td><a title="Нова українська букмекерська контора" href="https://betking.com.ua/sports-book/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Ставки на спорт" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/c56d2fe2-f9fb-4d63-947c-77575f4b15c6/stavki.jpg" width="96" height="96"></a></td>
|
||||
<td><a title="Non GamStop Bookies UK" href="https://netto.co.uk/betting-sites-not-on-gamstop/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Non GamStop Bookies UK" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/51bfaa05-02b3-4cd9-b1a4-9d0d8f34cbae/%D0%97%D0%BD%D1%96%D0%BC%D0%BE%D0%BA%20%D0%B5%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202025-07-04%20%D0%BE%2015.21.16%20(1)%20(1)%20(1).jpg" width="126" height="96"></a></td>
|
||||
<td><a title="Trusted last mile route planning and route optimization" href="https://route4me.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Route4Me Route Planner" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/237386c3-48a2-47c6-97ac-5f888cdb4cda/Route4MeIconLogo.png" width="96" height="96"></a></td>
|
||||
<td><a title="Bei Releaf erhalten Sie schnell und diskret Ihr Cannabis Rezept online. Unsere Ärzte prüfen Ihre Angaben und stellen bei Eignung das Rezept aus. Anschließend können Sie legal und sicher medizinisches Cannabis über unsere Partnerapotheken kaufen." href="https://releaf.com/de?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Releaf – Medizinischer Cannabis Shop" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/b686d646-5029-4b4c-8cab-9645ab2679de/9da596d1-f48a-41ec-947d-a64dd8e7529c.png" width="96" height="96"></a></td>
|
||||
<td><a title="Best non Gamstop sites in the UK" href="https://www.pieria.co.uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Best non Gamstop sites in the UK" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/34e340b8-e1de-4932-8a76-1b3ce2ec7ee8/logo_white%20bg%20(8).png" width="96" height="96"></a></td>
|
||||
<td><a title="#1 Guide To Online Gambling In Canada" href="https://casinohex.org/canada/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="CasinoHex Canada" src="https://opencollective-production.s3.us-west-1.amazonaws.com/79fdbcc0-a997-11eb-abbc-25e48b63c6dc.jpg" width="127.5" height="96"></a></td>
|
||||
<td><a title="We specialize in the online gambling industry, helping players access reliable and verified information about the best online casinos and pokies in Australia. Our team tests casinos and games, collects user reviews from Trustpilot, and organizes them in o" href="https://au.trustpilot.com/review/bestpayidpokies.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="PayID Pokies" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/985a0ae7-54c3-4680-8816-bc8d656f7562/payidpokies.png" width="64" height="64"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a title="Mi misión es la educación y transparencia en el mundo de los casinos online" href="https://www.educatransparencia.cl/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Transparencia en Casinos Online" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/c034fdcb-1d17-4c83-8105-f3cfa4f874d6/educalogocito.png" width="128" height="64"></a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<details><summary>See more</summary>
|
||||
<table>
|
||||
<tr>
|
||||
<td><a title="gaia-wines.gr" href="https://www.gaia-wines.gr/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="gaia-wines.gr" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/a9b971ee-db5f-4400-8c4b-76cf9bc35015/IMAGE%202024-06-14%2013%3A54%3A14.jpg" width="96" height="96"></a></td>
|
||||
<td><a title="OnlineCasinosSpelen" href="https://onlinecasinosspelen.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="OnlineCasinosSpelen" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/47e87426-6a55-4f69-9fb5-4e5032dc35a8/5d10dd22-320e-47d4-84e6-d144874f1f5f.png" width="64" height="64"></a></td>
|
||||
<td><a title="We test dozens of casinos every month and select the coolest ones for Australian players." href="https://au.trustpilot.com/review/payid-casino.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="PayID Pokies Sites" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/ecd8a5f4-fd86-4903-a512-cbfaff35e7ef/payidpokiessites.png" width="69" height="64"></a></td>
|
||||
<td><a title="We collect all reviews about the best online pokies." href="https://au.trustpilot.com/review/aussiepokies.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Online Pokies in Australia" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/44d84116-8762-4167-9433-a9e5da542e29/pokies.png" width="64" height="64"></a></td>
|
||||
<td><a title="Plinko Game" href="https://www.trustpilot.com/review/plinkoplay.top?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Plinko Game" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/5e953df9-1876-45b6-9ffc-f2009804935b/plinkoo.png" width="64" height="64"></a></td>
|
||||
<td><a title="Casinomithandyrechnung" href="https://at.trustpilot.com/review/casinomithandyrechnung.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casinomithandyrechnung" src="https://images.opencollective.com/casinomithandyrechnung/avatar/256.png" width="64" height="64"></a></td>
|
||||
<td><a title="lolajack" href="https://nl.trustpilot.com/review/lolajack-casino-nl.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="lolajack" src="https://images.opencollective.com/lolajack/avatar/256.png" width="64" height="64"></a></td>
|
||||
<td><a title="marketing in germany" href="https://de.trustpilot.com/review/paysafecardcasinos.org?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Paysafecard Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/1b2f45ea-02bc-4a78-a84a-355f68c8a293/paysafe.png" width="64" height="64"></a></td>
|
||||
<td><a title="Games" href="https://au.trustpilot.com/review/bestaustraliaonlinepokies.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Australian Online Pokies" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/7ca6ca2e-6542-4736-8952-b9adb7f4c9cf/39aac4bc53ff11f198d9ce36ed903bf5_1.jpg" width="64" height="64"></a></td>
|
||||
<td><a title="Buitenlandse Online Casino" href="https://nl.trustpilot.com/review/buitenlandsecasino.vip?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Buitenlandse Online Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/9465308a-8e44-4606-af5d-5a81a3c6567b/ChatGPT%20Image%20Nov%2015%2C%202025%2C%2002_53_25%20PM.png" width="64" height="64"></a></td>
|
||||
<td><a title="Betwinner is an online bookmaker offering sports betting, casino games, and more." href="https://guidebook.betwinner.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Guidebook.BetWinner" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/82cab29a-7002-4924-83bf-2eecb03d07c4/0x0.png" width="64" height="64"></a></td>
|
||||
<td><a title="Porównanie kasyn online w Polsce. Darmowe automaty online." href="https://onlinekasyno-polis.pl/" target="_blank"><img alt="Online Kasyno Polis" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/12fe53d4-b2e4-4601-b9ea-7b652c414a38/274px%20274px-2.png" width="64" height="64"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a title="Online Casino Zonder Registratie" href="https://nl.trustpilot.com/review/zonderregistratiecasinos.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Online Casino Zonder Registratie" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/cf382ddc-627b-4bd9-8870-43ee28d2a628/casino-zonder-registratie.png" width="85" height="64"></a></td>
|
||||
<td><a title="TopRating.casino ➢ Гід по онлайн-казино в Україні" href="https://toprating.casino/ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Top Rating casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/fec14fc4-85b1-4fdc-971e-e8aabfc60926/toprating%20logo.jpg" width="64" height="64"></a></td>
|
||||
<td><a title="iDealeCasinos" href="https://idealecasinos.nl/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="iDealeCasinos" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/907841d3-435e-44b4-9684-c33fd8635ece/ideale-casinos-square-white-logo-300.png" width="64" height="64"></a></td>
|
||||
<td><a title="Uudet Nettikasinot" href="https://fi.parhaatuudetkasinot.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="parhaatuudetkasinot.com" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/09e109d6-8ad2-4ade-ab24-4427028c8e38/260bfa9d-6a5c-494d-9ec0-a624327429ae.png" width="64" height="64"></a></td>
|
||||
<td><a title="New Casino Bonuses" href="https://newcasinobonuses.gb.net/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="New Casino Bonuses" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/38e356d8-3597-406a-a263-1c348723aa17/new_casino_bonuses_logo.png" width="64" height="64"></a></td>
|
||||
<td><a title="Best online sports betting and casino company." href="https://global.fun88.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Fun88" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/1688ebca-4984-4b9b-a24d-8fdd1233892f/fun88-logo.png" width="64" height="64"></a></td>
|
||||
<td><a title="Top 50 Online Casinos UK" href="https://eastvillafc.co.uk?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="East Villa FC" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/2560f1b5-20d6-4cf4-83cd-2457bf111fc3/trophy-fav-blue.png" width="64" height="64"></a></td>
|
||||
<td><a title="บริษัทรับแทงบอลออนไลน์ที่ดีที่สุดในประเทศไทย" href="https://www.fun88thf.com/th/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Fun88" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/bbf7174c-fc01-4ce6-86b5-f621e350969d/fun88-logo.png" width="64" height="64"></a></td>
|
||||
<td><a title="Nhà cái cá cược thể thao trực tuyến tốt nhất tại Việt Nam" href="https://www.fun88fp.com/vn/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Fun88" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/ed704e1d-3894-48bb-83e3-6094b2c68a5c/fun88-logo.png" width="64" height="64"></a></td>
|
||||
<td><a title="Casino ohne oasis" href="https://de.trustpilot.com/review/onlinecasinoohneoasis.me?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino ohne oasis" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/f59e1e3a-6378-4aa7-91f5-6934a58bc21d/oasis.png" width="64" height="64"></a></td>
|
||||
<td><a title="Najlepsi Bukmacherzy" href="https://najlepsibukmacherzy.pl/ranking-legalnych-bukmacherow/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Najlepsi Bukmacherzy" src="https://opencollective-production.s3.us-west-1.amazonaws.com/81588eb0-608a-11eb-ad1c-b119533ac7bb.png" width="64" height="64"></a></td>
|
||||
<td><a title="Paysafecard Casino" href="https://de.trustpilot.com/review/onlinecasinospaysafecard.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Paysafecard Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/641d34bb-f65f-4df5-a6ec-ad5ab35df1e0/paysafe.png" width="64" height="64"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a title="WNB Casino Bewertung" href="https://wnb-casino.de/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="WNB Casino Bewertung" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/1adcf96c-dba5-40c0-aa5f-cc352e98b376/WNB%20Casino%20Bewertung.png" width="64" height="64"></a></td>
|
||||
<td><a title="Casino mit Schneller Auszahlung" href="https://de.trustpilot.com/review/casinoschnellauszahlung.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino mit Schneller Auszahlung" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/031e76f8-0041-4c7c-a942-2d8f21b5a54b/casinoschnellauszahlung.com%202.png" width="64" height="64"></a></td>
|
||||
<td><a title="Casinos ohne OASIS" href="https://de.trustpilot.com/review/ohneoasis.de?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casinos ohne OASIS" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/49904abe-0786-4b30-a9c8-6c508441f7c7/ohneoasis.de.png" width="65" height="64"></a></td>
|
||||
<td><a title="Wettanbieter ohne OASIS" href="https://de.trustpilot.com/review/wettanbieterohneoasis.io?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Wettanbieter ohne OASIS" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/44468112-6a16-4cc7-aa0a-d30020fa78a5/wettenoasis2.png" width="62" height="64"></a></td>
|
||||
<td><a title="Casino ohne Lizenz" href="https://de.trustpilot.com/review/casinoohnelizenz.org?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino ohne Lizenz" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/f89d7bf4-c7d9-4ad1-a9e5-a904ba63126f/casinoohnelizenz.org.png" width="64" height="64"></a></td>
|
||||
<td><a title="Casino ohne Limit" href="https://de.trustpilot.com/review/limitfreicasino.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino ohne Limit" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/4525f686-fc19-47c6-9087-d5f41ecd6cfd/limitfreicasino.com.png" width="64" height="64"></a></td>
|
||||
<td><a title="Casino ohne Verifizierung" href="https://de.trustpilot.com/review/ohneverifizierungcasino.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino ohne Verifizierung" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/2255004a-1c42-4399-83bc-32c21a65b66a/ohneverifizierungcasino.com.png" width="64" height="64"></a></td>
|
||||
<td><a title="Casino ohne Anmeldung" href="https://de.trustpilot.com/review/ohneanmeldungcasino.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino ohne Anmeldung" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/0be23739-2dd0-4f3f-85a3-8d1d67164681/ohneanmeldungcasino.com.png" width="64" height="64"></a></td>
|
||||
<td><a title="Crypto Casino" href="https://de.trustpilot.com/review/cryptocasinozone.net?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Crypto Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/a5a37da5-46ad-4940-8d58-7cf4326bd53d/cryptocasinozone.net.png" width="64" height="64"></a></td>
|
||||
<td><a title="Paypal Casino" href="https://de.trustpilot.com/review/paypalcasinosite.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Paypal Casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/2c3c6c04-e009-4f93-a080-4f5f83b875b9/paypalcasinosite.com.png" width="64" height="64"></a></td>
|
||||
<td><a title="Онлайн казино casino.ua" href="https://casino.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Онлайн казино casino.ua" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/32790ee6-245b-45bd-acf7-7a661fe2cf9f/logo.png" width="64" height="64"></a></td>
|
||||
<td><a title="Real Money Pokies" href="https://onlinecasinoskiwi.co.nz/real-money-pokies/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Real Money Pokies" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/d0f7382e-32ea-4425-a8c4-3019f9ed501c/NZ_logo%20(6)%20(2).jpg" width="42" height="42"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a title="Get professional support for Carbon" href="https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=docs" target="_blank"><img alt="Tidelift" src="https://carbonphp.github.io/carbon/sponsors/tidelift-brand.png" width="84" height="42"></a></td>
|
||||
<td><a title="Find the best Interac online casinos in Canada with secure payments, exclusive bonuses, and fast withdrawals." href="https://interac-casino.com/en-ca/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Interac-casino.com - Canada" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/865d9613-74db-45b6-9f33-3ba992682259/2025-09-10%2019.33.08.jpg" width="42" height="42"></a></td>
|
||||
<td><a title="Discover the Top 10 Online Casino Australia sites for fast payouts, big bonuses, and top real money pokies" href="https://au.trustpilot.com/review/top-10-online-casino-australia.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Top 10 Casino Australia" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/cd3f2230-ca38-41e1-9f31-f3069b910be3/top-10-online-casino-aus.jpg" width="42" height="42"></a></td>
|
||||
<td><a title="Offshore bookmakers review site." href="https://www.sportsbookreviewsonline.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Sportsbook Reviews Online" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/6d499f24-d669-4fc6-bb5f-b87184aa7963/sportsbookreviewsonline_com.png" width="42" height="42"></a></td>
|
||||
<td><a title="Wildflower" href="https://www.trustpilot.com/review/wildflower.uno?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Wildflower" src="https://images.opencollective.com/wildflower_cases/avatar/256.png" width="42" height="42"></a></td>
|
||||
<td><a title="Casino-portugal.pt" href="https://casino-portugal.pt/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Casino-portugal.pt" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/870b4bd0-b6aa-4129-9827-e8ac02cfde56/167bdc1d-0a19-414d-a288-cfc3278b388f.png" width="42" height="42"></a></td>
|
||||
<td><a title="Ставки на спорт Favbet" href="https://www.favbet.ua/uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Ставки на спорт Favbet" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/d86d313e-7b17-42fa-8b76-3f17fbf681a2/favbet-logo.jpg" width="42" height="42"></a></td>
|
||||
<td><a title="Znajdź najlepsze zakłady bukmacherskie w Polsce w 2023 roku. Probukmacher.pl to Twoje kompendium wiedzy na temat bukmacherów!" href="https://www.probukmacher.pl?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Probukmacher" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/caf50271-4560-4ffe-a434-ea15239168db/Screenshot_1.png" width="58" height="42"></a></td>
|
||||
<td><a title="Instant withdrawal casino" href="https://au.trustpilot.com/review/quickcashoutcasinos.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Instant withdrawal casino" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/e4be26b6-a57a-4758-ad56-bd31c759465e/quickcashoutcasinos2.png" width="49" height="42"></a></td>
|
||||
<td><a title="Best Casinos not on Gamstop in the UK 2025" href="https://www.vso.org.uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="best non Gamstop casinos" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/3f48874e-f2f6-4062-a2a2-1500677ee3d9/125%D1%85125%20(1).jpg" width="42" height="42"></a></td>
|
||||
<td><a title="inkedin" href="https://inkedin.com?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="inkedin" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/6cb31863-b725-49c5-820c-2c2be7d54adf/cc930e12-04de-4574-9cca-171e07d277c3.png" width="42" height="42"></a></td>
|
||||
<td><a title="Онлайн казино та БК (ставки на спорт) в Україні" href="https://betking.com.ua/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="betking онлайн казино" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/08587758-582c-4136-aba5-2519230960d3/betking.jpg" width="42" height="42"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a title="Post-production resource scheduling app" href="https://freispace.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="freispace" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/7d553b00-78ff-4442-91dd-33c220e82ac4/freispace-icon-inverted.png" width="42" height="42"></a></td>
|
||||
<td><a title="bestecasinozondercruks" href="https://nl.trustpilot.com/review/bestecasinozondercruks.online?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="bestecasinozondercruks" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/4948eca9-abd5-49ea-bb70-1ea6053f8663/ChatGPT%20Image%20Dec%2027%2C%202025%2C%2010_22_47%20PM-min.png" width="42" height="42"></a></td>
|
||||
<td><a title="Run Weekly" href="https://www.runweekly.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="Run Weekly" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/4d7e1fad-f160-4b64-ab41-d493023f9369/2de8e56c-e9fa-497c-8882-3736ec946664.png" width="42" height="42"></a></td>
|
||||
<td><a title="Are you looking for the latest online casino sites to play in the UK? How about ones that actually deliver on their promises? Every year new online casinos pops up, but are they worth your time? Check out https://helpdirect.org.uk" href="https://helpdirect.org.uk/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="New Casino Sites UK (2025) Help Direct" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/d5e8c98f-7df3-40e8-bfe1-3c1583222eab/help-direct-logo-white-trans.png" width="42" height="42"></a></td>
|
||||
<td><a title="UnAIMyText" href="https://unaimytext.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="UnAIMyText" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/fa5b36d5-69e6-44a4-bbdf-b5d264399365/icon_resized.png" width="42" height="42"></a></td>
|
||||
<td><a title="TopKasynoOnline PL" href="https://pl.topkasynoonline.com/?utm_source=opencollective&utm_medium=github&utm_campaign=Carbon" target="_blank"><img alt="TopKasynoOnline PL" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/6cdee969-d731-44d6-b8ff-fc4f6d4dab9c/TKOlogo.png" width="42" height="42"></a></td>
|
||||
<td><a title="ssddanbrown" href="https://github.com/ssddanbrown" target="_blank"><img alt="ssddanbrown" src="https://avatars.githubusercontent.com/u/8343178?s=128&v=4" width="42" height="42"></a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</details><!-- </open-collective-sponsors> -->
|
||||
|
||||
[[See all](https://carbonphp.github.io/carbon/#sponsors)]
|
||||
|
||||
|
||||
@@ -48,6 +48,13 @@ abstract class AbstractTranslator extends SymfonyTranslator
|
||||
*/
|
||||
protected array $directories = [];
|
||||
|
||||
/**
|
||||
* Cache for language files.
|
||||
*
|
||||
* @var array<string, array>
|
||||
*/
|
||||
protected array $fileCache = [];
|
||||
|
||||
/**
|
||||
* Set to true while constructing.
|
||||
*/
|
||||
@@ -171,7 +178,7 @@ abstract class AbstractTranslator extends SymfonyTranslator
|
||||
|
||||
foreach ($this->getDirectories() as $directory) {
|
||||
$file = \sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale);
|
||||
$data = @include $file;
|
||||
$data = ($this->fileCache[$file] ??= self::loadFile($file));
|
||||
|
||||
if ($data !== false) {
|
||||
$this->messages[$locale] = $data;
|
||||
@@ -305,7 +312,7 @@ abstract class AbstractTranslator extends SymfonyTranslator
|
||||
*/
|
||||
public function getMessages(?string $locale = null): array
|
||||
{
|
||||
return $locale === null ? $this->messages : $this->messages[$locale];
|
||||
return $locale === null ? $this->messages : ($this->messages[$locale] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,6 +322,12 @@ abstract class AbstractTranslator extends SymfonyTranslator
|
||||
*/
|
||||
public function setLocale($locale): void
|
||||
{
|
||||
$previousLocale = $this->getLocale();
|
||||
|
||||
if ($previousLocale === $locale && isset($this->messages[$locale])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$locale = preg_replace_callback('/[-_]([a-z]{2,}|\d{2,})/', function ($matches) {
|
||||
// _2-letters or YUE is a region, _3+-letters is a variant
|
||||
$upper = strtoupper($matches[1]);
|
||||
@@ -326,8 +339,6 @@ abstract class AbstractTranslator extends SymfonyTranslator
|
||||
return '_'.ucfirst($matches[1]);
|
||||
}, strtolower($locale));
|
||||
|
||||
$previousLocale = $this->getLocale();
|
||||
|
||||
if ($previousLocale === $locale && isset($this->messages[$locale])) {
|
||||
return;
|
||||
}
|
||||
@@ -407,7 +418,12 @@ abstract class AbstractTranslator extends SymfonyTranslator
|
||||
$this->initializing = false;
|
||||
}
|
||||
|
||||
private static function compareChunkLists($referenceChunks, $chunks)
|
||||
private function loadFile(string $file): array|false
|
||||
{
|
||||
return file_exists($file) ? (include $file) : false;
|
||||
}
|
||||
|
||||
private static function compareChunkLists(array $referenceChunks, array $chunks): int
|
||||
{
|
||||
$score = 0;
|
||||
|
||||
|
||||
1592
plugins/vendor/nesbot/carbon/src/Carbon/Carbon.php
vendored
1592
plugins/vendor/nesbot/carbon/src/Carbon/Carbon.php
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -437,6 +437,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
|
||||
$spec = $years;
|
||||
$isStringSpec = (\is_string($spec) && !preg_match('/^[\d.]/', $spec));
|
||||
$inverted = false;
|
||||
|
||||
if (!$isStringSpec || (float) $years) {
|
||||
$spec = static::PERIOD_PREFIX;
|
||||
@@ -463,8 +464,17 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
}
|
||||
}
|
||||
|
||||
if ($isStringSpec && str_starts_with($spec, '-')) {
|
||||
$inverted = true;
|
||||
$spec = substr($spec, 1);
|
||||
}
|
||||
|
||||
try {
|
||||
parent::__construct($spec);
|
||||
|
||||
if ($inverted) {
|
||||
$this->invert = 1;
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
try {
|
||||
parent::__construct('PT0S');
|
||||
@@ -548,8 +558,17 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
}
|
||||
|
||||
foreach (['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'] as $unit) {
|
||||
if ($$unit < 0) {
|
||||
$this->set($unit, $$unit);
|
||||
$value = $$unit;
|
||||
|
||||
if (
|
||||
(
|
||||
\is_int($value)
|
||||
|| \is_float($value)
|
||||
|| (\is_string($value) && preg_match('/^[\d.-]+$/', $value))
|
||||
)
|
||||
&& $value < 0
|
||||
) {
|
||||
$this->set($unit, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -763,6 +782,42 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public static function monthWithAnchorDay(int $day): static
|
||||
{
|
||||
return new static(function (CarbonInterface $date, bool $negated) use ($day) {
|
||||
$next = $date->day(1)->addMonths($negated ? -1 : 1);
|
||||
|
||||
return $next->day(min($day, $next->daysInMonth));
|
||||
});
|
||||
}
|
||||
|
||||
public static function monthNoOverflow(): static
|
||||
{
|
||||
return new static(static function (CarbonInterface $date, bool $negated) {
|
||||
return $negated
|
||||
? $date->subMonthNoOverflow()
|
||||
: $date->addMonthNoOverflow();
|
||||
});
|
||||
}
|
||||
|
||||
public static function yearWithAnchorDay(int $day): static
|
||||
{
|
||||
return new static(function (CarbonInterface $date, bool $negated) use ($day) {
|
||||
$next = $date->day(1)->addYears($negated ? -1 : 1);
|
||||
|
||||
return $next->day(min($day, $next->daysInMonth));
|
||||
});
|
||||
}
|
||||
|
||||
public static function yearNoOverflow(): static
|
||||
{
|
||||
return new static(static function (CarbonInterface $date, bool $negated) {
|
||||
return $negated
|
||||
? $date->subYearNoOverflow()
|
||||
: $date->addYearNoOverflow();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the original source used to create the current interval.
|
||||
*
|
||||
@@ -1117,8 +1172,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
*/
|
||||
public static function diff($start, $end = null, bool $absolute = false, array $skip = []): static
|
||||
{
|
||||
$start = $start instanceof CarbonInterface ? $start : Carbon::make($start);
|
||||
$end = $end instanceof CarbonInterface ? $end : Carbon::make($end);
|
||||
$start = self::carbonOrMake($start);
|
||||
$end = self::carbonOrMake($end);
|
||||
$rawInterval = $start->diffAsDateInterval($end, $absolute);
|
||||
$interval = static::instance($rawInterval, $skip);
|
||||
|
||||
@@ -2159,6 +2214,14 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
|
||||
$class = ($params[0] ?? null) instanceof DateTime ? CarbonPeriod::class : CarbonPeriodImmutable::class;
|
||||
|
||||
if ($this->step) {
|
||||
$dates = array_filter($params, static fn (mixed $param) => $param instanceof DateTimeInterface);
|
||||
|
||||
if (\count($dates) >= 2 && $dates[0] > $dates[1]) {
|
||||
$this->invert();
|
||||
}
|
||||
}
|
||||
|
||||
return $class::create($this, ...$params);
|
||||
}
|
||||
|
||||
@@ -2225,13 +2288,15 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
/**
|
||||
* Add the passed interval to the current instance.
|
||||
*
|
||||
* @param string|DateInterval $unit
|
||||
* @param int|float $value
|
||||
* @param Unit|string|DateInterval $unit
|
||||
* @param int|float $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add($unit, $value = 1): static
|
||||
{
|
||||
$this->checkNoStepIsDefined(__METHOD__);
|
||||
|
||||
if (is_numeric($unit)) {
|
||||
[$value, $unit] = [$unit, $value];
|
||||
}
|
||||
@@ -2268,13 +2333,15 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
/**
|
||||
* Subtract the passed interval to the current instance.
|
||||
*
|
||||
* @param string|DateInterval $unit
|
||||
* @param int|float $value
|
||||
* @param Unit|string|DateInterval $unit
|
||||
* @param int|float $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function sub($unit, $value = 1): static
|
||||
{
|
||||
$this->checkNoStepIsDefined(__METHOD__);
|
||||
|
||||
if (is_numeric($unit)) {
|
||||
[$value, $unit] = [$unit, $value];
|
||||
}
|
||||
@@ -2326,7 +2393,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given parameters to the current interval.
|
||||
* Subtract given parameters to the current interval.
|
||||
*
|
||||
* @param int $years
|
||||
* @param int $months
|
||||
@@ -2372,6 +2439,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
*/
|
||||
public function times($factor): static
|
||||
{
|
||||
$this->checkNoStepIsDefined(__METHOD__);
|
||||
|
||||
if ($factor < 0) {
|
||||
$this->invert = $this->invert ? 0 : 1;
|
||||
$factor = -$factor;
|
||||
@@ -2434,6 +2503,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
*/
|
||||
public function multiply($factor): static
|
||||
{
|
||||
$this->checkNoStepIsDefined(__METHOD__);
|
||||
|
||||
if ($factor < 0) {
|
||||
$this->invert = $this->invert ? 0 : 1;
|
||||
$factor = -$factor;
|
||||
@@ -2472,38 +2543,46 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getDateIntervalSpec(DateInterval $interval, bool $microseconds = false, array $skip = []): string
|
||||
{
|
||||
public static function getDateIntervalSpec(
|
||||
DateInterval $interval,
|
||||
bool $microseconds = false,
|
||||
array $skip = [],
|
||||
bool $withNegatives = false,
|
||||
): string {
|
||||
$date = array_filter([
|
||||
static::PERIOD_YEARS => abs($interval->y),
|
||||
static::PERIOD_MONTHS => abs($interval->m),
|
||||
static::PERIOD_DAYS => abs($interval->d),
|
||||
static::PERIOD_YEARS => $withNegatives ? $interval->y : abs($interval->y),
|
||||
static::PERIOD_MONTHS => $withNegatives ? $interval->m : abs($interval->m),
|
||||
static::PERIOD_DAYS => $withNegatives ? $interval->d : abs($interval->d),
|
||||
]);
|
||||
|
||||
$skip = array_map([Unit::class, 'toNameIfUnit'], $skip);
|
||||
$days = abs((int) $interval->days);
|
||||
|
||||
if (
|
||||
$interval->days >= CarbonInterface::DAYS_PER_WEEK * CarbonInterface::WEEKS_PER_MONTH &&
|
||||
$days >= CarbonInterface::DAYS_PER_WEEK * CarbonInterface::WEEKS_PER_MONTH &&
|
||||
(!isset($date[static::PERIOD_YEARS]) || \count(array_intersect(['y', 'year', 'years'], $skip))) &&
|
||||
(!isset($date[static::PERIOD_MONTHS]) || \count(array_intersect(['m', 'month', 'months'], $skip)))
|
||||
) {
|
||||
$date = [
|
||||
static::PERIOD_DAYS => abs($interval->days),
|
||||
static::PERIOD_DAYS => $withNegatives ? $interval->days : $days,
|
||||
];
|
||||
}
|
||||
|
||||
$seconds = abs($interval->s);
|
||||
if ($microseconds && $interval->f > 0) {
|
||||
$seconds = \sprintf('%d.%06d', $seconds, abs($interval->f) * 1000000);
|
||||
$seconds = $withNegatives ? $interval->s : abs($interval->s);
|
||||
|
||||
if ($microseconds && $interval->f !== 0.0) {
|
||||
$seconds = $withNegatives
|
||||
? number_format($seconds + $interval->f, 6, '.', '')
|
||||
: \sprintf('%d.%06d', $seconds, abs($interval->f) * 1000000);
|
||||
}
|
||||
|
||||
$time = array_filter([
|
||||
static::PERIOD_HOURS => abs($interval->h),
|
||||
static::PERIOD_MINUTES => abs($interval->i),
|
||||
static::PERIOD_HOURS => $withNegatives ? $interval->h : abs($interval->h),
|
||||
static::PERIOD_MINUTES => $withNegatives ? $interval->i : abs($interval->i),
|
||||
static::PERIOD_SECONDS => $seconds,
|
||||
]);
|
||||
|
||||
$specString = static::PERIOD_PREFIX;
|
||||
$specString = ($withNegatives && $interval->invert ? '-' : '').static::PERIOD_PREFIX;
|
||||
|
||||
foreach ($date as $key => $value) {
|
||||
$specString .= $value.$key;
|
||||
@@ -2511,6 +2590,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
|
||||
if (\count($time) > 0) {
|
||||
$specString .= static::PERIOD_TIME_PREFIX;
|
||||
|
||||
foreach ($time as $key => $value) {
|
||||
$specString .= $value.$key;
|
||||
}
|
||||
@@ -2524,9 +2604,9 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function spec(bool $microseconds = false): string
|
||||
public function spec(bool $microseconds = false, bool $withNegatives = false): string
|
||||
{
|
||||
return static::getDateIntervalSpec($this, $microseconds);
|
||||
return static::getDateIntervalSpec($this, $microseconds, [], $withNegatives);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2981,6 +3061,12 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
)->invert($inverted)->cascade());
|
||||
}
|
||||
|
||||
$initiallyInverted = (bool) $this->invert;
|
||||
|
||||
if ($initiallyInverted) {
|
||||
$this->invert();
|
||||
}
|
||||
|
||||
$base = CarbonImmutable::parse('2000-01-01 00:00:00', 'UTC')
|
||||
->roundUnit($unit, $precision, $function);
|
||||
$next = $base->add($this);
|
||||
@@ -2996,7 +3082,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
->diff($base),
|
||||
);
|
||||
|
||||
return $this->invert($inverted);
|
||||
return $this->invert($initiallyInverted xor $inverted);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3514,6 +3600,13 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface, U
|
||||
}
|
||||
}
|
||||
|
||||
private static function carbonOrMake(mixed $dateTime): CarbonInterface
|
||||
{
|
||||
return $dateTime instanceof CarbonInterface
|
||||
? $dateTime
|
||||
: Carbon::make($dateTime);
|
||||
}
|
||||
|
||||
private static function incrementUnit(DateInterval $instance, string $unit, int $value): void
|
||||
{
|
||||
if ($value === 0) {
|
||||
|
||||
@@ -426,6 +426,96 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
return self::createFromIso($iso, $options);
|
||||
}
|
||||
|
||||
public static function monthly(
|
||||
DateTimeInterface|string|int|null $start = null,
|
||||
DateTimeInterface|string|int|null $end = null,
|
||||
?int $recurrences = null,
|
||||
?int $anchorDay = null,
|
||||
OverflowMode $mode = OverflowMode::AnchorDay,
|
||||
?int $options = null,
|
||||
): static {
|
||||
if ($anchorDay !== null && $mode !== OverflowMode::AnchorDay) {
|
||||
throw new InvalidArgumentException(
|
||||
'$anchorDay parameter must not be set for $mode OverflowMode::'.$mode->name,
|
||||
);
|
||||
}
|
||||
|
||||
if ($end !== null && $recurrences !== null) {
|
||||
throw new InvalidArgumentException(
|
||||
'You must specify $end or $recurrences but not both',
|
||||
);
|
||||
}
|
||||
|
||||
if (\is_int($start)) {
|
||||
$start = CarbonImmutable::createFromTimestamp($start);
|
||||
} elseif (\is_string($start)) {
|
||||
$start = CarbonImmutable::parse($start);
|
||||
}
|
||||
|
||||
$start ??= CarbonImmutable::now();
|
||||
|
||||
if (\is_int($end)) {
|
||||
$end = CarbonImmutable::createFromTimestamp($end);
|
||||
}
|
||||
|
||||
return (new static(
|
||||
$start,
|
||||
match ($mode) {
|
||||
OverflowMode::AnchorDay => CarbonInterval::monthWithAnchorDay(
|
||||
$anchorDay ?? $start->day,
|
||||
),
|
||||
OverflowMode::NoOverflow => CarbonInterval::monthNoOverflow(),
|
||||
OverflowMode::Overflow => CarbonInterval::month(),
|
||||
},
|
||||
$end ?? $recurrences,
|
||||
))->setOptions($options ?? self::IMMUTABLE);
|
||||
}
|
||||
|
||||
public static function yearly(
|
||||
DateTimeInterface|string|int|null $start = null,
|
||||
DateTimeInterface|string|int|null $end = null,
|
||||
?int $recurrences = null,
|
||||
?int $anchorDay = null,
|
||||
OverflowMode $mode = OverflowMode::AnchorDay,
|
||||
?int $options = null,
|
||||
): static {
|
||||
if ($anchorDay !== null && $mode !== OverflowMode::AnchorDay) {
|
||||
throw new InvalidArgumentException(
|
||||
'$anchorDay parameter must not be set for $mode OverflowMode::'.$mode->name,
|
||||
);
|
||||
}
|
||||
|
||||
if ($end !== null && $recurrences !== null) {
|
||||
throw new InvalidArgumentException(
|
||||
'You must specify $end or $recurrences but not both',
|
||||
);
|
||||
}
|
||||
|
||||
if (\is_int($start)) {
|
||||
$start = CarbonImmutable::createFromTimestamp($start);
|
||||
} elseif (\is_string($start)) {
|
||||
$start = CarbonImmutable::parse($start);
|
||||
}
|
||||
|
||||
$start ??= CarbonImmutable::now();
|
||||
|
||||
if (\is_int($end)) {
|
||||
$end = CarbonImmutable::createFromTimestamp($end);
|
||||
}
|
||||
|
||||
return (new static(
|
||||
$start,
|
||||
match ($mode) {
|
||||
OverflowMode::AnchorDay => CarbonInterval::yearWithAnchorDay(
|
||||
$anchorDay ?? $start->day,
|
||||
),
|
||||
OverflowMode::NoOverflow => CarbonInterval::yearNoOverflow(),
|
||||
OverflowMode::Overflow => CarbonInterval::month(),
|
||||
},
|
||||
$end ?? $recurrences,
|
||||
))->setOptions($options ?? self::IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given interval contains non-zero value of any time unit.
|
||||
*/
|
||||
@@ -695,20 +785,6 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
}
|
||||
}
|
||||
|
||||
if ($raw === null && isset($sortedArguments['start'])) {
|
||||
$end = $sortedArguments['end'] ?? max(1, $sortedArguments['recurrences'] ?? 1);
|
||||
|
||||
if (\is_float($end)) {
|
||||
$end = $end === INF ? PHP_INT_MAX : (int) round($end);
|
||||
}
|
||||
|
||||
$raw = [
|
||||
$sortedArguments['start'],
|
||||
$sortedArguments['interval'] ?? CarbonInterval::day(),
|
||||
$end,
|
||||
];
|
||||
}
|
||||
|
||||
$this->setFromAssociativeArray($sortedArguments);
|
||||
|
||||
if ($this->startDate === null) {
|
||||
@@ -1250,13 +1326,7 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
$self = $this->copyIfImmutable();
|
||||
$self->carbonRecurrences = $recurrences === INF ? INF : (int) $recurrences;
|
||||
|
||||
if (!$self->hasFilter(static::RECURRENCES_FILTER)) {
|
||||
return $self->addFilter(static::RECURRENCES_FILTER);
|
||||
}
|
||||
|
||||
$self->handleChangedParameters();
|
||||
|
||||
return $self;
|
||||
return self::addFilterOrHandleChangedParameters($self, static::RECURRENCES_FILTER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1282,6 +1352,8 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
$self = $self->toggleOptions(static::EXCLUDE_START_DATE, !$inclusive);
|
||||
}
|
||||
|
||||
$self->syncNativePeriod();
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
@@ -1301,22 +1373,38 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
throw new InvalidPeriodDateException('Invalid end date.');
|
||||
}
|
||||
|
||||
if (!$date) {
|
||||
return $this->removeFilter(static::END_DATE_FILTER);
|
||||
}
|
||||
// ::make() is responsible for converting strings to DateTimeInterface objects
|
||||
\assert(!\is_string($date));
|
||||
|
||||
$self = $this->copyIfImmutable();
|
||||
|
||||
if (!$date) {
|
||||
$self = $self->removeFilter(static::END_DATE_FILTER);
|
||||
$self->syncNativePeriod();
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
\assert($date instanceof DateTimeInterface);
|
||||
|
||||
$self->endDate = $date;
|
||||
|
||||
if (
|
||||
$self->startDate !== null
|
||||
&& $self->dateInterval !== null
|
||||
&& !$self->dateInterval->invert
|
||||
&& $self->startDate > $self->endDate
|
||||
) {
|
||||
$self->dateInterval->invert = 1;
|
||||
}
|
||||
|
||||
if ($inclusive !== null) {
|
||||
$self = $self->toggleOptions(static::EXCLUDE_END_DATE, !$inclusive);
|
||||
}
|
||||
|
||||
if (!$self->hasFilter(static::END_DATE_FILTER)) {
|
||||
return $self->addFilter(static::END_DATE_FILTER);
|
||||
}
|
||||
$self = self::addFilterOrHandleChangedParameters($self, static::END_DATE_FILTER);
|
||||
|
||||
$self->handleChangedParameters();
|
||||
$self->syncNativePeriod();
|
||||
|
||||
return $self;
|
||||
}
|
||||
@@ -2286,11 +2374,7 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
'options' => $this->setOptions(...),
|
||||
'recurrences' => $this->setRecurrences(...),
|
||||
'current' => function (mixed $current): void {
|
||||
if (!($current instanceof CarbonInterface)) {
|
||||
$current = $this->resolveCarbon($current);
|
||||
}
|
||||
|
||||
$this->carbonCurrent = $current;
|
||||
$this->carbonCurrent = $this->carbonOrResolve($current);
|
||||
},
|
||||
'start' => 'startDate',
|
||||
'interval' => $this->setDateInterval(...),
|
||||
@@ -2409,7 +2493,7 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->dateInterval->invert ? $current > $this->endDate : $current < $this->endDate) {
|
||||
if ($this->dateInterval->invert ? ($current > $this->endDate) : ($current < $this->endDate)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2440,6 +2524,28 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
$this->validationResult = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the native DatePeriod properties with the current state.
|
||||
*/
|
||||
protected function syncNativePeriod(): void
|
||||
{
|
||||
if (\PHP_VERSION_ID < 80200) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// Default interval if not set (matches __construct logic)
|
||||
$interval = $this->dateInterval ?? \Carbon\CarbonInterval::day();
|
||||
|
||||
// Reinitialize the parent DatePeriod to update $start, $end, etc.
|
||||
// This mirrors the logic in __construct and initializeSerialization.
|
||||
parent::__construct(
|
||||
$this->startDate,
|
||||
$interval,
|
||||
$this->endDate ?? max(1, min(2147483639, $this->recurrences ?? 1)),
|
||||
$this->options ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate current date and stop iteration when necessary.
|
||||
*
|
||||
@@ -2510,7 +2616,10 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
$attempts = 0;
|
||||
|
||||
do {
|
||||
$this->carbonCurrent = $this->carbonCurrent->add($this->dateInterval);
|
||||
$this->carbonCurrent = $this->carbonCurrent->add(
|
||||
$this->dateInterval,
|
||||
$this->dateInterval->getStep() && $this->dateInterval->invert ? -1 : 1,
|
||||
);
|
||||
|
||||
$this->validationResult = null;
|
||||
|
||||
@@ -2563,6 +2672,13 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
: static::create($period, ...$arguments);
|
||||
}
|
||||
|
||||
private function carbonOrResolve(mixed $dateTime): CarbonInterface
|
||||
{
|
||||
return $dateTime instanceof CarbonInterface
|
||||
? $dateTime
|
||||
: $this->resolveCarbon($dateTime);
|
||||
}
|
||||
|
||||
private function orderCouple($first, $second): array
|
||||
{
|
||||
return $first > $second ? [$second, $first] : [$first, $second];
|
||||
@@ -2715,4 +2831,17 @@ class CarbonPeriod extends DatePeriodBase implements Countable, JsonSerializable
|
||||
);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
private static function addFilterOrHandleChangedParameters(
|
||||
self $period,
|
||||
array|callable|string $filter,
|
||||
): self {
|
||||
if (!$period->hasFilter($filter)) {
|
||||
return $period->addFilter($filter);
|
||||
}
|
||||
|
||||
$period->handleChangedParameters();
|
||||
|
||||
return $period;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,33 +16,40 @@ namespace Carbon\Exceptions;
|
||||
use RuntimeException as BaseRuntimeException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class ImmutableException extends BaseRuntimeException implements RuntimeException
|
||||
{
|
||||
/**
|
||||
* The value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $value;
|
||||
protected string $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $value the immutable type/value
|
||||
* @param string $value the immutable message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*
|
||||
* @deprecated Use ImmutableException::fromClass() or ImmutableException::fromMethod() to construct an
|
||||
* ImmutableException instance.
|
||||
*/
|
||||
public function __construct($value, $code = 0, ?Throwable $previous = null)
|
||||
public function __construct($message, int $code = 0, ?Throwable $previous = null, ?string $value = null)
|
||||
{
|
||||
$this->value = $value;
|
||||
parent::__construct("$value is immutable.", $code, $previous);
|
||||
$this->value ??= $value ?? $message;
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
public static function fromClass(string $class, int $code = 0, ?Throwable $previous = null): self
|
||||
{
|
||||
return new self("$class class is immutable.", $code, $previous, "$class class");
|
||||
}
|
||||
|
||||
public static function fromMethod(string $class, string $method, int $code = 0, ?Throwable $previous = null): self
|
||||
{
|
||||
return new self("$method not allowed on $class.", $code, $previous, "$class::$method method");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
|
||||
@@ -14,6 +14,7 @@ declare(strict_types=1);
|
||||
namespace Carbon;
|
||||
|
||||
use Closure;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
@@ -70,7 +71,7 @@ use Throwable;
|
||||
* the types of objects that can be built, for instance:
|
||||
* @method array getAvailableLocales() Returns the list of internally available locales and already loaded custom locales.
|
||||
* (It will ignore custom translator dynamic loading.)
|
||||
* @method Language[] getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native
|
||||
* @method array getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native
|
||||
* name, region and variant of the locale.
|
||||
* @method array getDays() Get the days of the week.
|
||||
* @method ?string getFallbackLocale() Get the fallback locale.
|
||||
@@ -553,16 +554,13 @@ class Factory
|
||||
|
||||
/**
|
||||
* Set a Carbon instance (real or mock) to be returned when a "now"
|
||||
* instance is created. The provided instance will be returned
|
||||
* instance is created. The provided instance will be returned
|
||||
* specifically under the following conditions:
|
||||
* - A call to the static now() method, ex. Carbon::now()
|
||||
* - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)
|
||||
* - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now')
|
||||
* - When a string containing the desired time is passed to Carbon::parse().
|
||||
*
|
||||
* Note the timezone parameter was left out of the examples above and
|
||||
* has no affect as the mock value will be returned regardless of its value.
|
||||
*
|
||||
* Only the moment is mocked with setTestNow(), the timezone will still be the one passed
|
||||
* as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()).
|
||||
*
|
||||
@@ -576,14 +574,14 @@ class Factory
|
||||
public function setTestNow(mixed $testNow = null): void
|
||||
{
|
||||
$this->useTimezoneFromTestNow = false;
|
||||
$this->testNow = $testNow instanceof self || $testNow instanceof Closure
|
||||
$this->testNow = $testNow instanceof Closure
|
||||
? $testNow
|
||||
: $this->make($testNow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Carbon instance (real or mock) to be returned when a "now"
|
||||
* instance is created. The provided instance will be returned
|
||||
* instance is created. The provided instance will be returned
|
||||
* specifically under the following conditions:
|
||||
* - A call to the static now() method, ex. Carbon::now()
|
||||
* - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)
|
||||
@@ -696,11 +694,21 @@ class Factory
|
||||
}
|
||||
|
||||
if (!($testNow instanceof CarbonInterface)) {
|
||||
$timezone ??= $this->useTimezoneFromTestNow ? $testNow->getTimezone() : null;
|
||||
$timezone ??= $this->useTimezoneFromTestNow
|
||||
? $testNow->getTimezone()
|
||||
: new CarbonTimeZone(date_default_timezone_get());
|
||||
$testNow = $this->__call('instance', [$testNow, $timezone]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($testNow !== null && $timezone === null) {
|
||||
if ($testNow instanceof DateTime) {
|
||||
$testNow = clone $testNow;
|
||||
}
|
||||
|
||||
$testNow = $testNow->setTimezone(date_default_timezone_get());
|
||||
}
|
||||
|
||||
return $testNow;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
* the types of objects that can be built, for instance:
|
||||
* @method array getAvailableLocales() Returns the list of internally available locales and already loaded custom locales.
|
||||
* (It will ignore custom translator dynamic loading.)
|
||||
* @method Language[] getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native
|
||||
* @method array getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native
|
||||
* name, region and variant of the locale.
|
||||
* @method array getDays() Get the days of the week.
|
||||
* @method ?string getFallbackLocale() Get the fallback locale.
|
||||
|
||||
21
plugins/vendor/nesbot/carbon/src/Carbon/OverflowMode.php
vendored
Normal file
21
plugins/vendor/nesbot/carbon/src/Carbon/OverflowMode.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of the Carbon package.
|
||||
*
|
||||
* (c) Brian Nesbitt <brian@nesbot.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Carbon;
|
||||
|
||||
enum OverflowMode
|
||||
{
|
||||
case AnchorDay;
|
||||
case NoOverflow;
|
||||
case Overflow;
|
||||
}
|
||||
1792
plugins/vendor/nesbot/carbon/src/Carbon/Traits/Date.php
vendored
1792
plugins/vendor/nesbot/carbon/src/Carbon/Traits/Date.php
vendored
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Traits;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Carbon\Callback;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
@@ -28,12 +29,12 @@ trait IntervalStep
|
||||
*
|
||||
* @var Closure|null
|
||||
*/
|
||||
protected $step;
|
||||
protected ?Closure $step = null;
|
||||
|
||||
/**
|
||||
* Get the dynamic step in use.
|
||||
*
|
||||
* @return Closure
|
||||
* @return Closure|null
|
||||
*/
|
||||
public function getStep(): ?Closure
|
||||
{
|
||||
@@ -64,8 +65,7 @@ trait IntervalStep
|
||||
*/
|
||||
public function convertDate(DateTimeInterface $dateTime, bool $negated = false): CarbonInterface
|
||||
{
|
||||
/** @var CarbonInterface $carbonDate */
|
||||
$carbonDate = $dateTime instanceof CarbonInterface ? $dateTime : $this->resolveCarbon($dateTime);
|
||||
$carbonDate = $this->carbonOrResolve($dateTime);
|
||||
|
||||
if ($this->step) {
|
||||
$carbonDate = Callback::parameter($this->step, $carbonDate->avoidMutation());
|
||||
@@ -91,4 +91,23 @@ trait IntervalStep
|
||||
|
||||
return Carbon::instance($dateTime);
|
||||
}
|
||||
|
||||
private function carbonOrResolve(mixed $dateTime): CarbonInterface
|
||||
{
|
||||
return $dateTime instanceof CarbonInterface
|
||||
? $dateTime
|
||||
: $this->resolveCarbon($dateTime);
|
||||
}
|
||||
|
||||
private function checkNoStepIsDefined(string $method): void
|
||||
{
|
||||
if ($this->step !== null) {
|
||||
$chunks = explode('::', $method, 2);
|
||||
$method = $chunks[1] ?? $method;
|
||||
|
||||
throw new BadMethodCallException(
|
||||
"->$method() cannot be called on an interval with a step",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ trait Localization
|
||||
* @param string|null $locale
|
||||
* @param string ...$fallbackLocales
|
||||
*
|
||||
* @return $this|string
|
||||
* @return ($locale is null ? string : static)
|
||||
*/
|
||||
public function locale(?string $locale = null, string ...$fallbackLocales): static|string
|
||||
{
|
||||
@@ -407,7 +407,16 @@ trait Localization
|
||||
$translator = static::getTranslator();
|
||||
|
||||
if (method_exists($translator, 'setFallbackLocales')) {
|
||||
$translator->setFallbackLocales([$locale]);
|
||||
$fallbackLocales = [$locale];
|
||||
|
||||
if (
|
||||
method_exists($translator, 'getFallbackLocales')
|
||||
&& $fallbackLocales === $translator->getFallbackLocales()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$translator->setFallbackLocales($fallbackLocales);
|
||||
|
||||
if ($translator instanceof Translator) {
|
||||
$preferredLocale = $translator->getLocale();
|
||||
|
||||
@@ -30,16 +30,13 @@ trait Test
|
||||
|
||||
/**
|
||||
* Set a Carbon instance (real or mock) to be returned when a "now"
|
||||
* instance is created. The provided instance will be returned
|
||||
* instance is created. The provided instance will be returned
|
||||
* specifically under the following conditions:
|
||||
* - A call to the static now() method, ex. Carbon::now()
|
||||
* - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)
|
||||
* - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now')
|
||||
* - When a string containing the desired time is passed to Carbon::parse().
|
||||
*
|
||||
* Note the timezone parameter was left out of the examples above and
|
||||
* has no affect as the mock value will be returned regardless of its value.
|
||||
*
|
||||
* Only the moment is mocked with setTestNow(), the timezone will still be the one passed
|
||||
* as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()).
|
||||
*
|
||||
@@ -57,7 +54,7 @@ trait Test
|
||||
|
||||
/**
|
||||
* Set a Carbon instance (real or mock) to be returned when a "now"
|
||||
* instance is created. The provided instance will be returned
|
||||
* instance is created. The provided instance will be returned
|
||||
* specifically under the following conditions:
|
||||
* - A call to the static now() method, ex. Carbon::now()
|
||||
* - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)
|
||||
|
||||
@@ -20,10 +20,12 @@ use Carbon\Exceptions\InvalidFormatException;
|
||||
use Carbon\Exceptions\InvalidIntervalException;
|
||||
use Carbon\Exceptions\UnitException;
|
||||
use Carbon\Exceptions\UnsupportedUnitException;
|
||||
use Carbon\OverflowMode;
|
||||
use Carbon\Unit;
|
||||
use Closure;
|
||||
use DateInterval;
|
||||
use DateMalformedStringException;
|
||||
use InvalidArgumentException;
|
||||
use ReturnTypeWillChange;
|
||||
|
||||
/**
|
||||
@@ -244,12 +246,13 @@ trait Units
|
||||
*
|
||||
* @param Unit|int|string|DateInterval|Closure|CarbonConverterInterface $unit
|
||||
* @param Unit|int|float|string $value
|
||||
* @param bool|null $overflow
|
||||
* @param OverflowMode|bool|null $overflow
|
||||
* @param int|null $anchorDay
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function add($unit, $value = 1, ?bool $overflow = null): static
|
||||
public function add($unit, $value = 1, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null): static
|
||||
{
|
||||
$unit = Unit::toNameIfUnit($unit);
|
||||
$value = Unit::toNameIfUnit($value);
|
||||
@@ -263,7 +266,14 @@ trait Units
|
||||
}
|
||||
|
||||
if ($unit instanceof Closure) {
|
||||
$result = $this->resolveCarbon($unit($this, false));
|
||||
$inverted = ($value < 0);
|
||||
$result = $this;
|
||||
|
||||
self::disallowDecimalPart($value);
|
||||
|
||||
for ($i = abs($value); $i > 0; $i--) {
|
||||
$result = $result->resolveCarbon($unit($result, $inverted));
|
||||
}
|
||||
|
||||
if ($this !== $result && $this->isMutable()) {
|
||||
return $this->modify($result->rawFormat('Y-m-d H:i:s.u e O'));
|
||||
@@ -280,16 +290,22 @@ trait Units
|
||||
[$value, $unit] = [$unit, $value];
|
||||
}
|
||||
|
||||
return $this->addUnit((string) $unit, $value, $overflow);
|
||||
return $this->addUnit((string) $unit, $value, $overflow, $anchorDay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given units to the current instance.
|
||||
*/
|
||||
public function addUnit(Unit|string $unit, $value = 1, ?bool $overflow = null): static
|
||||
{
|
||||
public function addUnit(
|
||||
Unit|string $unit,
|
||||
$value = 1,
|
||||
OverflowMode|bool|null $overflow = null,
|
||||
?int $anchorDay = null,
|
||||
): static {
|
||||
$unit = Unit::toName($unit);
|
||||
|
||||
$overflow = $this->getOverflowMode($overflow, $anchorDay);
|
||||
|
||||
$originalArgs = \func_get_args();
|
||||
|
||||
$date = $this;
|
||||
@@ -311,8 +327,13 @@ trait Units
|
||||
$value *= $factor;
|
||||
}
|
||||
|
||||
if ($overflow === OverflowMode::AnchorDay) {
|
||||
$anchorDay ??= $date->day;
|
||||
$overflow = OverflowMode::NoOverflow;
|
||||
}
|
||||
|
||||
if ($unit === 'weekday') {
|
||||
$weekendDays = $this->transmitFactory(static fn () => static::getWeekendDays());
|
||||
$weekendDays = $this->transmitFactory(static::getWeekendDays(...));
|
||||
|
||||
if ($weekendDays !== [static::SATURDAY, static::SUNDAY]) {
|
||||
$absoluteValue = abs($value);
|
||||
@@ -337,10 +358,9 @@ trait Units
|
||||
} elseif ($canOverflow = (\in_array($unit, [
|
||||
'month',
|
||||
'year',
|
||||
]) && ($overflow === false || (
|
||||
]) && ($overflow === OverflowMode::NoOverflow || (
|
||||
$overflow === null &&
|
||||
($ucUnit = ucfirst($unit).'s') &&
|
||||
!($this->{'local'.$ucUnit.'Overflow'} ?? static::{'shouldOverflow'.$ucUnit}())
|
||||
!$this->shouldUnitOverflow($unit)
|
||||
)))) {
|
||||
$day = $date->day;
|
||||
}
|
||||
@@ -355,10 +375,16 @@ trait Units
|
||||
try {
|
||||
$date = self::rawAddUnit($date, $unit, $value);
|
||||
|
||||
if (isset($timeString)) {
|
||||
$date = $date?->setTimeFromTimeString($timeString);
|
||||
} elseif (isset($canOverflow, $day) && $canOverflow && $day !== $date?->day) {
|
||||
$date = $date?->modify('last day of previous month');
|
||||
if ($date !== null) {
|
||||
if (isset($timeString)) {
|
||||
$date = $date->setTimeFromTimeString($timeString);
|
||||
} elseif (isset($canOverflow, $day) && $canOverflow && $day !== $date->day) {
|
||||
$date = $date->modify('last day of previous month');
|
||||
}
|
||||
|
||||
if ($anchorDay !== null) {
|
||||
$date = $date->setAnchorDay($anchorDay);
|
||||
}
|
||||
}
|
||||
} catch (DateMalformedStringException|InvalidFormatException|UnsupportedUnitException $exception) {
|
||||
$date = null;
|
||||
@@ -374,9 +400,13 @@ trait Units
|
||||
/**
|
||||
* Subtract given units to the current instance.
|
||||
*/
|
||||
public function subUnit(Unit|string $unit, $value = 1, ?bool $overflow = null): static
|
||||
{
|
||||
return $this->addUnit($unit, -$value, $overflow);
|
||||
public function subUnit(
|
||||
Unit|string $unit,
|
||||
$value = 1,
|
||||
OverflowMode|bool|null $overflow = null,
|
||||
?int $anchorDay = null,
|
||||
): static {
|
||||
return $this->addUnit($unit, -$value, $overflow, $anchorDay);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,12 +426,13 @@ trait Units
|
||||
*
|
||||
* @param Unit|int|string|DateInterval|Closure|CarbonConverterInterface $unit
|
||||
* @param Unit|int|float|string $value
|
||||
* @param bool|null $overflow
|
||||
* @param OverflowMode|bool|null $overflow
|
||||
* @param int|null $anchorDay
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function sub($unit, $value = 1, ?bool $overflow = null): static
|
||||
public function sub($unit, $value = 1, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null): static
|
||||
{
|
||||
$unit = Unit::toNameIfUnit($unit);
|
||||
$value = Unit::toNameIfUnit($value);
|
||||
@@ -415,7 +446,14 @@ trait Units
|
||||
}
|
||||
|
||||
if ($unit instanceof Closure) {
|
||||
$result = $this->resolveCarbon($unit($this, true));
|
||||
$inverted = ($value < 0);
|
||||
$result = $this;
|
||||
|
||||
self::disallowDecimalPart($value);
|
||||
|
||||
for ($i = abs($value); $i > 0; $i--) {
|
||||
$result = $result->resolveCarbon($unit($result, !$inverted));
|
||||
}
|
||||
|
||||
if ($this !== $result && $this->isMutable()) {
|
||||
return $this->modify($result->rawFormat('Y-m-d H:i:s.u e O'));
|
||||
@@ -432,7 +470,7 @@ trait Units
|
||||
[$value, $unit] = [$unit, $value];
|
||||
}
|
||||
|
||||
return $this->addUnit((string) $unit, -(float) $value, $overflow);
|
||||
return $this->addUnit((string) $unit, -(float) $value, $overflow, $anchorDay);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,31 +480,163 @@ trait Units
|
||||
*
|
||||
* @param Unit|int|string|DateInterval $unit
|
||||
* @param Unit|int|float|string $value
|
||||
* @param bool|null $overflow
|
||||
* @param OverflowMode|bool|null $overflow
|
||||
* @param int|null $anchorDay
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function subtract($unit, $value = 1, ?bool $overflow = null): static
|
||||
public function subtract($unit, $value = 1, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null): static
|
||||
{
|
||||
if (\is_string($unit) && \func_num_args() === 1) {
|
||||
$unit = CarbonInterval::make($unit, [], true);
|
||||
}
|
||||
|
||||
return $this->sub($unit, $value, $overflow);
|
||||
return $this->sub($unit, $value, $overflow, $anchorDay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given amount of time to the current date.
|
||||
*
|
||||
* @SuppressWarnings(ExcessiveParameterList)
|
||||
*/
|
||||
private function doPlus(
|
||||
int $years = 0,
|
||||
int $months = 0,
|
||||
int|float $weeks = 0,
|
||||
int|float $days = 0,
|
||||
int|float $hours = 0,
|
||||
int|float $minutes = 0,
|
||||
int|float $seconds = 0,
|
||||
int|float $microseconds = 0,
|
||||
OverflowMode|bool|null $overflow = null,
|
||||
?int $anchorDay = null,
|
||||
): static {
|
||||
return $this->addUnit(Unit::Year, $years, $overflow, $anchorDay)
|
||||
->addUnit(Unit::Month, $months, $overflow, $anchorDay)
|
||||
->add("
|
||||
$weeks weeks $days days
|
||||
$hours hours $minutes minutes $seconds seconds $microseconds microseconds
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract given amount of time to the current date.
|
||||
*
|
||||
* @SuppressWarnings(ExcessiveParameterList)
|
||||
*/
|
||||
private function doMinus(
|
||||
int $years = 0,
|
||||
int $months = 0,
|
||||
int|float $weeks = 0,
|
||||
int|float $days = 0,
|
||||
int|float $hours = 0,
|
||||
int|float $minutes = 0,
|
||||
int|float $seconds = 0,
|
||||
int|float $microseconds = 0,
|
||||
OverflowMode|bool|null $overflow = null,
|
||||
?int $anchorDay = null,
|
||||
): static {
|
||||
return $this->subUnit(Unit::Year, $years, $overflow, $anchorDay)
|
||||
->subUnit(Unit::Month, $months, $overflow, $anchorDay)
|
||||
->sub("
|
||||
$weeks weeks $days days
|
||||
$hours hours $minutes minutes $seconds seconds $microseconds microseconds
|
||||
");
|
||||
}
|
||||
|
||||
private function callPlusOrMinus(string $method, array $parameters): ?static
|
||||
{
|
||||
return match ($method) {
|
||||
'plus' => $this->doPlus(...$parameters),
|
||||
'minus' => $this->doMinus(...$parameters),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
private static function rawAddUnit(self $date, string $unit, int|float $value): ?static
|
||||
{
|
||||
try {
|
||||
$absoluteValue = abs($value);
|
||||
|
||||
return $date->rawAdd(
|
||||
CarbonInterval::fromString(abs($value)." $unit")->invert($value < 0),
|
||||
CarbonInterval::fromString(self::getNumberAsString($absoluteValue)." $unit")
|
||||
->invert($value < 0),
|
||||
);
|
||||
} catch (InvalidIntervalException $exception) {
|
||||
try {
|
||||
return $date->modify("$value $unit");
|
||||
return $date->modify(self::getNumberAsString($value)." $unit");
|
||||
} catch (InvalidFormatException) {
|
||||
throw new UnsupportedUnitException($unit, previous: $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function getNumberAsString(int|float $value): string
|
||||
{
|
||||
$stringValue = (string) $value;
|
||||
|
||||
if ($value < -1 || $value > 1) {
|
||||
if (str_contains($stringValue, 'E')) {
|
||||
return number_format($value, 0, '.', '');
|
||||
}
|
||||
|
||||
return $stringValue;
|
||||
}
|
||||
|
||||
if (str_contains($stringValue, 'E')) {
|
||||
return number_format($value, 14, '.', '');
|
||||
}
|
||||
|
||||
return $stringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current day of the instance to the passed value if it exits in the
|
||||
* current month, else set current day to the last day of the month.
|
||||
*/
|
||||
public function setAnchorDay(int $anchorDay): static
|
||||
{
|
||||
if ($anchorDay < 1) {
|
||||
throw new InvalidArgumentException('$anchorDay must be greater than 0');
|
||||
}
|
||||
|
||||
return $this->day(min($anchorDay, $this->daysInMonth));
|
||||
}
|
||||
|
||||
private static function disallowDecimalPart(mixed $value): void
|
||||
{
|
||||
if (((float) $value) !== ((float) (int) $value)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Interval objects cannot be multiplied by a non-integer value.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function getOverflowMode(
|
||||
OverflowMode|bool|null $overflow = null,
|
||||
?int $anchorDay = null,
|
||||
): ?OverflowMode {
|
||||
if ($anchorDay !== null) {
|
||||
$overflow ??= OverflowMode::AnchorDay;
|
||||
|
||||
if ($overflow !== OverflowMode::AnchorDay) {
|
||||
throw new InvalidArgumentException(
|
||||
'$anchorDay can be set only $overflow = OverflowMode::AnchorDay',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return match ($overflow) {
|
||||
true => OverflowMode::Overflow,
|
||||
false => OverflowMode::NoOverflow,
|
||||
default => $overflow,
|
||||
};
|
||||
}
|
||||
|
||||
private function shouldUnitOverflow(string $unit): bool
|
||||
{
|
||||
$ucUnit = ucfirst($unit).'s';
|
||||
|
||||
return $this->{'local'.$ucUnit.'Overflow'} ?? static::{'shouldOverflow'.$ucUnit}();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class TranslatorImmutable extends Translator
|
||||
private function disallowMutation($method)
|
||||
{
|
||||
if ($this->constructed) {
|
||||
throw new ImmutableException($method.' not allowed on '.static::class);
|
||||
throw ImmutableException::fromMethod(static::class, $method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user