Compare commits

...

372 commits

Author SHA1 Message Date
16a8172c37 Merge pull request 'Accessibility: Use different id values for options' (#1597) from heluecht/friendica-addons:accessibility into develop
Reviewed-on: friendica/friendica-addons#1597
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-28 23:09:04 +01:00
16127854dd Accessibility: Use different id values for options 2025-01-28 20:27:52 +00:00
7e1bcbdedb Merge pull request 'Add additional theme-filter for disabling/enabling divs.' (#1596) from jakob/friendica-addons:fix-saml-display-settings into develop
Reviewed-on: friendica/friendica-addons#1596
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-25 14:06:07 +01:00
Jakobus Schürz
8384b74696 add condition for selected theme 2025-01-25 08:05:32 -05:00
c5e3d1f047 Merge pull request 'Issue 14692: Avoid loop situation' (#1595) from heluecht/friendica-addons:issue-14692 into develop
Reviewed-on: friendica/friendica-addons#1595
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-25 13:59:52 +01:00
cbfcfb3349 Issue 14692: Avoid loop situation 2025-01-25 02:44:54 +00:00
cdba300c7b Merge pull request 'Replace Logger class with DI::logger()' (#1594) from Art4/friendica-addons:replace-logger-with-loggerinterface into develop
Reviewed-on: friendica/friendica-addons#1594
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-24 14:34:43 +01:00
Art4
4c8c262b07 fix in googlemaps addon 2025-01-24 12:10:58 +00:00
Art4
dd775645d4 Replace call for Logger with DI::logger() in wppost addon 2025-01-24 11:58:32 +00:00
Art4
e4d14cab62 Replace call for Logger with DI::logger() in twitter addon 2025-01-24 11:58:10 +00:00
Art4
a7b26f6453 Replace call for Logger with DI::logger() in tesseract addon 2025-01-24 11:57:34 +00:00
Art4
763c5026f2 Replace call for Logger with DI::logger() in tumblr addon 2025-01-24 11:57:12 +00:00
Art4
bfdccb451c Replace call for Logger with DI::logger() in statusnet addon 2025-01-24 11:56:45 +00:00
Art4
ac6c1d7a49 Replace call for Logger with DI::logger() in saml addon 2025-01-24 11:56:29 +00:00
Art4
32a3160445 Replace call for Logger with DI::logger() in randplace addon 2025-01-24 11:56:09 +00:00
Art4
d50650b8cf Replace call for Logger with DI::logger() in pumpio addon 2025-01-24 11:55:13 +00:00
Art4
e32ba1ce7b Replace call for Logger with DI::logger() in public_server addon 2025-01-24 11:54:34 +00:00
Art4
119ba0a78e Replace call for Logger with DI::logger() in pnut addon 2025-01-24 11:48:21 +00:00
Art4
469d3e6d61 Replace call for Logger with DI::logger() in planets addon 2025-01-24 11:47:40 +00:00
Art4
757d72c360 Replace call for Logger with DI::logger() in openstreetmap addon 2025-01-24 11:47:24 +00:00
Art4
9ceff8f592 Replace call for Logger with DI::logger() in nominatim addon 2025-01-24 11:46:58 +00:00
Art4
9a91bae363 Replace call for Logger with DI::logger() in mailstream addon 2025-01-24 11:46:30 +00:00
Art4
9ed02034f1 Replace call for Logger with DI::logger() in ljpost addon 2025-01-24 11:46:04 +00:00
Art4
f08750199d Replace call for Logger with DI::logger() in libertree addon 2025-01-24 11:45:25 +00:00
Art4
a488f25131 Replace call for Logger with DI::logger() in ldapauth addon 2025-01-24 11:44:48 +00:00
Art4
5d51c5b56e Replace call for Logger with DI::logger() in js_upload addon 2025-01-24 11:42:25 +00:00
Art4
5002318089 Replace call for Logger with DI::logger() in ijpost addon 2025-01-24 11:41:02 +00:00
Art4
15a951235f Replace call for Logger with DI::logger() in ifttt addon 2025-01-24 11:40:32 +00:00
Art4
e7755584cb Replace call for Logger with DI::logger() in geocoordinates addon 2025-01-24 11:40:12 +00:00
Art4
1db552ead9 Replace call for Logger with DI::logger() in dwpost addon 2025-01-24 11:39:11 +00:00
Art4
b38c2d18be Replace call for Logger with DI::logger() in discourse addon 2025-01-24 11:38:48 +00:00
Art4
4881e6004a Replace call for Logger with DI::logger() in diaspora addon 2025-01-24 11:38:27 +00:00
Art4
1d1a00df27 Replace call for Logger with DI::logger() in cld addon 2025-01-24 11:37:58 +00:00
Art4
77ebaca281 Replace call for Logger with DI::logger() in ratioed addon 2025-01-24 11:37:28 +00:00
Art4
d78ea50516 Replace call for Logger with DI::logger() in bluesky addon 2025-01-24 11:36:23 +00:00
Art4
41f280f0c7 Replace call for Logger with DI::logger() in blockbot addon 2025-01-24 11:34:33 +00:00
Art4
4310c1355d Replace call for Logger with DI::logger() 2025-01-24 10:53:01 +00:00
1cc5a6688e Merge pull request 'rework saml addon' (#1588) from jakob/friendica-addons:fix-saml-display-settings into develop
Reviewed-on: friendica/friendica-addons#1588
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-23 14:31:49 +01:00
Jakobus Schürz
0b4aaac9fd translation for saml-hint 2025-01-23 14:31:49 +01:00
Jakobus Schürz
c506367273 replace password-handling with hint
also add hint to email-field
2025-01-23 14:31:49 +01:00
Jakobus Schürz
792f50f835 fix view in vier and frio 2025-01-23 14:31:49 +01:00
Jakobus Schürz
2b5764c132 rework saml addon
fix #1587
remove css-side hiding of elements, which was broken.
remove them or make them readonly via javascript
2025-01-23 14:31:49 +01:00
69e75ef88b Merge pull request 'Check PHPStan in addons' (#1592) from Art4/friendica-addons:fix-phpstan-error into develop
Reviewed-on: friendica/friendica-addons#1592
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-23 14:29:59 +01:00
Art4
7a7940a8ed Fix PHPStan errors 2025-01-23 08:29:13 -05:00
Art4
2741227bfa Add phpstan in woodpacker 2025-01-23 08:27:48 -05:00
13cffd76db Merge pull request 'Clean up phpstan warning' (#1591) from mexon/friendica-addons:mat/ratioed-fix-warning into develop
Reviewed-on: friendica/friendica-addons#1591
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-23 14:26:41 +01:00
Matthew Exon
0d0aae36cd Clean up phpstan warning 2025-01-23 08:26:23 -05:00
28d3041694 Merge pull request 'Fix codestyle' (#1590) from heluecht/friendica-addons:ratiod-fix into develop
Reviewed-on: friendica/friendica-addons#1590
2025-01-22 08:49:57 +01:00
cb70a4eaff Fix codestyle 2025-01-18 15:25:50 +00:00
0c96d0f4bb Merge pull request 'Ratioed: add statistics about reply likes and reply guy score' (#1589) from mexon/friendica-addons:mat/reply-guy-score into develop
Reviewed-on: friendica/friendica-addons#1589
2025-01-16 06:43:41 +01:00
Matthew Exon
ee8c852d38 Ratioed: remove action buttons 2025-01-15 19:33:11 +01:00
Matthew Exon
807598dbd0 Ratioed: wrap long lines 2025-01-15 19:32:55 +01:00
Matthew Exon
8ba4cd5f61 Ratioed: bump version number 2025-01-12 14:33:21 +01:00
Matthew Exon
3441c9bd0e Ratioed: add statistics about reply likes and reply guy score 2025-01-12 14:33:21 +01:00
44d2079da2 Merge pull request 'Ratioed: several fixes to functionality' (#1586) from mexon/friendica-addons:mat/ratioed-fixes into develop
Reviewed-on: friendica/friendica-addons#1586
2025-01-12 12:03:00 +01:00
Matthew Exon
b360b553ed Ratioed: remove actions 2025-01-12 12:03:00 +01:00
Matthew Exon
46b3836720 Ratioed: remove create user button 2025-01-12 12:03:00 +01:00
Matthew Exon
81639ff615 Ratioed: fix sorting by columns 2025-01-12 12:03:00 +01:00
Matthew Exon
d495810b2d Ratioed: allow both sorting directions 2025-01-12 12:03:00 +01:00
Matthew Exon
2ef9cb8add Ratioed: fill in zeroes for empty values 2025-01-12 12:03:00 +01:00
Matthew Exon
8e65141cb5 Ratioed: bump version number 2025-01-12 12:03:00 +01:00
Matthew Exon
d034e311cb Ratioed: add help link 2025-01-12 12:03:00 +01:00
db10da2f02 Merge pull request '[CI] Fix releaser' (#1585) from nupplaPhil/friendica-addons:ci/stable_pick into develop
Reviewed-on: friendica/friendica-addons#1585
2025-01-02 08:37:19 +01:00
995e81e951
[CI] Fix releaser 2025-01-01 20:22:42 +01:00
cb2ab0684e Merge branch 'stable' into develop 2024-12-31 18:57:15 +01:00
3b079aef8d Merge pull request 'Bluesky: Preparation to be able to fetch AT links' (#1584) from heluecht/friendica-addons:bluesky-fetch-uri into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1584
2024-12-28 22:23:22 +01:00
9e1f7dc468 Bluesky: Preparation to be able to fetch AT links 2024-12-28 22:23:22 +01:00
Art4
5f557ed0ab Merge branch '2024.09-rc' into merge-2024.09-rc-into-develop 2024-12-23 10:15:53 +00:00
7172695705 Merge pull request '[CI] Fix codecov' (#1583) from nupplaPhil/friendica-addons:bug/ci into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1583
2024-12-23 07:19:43 +01:00
5f50fd2498
Fix codecov token env 2024-12-22 08:54:51 +01:00
0697f078f1
[CI] Fix codecov 2024-12-22 08:38:17 +01:00
f2a9eb151d Merge pull request 'Small bug fix' (#1566) from loma-one/friendica-addons:2024.09-rc into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1566
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-21 21:57:57 +01:00
16e06f9b2b Small bug fix
Close the Uni-Code Smilies link with a ’;’
2024-12-21 15:56:34 -05:00
d0e8b2b4be Merge pull request 'Bluesky: Handle problems when uploading pictures' (#1582) from heluecht/friendica-addons:bs-upload into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1582
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-21 17:44:32 +01:00
01ec6ecb8e Bluesky: Handle problems when uploading pictures 2024-12-21 09:34:52 +00:00
a63fb08525 Merge remote-tracking branch '2024.09-rc' into develop
# Conflicts:
#	bluesky/bluesky.php
2024-12-16 09:12:09 -05:00
6cf388f141 Merge remote-tracking branch 'Art4/remove-app-usage' into develop 2024-12-16 09:04:45 -05:00
Art4
c4bea164c7 Merge branch 'develop' into remove-app-usage 2024-12-15 15:55:54 +00:00
04c402607b Merge branch 'Art4/fix-phpstan-error-level-2' into develop 2024-12-15 09:18:47 -05:00
4437f79380 Merge pull request 'Bluesky: Functionality moved to the core' (#1580) from heluecht/friendica-addons:bs-password into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1580
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-15 15:13:52 +01:00
52b18c7d9a Bluesky: Functionality moved to the core 2024-12-14 19:20:27 +00:00
f29908464b Bluesky: Fix token problems 2024-12-14 19:20:27 +00:00
3719d1eee5 Set extid via guid, nit via id 2024-12-14 19:20:27 +00:00
Artur Weigandt
68ee5260b0
Merge branch 'develop' into fix-phpstan-error-level-2 2024-12-13 10:28:15 +01:00
81a84fb895 Merge pull request 'fix-phpstan-error-level-1' (#1579) from MrPetovan/friendica-addons:fix-phpstan-error-level-1 into develop
Reviewed-on: friendica/friendica-addons#1579
2024-12-12 22:37:42 +01:00
Artur Weigandt
729b6e5210 Update mailstream/phpmailer/class.phpmailer.php
Co-authored-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-12 22:37:42 +01:00
Art4
a71db771d9 Fix errors in wppost addon 2024-12-12 22:37:42 +01:00
Art4
2f89827dea fix errors in tictac addon 2024-12-12 22:37:42 +01:00
Art4
8e778593ca fix errors in statusnet addon 2024-12-12 22:37:42 +01:00
Art4
5b623c8368 fix errors in ratioed addon 2024-12-12 22:37:42 +01:00
Art4
bda683c56b fix errors in pumpio addon 2024-12-12 22:37:42 +01:00
Art4
7fa2dfc608 Fix errors in pnut addon 2024-12-12 22:37:42 +01:00
Art4
c0971779c6 Fix errors in nsfw addon 2024-12-12 22:37:42 +01:00
Art4
6b1b043dd8 fix errors in mailstream addon 2024-12-12 22:37:42 +01:00
Art4
984e7c5e5d Fix errors in ljpost addon 2024-12-12 22:37:42 +01:00
Art4
d08a280ba6 Fix errors in libravatar addon 2024-12-12 22:37:42 +01:00
Art4
ee1a917612 Fix errors in leistungsschutzrecht addon 2024-12-12 22:37:42 +01:00
Art4
a53d5ae29b Fix errors in langfilter addon 2024-12-12 22:37:42 +01:00
Art4
3cf53a334d Fix errors in keycloakpassword addon 2024-12-12 22:37:42 +01:00
Art4
81f232d57e Fix errors in js_upload addon 2024-12-12 22:37:42 +01:00
Art4
1860e732ae Fix errors in convert addon 2024-12-12 22:37:42 +01:00
Art4
cf8a7870f3 Fix errors in bluesky addon 2024-12-12 22:37:42 +01:00
Art4
31198294c7 Fix error in bluesky addon 2024-12-12 22:37:42 +01:00
Art4
84659fc1ad Replace DI::app() with DI::appHelper() 2024-12-11 21:47:10 +00:00
Art4
5f7482d081 Remove unused use statements for App 2024-12-11 21:42:48 +00:00
Art4
fff140ad43 Fix last 3 errors 2024-12-09 23:08:31 +00:00
Art4
cfb6b3123f Fix errors in statusnet addon 2024-12-08 23:06:51 +00:00
Art4
b99ac65c0b Fix errors in membersince addon 2024-12-08 22:49:23 +00:00
Art4
89a673cc11 Fix typo 2024-12-08 22:19:58 +00:00
Art4
2fe37c6d4a Fix errors in pnut addon 2024-12-08 21:24:03 +00:00
Art4
5b13274bed Fix class name collision 2024-12-08 21:02:07 +00:00
Art4
82ed43f507 Fix errors 2024-12-07 22:08:59 +00:00
a04d22ad01 Merge pull request 'Bluesky: Set a status when the token refresh failed' (#1578) from heluecht/friendica-addons:bluesky-status into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1578
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-06 22:46:14 +01:00
b3c286ab85 Bluesky: Set a status when the token refresh failed 2024-12-06 22:46:14 +01:00
Art4
43c71412e4 Merge branch 'develop' into fix-phpstan-error-level-1 2024-12-01 07:41:27 +00:00
fb9c10f8c5 Merge pull request 'Fix phpstan error level 0 part2' (#1577) from fix-phpstan-error-level-0-part2 into develop
Reviewed-on: friendica/friendica-addons#1577
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-01 03:20:18 +01:00
Art4
1e68417278 Fix classes in s3_storage addon 2024-12-01 03:20:18 +01:00
Art4
7d02c9b53c Fix errors in pumpio addon 2024-12-01 03:20:18 +01:00
Art4
b5c647bd5d fix errors in pnut addon, add support for PHP 7.4 2024-12-01 03:20:18 +01:00
Art4
1bd7cd6e71 fix error in PHPMailer 2024-12-01 03:20:18 +01:00
Art4
def43f3167 Fix errors in mailstream addon 2024-12-01 03:20:18 +01:00
Art4
b661448344 Fix errors in libravatar addon 2024-12-01 03:20:18 +01:00
Art4
922bace555 Fix errors in diaspora addon 2024-12-01 03:20:18 +01:00
Art4
4a2fc7884c remove wrong return tag 2024-12-01 03:20:18 +01:00
Art4
9d172b7082 refactor convert addon, replace each() calls with foreach loop 2024-12-01 03:20:18 +01:00
Art4
4527df602f Add checks for CLD2Detector ans CLD2Encoding classes 2024-12-01 03:20:18 +01:00
Art4
15c21cebb1 Fix errors in wppost addon 2024-11-30 20:36:58 +00:00
Art4
b6a47699bf fix errors in tictac addon 2024-11-30 20:36:07 +00:00
Art4
a41f8c13fe fix errors in statusnet addon 2024-11-30 20:27:57 +00:00
Art4
fccf361ef1 fix errors in ratioed addon 2024-11-30 20:13:41 +00:00
Art4
43ee267d38 fix errors in pumpio addon 2024-11-30 20:12:23 +00:00
Art4
3f89aa1806 Fix errors in pnut addon 2024-11-30 19:51:18 +00:00
Art4
50912fdc17 Fix errors in nsfw addon 2024-11-30 19:50:06 +00:00
Art4
c04016b7d3 fix errors in mailstream addon 2024-11-30 19:48:49 +00:00
Art4
5f6f374f09 Fix errors in ljpost addon 2024-11-30 19:42:40 +00:00
Art4
e86d15993b Fix errors in libravatar addon 2024-11-30 19:41:11 +00:00
Art4
ace19814d7 Fix errors in leistungsschutzrecht addon 2024-11-30 19:37:58 +00:00
Art4
fcec1a3d83 Fix errors in langfilter addon 2024-11-30 19:35:19 +00:00
Art4
04afbe36e3 Fix errors in keycloakpassword addon 2024-11-30 19:32:07 +00:00
Art4
07993f7098 Fix errors in js_upload addon 2024-11-30 19:30:39 +00:00
Art4
bee780552d Fix errors in convert addon 2024-11-30 19:28:38 +00:00
Art4
5664bc84fb Fix errors in bluesky addon 2024-11-30 19:27:50 +00:00
Art4
7246f3deda Merge branch 'fix-phpstan-error-level-0-part2' into fix-phpstan-error-level-1 2024-11-30 19:23:00 +00:00
Art4
0204f54b0e Merge branch 'develop' into fix-phpstan-error-level-0-part2 2024-11-30 06:51:49 +00:00
72e7e2a5b7 Merge remote-tracking branch 'friendica/2024.09-rc' into develop 2024-11-29 21:15:25 -05:00
51c6b5c6cc Merge pull request 'Bluesky: New parameter to set the protocol for a fetched post' (#1576) from heluecht/friendica-addons:bluesky-protocol into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1576
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-11-30 03:13:10 +01:00
Art4
5f2a9e9891 Fix error in bluesky addon 2024-11-29 22:36:09 +00:00
176cbcaf3a Bluesky: New option to set the protocol for a fetched post 2024-11-29 17:49:45 +00:00
Art4
a6de4225c6 Merge branch 'port-rc-branch-into-develop' into fix-phpstan-error-level-0-part2 2024-11-27 23:19:19 +00:00
Art4
23227e5b0f Fix classes in s3_storage addon 2024-11-27 23:18:20 +00:00
Art4
7872400467 Fix errors in pumpio addon 2024-11-27 23:14:01 +00:00
Art4
a5aaea5211 fix errors in pnut addon, add support for PHP 7.4 2024-11-27 22:55:15 +00:00
Art4
7453c6f41a fix error in PHPMailer 2024-11-27 22:33:12 +00:00
Art4
9cb728d19a Merge branch 'develop' into fix-phpstan-error-level-0-part2 2024-11-27 22:25:42 +00:00
Art4
e488f597be Fix errors in mailstream addon 2024-11-27 11:52:59 +00:00
Art4
1346a92505 Fix errors in libravatar addon 2024-11-27 11:43:21 +00:00
Art4
9117626c6a Fix errors in diaspora addon 2024-11-27 11:40:45 +00:00
Art4
90ffd40d58 remove wrong return tag 2024-11-27 11:38:55 +00:00
93a91a95e9 Merge pull request 'Fix PHPStan errors on level 0' (#1575) from MrPetovan/friendica-addons:bug/Art4-1367 into develop
Reviewed-on: friendica/friendica-addons#1575
2024-11-27 08:36:08 +01:00
Art4
fc0dda0cd9 refactor convert addon, replace each() calls with foreach loop 2024-11-26 08:23:27 +00:00
Art4
d7d6a43655 Add checks for CLD2Detector ans CLD2Encoding classes 2024-11-26 07:55:01 +00:00
Art4
c58ca7dcc9 Merge branch '2024.09-rc' into port-rc-branch-into-develop 2024-11-26 07:33:57 +00:00
fecae6564b Merge pull request 'Bluesky: Fetch quoted post for "uid=0"' (#1573) from heluecht/friendica-addons:bluesky-quoted-post into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1573
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-11-26 03:19:34 +01:00
422e4fd48f Bluesky: Fetch quoted post for "uid=0" 2024-11-25 11:47:42 +00:00
Art4
6df91dd37b Fix errors in statusnet addon 2024-11-24 19:55:54 +00:00
Art4
e9d3afb483 Fix errors in tictac addon 2024-11-24 19:51:37 +00:00
Art4
348c44c972 inline slim routes and middlewares into advancedcontentfilter addon 2024-11-24 15:36:37 +00:00
58180bd732 Merge pull request 'Remove unused parameter in saml addon' (#1572) from MrPetovan/friendica-addons:bug/Art4-1366 into develop
Reviewed-on: friendica/friendica-addons#1572
2024-11-24 10:17:44 +01:00
Artur Weigandt
bf679262b0 Remove unused parameter in saml addon 2024-11-24 10:17:44 +01:00
c4e24833eb Merge pull request 'Remove unused parameter webdav_storage addon' (#1570) from MrPetovan/friendica-addons:bug/Art4-1364 into develop
Reviewed-on: friendica/friendica-addons#1570
2024-11-24 10:16:47 +01:00
Artur Weigandt
ecf0edb520 Remove unused parameter webdav_storage addon 2024-11-24 10:16:47 +01:00
3a5acf95f7 Merge pull request 'Remove unused App paramter in securemail addon' (#1571) from MrPetovan/friendica-addons:bug/Art4-1365 into develop
Reviewed-on: friendica/friendica-addons#1571
2024-11-24 10:16:25 +01:00
6a2c0d974e Merge pull request 'Blockbot: Drupal added' (#1569) from heluecht/friendica-addons:drupal into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1569
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-11-24 04:29:39 +01:00
Artur Weigandt
2ea40dc897 Remove unused App paramter in securemail addon 2024-11-23 21:24:34 -05:00
f52bb75c97 Blockbot: Drupal added 2024-11-20 21:39:09 +00:00
8989e0dab6 Merge pull request 'Bluesky: Improved handling of starter packs' (#1568) from heluecht/friendica-addons:starterpack into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1568
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-11-20 18:40:54 +01:00
7fcbd76c6b Bluesky: Improved handling of starter packs 2024-11-20 07:03:42 +00:00
dc0b79bed1 Merge pull request '[advancedcontentfilter] Remove unused vendor files' (#1567) from MrPetovan/friendica-addons:task/composer into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1567
2024-11-17 19:21:43 +01:00
Hypolite Petovan
a0c727ac35 [advancedcontentfilter] Remove unused vendor files
Thanks to @Art4 for the initial submission in https://github.com/friendica/friendica-addons/pull/1363
2024-11-17 19:21:43 +01:00
e133a693c2 Merge pull request '[pumpio] Remove two superfluous parentheses' (#1565) from MrPetovan/friendica-addons:bug/1564-fix into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1565
2024-11-17 19:19:23 +01:00
aa5130247b [pumpio] Remove two superfluous parentheses
- Thanks to @SteffenK9 for the report!
2024-11-16 21:19:06 -05:00
aeefb92926 Merge pull request 'Connectors: Fix handling of the 'private' field / reformatted code' (#1564) from heluecht/friendica-addons:private into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1564
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-11-16 19:15:37 +01:00
c22e0ae831 Fix handling of the 'private' field / reformatted code 2024-11-16 05:43:35 +00:00
f499875f5b Merge pull request 'Bluesky/Tumblr: Add "connector" parcel to each incoming post' (#1561) from heluecht/friendica-addons:parcel into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1561
2024-11-13 10:16:35 +01:00
6a1cbe9040 Bluesky/Tumblr: Add "connector" parcel to each incoming post 2024-11-13 10:16:35 +01:00
6980d3b02b Merge pull request 'deprecate fancybox addon' (#1563) from tobias/friendica-addons:2024.09-rc into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1563
2024-11-13 10:11:50 +01:00
e89b5b1466 deprecate fancybox addon
replaces #1562
2024-11-13 10:10:25 +01:00
5638e7f065 Merge pull request 'Bluesky: Fix probe mistake' (#1560) from heluecht/friendica-addons:bluesky-full-path into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1560
2024-10-30 07:33:34 +01:00
4165479079 Bluesky: Fix probe mistake 2024-10-30 05:11:50 +00:00
fca2d609c9 Merge pull request 'Bluesky: Fix following of a contact and adding a post' (#1559) from heluecht/friendica-addons:bluesky-fix-follow into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1559
2024-10-27 08:42:34 +01:00
8b694fbb4c Bluesky: Fix following of a contact and adding a post 2024-10-27 04:50:45 +00:00
5a9dafec70 Merge pull request 'Bluesky: "block" now works / label names are now displayed' (#1558) from heluecht/friendica-addons:bluesky-block into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1558
2024-10-24 19:09:54 +02:00
586ebe9699 Bluesky: "block" now works / label names are now displayed 2024-10-23 12:14:40 +00:00
10bd219bd1 Merge pull request 'Bluesky: Fixes "E_WARNING: Undefined property: stdClass::$post"' (#1557) from heluecht/friendica-addons:warning into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1557
2024-10-20 21:45:55 +02:00
08c17c9dd4 Bluesky: Fixes "E_WARNING: Undefined property: stdClass::$post" 2024-10-19 07:41:24 +00:00
feb7722f72 Merge pull request 'Bluesky: New option to complete threads' (#1556) from heluecht/friendica-addons:bluesky-complete-threads into develop
Reviewed-on: friendica/friendica-addons#1556
2024-10-06 15:07:14 +02:00
f8f63532f4 Bluesky: New option to complete threads 2024-10-02 07:54:58 +00:00
ef37aa60e3 Merge pull request 'Bluesky: Preparation for video posts' (#1554) from heluecht/friendica-addons:hls into develop
Reviewed-on: friendica/friendica-addons#1554
2024-09-17 07:02:47 +02:00
6f3ba10466 Bluesky: Preparation for video posts 2024-09-17 07:02:47 +02:00
778b9e3f61 Merge pull request 'More and updated icons for the smiley pack' (#1555) from heluecht/friendica-addons:loma-patch into develop
Reviewed-on: friendica/friendica-addons#1555
2024-09-17 07:02:03 +02:00
10521115c4 More and updated icons for the smiley pack 2024-09-16 21:20:11 +00:00
956233ff1d Merge pull request 'Bluesky: Fix for the handling of invalid profiles' (#1553) from heluecht/friendica-addons:bluesky-fix into develop
Reviewed-on: friendica/friendica-addons#1553
2024-09-11 19:42:59 +02:00
14e1c96775 Bluesky: Fix for the handling of invalid profiles 2024-09-10 10:26:05 +00:00
7a7dbb579d Merge pull request 'invidious updated' (#1537) from loma-one/friendica-addons:develop into develop
Reviewed-on: friendica/friendica-addons#1537
2024-09-08 08:50:39 +02:00
712edf4236 invidious/invidious.php aktualisiert
Further addresses have been added, which are now redirected.
2024-09-08 08:50:39 +02:00
5c0cddfc1d Merge pull request 'unicode_smilies updated' (#1536) from loma-one/friendica-addons:loma-one-patch-1 into develop
Reviewed-on: friendica/friendica-addons#1536
2024-09-08 08:50:12 +02:00
3dc77b2102 unicode_smilies/unicode_smilies.php aktualisiert
Addition of the unicode character ‘asterism’ & ‘outlines white star’
2024-09-07 21:04:43 +02:00
6c43a14198 Merge pull request '"fetchFull" is replaced by "get"' (#1535) from heluecht/friendica-addons:fetchfull into develop
Reviewed-on: friendica/friendica-addons#1535
2024-09-06 07:22:58 +02:00
0dfb345f85 "fetchFull" is replaced by "get" 2024-09-06 07:22:58 +02:00
ab837dfec5 Merge pull request 'Bluesky: probing for bluesky handles' (#1534) from heluecht/friendica-addons:bluesky-handle into develop
Reviewed-on: friendica/friendica-addons#1534
2024-09-06 07:20:55 +02:00
2f9076bffd Bluesky: probing for bluesky handles 2024-09-04 04:02:30 +00:00
454e9834bf Merge pull request 'Bluesky: Improve DID detection for custom PDS' (#1533) from heluecht/friendica-addons:bluesky-pds into develop
Reviewed-on: friendica/friendica-addons#1533
2024-09-02 06:32:54 +02:00
50930c301d Bluesky: Improve DID detection for custom PDS 2024-09-02 06:32:54 +02:00
3457ab2f3f Merge pull request 'Add safe.directory config' (#1532) from nupplaPhil/friendica-addons:bug/ci into develop
Reviewed-on: friendica/friendica-addons#1532
2024-08-23 20:24:16 +02:00
276c27678f
[CI] Add safe.directory config 2024-08-20 18:07:51 +02:00
cd95ca1a0a Merge branch 'stable' into develop 2024-08-17 16:55:10 +02:00
5c04e7136f Merge branch '2024.06-rc' into stable 2024-08-17 16:54:44 +02:00
179382d8a9 Merge pull request 'updated translations' (#1531) from tobias/friendica-addons:20240815-lng into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1531
2024-08-15 07:55:36 +02:00
a55f80cb39 updated translations 2024-08-15 07:55:36 +02:00
4ad7d61893 Merge pull request 'Bluesky/Tumblr: Improved statistics' (#1530) from heluecht/friendica-addons:stats2 into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1530
2024-08-14 08:09:37 +02:00
4bfdb45e81 Bluesky/Tumblr: Improved statistics 2024-08-12 20:24:09 +00:00
4414471100 Merge pull request 'Ratioed: add help text' (#1528) from mexon/friendica-addons:mat/ratioed-help into develop
Reviewed-on: friendica/friendica-addons#1528
2024-08-09 13:58:48 +02:00
Matthew Exon
46a55f13f7 Ratioed: add help text 2024-08-09 13:58:48 +02:00
a97cccb6b2 Merge pull request 'Statistics: inbound / outbound for Tumblr and Bluesky' (#1529) from heluecht/friendica-addons:stats into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1529
2024-08-09 13:55:51 +02:00
c0535db742 Statistics: inbound / outbound for Tumblr and Bluesky 2024-08-09 13:55:51 +02:00
0c04b086cb Merge pull request 'Remove old version conversion code' (#1526) from mexon/friendica-addons:mat/remove-conversion into develop
Reviewed-on: friendica/friendica-addons#1526
2024-07-29 19:17:39 +02:00
Matthew Exon
589cf712cc Remove old version conversion code 2024-07-20 13:00:07 +02:00
ce53e48cb2 Merge pull request 'More comprehensible check for root user contact' (#1525) from mexon/friendica-addons:mat/mailstream-clarify-log into develop
Reviewed-on: friendica/friendica-addons#1525
2024-07-20 11:57:32 +02:00
Matthew Exon
f3db763c59 More comprehensible check for root user contact 2024-07-14 18:50:56 +02:00
4e5998c73d Merge pull request 'Mailstream: streamline log lines' (#1522) from mexon/friendica-addons:mat/mailstream-log into develop
Reviewed-on: friendica/friendica-addons#1522
2024-07-14 18:10:10 +02:00
Matthew Exon
5f27f72b0d Streamline log lines 2024-07-01 19:12:10 +02:00
b0a95ca2d2 Merge pull request 'fix for curweather' (#1521) from haheute/friendica-addons:fix-curweather into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1521
2024-06-28 18:27:26 +02:00
b2108c7a4c fix for curweather 2024-06-27 11:44:15 +02:00
abca07b29d Merge pull request 'Add Relatica to blockbot fediverse client list' (#1520) from hankg/friendica-addons:2024.06-rc into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1520
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-06-25 01:07:09 +02:00
14e7413eb2 Add Relatica to blockbot fediverse client list 2024-06-24 22:20:35 +02:00
d3dcd5428c Merge pull request 'mat/ratioed-plugin-2' (#1519) from mexon/friendica-addons:mat/ratioed-plugin-2 into develop
Reviewed-on: friendica/friendica-addons#1519
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-06-23 21:25:47 +02:00
Matthew Exon
18e512cc8b Ratioed: move panel class into separate file 2024-06-23 15:43:05 +02:00
Matthew Exon
7d5446a778 Ratioed: remove unnecessary uninstall function 2024-06-23 15:15:06 +02:00
38ea90104d Merge pull request 'New addon providing additional statistics for moderation' (#1518) from mexon/friendica-addons:mat/ratioed-plugin into develop
Reviewed-on: friendica/friendica-addons#1518
2024-06-23 14:13:34 +02:00
Matthew Exon
08b46e5536 New addon providing additional statistics for moderation 2024-06-22 18:56:32 +02:00
39567cf701 Merge pull request 'translation updates' (#1517) from tobias/friendica-addons:20240621-lng into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1517
2024-06-22 03:40:13 +02:00
2789e880dc translation updates
AR, CS, DE, IT, PL, SV for various addons
2024-06-21 20:38:42 +02:00
1556ebfb33 Merge pull request 'Leave failed image URLs in place' (#1516) from mexon/friendica-addons:mat/mailstream-fetch-failure into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1516
2024-06-17 06:54:06 +02:00
Matthew Exon
3e1b98d5d9 Leave failed image URLs in place 2024-06-17 06:54:06 +02:00
ed07c987a6 Merge pull request 'JS Uploader: "jpg" added to the list of allowed file extensions' (#1515) from heluecht/friendica-addons:jsupload into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1515
2024-06-16 16:47:11 +02:00
af868f45ab JS Uploader: "jpg" added to the list of allowed file extensions 2024-06-16 14:35:19 +00:00
7f0cf2527c Merge pull request 'Tumblr: Add link for quoted post' (#1514) from heluecht/friendica-addons:tumblr-quoted into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1514
2024-06-16 09:37:58 +02:00
9525259fc8 Tumblr: Add link for quoted post 2024-06-15 13:51:47 +00:00
f7ca152754 Merge pull request 'Bluesky: Handle API error when fetching feeds' (#1513) from heluecht/friendica-addons:bluesky into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1513
2024-06-13 07:19:43 +02:00
6f56932f12 Bluesky: Handle API error when fetching feeds 2024-06-13 04:32:00 +00:00
b6f2e7dd50 Merge pull request 'Bluesky: more logging added' (#1512) from heluecht/friendica-addons:bluesky-logging into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1512
2024-06-10 08:00:39 +02:00
fa16adccaf Bluesky: more logging added 2024-06-10 05:43:35 +00:00
252f3e222a Merge pull request 'Bluesky: Fix overwritten handle when "friendica handles" is selected' (#1511) from heluecht/friendica-addons:blockbot-fixes into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1511
2024-06-10 06:59:58 +02:00
231d830db0 Bluesky: Fix overwritten handle when "friendica handles" is selected 2024-06-09 20:41:18 +00:00
27e362213f Merge pull request 'Blockbot: Logging of AP actors' (#1510) from heluecht/friendica-addons:ap-actor-logging into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1510
2024-06-07 07:00:33 +02:00
734d35d22b Blockbot: Logging of AP actors 2024-06-07 04:19:53 +00:00
722fdc07fb Merge pull request 'Bluesky: Fix error on restricted posts / improve performance' (#1509) from heluecht/friendica-addons:bluesky-fix into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1509
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-06-06 16:29:24 +02:00
77c471ab4d Bluesky: Fix error on restricted posts / improve performance 2024-06-06 16:29:24 +02:00
bac665864e Merge pull request 'FR translation updates - nsfw, securemail, tumblr' (#1508) from tobias/friendica-addons:20240603-fr into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1508
2024-06-05 05:43:24 +02:00
c7f4d183b1 FR translation updates - nsfw, securemail, tumblr 2024-06-03 08:13:08 +02:00
7f073ec520 Merge pull request '"zrl" functionility is moved' (#1507) from heluecht/friendica-addons:openwebauth into develop
Reviewed-on: friendica/friendica-addons#1507
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-29 15:12:10 +02:00
39247ca28f Function renamed 2024-05-29 06:07:48 +00:00
084a2a7057 "zrl" functionility is moved 2024-05-27 04:45:17 +00:00
c8fab935ee Merge pull request 'Upload: Fix available file extension check' (#1506) from heluecht/friendica-addons:upload into develop
Reviewed-on: friendica/friendica-addons#1506
2024-05-20 12:09:56 +02:00
9ae8925069 Upload: Fix available file extension check 2024-05-19 18:08:19 +00:00
0eff72fa03 Merge pull request 'Tumblr: "isLocalLink" is now "isLocalUrl" / Bluesky: Fix for an empty uri' (#1505) from heluecht/friendica-addons:unparseurl into develop
Reviewed-on: friendica/friendica-addons#1505
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-16 15:12:26 +02:00
2306261ab2 Tumblr: "isLocalLink" is now "isLocalUrl" / Bluesky: Fix for an empty uri 2024-05-16 12:24:34 +00:00
26eea26f95 Merge pull request 'Bluesky: fix unneeded check for user PDS' (#1504) from heluecht/friendica-addons:bluesky-notification into develop
Reviewed-on: friendica/friendica-addons#1504
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-12 03:11:39 +02:00
e7dd7111ac Bluesky: fix unneeded check for user PDS 2024-05-12 00:56:06 +00:00
60f5d14b8e Merge pull request 'Blockbot: More agents added' (#1503) from heluecht/friendica-addons:blockbot-again into develop
Reviewed-on: friendica/friendica-addons#1503
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-12 01:59:27 +02:00
c7a6ecb346 Blockbot: More agents added 2024-05-10 09:33:36 +00:00
38b75b6529 Merge pull request 'Blockbot: Reworked user agent parsing' (#1500) from heluecht/friendica-addons:blockbot-2 into develop
Reviewed-on: friendica/friendica-addons#1500
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-04 15:09:55 +02:00
67b464cc47 Blockbot: Reworked user agent parsing 2024-05-04 01:23:32 +00:00
20f2f12871 Merge pull request 'Bluesky: Fix error for missing handles' (#1502) from heluecht/friendica-addons:bluesky-error into develop
Reviewed-on: friendica/friendica-addons#1502
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-04 03:06:27 +02:00
85d254f2f8 Bluesky: Fix error for missing handles 2024-05-04 03:06:27 +02:00
a4598a2427 Merge pull request 'Bluesky: Fixes "bluesky_get_did(): Argument #1 ($handle) must be of type string, null given"' (#1501) from heluecht/friendica-addons:bluesky-error into develop
Reviewed-on: friendica/friendica-addons#1501
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-03 17:00:21 +02:00
6c76139ce1 Bluesky: Fixes "bluesky_get_did(): Argument #1 ($handle) must be of type string, null given" 2024-05-03 02:58:45 +00:00
8e81330f21 Merge pull request 'Bluesky: Improved fetching of the user DID' (#1499) from heluecht/friendica-addons:bluesky-did into develop
Reviewed-on: friendica/friendica-addons#1499
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-05-01 03:07:01 +02:00
b9d0cece0a Bluesky: Improved fetching of the user DID 2024-04-28 10:36:47 +00:00
d4abc9bac8 Merge pull request 'Issue 13812: Public groups with manual request approval' (#1496) from heluecht/friendica-addons:issue-13812 into develop
Reviewed-on: friendica/friendica-addons#1496
2024-04-16 07:59:08 +02:00
dc7a8adf29 Issue 13812: Public groups with manual request approval 2024-04-16 07:59:08 +02:00
739041b74f Merge pull request 'Proxify functionality is removed' (#1495) from heluecht/friendica-addons:noproxy into develop
Reviewed-on: friendica/friendica-addons#1495
2024-04-16 07:58:12 +02:00
9c6a86ffaa Proxify functionality is removed 2024-04-16 05:05:53 +00:00
38466415b3 Merge pull request '[invidious] Now replaces YouTube links without a leading "www."' (#1494) from loma-one/friendica-addons:develop into develop
Reviewed-on: friendica/friendica-addons#1494
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-04-15 07:12:31 +02:00
3bf547ee6e invidious/invidious.php aktualisiert
Note taken from @MrPetovan
2024-04-15 01:12:06 -04:00
9627e95b19 invidious/invidious.php aktualisiert
Now intercepts YouTube links without a leading "www".
2024-04-15 01:08:29 -04:00
aea944c8b5 Merge pull request 'Bluesky: Added support for sensitive posts' (#1492) from heluecht/friendica-addons:sensitive into develop
Reviewed-on: friendica/friendica-addons#1492
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-26 17:12:21 +01:00
340f5e627c Bluesky: Added support for sensitive posts 2024-03-23 21:05:54 +00:00
9153ca05fd Merge pull request '[Hotfix] Fix REPO_URL for woodpecker' (#1491) from nupplaPhil/friendica-addons:bug/stable_hf into develop
Reviewed-on: friendica/friendica-addons#1491
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-22 16:30:56 +01:00
3bdbcd3b02
[Hotfix] Fix REPO_URL for woodpecker 2024-03-22 16:23:20 +01:00
010261c1dc Merge pull request '[Hotfix] Fix REPO_URL for woodpecker' (#1490) from nupplaPhil/friendica-addons:bug/repo_link into stable
Reviewed-on: friendica/friendica-addons#1490
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-22 16:03:06 +01:00
3f26f9785e
[Hotfix] Fix REPO_URL for woodpecker 2024-03-22 15:53:47 +01:00
b4eee553d1 Merge pull request 'Bluesky: Support Restrictions / Updated Friendica handle description' (#1489) from heluecht/friendica-addons:restrictions into develop
Reviewed-on: friendica/friendica-addons#1489
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-22 14:14:03 +01:00
04ce1fd2b4 Bluesky: Support Restrictions / Updated Friendica handle description 2024-03-22 05:32:17 +00:00
569931986d Merge pull request '[various] Update Composer dependencies ahead of release' (#1487) from MrPetovan/friendica-addons:task/composer into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1487
2024-03-20 10:16:50 +01:00
0a69c66d09 [securemail] Update Composer dependency ahead of release
- Updating phpseclib/phpseclib (3.0.19 => 3.0.37)
2024-03-19 23:11:09 -04:00
7bff983d21 [saml] Update Composer dependency ahead of release
- Updating onelogin/php-saml (4.0.0 => 4.1.0)
2024-03-19 23:10:10 -04:00
d910502a17 [s3_storage] Update Composer dependency ahead of release
- Updating akeeba/s3 (2.3.1 => 2.3.2)
2024-03-19 23:10:09 -04:00
c6b2ed96d7 [phpmailer] Update Composer dependency ahead of release
- Updating phpmailer/phpmailer (v6.5.0 => v6.9.1)
2024-03-19 23:10:09 -04:00
a020ac4309 [monolog] Update Composer dependencies ahead of release
- Updating monolog/monolog (2.9.1 => 2.9.2)
2024-03-19 23:10:09 -04:00
d838fc6421 [blockbot] Update Composer dependency ahead of release
- Updating jaybizzle/crawler-detect (v1.2.80 => v1.2.116)
2024-03-19 23:10:09 -04:00
b0ee9fdf2a [advancedcontentfilter] Update Composer dependencies ahead of release
- Removing symfony/polyfill-apcu (v1.28.0)
- Removing psr/simple-cache (1.0.1)
- Updating psr/http-message (1.1 => 2.0)
- Downgrading psr/container (2.0.2 => 1.1.2)
- Updating slim/slim (4.12.0 => 4.13.0)
- Installing symfony/polyfill-php80 (v1.29.0)
- Installing symfony/var-exporter (v5.4.35)
- Installing symfony/deprecation-contracts (v2.5.2)
- Installing symfony/service-contracts (v2.5.2)
- Installing symfony/polyfill-php73 (v1.29.0)
- Installing symfony/cache-contracts (v2.5.2)
- Updating symfony/cache (v3.4.47 => v4.4.48)
2024-03-19 23:10:07 -04:00
46c65b79be [advancedcontentfilter] Improve error handling
- Add Logger to Slim application to log to Friendica log file
- Show more specific error message when rule syntax check fails
- Align editorconfig with Composer style
- Add minimum PHP version to composer.json
2024-03-19 22:57:32 -04:00
11cc359434 Merge pull request 'Updated URL Replace addon' (#1483) from toddy/friendica-addons:2024.03-rc into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1483
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-19 18:00:45 +01:00
872a438dcf [nitter] Drop support for the addon
- Please use the URL replace addon instead
2024-03-19 17:57:40 +01:00
da8681c8c4 [invidious] Drop support for the addon
- Please use the URL replace addon instead
2024-03-19 17:57:40 +01:00
67c44792fd [url_replace] Simplify config setting conditions
- Add default values for config values in url_replace_addon_admin()
- Capitalize brand names
2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
cfbbeaac62 Use invidio.us as default 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
32f698ce10 Only show small info about replacements if the original has changed 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
a110b2f6c1 Reformat code to apply standards 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
fc33555cd6 Remove configuration value if no server URL is provided 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
e24e3f758a Fix formatting 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
127ab370fc Update message catalog 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
890bc3712f Use constants for the default servers 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
2cff751b12 Increment version 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
89134542b4 Update message catalog 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
453772e393 Remove now unnecessary variable 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
0bcf2d7c89 Reformat code, no content changes 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
c6daf2381c Enable individual replacement preferences 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
51797d975b Update README 2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
a40bd7009b Add proxigram for instagram redirection.
Based on an idea and patch from loma-one. Thanks!
2024-03-19 17:57:40 +01:00
Dr. Tobias Quathamer
1bcd23f684 Simplify providing a default empty array 2024-03-19 17:57:40 +01:00
f3bddaf7d6 Merge pull request 'Blockbot: More agents added' (#1486) from heluecht/friendica-addons:blockbot-agents into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1486
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-16 09:06:25 +01:00
4a14bc47ee Blockbot: More agents added 2024-03-16 09:06:25 +01:00
09b3f01558 Merge pull request '[CI] Add PHP 8.3 and upgrade CI images' (#1485) from nupplaPhil/friendica-addons:feat/CI_php83 into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1485
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-15 23:19:15 +01:00
e1f27d88b7
Fixup :) 2024-03-15 23:15:42 +01:00
57c4735ad6
Use PHP 8.2 for other pipelines 2024-03-15 23:08:52 +01:00
372a850103
Use PHP 8.2 for codecoverage 2024-03-15 23:06:13 +01:00
7e890124a8
Update PHP 8.1 and PHP 8.2 CI image 2024-03-15 23:03:44 +01:00
904bf11e54
[CI] Add PHP 8.3 2024-03-15 22:55:48 +01:00
1af97e5c9e Merge pull request 'Blockbot: More agents added' (#1484) from heluecht/friendica-addons:blockbots into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1484
2024-03-14 07:30:29 +01:00
02a6fdd9a2 Blockbot: More agents added 2024-03-14 05:19:54 +00:00
d11efc108c Merge pull request 'Bluesky: fix the fetching of media in quoted posts' (#1481) from heluecht/friendica-addons:bluesky-media into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1481
2024-03-10 15:02:28 +01:00
d5dfa8028c Bluesky: fix the fetching of media in quoted posts 2024-03-10 15:02:28 +01:00
3da448b01f Merge pull request 'Tumblr: Handle quote shares' (#1480) from heluecht/friendica-addons:issue-13972 into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1480
2024-03-10 15:01:33 +01:00
0fc8285f87 Tumblr: Handle quote shares 2024-03-10 15:01:33 +01:00
167b7f9466 Merge pull request 'Blockbot: New user agents added' (#1482) from heluecht/friendica-addons:blockbot-forte into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1482
2024-03-10 14:59:56 +01:00
ef7548f5bc Blockbot: New user agents added 2024-03-10 06:46:41 +00:00
c9923e47de Merge pull request '[url_replace] Add support for empty config value' (#1478) from MrPetovan/friendica-addons:bug/13968-url_replace-fatal into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1478
2024-03-07 19:52:53 +01:00
6a9287dc6f [url_replace] Add support for empty config value 2024-03-07 07:22:41 -05:00
eeb783d71d [url_replace] Normalize formatting 2024-03-07 07:21:56 -05:00
0812886b61 Merge pull request 'Blockbot: HTTP library section added' (#1477) from heluecht/friendica-addons:blockbot-forte into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1477
2024-03-06 08:38:32 +01:00
09ae5cfaff More agents added 2024-03-06 08:38:32 +01:00
0751b2ac16 Blockbot: HTTP library section added 2024-03-06 08:38:32 +01:00
ed641e6ccb Merge pull request 'Blockbot: Misskey-Crawler added' (#1476) from heluecht/friendica-addons:blockbot into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1476
2024-03-04 16:32:29 +01:00
a05e429470 Blockbot: Misskey-Crawler added 2024-03-04 15:27:44 +00:00
6e355979e8 Merge pull request '[advancedcontentfilter] Stop using advancedcontentfilter_get_rules() outside of router context' (#1475) from MrPetovan/friendica-addons:bug/13950-advancedcontentfilter-wsod into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1475
2024-03-04 07:23:51 +01:00
3c0f4e3926 [advancedcontentfilter] Stop using advancedcontentfilter_get_rules() outside of router context
- This used to work with Slim v2, but the new requirements for module functions broke it
2024-03-04 01:16:49 -05:00
affa8829d5 Merge pull request 'Blockbot: You can now allow social media agents' (#1474) from heluecht/friendica-addons:blockbot into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1474
2024-03-04 07:00:49 +01:00
b6d706822a Blockbot: You can now allow social media agents 2024-03-04 05:37:04 +00:00
c49b61be8b Merge pull request 'Pnut: Client Id/Secret can be set by admins' (#1473) from heluecht/friendica-addons:pnut into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1473
2024-03-03 18:29:53 +01:00
90ec1bc838 Newlines added 2024-03-03 18:29:34 +01:00
dcafad573e Pnut: Client Id/Secret can be set by admins 2024-03-03 18:29:34 +01:00
dc709c699a Merge pull request 'mailstream: do not mail dislike messages' (#1472) from mexon/friendica-addons:mailstream-dislike into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1472
2024-03-03 13:05:27 +01:00
Matthew Exon
58cb933779 do not mail dislike messages 2024-03-03 13:05:27 +01:00
53be7d9423 Merge pull request 'Bluesky: Handle media links and shared posts' (#1471) from heluecht/friendica-addons:bluesky-media into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1471
2024-03-02 15:38:28 +01:00
2ee78d2f0b Bluesky: Handle media links and shared posts 2024-03-02 13:32:11 +00:00
d19b9ba9e3 Merge pull request 'Bluesky: Enabled support for Friendica handles' (#1469) from heluecht/friendica-addons:bluesky-friendica-handles into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1469
2024-03-01 07:45:35 +01:00
5f7233fd20 Bluesky: Enabled support for Friendica handles 2024-03-01 07:45:35 +01:00
9168f3d167 Merge pull request 'Bluesky: fix problems with links and hashtags' (#1470) from heluecht/friendica-addons:bluesky-tags into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1470
2024-03-01 07:44:23 +01:00
7580054394 Bluesky: fix problems with links and hashtags 2024-03-01 05:53:42 +00:00
bdc27184fc Merge pull request 'Tumblr: Fixed token exchange' (#1468) from heluecht/friendica-addons:Tumblr--Fixed-token-exchange into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1468
2024-02-27 01:34:22 +01:00
346e22c5f5 Tumblr: Fixed token exchange 2024-02-27 01:34:22 +01:00
de784bdc95 Merge pull request 'Bluesky: Several improvements and fixes' (#1467) from heluecht/friendica-addons:bluesky into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1467
2024-02-27 01:33:44 +01:00
6d578d1495 Changed post reason 2024-02-27 01:33:44 +01:00
bcef83e148 Set post reasons 2024-02-27 01:33:44 +01:00
2b5f8e9c82 Fix coding standards 2024-02-27 01:33:44 +01:00
e4bb463b5b Bluesky: Several improvements and fixes 2024-02-27 01:33:44 +01:00
52f7910f4c Merge pull request 'Pnut: add connector for pnut.io' (#1466) from spacenerdmo/friendica-addons:pnut into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1466
2024-02-21 18:22:44 +01:00
9208fd46a4 Pnut: add connector for pnut.io 2024-02-20 17:53:21 -08:00
810dc02dd4 Merge pull request 'Bluesky/Twitter: New parameter added for rhe picture creation' (#1465) from heluecht/friendica-addons:images into 2024.03-rc
Reviewed-on: friendica/friendica-addons#1465
2024-02-17 07:47:00 +01:00
f678468d42 Bluesky/Twitter: New parameter added for rhe picture creation 2024-02-16 02:29:12 +00:00
616 changed files with 22718 additions and 12807 deletions

View file

@ -27,3 +27,6 @@ indent_size = 2
[*.json] [*.json]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[composer.json]
indent_size = 4

View file

@ -1,9 +1,12 @@
skip_clone: true skip_clone: true
pipeline: steps:
clone_friendica_base: clone_friendica_base:
image: alpine/git image: alpine/git
commands: commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git . - git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
when: when:
@ -13,7 +16,7 @@ pipeline:
commands: commands:
- git config --global user.email "no-reply@friendi.ca" - git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica" - git config --global user.name "Friendica"
- git clone $CI_REPO_LINK addon - git clone $CI_REPO_CLONE_URL addon
- cd addon/ - cd addon/
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
- git fetch origin $CI_COMMIT_REF - git fetch origin $CI_COMMIT_REF
@ -53,6 +56,10 @@ pipeline:
- /tmp/drone-cache:/tmp/cache - /tmp/drone-cache:/tmp/cache
when: when:
event: pull_request event: pull_request
phpstan:
image: friendicaci/php8.3:php8.3.3
commands:
- ./bin/composer.phar run phpstan;
check: check:
image: friendicaci/php-cs image: friendicaci/php-cs
commands: commands:

View file

@ -5,10 +5,13 @@ labels:
skip_clone: true skip_clone: true
pipeline: steps:
clone_friendica_base: clone_friendica_base:
image: alpine/git image: alpine/git
commands: commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git . - git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
when: when:
@ -20,7 +23,7 @@ pipeline:
commands: commands:
- git config --global user.email "no-reply@friendi.ca" - git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica" - git config --global user.name "Friendica"
- git clone $CI_REPO_LINK addon - git clone $CI_REPO_CLONE_URL addon
- cd addon/ - cd addon/
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
- git fetch origin $CI_COMMIT_REF - git fetch origin $CI_COMMIT_REF
@ -45,7 +48,7 @@ pipeline:
branch: [ develop, '*-rc' ] branch: [ develop, '*-rc' ]
event: push event: push
composer_install: composer_install:
image: friendicaci/php7.4:php7.4.33 image: friendicaci/php8.2:php8.2.16
commands: commands:
- export COMPOSER_HOME=.composer - export COMPOSER_HOME=.composer
- composer validate - composer validate

View file

@ -1,9 +1,12 @@
skip_clone: true skip_clone: true
pipeline: steps:
clone_friendica_base: clone_friendica_base:
image: alpine/git image: alpine/git
commands: commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git . - git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
when: when:
@ -13,7 +16,7 @@ pipeline:
commands: commands:
- git config --global user.email "no-reply@friendi.ca" - git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica" - git config --global user.name "Friendica"
- git clone $CI_REPO_LINK addon - git clone $CI_REPO_CLONE_URL addon
- cd addon/ - cd addon/
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
- git fetch origin $CI_COMMIT_REF - git fetch origin $CI_COMMIT_REF

View file

@ -5,9 +5,11 @@ matrix:
- PHP_MAJOR_VERSION: 8.0 - PHP_MAJOR_VERSION: 8.0
PHP_VERSION: 8.0.30 PHP_VERSION: 8.0.30
- PHP_MAJOR_VERSION: 8.1 - PHP_MAJOR_VERSION: 8.1
PHP_VERSION: 8.1.23 PHP_VERSION: 8.1.27
- PHP_MAJOR_VERSION: 8.2 - PHP_MAJOR_VERSION: 8.2
PHP_VERSION: 8.2.11 PHP_VERSION: 8.2.16
- PHP_MAJOR_VERSION: 8.3
PHP_VERSION: 8.3.3
# This forces PHP Unit executions at the "opensocial" labeled location (because of much more power...) # This forces PHP Unit executions at the "opensocial" labeled location (because of much more power...)
labels: labels:
@ -15,10 +17,13 @@ labels:
skip_clone: true skip_clone: true
pipeline: steps:
clone_friendica_base: clone_friendica_base:
image: alpine/git image: alpine/git
commands: commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git . - git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
clone_friendica_addon: clone_friendica_addon:
@ -26,7 +31,7 @@ pipeline:
commands: commands:
- git config --global user.email "no-reply@friendi.ca" - git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica" - git config --global user.name "Friendica"
- git clone $CI_REPO_LINK addon - git clone $CI_REPO_CLONE_URL addon
- cd addon/ - cd addon/
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
- git fetch origin $CI_COMMIT_REF - git fetch origin $CI_COMMIT_REF
@ -76,7 +81,7 @@ pipeline:
- cp config/local-sample.config.php config/local.config.php - cp config/local-sample.config.php config/local.config.php
- if ! bin/wait-for-connection $MYSQL_HOST $MYSQL_PORT 300; then echo "[ERROR] Waited 300 seconds, no response" >&2; exit 1; fi - if ! bin/wait-for-connection $MYSQL_HOST $MYSQL_PORT 300; then echo "[ERROR] Waited 300 seconds, no response" >&2; exit 1; fi
- mysql -h$MYSQL_HOST -P$MYSQL_PORT -p$MYSQL_PASSWORD -u$MYSQL_USER $MYSQL_DATABASE < database.sql - mysql -h$MYSQL_HOST -P$MYSQL_PORT -p$MYSQL_PASSWORD -u$MYSQL_USER $MYSQL_DATABASE < database.sql
- if [ "${PHP_MAJOR_VERSION}" = "7.4" -a "${CI_REPO}" = "friendica/friendica-addons" ]; then - if [ "${PHP_MAJOR_VERSION}" = "8.2" -a "${CI_REPO}" = "friendica/friendica-addons" ]; then
phpenmod xdebug; phpenmod xdebug;
export XDEBUG_MODE=coverage; export XDEBUG_MODE=coverage;
phpunit --configuration tests/phpunit-addons.xml --coverage-clover clover.xml; phpunit --configuration tests/phpunit-addons.xml --coverage-clover clover.xml;
@ -87,15 +92,15 @@ pipeline:
image: friendicaci/codecov image: friendicaci/codecov
when: when:
matrix: matrix:
PHP_MAJOR_VERSION: 7.4 PHP_MAJOR_VERSION: 8.2
PHP_VERSION: 7.4.33 PHP_VERSION: 8.2.16
repo: repo:
- friendica/friendica-addons - friendica/friendica-addons
commands: commands:
- codecov -R '.' -Z -f 'clover.xml' - codecov -R '.' -Z -f 'clover.xml'
secrets: environment:
- source: codecov-token CODECOV_TOKEN:
target: codecov_token from_secret: codecov-token
services: services:
mariadb: mariadb:

View file

@ -5,10 +5,13 @@ labels:
skip_clone: true skip_clone: true
pipeline: steps:
clone_friendica_base: clone_friendica_base:
image: alpine/git image: alpine/git
commands: commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git . - git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
when: when:
@ -19,7 +22,7 @@ pipeline:
commands: commands:
- git config --global user.email "no-reply@friendi.ca" - git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica" - git config --global user.name "Friendica"
- git clone $CI_REPO_LINK addon - git clone $CI_REPO_CLONE_URL addon
- cd addon/ - cd addon/
- git checkout $CI_COMMIT_BRANCH - git checkout $CI_COMMIT_BRANCH
- git fetch origin $CI_COMMIT_REF - git fetch origin $CI_COMMIT_REF
@ -42,7 +45,7 @@ pipeline:
repo: friendica/friendica-addons repo: friendica/friendica-addons
event: tag event: tag
composer_install: composer_install:
image: friendicaci/php7.4:php7.4.33 image: friendicaci/php8.2:php8.2.16
commands: commands:
- export COMPOSER_HOME=.composer - export COMPOSER_HOME=.composer
- composer validate - composer validate

View file

@ -54,7 +54,7 @@ new Vue({
self.rules.push(responseJSON.rule); self.rules.push(responseJSON.rule);
self.resetForm(); self.resetForm();
}, function (response) { }, function (response) {
self.errorMessage = response.responseJSON.message; self.errorMessage = response.responseJSON.exception[0].message;
}); });
} }
}, },
@ -74,7 +74,7 @@ new Vue({
self.rules[self.editedIndex] = rule; self.rules[self.editedIndex] = rule;
self.resetForm(); self.resetForm();
}, function (response) { }, function (response) {
self.errorMessage = response.responseJSON.message; self.errorMessage = response.responseJSON.exception[0].message;
}); });
}, },

View file

@ -33,16 +33,13 @@
* *
*/ */
use Friendica\App;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Content\Text\Markdown; use Friendica\Content\Text\Markdown;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Database\DBStructure; use Friendica\Database\DBStructure;
use Friendica\DI; use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Post; use Friendica\Model\Post;
use Friendica\Model\Tag; use Friendica\Model\Tag;
use Friendica\Model\User; use Friendica\Model\User;
@ -64,7 +61,7 @@ function advancedcontentfilter_install()
Hook::add('dbstructure_definition' , __FILE__, 'advancedcontentfilter_dbstructure_definition'); Hook::add('dbstructure_definition' , __FILE__, 'advancedcontentfilter_dbstructure_definition');
DBStructure::performUpdate(); DBStructure::performUpdate();
Logger::notice('installed advancedcontentfilter'); DI::logger()->notice('installed advancedcontentfilter');
} }
/* /*
@ -192,9 +189,30 @@ function advancedcontentfilter_init()
if (DI::args()->getArgc() > 1 && DI::args()->getArgv()[1] == 'api') { if (DI::args()->getArgc() > 1 && DI::args()->getArgv()[1] == 'api') {
$slim = \Slim\Factory\AppFactory::create(); $slim = \Slim\Factory\AppFactory::create();
require __DIR__ . '/src/middlewares.php'; /**
* The routing middleware should be added before the ErrorMiddleware
* Otherwise exceptions thrown from it will not be handled
*/
$slim->addRoutingMiddleware();
$slim->addErrorMiddleware(true, true, true, DI::logger());
// register routes
$slim->group('/advancedcontentfilter/api', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->group('/rules', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('', 'advancedcontentfilter_get_rules');
$app->post('', 'advancedcontentfilter_post_rules');
$app->get('/{id}', 'advancedcontentfilter_get_rules_id');
$app->put('/{id}', 'advancedcontentfilter_put_rules_id');
$app->delete('/{id}', 'advancedcontentfilter_delete_rules_id');
});
$app->group('/variables', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('/{guid}', 'advancedcontentfilter_get_variables_guid');
});
});
require __DIR__ . '/src/routes.php';
$slim->run(); $slim->run();
exit; exit;
@ -252,8 +270,8 @@ function advancedcontentfilter_content()
'rule_expression' => DI::l10n()->t('Rule Expression'), 'rule_expression' => DI::l10n()->t('Rule Expression'),
'cancel' => DI::l10n()->t('Cancel'), 'cancel' => DI::l10n()->t('Cancel'),
], ],
'$current_theme' => DI::app()->getCurrentTheme(), '$current_theme' => DI::appHelper()->getCurrentTheme(),
'$rules' => advancedcontentfilter_get_rules(), '$rules' => DBA::toArray(DBA::select('advancedcontentfilter_rules', [], ['uid' => DI::userSession()->getLocalUserId()])),
'$form_security_token' => BaseModule::getFormSecurityToken() '$form_security_token' => BaseModule::getFormSecurityToken()
]); ]);
} }
@ -305,7 +323,7 @@ function advancedcontentfilter_build_fields($data)
* API * API
*/ */
function advancedcontentfilter_get_rules(ServerRequestInterface $request, ResponseInterface $response) function advancedcontentfilter_get_rules(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{ {
if (!DI::userSession()->getLocalUserId()) { if (!DI::userSession()->getLocalUserId()) {
throw new HTTPException\UnauthorizedException(DI::l10n()->t('You must be logged in to use this method')); throw new HTTPException\UnauthorizedException(DI::l10n()->t('You must be logged in to use this method'));

View file

@ -1,24 +1,27 @@
{ {
"name": "friendica-addons/advancedcontentfilter", "name": "friendica-addons/advancedcontentfilter",
"description": "Advanced Content Filter addon for Friendica", "description": "Advanced Content Filter addon for Friendica",
"type": "friendica-addon", "type": "friendica-addon",
"authors": [ "authors": [
{ {
"name": "Hypolite Petovan", "name": "Hypolite Petovan",
"email": "hypolite@mrpetovan.com", "email": "hypolite@mrpetovan.com",
"homepage": "https://friendica.mrpetovan.com/profile/hypolite", "homepage": "https://friendica.mrpetovan.com/profile/hypolite",
"role": "Developer" "role": "Developer"
} }
], ],
"require": { "require": {
"slim/slim": "^4", "slim/slim": "^4",
"symfony/expression-language": "^3.4" "symfony/expression-language": "^3.4"
}, },
"license": "3-clause BSD license", "license": "3-clause BSD license",
"minimum-stability": "stable", "minimum-stability": "stable",
"config": { "config": {
"optimize-autoloader": true, "platform": {
"autoloader-suffix": "AdvancedContentFilterAddon", "php": "7.4"
"preferred-install": "dist" },
} "optimize-autoloader": true,
"autoloader-suffix": "AdvancedContentFilterAddon",
"preferred-install": "dist"
}
} }

View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "3e87f0369e4799fc35d98f399c67f1e9", "content-hash": "a7276eb2d2108a26699f69c750d02d27",
"packages": [ "packages": [
{ {
"name": "nikic/fast-route", "name": "nikic/fast-route",
@ -100,27 +100,22 @@
}, },
{ {
"name": "psr/container", "name": "psr/container",
"version": "2.0.2", "version": "1.1.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/container.git", "url": "https://github.com/php-fig/container.git",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" "reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.4.0" "php": ">=7.4.0"
}, },
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Psr\\Container\\": "src/" "Psr\\Container\\": "src/"
@ -145,7 +140,7 @@
"container-interop", "container-interop",
"psr" "psr"
], ],
"time": "2021-11-05T16:47:00+00:00" "time": "2021-11-05T16:50:12+00:00"
}, },
{ {
"name": "psr/http-factory", "name": "psr/http-factory",
@ -201,16 +196,16 @@
}, },
{ {
"name": "psr/http-message", "name": "psr/http-message",
"version": "1.1", "version": "2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/http-message.git", "url": "https://github.com/php-fig/http-message.git",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -219,7 +214,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.1.x-dev" "dev-master": "2.0.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -234,7 +229,7 @@
"authors": [ "authors": [
{ {
"name": "PHP-FIG", "name": "PHP-FIG",
"homepage": "http://www.php-fig.org/" "homepage": "https://www.php-fig.org/"
} }
], ],
"description": "Common interface for HTTP messages", "description": "Common interface for HTTP messages",
@ -247,7 +242,7 @@
"request", "request",
"response" "response"
], ],
"time": "2023-04-04T09:50:52+00:00" "time": "2023-04-04T09:54:51+00:00"
}, },
{ {
"name": "psr/http-server-handler", "name": "psr/http-server-handler",
@ -402,66 +397,18 @@
], ],
"time": "2021-05-03T11:20:27+00:00" "time": "2021-05-03T11:20:27+00:00"
}, },
{
"name": "psr/simple-cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"time": "2017-10-23T01:57:42+00:00"
},
{ {
"name": "slim/slim", "name": "slim/slim",
"version": "4.12.0", "version": "4.13.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slimphp/Slim.git", "url": "https://github.com/slimphp/Slim.git",
"reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18" "reference": "038fd5713d5a41636fdff0e8dcceedecdd17fc17"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/e9e99c2b24398b967841c6c4c3048622cc7e2b18", "url": "https://api.github.com/repos/slimphp/Slim/zipball/038fd5713d5a41636fdff0e8dcceedecdd17fc17",
"reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18", "reference": "038fd5713d5a41636fdff0e8dcceedecdd17fc17",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -470,7 +417,7 @@
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
"psr/container": "^1.0 || ^2.0", "psr/container": "^1.0 || ^2.0",
"psr/http-factory": "^1.0", "psr/http-factory": "^1.0",
"psr/http-message": "^1.1", "psr/http-message": "^1.1 || ^2.0",
"psr/http-server-handler": "^1.0", "psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0", "psr/http-server-middleware": "^1.0",
"psr/log": "^1.1 || ^2.0 || ^3.0" "psr/log": "^1.1 || ^2.0 || ^3.0"
@ -478,19 +425,19 @@
"require-dev": { "require-dev": {
"adriansuter/php-autoload-override": "^1.4", "adriansuter/php-autoload-override": "^1.4",
"ext-simplexml": "*", "ext-simplexml": "*",
"guzzlehttp/psr7": "^2.5", "guzzlehttp/psr7": "^2.6",
"httpsoft/http-message": "^1.1", "httpsoft/http-message": "^1.1",
"httpsoft/http-server-request": "^1.1", "httpsoft/http-server-request": "^1.1",
"laminas/laminas-diactoros": "^2.17", "laminas/laminas-diactoros": "^2.17 || ^3",
"nyholm/psr7": "^1.8", "nyholm/psr7": "^1.8",
"nyholm/psr7-server": "^1.0", "nyholm/psr7-server": "^1.1",
"phpspec/prophecy": "^1.17", "phpspec/prophecy": "^1.19",
"phpspec/prophecy-phpunit": "^2.0", "phpspec/prophecy-phpunit": "^2.1",
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.6", "phpunit/phpunit": "^9.6",
"slim/http": "^1.3", "slim/http": "^1.3",
"slim/psr7": "^1.6", "slim/psr7": "^1.6",
"squizlabs/php_codesniffer": "^3.7" "squizlabs/php_codesniffer": "^3.9"
}, },
"suggest": { "suggest": {
"ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
@ -553,41 +500,54 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-23T04:54:29+00:00" "time": "2024-03-03T21:25:30+00:00"
}, },
{ {
"name": "symfony/cache", "name": "symfony/cache",
"version": "v3.4.47", "version": "v4.4.48",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/cache.git", "url": "https://github.com/symfony/cache.git",
"reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813" "reference": "3b98ed664887ad197b8ede3da2432787212eb915"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/a7a14c4832760bd1fbd31be2859ffedc9b6ff813", "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915",
"reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813", "reference": "3b98ed664887ad197b8ede3da2432787212eb915",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^5.5.9|>=7.0.8", "php": ">=7.1.3",
"psr/cache": "~1.0", "psr/cache": "^1.0|^2.0",
"psr/log": "~1.0", "psr/log": "^1|^2|^3",
"psr/simple-cache": "^1.0", "symfony/cache-contracts": "^1.1.7|^2",
"symfony/polyfill-apcu": "~1.1" "symfony/polyfill-php73": "^1.9",
"symfony/polyfill-php80": "^1.16",
"symfony/service-contracts": "^1.1|^2",
"symfony/var-exporter": "^4.2|^5.0"
}, },
"conflict": { "conflict": {
"symfony/var-dumper": "<3.3" "doctrine/dbal": "<2.7",
"symfony/dependency-injection": "<3.4",
"symfony/http-kernel": "<4.4|>=5.0",
"symfony/var-dumper": "<4.4"
}, },
"provide": { "provide": {
"psr/cache-implementation": "1.0", "psr/cache-implementation": "1.0|2.0",
"psr/simple-cache-implementation": "1.0" "psr/simple-cache-implementation": "1.0|2.0",
"symfony/cache-implementation": "1.0|2.0"
}, },
"require-dev": { "require-dev": {
"cache/integration-tests": "dev-master", "cache/integration-tests": "dev-master",
"doctrine/cache": "^1.6", "doctrine/cache": "^1.6|^2.0",
"doctrine/dbal": "^2.4|^3.0", "doctrine/dbal": "^2.7|^3.0",
"predis/predis": "^1.0" "predis/predis": "^1.1",
"psr/simple-cache": "^1.0|^2.0",
"symfony/config": "^4.2|^5.0",
"symfony/dependency-injection": "^3.4|^4.1|^5.0",
"symfony/filesystem": "^4.4|^5.0",
"symfony/http-kernel": "^4.4",
"symfony/var-dumper": "^4.4|^5.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -612,7 +572,7 @@
"homepage": "https://symfony.com/contributors" "homepage": "https://symfony.com/contributors"
} }
], ],
"description": "Symfony Cache component with PSR-6, PSR-16, and tags", "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"keywords": [ "keywords": [
"caching", "caching",
@ -632,7 +592,147 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-10-24T10:57:07+00:00" "time": "2022-10-17T20:21:54+00:00"
},
{
"name": "symfony/cache-contracts",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache-contracts.git",
"reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
"reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/cache": "^1.0|^2.0|^3.0"
},
"suggest": {
"symfony/cache-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Cache\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to caching",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-01-02T09:53:40+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-01-02T09:53:40+00:00"
}, },
{ {
"name": "symfony/expression-language", "name": "symfony/expression-language",
@ -694,80 +794,6 @@
], ],
"time": "2020-10-24T10:57:07+00:00" "time": "2020-10-24T10:57:07+00:00"
}, },
{
"name": "symfony/polyfill-apcu",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-apcu.git",
"reference": "c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899",
"reference": "c6c2c0f5f4cb0b100c5dfea807ef5cd27bbe9899",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Apcu\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"apcu",
"compatibility",
"polyfill",
"portable",
"shim"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2023-01-26T09:26:14+00:00"
},
{ {
"name": "symfony/polyfill-php70", "name": "symfony/polyfill-php70",
"version": "v1.20.0", "version": "v1.20.0",
@ -832,6 +858,306 @@
} }
], ],
"time": "2020-10-23T14:02:19+00:00" "time": "2020-10-23T14:02:19+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2",
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php73\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.1",
"symfony/deprecation-contracts": "^2.1|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-05-30T19:17:29+00:00"
},
{
"name": "symfony/var-exporter",
"version": "v5.4.35",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "abb0a151b62d6b07e816487e20040464af96cae7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/abb0a151b62d6b07e816487e20040464af96cae7",
"reference": "abb0a151b62d6b07e816487e20040464af96cae7",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\VarExporter\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Allows exporting any serializable PHP data structure to plain PHP code",
"homepage": "https://symfony.com",
"keywords": [
"clone",
"construct",
"export",
"hydrate",
"instantiate",
"serialize"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-01-23T13:51:25+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],
@ -840,9 +1166,10 @@
"stability-flags": [], "stability-flags": [],
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": [],
"php": ">=5.6.0"
},
"platform-dev": [], "platform-dev": [],
"platform-overrides": {
"php": "7.4"
},
"plugin-api-version": "1.1.0" "plugin-api-version": "1.1.0"
} }

View file

@ -5,7 +5,7 @@
# #
# Translators: # Translators:
# fabrixxm <fabrix.xm@gmail.com>, 2018 # fabrixxm <fabrix.xm@gmail.com>, 2018
# Sylke Vicious <silkevicious@gmail.com>, 2021 # Sylke Vicious <silkevicious@gmail.com>, 2023
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
@ -14,7 +14,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-05-11 08:54-0400\n" "POT-Creation-Date: 2022-05-11 08:54-0400\n"
"PO-Revision-Date: 2018-05-24 06:41+0000\n" "PO-Revision-Date: 2018-05-24 06:41+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2021\n" "Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2023\n"
"Language-Team: Italian (https://app.transifex.com/Friendica/teams/12172/it/)\n" "Language-Team: Italian (https://app.transifex.com/Friendica/teams/12172/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -125,7 +125,7 @@ msgstr "Annulla"
#: advancedcontentfilter.php:295 #: advancedcontentfilter.php:295
msgid "This addon requires this node having at least one post" msgid "This addon requires this node having at least one post"
msgstr "" msgstr "Questo addon richiede che questo nodo abbia almeno un messaggio"
#: advancedcontentfilter.php:325 advancedcontentfilter.php:336 #: advancedcontentfilter.php:325 advancedcontentfilter.php:336
#: advancedcontentfilter.php:347 advancedcontentfilter.php:383 #: advancedcontentfilter.php:347 advancedcontentfilter.php:383

View file

@ -27,6 +27,7 @@ $a->strings['Add new rule'] = 'Aggiungi nuova regola';
$a->strings['Rule Name'] = 'Nome Regola'; $a->strings['Rule Name'] = 'Nome Regola';
$a->strings['Rule Expression'] = 'Espressione Regola'; $a->strings['Rule Expression'] = 'Espressione Regola';
$a->strings['Cancel'] = 'Annulla'; $a->strings['Cancel'] = 'Annulla';
$a->strings['This addon requires this node having at least one post'] = 'Questo addon richiede che questo nodo abbia almeno un messaggio';
$a->strings['You must be logged in to use this method'] = 'Devi essere autenticato per usare questo metodo'; $a->strings['You must be logged in to use this method'] = 'Devi essere autenticato per usare questo metodo';
$a->strings['Invalid form security token, please refresh the page.'] = 'Token di sicurezza invalido, aggiorna la pagina.'; $a->strings['Invalid form security token, please refresh the page.'] = 'Token di sicurezza invalido, aggiorna la pagina.';
$a->strings['The rule name and expression are required.'] = 'Il nome e l\'espressione della regola sono richiesti.'; $a->strings['The rule name and expression are required.'] = 'Il nome e l\'espressione della regola sono richiesti.';

View file

@ -1,32 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use Friendica\DI;
/** @var $slim \Slim\App */
/**
* The routing middleware should be added before the ErrorMiddleware
* Otherwise exceptions thrown from it will not be handled
*/
$slim->addRoutingMiddleware();
$errorMiddleware = $slim->addErrorMiddleware(true, true, true);

View file

@ -1,36 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/* @var $slim Slim\App */
$slim->group('/advancedcontentfilter/api', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->group('/rules', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('', 'advancedcontentfilter_get_rules');
$app->post('', 'advancedcontentfilter_post_rules');
$app->get('/{id}', 'advancedcontentfilter_get_rules_id');
$app->put('/{id}', 'advancedcontentfilter_put_rules_id');
$app->delete('/{id}', 'advancedcontentfilter_delete_rules_id');
});
$app->group('/variables', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('/{guid}', 'advancedcontentfilter_get_variables_guid');
});
});

View file

@ -3,7 +3,7 @@
<div id="rules"></div> <div id="rules"></div>
<script> <script>
var existingRules = {{$rules nofilter}}; var existingRules = {{$rules|json_encode nofilter}};
var messages = { var messages = {
{{foreach $messages as $key => $value}} {{foreach $messages as $key => $value}}

View file

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

View file

@ -37,26 +37,81 @@ namespace Composer\Autoload;
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/ * @see https://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/ * @see https://www.php-fig.org/psr/psr-4/
*/ */
class ClassLoader class ClassLoader
{ {
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4 // PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array(); private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array(); private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array(); private $fallbackDirsPsr4 = array();
// PSR-0 // PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array(); private $prefixesPsr0 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr0 = array(); private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false; private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array(); private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false; private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array(); private $missingClasses = array();
/** @var string|null */
private $apcuPrefix; private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes() public function getPrefixes()
{ {
if (!empty($this->prefixesPsr0)) { if (!empty($this->prefixesPsr0)) {
@ -66,28 +121,42 @@ class ClassLoader
return array(); return array();
} }
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4() public function getPrefixesPsr4()
{ {
return $this->prefixDirsPsr4; return $this->prefixDirsPsr4;
} }
/**
* @return list<string>
*/
public function getFallbackDirs() public function getFallbackDirs()
{ {
return $this->fallbackDirsPsr0; return $this->fallbackDirsPsr0;
} }
/**
* @return list<string>
*/
public function getFallbackDirsPsr4() public function getFallbackDirsPsr4()
{ {
return $this->fallbackDirsPsr4; return $this->fallbackDirsPsr4;
} }
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap() public function getClassMap()
{ {
return $this->classMap; return $this->classMap;
} }
/** /**
* @param array $classMap Class to filename map * @param array<string, string> $classMap Class to filename map
*
* @return void
*/ */
public function addClassMap(array $classMap) public function addClassMap(array $classMap)
{ {
@ -102,22 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either * Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix. * appending or prepending to the ones previously set for this prefix.
* *
* @param string $prefix The prefix * @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories * @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories * @param bool $prepend Whether to prepend the directories
*
* @return void
*/ */
public function add($prefix, $paths, $prepend = false) public function add($prefix, $paths, $prepend = false)
{ {
$paths = (array) $paths;
if (!$prefix) { if (!$prefix) {
if ($prepend) { if ($prepend) {
$this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0 = array_merge(
(array) $paths, $paths,
$this->fallbackDirsPsr0 $this->fallbackDirsPsr0
); );
} else { } else {
$this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0, $this->fallbackDirsPsr0,
(array) $paths $paths
); );
} }
@ -126,19 +198,19 @@ class ClassLoader
$first = $prefix[0]; $first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) { if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths; $this->prefixesPsr0[$first][$prefix] = $paths;
return; return;
} }
if ($prepend) { if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths, $paths,
$this->prefixesPsr0[$first][$prefix] $this->prefixesPsr0[$first][$prefix]
); );
} else { } else {
$this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix], $this->prefixesPsr0[$first][$prefix],
(array) $paths $paths
); );
} }
} }
@ -147,25 +219,28 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either * Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace. * appending or prepending to the ones previously set for this namespace.
* *
* @param string $prefix The prefix/namespace, with trailing '\\' * @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories * @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories * @param bool $prepend Whether to prepend the directories
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*
* @return void
*/ */
public function addPsr4($prefix, $paths, $prepend = false) public function addPsr4($prefix, $paths, $prepend = false)
{ {
$paths = (array) $paths;
if (!$prefix) { if (!$prefix) {
// Register directories for the root namespace. // Register directories for the root namespace.
if ($prepend) { if ($prepend) {
$this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4 = array_merge(
(array) $paths, $paths,
$this->fallbackDirsPsr4 $this->fallbackDirsPsr4
); );
} else { } else {
$this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4, $this->fallbackDirsPsr4,
(array) $paths $paths
); );
} }
} elseif (!isset($this->prefixDirsPsr4[$prefix])) { } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@ -175,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
} }
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths; $this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) { } elseif ($prepend) {
// Prepend directories for an already registered namespace. // Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths, $paths,
$this->prefixDirsPsr4[$prefix] $this->prefixDirsPsr4[$prefix]
); );
} else { } else {
// Append directories for an already registered namespace. // Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix], $this->prefixDirsPsr4[$prefix],
(array) $paths $paths
); );
} }
} }
@ -195,8 +270,10 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, * Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix. * replacing any others previously set for this prefix.
* *
* @param string $prefix The prefix * @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories * @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/ */
public function set($prefix, $paths) public function set($prefix, $paths)
{ {
@ -211,10 +288,12 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, * Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace. * replacing any others previously set for this namespace.
* *
* @param string $prefix The prefix/namespace, with trailing '\\' * @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories * @param list<string>|string $paths The PSR-4 base directories
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*
* @return void
*/ */
public function setPsr4($prefix, $paths) public function setPsr4($prefix, $paths)
{ {
@ -234,6 +313,8 @@ class ClassLoader
* Turns on searching the include path for class files. * Turns on searching the include path for class files.
* *
* @param bool $useIncludePath * @param bool $useIncludePath
*
* @return void
*/ */
public function setUseIncludePath($useIncludePath) public function setUseIncludePath($useIncludePath)
{ {
@ -256,6 +337,8 @@ class ClassLoader
* that have not been registered with the class map. * that have not been registered with the class map.
* *
* @param bool $classMapAuthoritative * @param bool $classMapAuthoritative
*
* @return void
*/ */
public function setClassMapAuthoritative($classMapAuthoritative) public function setClassMapAuthoritative($classMapAuthoritative)
{ {
@ -276,6 +359,8 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled. * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
* *
* @param string|null $apcuPrefix * @param string|null $apcuPrefix
*
* @return void
*/ */
public function setApcuPrefix($apcuPrefix) public function setApcuPrefix($apcuPrefix)
{ {
@ -296,33 +381,55 @@ class ClassLoader
* Registers this instance as an autoloader. * Registers this instance as an autoloader.
* *
* @param bool $prepend Whether to prepend the autoloader or not * @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/ */
public function register($prepend = false) public function register($prepend = false)
{ {
spl_autoload_register(array($this, 'loadClass'), true, $prepend); spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
} }
/** /**
* Unregisters this instance as an autoloader. * Unregisters this instance as an autoloader.
*
* @return void
*/ */
public function unregister() public function unregister()
{ {
spl_autoload_unregister(array($this, 'loadClass')); spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
} }
/** /**
* Loads the given class or interface. * Loads the given class or interface.
* *
* @param string $class The name of the class * @param string $class The name of the class
* @return bool|null True if loaded, null otherwise * @return true|null True if loaded, null otherwise
*/ */
public function loadClass($class) public function loadClass($class)
{ {
if ($file = $this->findFile($class)) { if ($file = $this->findFile($class)) {
includeFile($file); $includeFile = self::$includeFile;
$includeFile($file);
return true; return true;
} }
return null;
} }
/** /**
@ -367,6 +474,21 @@ class ClassLoader
return $file; return $file;
} }
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext) private function findFileWithExtension($class, $ext)
{ {
// PSR-4 lookup // PSR-4 lookup
@ -432,14 +554,26 @@ class ClassLoader
return false; return false;
} }
}
/** /**
* Scope isolated include. * @return void
* */
* Prevents access to $this/self from included files. private static function initializeIncludeClosure()
*/ {
function includeFile($file) if (self::$includeFile !== null) {
{ return;
include $file; }
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
} }

View file

@ -0,0 +1,359 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array()) {
$installed[] = self::$installed;
}
return $installed;
}
}

View file

@ -2,10 +2,12 @@
// autoload_classmap.php @generated by Composer // autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'FastRoute\\BadRouteException' => $vendorDir . '/nikic/fast-route/src/BadRouteException.php', 'FastRoute\\BadRouteException' => $vendorDir . '/nikic/fast-route/src/BadRouteException.php',
'FastRoute\\DataGenerator' => $vendorDir . '/nikic/fast-route/src/DataGenerator.php', 'FastRoute\\DataGenerator' => $vendorDir . '/nikic/fast-route/src/DataGenerator.php',
'FastRoute\\DataGenerator\\CharCountBased' => $vendorDir . '/nikic/fast-route/src/DataGenerator/CharCountBased.php', 'FastRoute\\DataGenerator\\CharCountBased' => $vendorDir . '/nikic/fast-route/src/DataGenerator/CharCountBased.php',
@ -23,6 +25,8 @@ return array(
'FastRoute\\RouteCollector' => $vendorDir . '/nikic/fast-route/src/RouteCollector.php', 'FastRoute\\RouteCollector' => $vendorDir . '/nikic/fast-route/src/RouteCollector.php',
'FastRoute\\RouteParser' => $vendorDir . '/nikic/fast-route/src/RouteParser.php', 'FastRoute\\RouteParser' => $vendorDir . '/nikic/fast-route/src/RouteParser.php',
'FastRoute\\RouteParser\\Std' => $vendorDir . '/nikic/fast-route/src/RouteParser/Std.php', 'FastRoute\\RouteParser\\Std' => $vendorDir . '/nikic/fast-route/src/RouteParser/Std.php',
'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Psr\\Cache\\CacheException' => $vendorDir . '/psr/cache/src/CacheException.php', 'Psr\\Cache\\CacheException' => $vendorDir . '/psr/cache/src/CacheException.php',
'Psr\\Cache\\CacheItemInterface' => $vendorDir . '/psr/cache/src/CacheItemInterface.php', 'Psr\\Cache\\CacheItemInterface' => $vendorDir . '/psr/cache/src/CacheItemInterface.php',
'Psr\\Cache\\CacheItemPoolInterface' => $vendorDir . '/psr/cache/src/CacheItemPoolInterface.php', 'Psr\\Cache\\CacheItemPoolInterface' => $vendorDir . '/psr/cache/src/CacheItemPoolInterface.php',
@ -56,9 +60,6 @@ return array(
'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php', 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php',
'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php', 'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php',
'Psr\\SimpleCache\\CacheException' => $vendorDir . '/psr/simple-cache/src/CacheException.php',
'Psr\\SimpleCache\\CacheInterface' => $vendorDir . '/psr/simple-cache/src/CacheInterface.php',
'Psr\\SimpleCache\\InvalidArgumentException' => $vendorDir . '/psr/simple-cache/src/InvalidArgumentException.php',
'Slim\\App' => $vendorDir . '/slim/slim/Slim/App.php', 'Slim\\App' => $vendorDir . '/slim/slim/Slim/App.php',
'Slim\\CallableResolver' => $vendorDir . '/slim/slim/Slim/CallableResolver.php', 'Slim\\CallableResolver' => $vendorDir . '/slim/slim/Slim/CallableResolver.php',
'Slim\\Error\\AbstractErrorRenderer' => $vendorDir . '/slim/slim/Slim/Error/AbstractErrorRenderer.php', 'Slim\\Error\\AbstractErrorRenderer' => $vendorDir . '/slim/slim/Slim/Error/AbstractErrorRenderer.php',
@ -75,6 +76,7 @@ return array(
'Slim\\Exception\\HttpNotFoundException' => $vendorDir . '/slim/slim/Slim/Exception/HttpNotFoundException.php', 'Slim\\Exception\\HttpNotFoundException' => $vendorDir . '/slim/slim/Slim/Exception/HttpNotFoundException.php',
'Slim\\Exception\\HttpNotImplementedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpNotImplementedException.php', 'Slim\\Exception\\HttpNotImplementedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpNotImplementedException.php',
'Slim\\Exception\\HttpSpecializedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpSpecializedException.php', 'Slim\\Exception\\HttpSpecializedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpSpecializedException.php',
'Slim\\Exception\\HttpTooManyRequestsException' => $vendorDir . '/slim/slim/Slim/Exception/HttpTooManyRequestsException.php',
'Slim\\Exception\\HttpUnauthorizedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpUnauthorizedException.php', 'Slim\\Exception\\HttpUnauthorizedException' => $vendorDir . '/slim/slim/Slim/Exception/HttpUnauthorizedException.php',
'Slim\\Factory\\AppFactory' => $vendorDir . '/slim/slim/Slim/Factory/AppFactory.php', 'Slim\\Factory\\AppFactory' => $vendorDir . '/slim/slim/Slim/Factory/AppFactory.php',
'Slim\\Factory\\Psr17\\GuzzlePsr17Factory' => $vendorDir . '/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php', 'Slim\\Factory\\Psr17\\GuzzlePsr17Factory' => $vendorDir . '/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php',
@ -130,32 +132,47 @@ return array(
'Slim\\Routing\\RouteResolver' => $vendorDir . '/slim/slim/Slim/Routing/RouteResolver.php', 'Slim\\Routing\\RouteResolver' => $vendorDir . '/slim/slim/Slim/Routing/RouteResolver.php',
'Slim\\Routing\\RouteRunner' => $vendorDir . '/slim/slim/Slim/Routing/RouteRunner.php', 'Slim\\Routing\\RouteRunner' => $vendorDir . '/slim/slim/Slim/Routing/RouteRunner.php',
'Slim\\Routing\\RoutingResults' => $vendorDir . '/slim/slim/Slim/Routing/RoutingResults.php', 'Slim\\Routing\\RoutingResults' => $vendorDir . '/slim/slim/Slim/Routing/RoutingResults.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => $vendorDir . '/symfony/cache/Adapter/AbstractAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => $vendorDir . '/symfony/cache/Adapter/AbstractAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\AbstractTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/AbstractTagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => $vendorDir . '/symfony/cache/Adapter/AdapterInterface.php', 'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => $vendorDir . '/symfony/cache/Adapter/AdapterInterface.php',
'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => $vendorDir . '/symfony/cache/Adapter/ApcuAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => $vendorDir . '/symfony/cache/Adapter/ApcuAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/ArrayAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/ArrayAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => $vendorDir . '/symfony/cache/Adapter/ChainAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => $vendorDir . '/symfony/cache/Adapter/ChainAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\DoctrineAdapter' => $vendorDir . '/symfony/cache/Adapter/DoctrineAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\DoctrineAdapter' => $vendorDir . '/symfony/cache/Adapter/DoctrineAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => $vendorDir . '/symfony/cache/Adapter/FilesystemAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => $vendorDir . '/symfony/cache/Adapter/FilesystemAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\FilesystemTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/FilesystemTagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => $vendorDir . '/symfony/cache/Adapter/MemcachedAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => $vendorDir . '/symfony/cache/Adapter/MemcachedAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => $vendorDir . '/symfony/cache/Adapter/NullAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => $vendorDir . '/symfony/cache/Adapter/NullAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => $vendorDir . '/symfony/cache/Adapter/PdoAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => $vendorDir . '/symfony/cache/Adapter/PdoAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpArrayAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpArrayAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpFilesAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpFilesAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => $vendorDir . '/symfony/cache/Adapter/ProxyAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => $vendorDir . '/symfony/cache/Adapter/ProxyAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\Psr16Adapter' => $vendorDir . '/symfony/cache/Adapter/Psr16Adapter.php',
'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => $vendorDir . '/symfony/cache/Adapter/RedisAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => $vendorDir . '/symfony/cache/Adapter/RedisAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\RedisTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/RedisTagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\SimpleCacheAdapter' => $vendorDir . '/symfony/cache/Adapter/SimpleCacheAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\SimpleCacheAdapter' => $vendorDir . '/symfony/cache/Adapter/SimpleCacheAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapterInterface.php', 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapterInterface.php',
'Symfony\\Component\\Cache\\Adapter\\TraceableAdapter' => $vendorDir . '/symfony/cache/Adapter/TraceableAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\TraceableAdapter' => $vendorDir . '/symfony/cache/Adapter/TraceableAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TraceableAdapterEvent' => $vendorDir . '/symfony/cache/Adapter/TraceableAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php',
'Symfony\\Component\\Cache\\CacheItem' => $vendorDir . '/symfony/cache/CacheItem.php', 'Symfony\\Component\\Cache\\CacheItem' => $vendorDir . '/symfony/cache/CacheItem.php',
'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => $vendorDir . '/symfony/cache/DataCollector/CacheDataCollector.php', 'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => $vendorDir . '/symfony/cache/DataCollector/CacheDataCollector.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CacheCollectorPass' => $vendorDir . '/symfony/cache/DependencyInjection/CacheCollectorPass.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolClearerPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolClearerPass.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolPass.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPrunerPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolPrunerPass.php',
'Symfony\\Component\\Cache\\DoctrineProvider' => $vendorDir . '/symfony/cache/DoctrineProvider.php', 'Symfony\\Component\\Cache\\DoctrineProvider' => $vendorDir . '/symfony/cache/DoctrineProvider.php',
'Symfony\\Component\\Cache\\Exception\\CacheException' => $vendorDir . '/symfony/cache/Exception/CacheException.php', 'Symfony\\Component\\Cache\\Exception\\CacheException' => $vendorDir . '/symfony/cache/Exception/CacheException.php',
'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/cache/Exception/InvalidArgumentException.php', 'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/cache/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Cache\\Exception\\LogicException' => $vendorDir . '/symfony/cache/Exception/LogicException.php',
'Symfony\\Component\\Cache\\LockRegistry' => $vendorDir . '/symfony/cache/LockRegistry.php',
'Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller' => $vendorDir . '/symfony/cache/Marshaller/DefaultMarshaller.php',
'Symfony\\Component\\Cache\\Marshaller\\DeflateMarshaller' => $vendorDir . '/symfony/cache/Marshaller/DeflateMarshaller.php',
'Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface' => $vendorDir . '/symfony/cache/Marshaller/MarshallerInterface.php',
'Symfony\\Component\\Cache\\Marshaller\\TagAwareMarshaller' => $vendorDir . '/symfony/cache/Marshaller/TagAwareMarshaller.php',
'Symfony\\Component\\Cache\\PruneableInterface' => $vendorDir . '/symfony/cache/PruneableInterface.php', 'Symfony\\Component\\Cache\\PruneableInterface' => $vendorDir . '/symfony/cache/PruneableInterface.php',
'Symfony\\Component\\Cache\\Psr16Cache' => $vendorDir . '/symfony/cache/Psr16Cache.php',
'Symfony\\Component\\Cache\\ResettableInterface' => $vendorDir . '/symfony/cache/ResettableInterface.php', 'Symfony\\Component\\Cache\\ResettableInterface' => $vendorDir . '/symfony/cache/ResettableInterface.php',
'Symfony\\Component\\Cache\\Simple\\AbstractCache' => $vendorDir . '/symfony/cache/Simple/AbstractCache.php', 'Symfony\\Component\\Cache\\Simple\\AbstractCache' => $vendorDir . '/symfony/cache/Simple/AbstractCache.php',
'Symfony\\Component\\Cache\\Simple\\ApcuCache' => $vendorDir . '/symfony/cache/Simple/ApcuCache.php', 'Symfony\\Component\\Cache\\Simple\\ApcuCache' => $vendorDir . '/symfony/cache/Simple/ApcuCache.php',
@ -171,10 +188,11 @@ return array(
'Symfony\\Component\\Cache\\Simple\\Psr6Cache' => $vendorDir . '/symfony/cache/Simple/Psr6Cache.php', 'Symfony\\Component\\Cache\\Simple\\Psr6Cache' => $vendorDir . '/symfony/cache/Simple/Psr6Cache.php',
'Symfony\\Component\\Cache\\Simple\\RedisCache' => $vendorDir . '/symfony/cache/Simple/RedisCache.php', 'Symfony\\Component\\Cache\\Simple\\RedisCache' => $vendorDir . '/symfony/cache/Simple/RedisCache.php',
'Symfony\\Component\\Cache\\Simple\\TraceableCache' => $vendorDir . '/symfony/cache/Simple/TraceableCache.php', 'Symfony\\Component\\Cache\\Simple\\TraceableCache' => $vendorDir . '/symfony/cache/Simple/TraceableCache.php',
'Symfony\\Component\\Cache\\Simple\\TraceableCacheEvent' => $vendorDir . '/symfony/cache/Simple/TraceableCache.php', 'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => $vendorDir . '/symfony/cache/Traits/AbstractAdapterTrait.php',
'Symfony\\Component\\Cache\\Traits\\AbstractTrait' => $vendorDir . '/symfony/cache/Traits/AbstractTrait.php', 'Symfony\\Component\\Cache\\Traits\\AbstractTrait' => $vendorDir . '/symfony/cache/Traits/AbstractTrait.php',
'Symfony\\Component\\Cache\\Traits\\ApcuTrait' => $vendorDir . '/symfony/cache/Traits/ApcuTrait.php', 'Symfony\\Component\\Cache\\Traits\\ApcuTrait' => $vendorDir . '/symfony/cache/Traits/ApcuTrait.php',
'Symfony\\Component\\Cache\\Traits\\ArrayTrait' => $vendorDir . '/symfony/cache/Traits/ArrayTrait.php', 'Symfony\\Component\\Cache\\Traits\\ArrayTrait' => $vendorDir . '/symfony/cache/Traits/ArrayTrait.php',
'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => $vendorDir . '/symfony/cache/Traits/ContractsTrait.php',
'Symfony\\Component\\Cache\\Traits\\DoctrineTrait' => $vendorDir . '/symfony/cache/Traits/DoctrineTrait.php', 'Symfony\\Component\\Cache\\Traits\\DoctrineTrait' => $vendorDir . '/symfony/cache/Traits/DoctrineTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemCommonTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemCommonTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemTrait.php',
@ -183,6 +201,8 @@ return array(
'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => $vendorDir . '/symfony/cache/Traits/PhpArrayTrait.php', 'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => $vendorDir . '/symfony/cache/Traits/PhpArrayTrait.php',
'Symfony\\Component\\Cache\\Traits\\PhpFilesTrait' => $vendorDir . '/symfony/cache/Traits/PhpFilesTrait.php', 'Symfony\\Component\\Cache\\Traits\\PhpFilesTrait' => $vendorDir . '/symfony/cache/Traits/PhpFilesTrait.php',
'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => $vendorDir . '/symfony/cache/Traits/ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => $vendorDir . '/symfony/cache/Traits/ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterNodeProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisProxy' => $vendorDir . '/symfony/cache/Traits/RedisProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisProxy' => $vendorDir . '/symfony/cache/Traits/RedisProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisTrait' => $vendorDir . '/symfony/cache/Traits/RedisTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisTrait' => $vendorDir . '/symfony/cache/Traits/RedisTrait.php',
'Symfony\\Component\\ExpressionLanguage\\Compiler' => $vendorDir . '/symfony/expression-language/Compiler.php', 'Symfony\\Component\\ExpressionLanguage\\Compiler' => $vendorDir . '/symfony/expression-language/Compiler.php',
@ -210,5 +230,32 @@ return array(
'Symfony\\Component\\ExpressionLanguage\\SyntaxError' => $vendorDir . '/symfony/expression-language/SyntaxError.php', 'Symfony\\Component\\ExpressionLanguage\\SyntaxError' => $vendorDir . '/symfony/expression-language/SyntaxError.php',
'Symfony\\Component\\ExpressionLanguage\\Token' => $vendorDir . '/symfony/expression-language/Token.php', 'Symfony\\Component\\ExpressionLanguage\\Token' => $vendorDir . '/symfony/expression-language/Token.php',
'Symfony\\Component\\ExpressionLanguage\\TokenStream' => $vendorDir . '/symfony/expression-language/TokenStream.php', 'Symfony\\Component\\ExpressionLanguage\\TokenStream' => $vendorDir . '/symfony/expression-language/TokenStream.php',
'Symfony\\Polyfill\\Apcu\\Apcu' => $vendorDir . '/symfony/polyfill-apcu/Apcu.php', 'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => $vendorDir . '/symfony/var-exporter/Exception/ClassNotFoundException.php',
'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/var-exporter/Exception/ExceptionInterface.php',
'Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => $vendorDir . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php',
'Symfony\\Component\\VarExporter\\Instantiator' => $vendorDir . '/symfony/var-exporter/Instantiator.php',
'Symfony\\Component\\VarExporter\\Internal\\Exporter' => $vendorDir . '/symfony/var-exporter/Internal/Exporter.php',
'Symfony\\Component\\VarExporter\\Internal\\Hydrator' => $vendorDir . '/symfony/var-exporter/Internal/Hydrator.php',
'Symfony\\Component\\VarExporter\\Internal\\Reference' => $vendorDir . '/symfony/var-exporter/Internal/Reference.php',
'Symfony\\Component\\VarExporter\\Internal\\Registry' => $vendorDir . '/symfony/var-exporter/Internal/Registry.php',
'Symfony\\Component\\VarExporter\\Internal\\Values' => $vendorDir . '/symfony/var-exporter/Internal/Values.php',
'Symfony\\Component\\VarExporter\\VarExporter' => $vendorDir . '/symfony/var-exporter/VarExporter.php',
'Symfony\\Contracts\\Cache\\CacheInterface' => $vendorDir . '/symfony/cache-contracts/CacheInterface.php',
'Symfony\\Contracts\\Cache\\CacheTrait' => $vendorDir . '/symfony/cache-contracts/CacheTrait.php',
'Symfony\\Contracts\\Cache\\CallbackInterface' => $vendorDir . '/symfony/cache-contracts/CallbackInterface.php',
'Symfony\\Contracts\\Cache\\ItemInterface' => $vendorDir . '/symfony/cache-contracts/ItemInterface.php',
'Symfony\\Contracts\\Cache\\TagAwareCacheInterface' => $vendorDir . '/symfony/cache-contracts/TagAwareCacheInterface.php',
'Symfony\\Contracts\\Service\\Attribute\\Required' => $vendorDir . '/symfony/service-contracts/Attribute/Required.php',
'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => $vendorDir . '/symfony/service-contracts/Attribute/SubscribedService.php',
'Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php',
'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php',
'Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php',
'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => $vendorDir . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
'Symfony\\Polyfill\\Php73\\Php73' => $vendorDir . '/symfony/polyfill-php73/Php73.php',
'Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php',
'Symfony\\Polyfill\\Php80\\PhpToken' => $vendorDir . '/symfony/polyfill-php80/PhpToken.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
); );

View file

@ -2,10 +2,12 @@
// autoload_files.php @generated by Composer // autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php', '253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
); );

View file

@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer // autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(

View file

@ -2,18 +2,21 @@
// autoload_psr4.php @generated by Composer // autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'Symfony\\Polyfill\\Apcu\\' => array($vendorDir . '/symfony/polyfill-apcu'), 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
'Symfony\\Contracts\\Cache\\' => array($vendorDir . '/symfony/cache-contracts'),
'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'),
'Symfony\\Component\\ExpressionLanguage\\' => array($vendorDir . '/symfony/expression-language'), 'Symfony\\Component\\ExpressionLanguage\\' => array($vendorDir . '/symfony/expression-language'),
'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'), 'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'),
'Slim\\' => array($vendorDir . '/slim/slim/Slim'), 'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'), 'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'), 'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),

View file

@ -22,52 +22,29 @@ class ComposerAutoloaderInitAdvancedContentFilterAddon
return self::$loader; return self::$loader;
} }
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInitAdvancedContentFilterAddon', 'loadClassLoader'), true, true); spl_autoload_register(array('ComposerAutoloaderInitAdvancedContentFilterAddon', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitAdvancedContentFilterAddon', 'loadClassLoader')); spl_autoload_unregister(array('ComposerAutoloaderInitAdvancedContentFilterAddon', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); require __DIR__ . '/autoload_static.php';
if ($useStaticLoader) { call_user_func(\Composer\Autoload\ComposerStaticInitAdvancedContentFilterAddon::getInitializer($loader));
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitAdvancedContentFilterAddon::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true); $loader->register(true);
if ($useStaticLoader) { $filesToLoad = \Composer\Autoload\ComposerStaticInitAdvancedContentFilterAddon::$files;
$includeFiles = Composer\Autoload\ComposerStaticInitAdvancedContentFilterAddon::$files; $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
} else { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$includeFiles = require __DIR__ . '/autoload_files.php'; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
foreach ($includeFiles as $fileIdentifier => $file) { require $file;
composerRequireAdvancedContentFilterAddon($fileIdentifier, $file); }
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
} }
return $loader; return $loader;
} }
} }
function composerRequireAdvancedContentFilterAddon($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View file

@ -7,21 +7,26 @@ namespace Composer\Autoload;
class ComposerStaticInitAdvancedContentFilterAddon class ComposerStaticInitAdvancedContentFilterAddon
{ {
public static $files = array ( public static $files = array (
'32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php', '253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
); );
public static $prefixLengthsPsr4 = array ( public static $prefixLengthsPsr4 = array (
'S' => 'S' =>
array ( array (
'Symfony\\Polyfill\\Apcu\\' => 22, 'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php73\\' => 23,
'Symfony\\Contracts\\Service\\' => 26,
'Symfony\\Contracts\\Cache\\' => 24,
'Symfony\\Component\\VarExporter\\' => 30,
'Symfony\\Component\\ExpressionLanguage\\' => 37, 'Symfony\\Component\\ExpressionLanguage\\' => 37,
'Symfony\\Component\\Cache\\' => 24, 'Symfony\\Component\\Cache\\' => 24,
'Slim\\' => 5, 'Slim\\' => 5,
), ),
'P' => 'P' =>
array ( array (
'Psr\\SimpleCache\\' => 16,
'Psr\\Log\\' => 8, 'Psr\\Log\\' => 8,
'Psr\\Http\\Server\\' => 16, 'Psr\\Http\\Server\\' => 16,
'Psr\\Http\\Message\\' => 17, 'Psr\\Http\\Message\\' => 17,
@ -35,9 +40,25 @@ class ComposerStaticInitAdvancedContentFilterAddon
); );
public static $prefixDirsPsr4 = array ( public static $prefixDirsPsr4 = array (
'Symfony\\Polyfill\\Apcu\\' => 'Symfony\\Polyfill\\Php80\\' =>
array ( array (
0 => __DIR__ . '/..' . '/symfony/polyfill-apcu', 0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Php73\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
),
'Symfony\\Contracts\\Service\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/service-contracts',
),
'Symfony\\Contracts\\Cache\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/cache-contracts',
),
'Symfony\\Component\\VarExporter\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/var-exporter',
), ),
'Symfony\\Component\\ExpressionLanguage\\' => 'Symfony\\Component\\ExpressionLanguage\\' =>
array ( array (
@ -51,10 +72,6 @@ class ComposerStaticInitAdvancedContentFilterAddon
array ( array (
0 => __DIR__ . '/..' . '/slim/slim/Slim', 0 => __DIR__ . '/..' . '/slim/slim/Slim',
), ),
'Psr\\SimpleCache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
),
'Psr\\Log\\' => 'Psr\\Log\\' =>
array ( array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log', 0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
@ -66,8 +83,8 @@ class ComposerStaticInitAdvancedContentFilterAddon
), ),
'Psr\\Http\\Message\\' => 'Psr\\Http\\Message\\' =>
array ( array (
0 => __DIR__ . '/..' . '/psr/http-factory/src', 0 => __DIR__ . '/..' . '/psr/http-message/src',
1 => __DIR__ . '/..' . '/psr/http-message/src', 1 => __DIR__ . '/..' . '/psr/http-factory/src',
), ),
'Psr\\Container\\' => 'Psr\\Container\\' =>
array ( array (
@ -84,6 +101,8 @@ class ComposerStaticInitAdvancedContentFilterAddon
); );
public static $classMap = array ( public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'FastRoute\\BadRouteException' => __DIR__ . '/..' . '/nikic/fast-route/src/BadRouteException.php', 'FastRoute\\BadRouteException' => __DIR__ . '/..' . '/nikic/fast-route/src/BadRouteException.php',
'FastRoute\\DataGenerator' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator.php', 'FastRoute\\DataGenerator' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator.php',
'FastRoute\\DataGenerator\\CharCountBased' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator/CharCountBased.php', 'FastRoute\\DataGenerator\\CharCountBased' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator/CharCountBased.php',
@ -101,6 +120,8 @@ class ComposerStaticInitAdvancedContentFilterAddon
'FastRoute\\RouteCollector' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteCollector.php', 'FastRoute\\RouteCollector' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteCollector.php',
'FastRoute\\RouteParser' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser.php', 'FastRoute\\RouteParser' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser.php',
'FastRoute\\RouteParser\\Std' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser/Std.php', 'FastRoute\\RouteParser\\Std' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser/Std.php',
'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Psr\\Cache\\CacheException' => __DIR__ . '/..' . '/psr/cache/src/CacheException.php', 'Psr\\Cache\\CacheException' => __DIR__ . '/..' . '/psr/cache/src/CacheException.php',
'Psr\\Cache\\CacheItemInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemInterface.php', 'Psr\\Cache\\CacheItemInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemInterface.php',
'Psr\\Cache\\CacheItemPoolInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemPoolInterface.php', 'Psr\\Cache\\CacheItemPoolInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemPoolInterface.php',
@ -134,9 +155,6 @@ class ComposerStaticInitAdvancedContentFilterAddon
'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php', 'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php',
'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php', 'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php',
'Psr\\SimpleCache\\CacheException' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheException.php',
'Psr\\SimpleCache\\CacheInterface' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheInterface.php',
'Psr\\SimpleCache\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/simple-cache/src/InvalidArgumentException.php',
'Slim\\App' => __DIR__ . '/..' . '/slim/slim/Slim/App.php', 'Slim\\App' => __DIR__ . '/..' . '/slim/slim/Slim/App.php',
'Slim\\CallableResolver' => __DIR__ . '/..' . '/slim/slim/Slim/CallableResolver.php', 'Slim\\CallableResolver' => __DIR__ . '/..' . '/slim/slim/Slim/CallableResolver.php',
'Slim\\Error\\AbstractErrorRenderer' => __DIR__ . '/..' . '/slim/slim/Slim/Error/AbstractErrorRenderer.php', 'Slim\\Error\\AbstractErrorRenderer' => __DIR__ . '/..' . '/slim/slim/Slim/Error/AbstractErrorRenderer.php',
@ -153,6 +171,7 @@ class ComposerStaticInitAdvancedContentFilterAddon
'Slim\\Exception\\HttpNotFoundException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpNotFoundException.php', 'Slim\\Exception\\HttpNotFoundException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpNotFoundException.php',
'Slim\\Exception\\HttpNotImplementedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpNotImplementedException.php', 'Slim\\Exception\\HttpNotImplementedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpNotImplementedException.php',
'Slim\\Exception\\HttpSpecializedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpSpecializedException.php', 'Slim\\Exception\\HttpSpecializedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpSpecializedException.php',
'Slim\\Exception\\HttpTooManyRequestsException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpTooManyRequestsException.php',
'Slim\\Exception\\HttpUnauthorizedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpUnauthorizedException.php', 'Slim\\Exception\\HttpUnauthorizedException' => __DIR__ . '/..' . '/slim/slim/Slim/Exception/HttpUnauthorizedException.php',
'Slim\\Factory\\AppFactory' => __DIR__ . '/..' . '/slim/slim/Slim/Factory/AppFactory.php', 'Slim\\Factory\\AppFactory' => __DIR__ . '/..' . '/slim/slim/Slim/Factory/AppFactory.php',
'Slim\\Factory\\Psr17\\GuzzlePsr17Factory' => __DIR__ . '/..' . '/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php', 'Slim\\Factory\\Psr17\\GuzzlePsr17Factory' => __DIR__ . '/..' . '/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php',
@ -208,32 +227,47 @@ class ComposerStaticInitAdvancedContentFilterAddon
'Slim\\Routing\\RouteResolver' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RouteResolver.php', 'Slim\\Routing\\RouteResolver' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RouteResolver.php',
'Slim\\Routing\\RouteRunner' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RouteRunner.php', 'Slim\\Routing\\RouteRunner' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RouteRunner.php',
'Slim\\Routing\\RoutingResults' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RoutingResults.php', 'Slim\\Routing\\RoutingResults' => __DIR__ . '/..' . '/slim/slim/Slim/Routing/RoutingResults.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/AbstractAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/AbstractAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\AbstractTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/AbstractTagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/AdapterInterface.php', 'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/AdapterInterface.php',
'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ApcuAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ApcuAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ArrayAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ArrayAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ChainAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ChainAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\DoctrineAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/DoctrineAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\DoctrineAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/DoctrineAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/FilesystemAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/FilesystemAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\FilesystemTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/FilesystemTagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/MemcachedAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/MemcachedAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/NullAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/NullAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PdoAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PdoAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpArrayAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpArrayAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpFilesAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpFilesAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ProxyAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ProxyAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\Psr16Adapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/Psr16Adapter.php',
'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/RedisAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/RedisAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\RedisTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/RedisTagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\SimpleCacheAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/SimpleCacheAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\SimpleCacheAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/SimpleCacheAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapterInterface.php', 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapterInterface.php',
'Symfony\\Component\\Cache\\Adapter\\TraceableAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\TraceableAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TraceableAdapterEvent' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableAdapter.php',
'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php', 'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php',
'Symfony\\Component\\Cache\\CacheItem' => __DIR__ . '/..' . '/symfony/cache/CacheItem.php', 'Symfony\\Component\\Cache\\CacheItem' => __DIR__ . '/..' . '/symfony/cache/CacheItem.php',
'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => __DIR__ . '/..' . '/symfony/cache/DataCollector/CacheDataCollector.php', 'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => __DIR__ . '/..' . '/symfony/cache/DataCollector/CacheDataCollector.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CacheCollectorPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CacheCollectorPass.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolClearerPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolClearerPass.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolPass.php',
'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPrunerPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolPrunerPass.php',
'Symfony\\Component\\Cache\\DoctrineProvider' => __DIR__ . '/..' . '/symfony/cache/DoctrineProvider.php', 'Symfony\\Component\\Cache\\DoctrineProvider' => __DIR__ . '/..' . '/symfony/cache/DoctrineProvider.php',
'Symfony\\Component\\Cache\\Exception\\CacheException' => __DIR__ . '/..' . '/symfony/cache/Exception/CacheException.php', 'Symfony\\Component\\Cache\\Exception\\CacheException' => __DIR__ . '/..' . '/symfony/cache/Exception/CacheException.php',
'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/cache/Exception/InvalidArgumentException.php', 'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/cache/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Cache\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/cache/Exception/LogicException.php',
'Symfony\\Component\\Cache\\LockRegistry' => __DIR__ . '/..' . '/symfony/cache/LockRegistry.php',
'Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/DefaultMarshaller.php',
'Symfony\\Component\\Cache\\Marshaller\\DeflateMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/DeflateMarshaller.php',
'Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface' => __DIR__ . '/..' . '/symfony/cache/Marshaller/MarshallerInterface.php',
'Symfony\\Component\\Cache\\Marshaller\\TagAwareMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/TagAwareMarshaller.php',
'Symfony\\Component\\Cache\\PruneableInterface' => __DIR__ . '/..' . '/symfony/cache/PruneableInterface.php', 'Symfony\\Component\\Cache\\PruneableInterface' => __DIR__ . '/..' . '/symfony/cache/PruneableInterface.php',
'Symfony\\Component\\Cache\\Psr16Cache' => __DIR__ . '/..' . '/symfony/cache/Psr16Cache.php',
'Symfony\\Component\\Cache\\ResettableInterface' => __DIR__ . '/..' . '/symfony/cache/ResettableInterface.php', 'Symfony\\Component\\Cache\\ResettableInterface' => __DIR__ . '/..' . '/symfony/cache/ResettableInterface.php',
'Symfony\\Component\\Cache\\Simple\\AbstractCache' => __DIR__ . '/..' . '/symfony/cache/Simple/AbstractCache.php', 'Symfony\\Component\\Cache\\Simple\\AbstractCache' => __DIR__ . '/..' . '/symfony/cache/Simple/AbstractCache.php',
'Symfony\\Component\\Cache\\Simple\\ApcuCache' => __DIR__ . '/..' . '/symfony/cache/Simple/ApcuCache.php', 'Symfony\\Component\\Cache\\Simple\\ApcuCache' => __DIR__ . '/..' . '/symfony/cache/Simple/ApcuCache.php',
@ -249,10 +283,11 @@ class ComposerStaticInitAdvancedContentFilterAddon
'Symfony\\Component\\Cache\\Simple\\Psr6Cache' => __DIR__ . '/..' . '/symfony/cache/Simple/Psr6Cache.php', 'Symfony\\Component\\Cache\\Simple\\Psr6Cache' => __DIR__ . '/..' . '/symfony/cache/Simple/Psr6Cache.php',
'Symfony\\Component\\Cache\\Simple\\RedisCache' => __DIR__ . '/..' . '/symfony/cache/Simple/RedisCache.php', 'Symfony\\Component\\Cache\\Simple\\RedisCache' => __DIR__ . '/..' . '/symfony/cache/Simple/RedisCache.php',
'Symfony\\Component\\Cache\\Simple\\TraceableCache' => __DIR__ . '/..' . '/symfony/cache/Simple/TraceableCache.php', 'Symfony\\Component\\Cache\\Simple\\TraceableCache' => __DIR__ . '/..' . '/symfony/cache/Simple/TraceableCache.php',
'Symfony\\Component\\Cache\\Simple\\TraceableCacheEvent' => __DIR__ . '/..' . '/symfony/cache/Simple/TraceableCache.php', 'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractAdapterTrait.php',
'Symfony\\Component\\Cache\\Traits\\AbstractTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractTrait.php', 'Symfony\\Component\\Cache\\Traits\\AbstractTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractTrait.php',
'Symfony\\Component\\Cache\\Traits\\ApcuTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ApcuTrait.php', 'Symfony\\Component\\Cache\\Traits\\ApcuTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ApcuTrait.php',
'Symfony\\Component\\Cache\\Traits\\ArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ArrayTrait.php', 'Symfony\\Component\\Cache\\Traits\\ArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ArrayTrait.php',
'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ContractsTrait.php',
'Symfony\\Component\\Cache\\Traits\\DoctrineTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/DoctrineTrait.php', 'Symfony\\Component\\Cache\\Traits\\DoctrineTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/DoctrineTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemCommonTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemCommonTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemTrait.php',
@ -261,6 +296,8 @@ class ComposerStaticInitAdvancedContentFilterAddon
'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpArrayTrait.php', 'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpArrayTrait.php',
'Symfony\\Component\\Cache\\Traits\\PhpFilesTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpFilesTrait.php', 'Symfony\\Component\\Cache\\Traits\\PhpFilesTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpFilesTrait.php',
'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterNodeProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisTrait.php',
'Symfony\\Component\\ExpressionLanguage\\Compiler' => __DIR__ . '/..' . '/symfony/expression-language/Compiler.php', 'Symfony\\Component\\ExpressionLanguage\\Compiler' => __DIR__ . '/..' . '/symfony/expression-language/Compiler.php',
@ -288,7 +325,34 @@ class ComposerStaticInitAdvancedContentFilterAddon
'Symfony\\Component\\ExpressionLanguage\\SyntaxError' => __DIR__ . '/..' . '/symfony/expression-language/SyntaxError.php', 'Symfony\\Component\\ExpressionLanguage\\SyntaxError' => __DIR__ . '/..' . '/symfony/expression-language/SyntaxError.php',
'Symfony\\Component\\ExpressionLanguage\\Token' => __DIR__ . '/..' . '/symfony/expression-language/Token.php', 'Symfony\\Component\\ExpressionLanguage\\Token' => __DIR__ . '/..' . '/symfony/expression-language/Token.php',
'Symfony\\Component\\ExpressionLanguage\\TokenStream' => __DIR__ . '/..' . '/symfony/expression-language/TokenStream.php', 'Symfony\\Component\\ExpressionLanguage\\TokenStream' => __DIR__ . '/..' . '/symfony/expression-language/TokenStream.php',
'Symfony\\Polyfill\\Apcu\\Apcu' => __DIR__ . '/..' . '/symfony/polyfill-apcu/Apcu.php', 'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ClassNotFoundException.php',
'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ExceptionInterface.php',
'Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php',
'Symfony\\Component\\VarExporter\\Instantiator' => __DIR__ . '/..' . '/symfony/var-exporter/Instantiator.php',
'Symfony\\Component\\VarExporter\\Internal\\Exporter' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Exporter.php',
'Symfony\\Component\\VarExporter\\Internal\\Hydrator' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Hydrator.php',
'Symfony\\Component\\VarExporter\\Internal\\Reference' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Reference.php',
'Symfony\\Component\\VarExporter\\Internal\\Registry' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Registry.php',
'Symfony\\Component\\VarExporter\\Internal\\Values' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Values.php',
'Symfony\\Component\\VarExporter\\VarExporter' => __DIR__ . '/..' . '/symfony/var-exporter/VarExporter.php',
'Symfony\\Contracts\\Cache\\CacheInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/CacheInterface.php',
'Symfony\\Contracts\\Cache\\CacheTrait' => __DIR__ . '/..' . '/symfony/cache-contracts/CacheTrait.php',
'Symfony\\Contracts\\Cache\\CallbackInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/CallbackInterface.php',
'Symfony\\Contracts\\Cache\\ItemInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/ItemInterface.php',
'Symfony\\Contracts\\Cache\\TagAwareCacheInterface' => __DIR__ . '/..' . '/symfony/cache-contracts/TagAwareCacheInterface.php',
'Symfony\\Contracts\\Service\\Attribute\\Required' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/Required.php',
'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/SubscribedService.php',
'Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php',
'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php',
'Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php',
'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php',
'Symfony\\Contracts\\Service\\Test\\ServiceLocatorTest' => __DIR__ . '/..' . '/symfony/service-contracts/Test/ServiceLocatorTest.php',
'Symfony\\Polyfill\\Php73\\Php73' => __DIR__ . '/..' . '/symfony/polyfill-php73/Php73.php',
'Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php',
'Symfony\\Polyfill\\Php80\\PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/PhpToken.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
); );
public static function getInitializer(ClassLoader $loader) public static function getInitializer(ClassLoader $loader)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,203 @@
<?php return array(
'root' => array(
'name' => 'friendica-addons/advancedcontentfilter',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'feb7722f723b21e76fdf20a7ce4b42fa5ffcdcb9',
'type' => 'friendica-addon',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => false,
),
'versions' => array(
'friendica-addons/advancedcontentfilter' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'feb7722f723b21e76fdf20a7ce4b42fa5ffcdcb9',
'type' => 'friendica-addon',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'nikic/fast-route' => array(
'pretty_version' => 'v1.3.0',
'version' => '1.3.0.0',
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
'type' => 'library',
'install_path' => __DIR__ . '/../nikic/fast-route',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/cache',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/cache-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0|2.0',
),
),
'psr/container' => array(
'pretty_version' => '1.1.2',
'version' => '1.1.2.0',
'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-factory' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'reference' => 'e616d01114759c4c489f93b099585439f795fe35',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-message' => array(
'pretty_version' => '2.0',
'version' => '2.0.0.0',
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-server-handler' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'reference' => '84c4fb66179be4caaf8e97bd239203245302e7d4',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-server-handler',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-server-middleware' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'reference' => 'c1481f747daaa6a0782775cd6a8c26a1bf4a3829',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-server-middleware',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/log' => array(
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/simple-cache-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0|2.0',
),
),
'slim/slim' => array(
'pretty_version' => '4.13.0',
'version' => '4.13.0.0',
'reference' => '038fd5713d5a41636fdff0e8dcceedecdd17fc17',
'type' => 'library',
'install_path' => __DIR__ . '/../slim/slim',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v4.4.48',
'version' => '4.4.48.0',
'reference' => '3b98ed664887ad197b8ede3da2432787212eb915',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/cache-contracts' => array(
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'reference' => '64be4a7acb83b6f2bf6de9a02cee6dad41277ebc',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/cache-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0|2.0',
),
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/expression-language' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'de38e66398fca1fcb9c48e80279910e6889cb28f',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/expression-language',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php70' => array(
'pretty_version' => 'v1.20.0',
'version' => '1.20.0.0',
'reference' => '5f03a781d984aae42cebd18e7912fa80f02ee644',
'type' => 'metapackage',
'install_path' => null,
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php73' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => '21bd091060673a1177ae842c0ef8fe30893114d2',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php73',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => '87b68208d5c1188808dd7839ee1e6c8ec3b02f1b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/service-contracts' => array(
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/service-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-exporter' => array(
'pretty_version' => 'v5.4.35',
'version' => '5.4.35.0',
'reference' => 'abb0a151b62d6b07e816487e20040464af96cae7',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-exporter',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

View file

@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70400)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}

View file

@ -18,10 +18,5 @@
"psr-4": { "psr-4": {
"Psr\\Container\\": "src/" "Psr\\Container\\": "src/"
} }
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
} }
} }

View file

@ -32,5 +32,5 @@ interface ContainerInterface
* *
* @return bool * @return bool
*/ */
public function has(string $id): bool; public function has(string $id);
} }

View file

@ -7,7 +7,7 @@
"authors": [ "authors": [
{ {
"name": "PHP-FIG", "name": "PHP-FIG",
"homepage": "http://www.php-fig.org/" "homepage": "https://www.php-fig.org/"
} }
], ],
"require": { "require": {
@ -20,7 +20,7 @@
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.1.x-dev" "dev-master": "2.0.x-dev"
} }
} }
} }

View file

@ -1,7 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -25,7 +23,7 @@ interface MessageInterface
* *
* @return string HTTP protocol version. * @return string HTTP protocol version.
*/ */
public function getProtocolVersion(); public function getProtocolVersion(): string;
/** /**
* Return an instance with the specified HTTP protocol version. * Return an instance with the specified HTTP protocol version.
@ -40,7 +38,7 @@ interface MessageInterface
* @param string $version HTTP protocol version * @param string $version HTTP protocol version
* @return static * @return static
*/ */
public function withProtocolVersion(string $version); public function withProtocolVersion(string $version): MessageInterface;
/** /**
* Retrieves all message header values. * Retrieves all message header values.
@ -67,7 +65,7 @@ interface MessageInterface
* key MUST be a header name, and each value MUST be an array of strings * key MUST be a header name, and each value MUST be an array of strings
* for that header. * for that header.
*/ */
public function getHeaders(); public function getHeaders(): array;
/** /**
* Checks if a header exists by the given case-insensitive name. * Checks if a header exists by the given case-insensitive name.
@ -77,7 +75,7 @@ interface MessageInterface
* name using a case-insensitive string comparison. Returns false if * name using a case-insensitive string comparison. Returns false if
* no matching header name is found in the message. * no matching header name is found in the message.
*/ */
public function hasHeader(string $name); public function hasHeader(string $name): bool;
/** /**
* Retrieves a message header value by the given case-insensitive name. * Retrieves a message header value by the given case-insensitive name.
@ -93,7 +91,7 @@ interface MessageInterface
* header. If the header does not appear in the message, this method MUST * header. If the header does not appear in the message, this method MUST
* return an empty array. * return an empty array.
*/ */
public function getHeader(string $name); public function getHeader(string $name): array;
/** /**
* Retrieves a comma-separated string of the values for a single header. * Retrieves a comma-separated string of the values for a single header.
@ -114,7 +112,7 @@ interface MessageInterface
* concatenated together using a comma. If the header does not appear in * concatenated together using a comma. If the header does not appear in
* the message, this method MUST return an empty string. * the message, this method MUST return an empty string.
*/ */
public function getHeaderLine(string $name); public function getHeaderLine(string $name): string;
/** /**
* Return an instance with the provided value replacing the specified header. * Return an instance with the provided value replacing the specified header.
@ -131,7 +129,7 @@ interface MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withHeader(string $name, $value); public function withHeader(string $name, $value): MessageInterface;
/** /**
* Return an instance with the specified header appended with the given value. * Return an instance with the specified header appended with the given value.
@ -149,7 +147,7 @@ interface MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withAddedHeader(string $name, $value); public function withAddedHeader(string $name, $value): MessageInterface;
/** /**
* Return an instance without the specified header. * Return an instance without the specified header.
@ -163,14 +161,14 @@ interface MessageInterface
* @param string $name Case-insensitive header field name to remove. * @param string $name Case-insensitive header field name to remove.
* @return static * @return static
*/ */
public function withoutHeader(string $name); public function withoutHeader(string $name): MessageInterface;
/** /**
* Gets the body of the message. * Gets the body of the message.
* *
* @return StreamInterface Returns the body as a stream. * @return StreamInterface Returns the body as a stream.
*/ */
public function getBody(); public function getBody(): StreamInterface;
/** /**
* Return an instance with the specified message body. * Return an instance with the specified message body.
@ -185,5 +183,5 @@ interface MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException When the body is not valid. * @throws \InvalidArgumentException When the body is not valid.
*/ */
public function withBody(StreamInterface $body); public function withBody(StreamInterface $body): MessageInterface;
} }

View file

@ -1,7 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -41,7 +39,7 @@ interface RequestInterface extends MessageInterface
* *
* @return string * @return string
*/ */
public function getRequestTarget(); public function getRequestTarget(): string;
/** /**
* Return an instance with the specific request-target. * Return an instance with the specific request-target.
@ -60,14 +58,15 @@ interface RequestInterface extends MessageInterface
* @param string $requestTarget * @param string $requestTarget
* @return static * @return static
*/ */
public function withRequestTarget(string $requestTarget); public function withRequestTarget(string $requestTarget): RequestInterface;
/** /**
* Retrieves the HTTP method of the request. * Retrieves the HTTP method of the request.
* *
* @return string Returns the request method. * @return string Returns the request method.
*/ */
public function getMethod(); public function getMethod(): string;
/** /**
* Return an instance with the provided HTTP method. * Return an instance with the provided HTTP method.
@ -84,7 +83,7 @@ interface RequestInterface extends MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException for invalid HTTP methods. * @throws \InvalidArgumentException for invalid HTTP methods.
*/ */
public function withMethod(string $method); public function withMethod(string $method): RequestInterface;
/** /**
* Retrieves the URI instance. * Retrieves the URI instance.
@ -95,7 +94,7 @@ interface RequestInterface extends MessageInterface
* @return UriInterface Returns a UriInterface instance * @return UriInterface Returns a UriInterface instance
* representing the URI of the request. * representing the URI of the request.
*/ */
public function getUri(); public function getUri(): UriInterface;
/** /**
* Returns an instance with the provided URI. * Returns an instance with the provided URI.
@ -127,5 +126,5 @@ interface RequestInterface extends MessageInterface
* @param bool $preserveHost Preserve the original state of the Host header. * @param bool $preserveHost Preserve the original state of the Host header.
* @return static * @return static
*/ */
public function withUri(UriInterface $uri, bool $preserveHost = false); public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface;
} }

View file

@ -1,7 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -29,7 +27,7 @@ interface ResponseInterface extends MessageInterface
* *
* @return int Status code. * @return int Status code.
*/ */
public function getStatusCode(); public function getStatusCode(): int;
/** /**
* Return an instance with the specified status code and, optionally, reason phrase. * Return an instance with the specified status code and, optionally, reason phrase.
@ -51,7 +49,7 @@ interface ResponseInterface extends MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException For invalid status code arguments. * @throws \InvalidArgumentException For invalid status code arguments.
*/ */
public function withStatus(int $code, string $reasonPhrase = ''); public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface;
/** /**
* Gets the response reason phrase associated with the status code. * Gets the response reason phrase associated with the status code.
@ -66,5 +64,5 @@ interface ResponseInterface extends MessageInterface
* @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
* @return string Reason phrase; must return an empty string if none present. * @return string Reason phrase; must return an empty string if none present.
*/ */
public function getReasonPhrase(); public function getReasonPhrase(): string;
} }

View file

@ -1,7 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -53,7 +51,7 @@ interface ServerRequestInterface extends RequestInterface
* *
* @return array * @return array
*/ */
public function getServerParams(); public function getServerParams(): array;
/** /**
* Retrieve cookies. * Retrieve cookies.
@ -65,7 +63,7 @@ interface ServerRequestInterface extends RequestInterface
* *
* @return array * @return array
*/ */
public function getCookieParams(); public function getCookieParams(): array;
/** /**
* Return an instance with the specified cookies. * Return an instance with the specified cookies.
@ -84,7 +82,7 @@ interface ServerRequestInterface extends RequestInterface
* @param array $cookies Array of key/value pairs representing cookies. * @param array $cookies Array of key/value pairs representing cookies.
* @return static * @return static
*/ */
public function withCookieParams(array $cookies); public function withCookieParams(array $cookies): ServerRequestInterface;
/** /**
* Retrieve query string arguments. * Retrieve query string arguments.
@ -98,7 +96,7 @@ interface ServerRequestInterface extends RequestInterface
* *
* @return array * @return array
*/ */
public function getQueryParams(); public function getQueryParams(): array;
/** /**
* Return an instance with the specified query string arguments. * Return an instance with the specified query string arguments.
@ -122,7 +120,7 @@ interface ServerRequestInterface extends RequestInterface
* $_GET. * $_GET.
* @return static * @return static
*/ */
public function withQueryParams(array $query); public function withQueryParams(array $query): ServerRequestInterface;
/** /**
* Retrieve normalized file upload data. * Retrieve normalized file upload data.
@ -136,7 +134,7 @@ interface ServerRequestInterface extends RequestInterface
* @return array An array tree of UploadedFileInterface instances; an empty * @return array An array tree of UploadedFileInterface instances; an empty
* array MUST be returned if no data is present. * array MUST be returned if no data is present.
*/ */
public function getUploadedFiles(); public function getUploadedFiles(): array;
/** /**
* Create a new instance with the specified uploaded files. * Create a new instance with the specified uploaded files.
@ -149,7 +147,7 @@ interface ServerRequestInterface extends RequestInterface
* @return static * @return static
* @throws \InvalidArgumentException if an invalid structure is provided. * @throws \InvalidArgumentException if an invalid structure is provided.
*/ */
public function withUploadedFiles(array $uploadedFiles); public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface;
/** /**
* Retrieve any parameters provided in the request body. * Retrieve any parameters provided in the request body.
@ -196,7 +194,7 @@ interface ServerRequestInterface extends RequestInterface
* @throws \InvalidArgumentException if an unsupported argument type is * @throws \InvalidArgumentException if an unsupported argument type is
* provided. * provided.
*/ */
public function withParsedBody($data); public function withParsedBody($data): ServerRequestInterface;
/** /**
* Retrieve attributes derived from the request. * Retrieve attributes derived from the request.
@ -209,7 +207,7 @@ interface ServerRequestInterface extends RequestInterface
* *
* @return array Attributes derived from the request. * @return array Attributes derived from the request.
*/ */
public function getAttributes(); public function getAttributes(): array;
/** /**
* Retrieve a single derived request attribute. * Retrieve a single derived request attribute.
@ -243,7 +241,7 @@ interface ServerRequestInterface extends RequestInterface
* @param mixed $value The value of the attribute. * @param mixed $value The value of the attribute.
* @return static * @return static
*/ */
public function withAttribute(string $name, $value); public function withAttribute(string $name, $value): ServerRequestInterface;
/** /**
* Return an instance that removes the specified derived request attribute. * Return an instance that removes the specified derived request attribute.
@ -259,5 +257,5 @@ interface ServerRequestInterface extends RequestInterface
* @param string $name The attribute name. * @param string $name The attribute name.
* @return static * @return static
*/ */
public function withoutAttribute(string $name); public function withoutAttribute(string $name): ServerRequestInterface;
} }

View file

@ -1,7 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -27,14 +25,14 @@ interface StreamInterface
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
* @return string * @return string
*/ */
public function __toString(); public function __toString(): string;
/** /**
* Closes the stream and any underlying resources. * Closes the stream and any underlying resources.
* *
* @return void * @return void
*/ */
public function close(); public function close(): void;
/** /**
* Separates any underlying resources from the stream. * Separates any underlying resources from the stream.
@ -50,7 +48,7 @@ interface StreamInterface
* *
* @return int|null Returns the size in bytes if known, or null if unknown. * @return int|null Returns the size in bytes if known, or null if unknown.
*/ */
public function getSize(); public function getSize(): ?int;
/** /**
* Returns the current position of the file read/write pointer * Returns the current position of the file read/write pointer
@ -58,21 +56,21 @@ interface StreamInterface
* @return int Position of the file pointer * @return int Position of the file pointer
* @throws \RuntimeException on error. * @throws \RuntimeException on error.
*/ */
public function tell(); public function tell(): int;
/** /**
* Returns true if the stream is at the end of the stream. * Returns true if the stream is at the end of the stream.
* *
* @return bool * @return bool
*/ */
public function eof(); public function eof(): bool;
/** /**
* Returns whether or not the stream is seekable. * Returns whether or not the stream is seekable.
* *
* @return bool * @return bool
*/ */
public function isSeekable(); public function isSeekable(): bool;
/** /**
* Seek to a position in the stream. * Seek to a position in the stream.
@ -86,7 +84,7 @@ interface StreamInterface
* SEEK_END: Set position to end-of-stream plus offset. * SEEK_END: Set position to end-of-stream plus offset.
* @throws \RuntimeException on failure. * @throws \RuntimeException on failure.
*/ */
public function seek(int $offset, int $whence = SEEK_SET); public function seek(int $offset, int $whence = SEEK_SET): void;
/** /**
* Seek to the beginning of the stream. * Seek to the beginning of the stream.
@ -98,14 +96,14 @@ interface StreamInterface
* @link http://www.php.net/manual/en/function.fseek.php * @link http://www.php.net/manual/en/function.fseek.php
* @throws \RuntimeException on failure. * @throws \RuntimeException on failure.
*/ */
public function rewind(); public function rewind(): void;
/** /**
* Returns whether or not the stream is writable. * Returns whether or not the stream is writable.
* *
* @return bool * @return bool
*/ */
public function isWritable(); public function isWritable(): bool;
/** /**
* Write data to the stream. * Write data to the stream.
@ -114,14 +112,14 @@ interface StreamInterface
* @return int Returns the number of bytes written to the stream. * @return int Returns the number of bytes written to the stream.
* @throws \RuntimeException on failure. * @throws \RuntimeException on failure.
*/ */
public function write(string $string); public function write(string $string): int;
/** /**
* Returns whether or not the stream is readable. * Returns whether or not the stream is readable.
* *
* @return bool * @return bool
*/ */
public function isReadable(); public function isReadable(): bool;
/** /**
* Read data from the stream. * Read data from the stream.
@ -133,7 +131,7 @@ interface StreamInterface
* if no bytes are available. * if no bytes are available.
* @throws \RuntimeException if an error occurs. * @throws \RuntimeException if an error occurs.
*/ */
public function read(int $length); public function read(int $length): string;
/** /**
* Returns the remaining contents in a string * Returns the remaining contents in a string
@ -142,7 +140,7 @@ interface StreamInterface
* @throws \RuntimeException if unable to read or an error occurs while * @throws \RuntimeException if unable to read or an error occurs while
* reading. * reading.
*/ */
public function getContents(); public function getContents(): string;
/** /**
* Get stream metadata as an associative array or retrieve a specific key. * Get stream metadata as an associative array or retrieve a specific key.

View file

@ -1,7 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -30,7 +28,7 @@ interface UploadedFileInterface
* @throws \RuntimeException in cases when no stream is available or can be * @throws \RuntimeException in cases when no stream is available or can be
* created. * created.
*/ */
public function getStream(); public function getStream(): StreamInterface;
/** /**
* Move the uploaded file to a new location. * Move the uploaded file to a new location.
@ -64,7 +62,7 @@ interface UploadedFileInterface
* @throws \RuntimeException on any error during the move operation, or on * @throws \RuntimeException on any error during the move operation, or on
* the second or subsequent call to the method. * the second or subsequent call to the method.
*/ */
public function moveTo(string $targetPath); public function moveTo(string $targetPath): void;
/** /**
* Retrieve the file size. * Retrieve the file size.
@ -75,7 +73,7 @@ interface UploadedFileInterface
* *
* @return int|null The file size in bytes or null if unknown. * @return int|null The file size in bytes or null if unknown.
*/ */
public function getSize(); public function getSize(): ?int;
/** /**
* Retrieve the error associated with the uploaded file. * Retrieve the error associated with the uploaded file.
@ -91,7 +89,7 @@ interface UploadedFileInterface
* @see http://php.net/manual/en/features.file-upload.errors.php * @see http://php.net/manual/en/features.file-upload.errors.php
* @return int One of PHP's UPLOAD_ERR_XXX constants. * @return int One of PHP's UPLOAD_ERR_XXX constants.
*/ */
public function getError(); public function getError(): int;
/** /**
* Retrieve the filename sent by the client. * Retrieve the filename sent by the client.
@ -106,7 +104,7 @@ interface UploadedFileInterface
* @return string|null The filename sent by the client or null if none * @return string|null The filename sent by the client or null if none
* was provided. * was provided.
*/ */
public function getClientFilename(); public function getClientFilename(): ?string;
/** /**
* Retrieve the media type sent by the client. * Retrieve the media type sent by the client.
@ -121,5 +119,5 @@ interface UploadedFileInterface
* @return string|null The media type sent by the client or null if none * @return string|null The media type sent by the client or null if none
* was provided. * was provided.
*/ */
public function getClientMediaType(); public function getClientMediaType(): ?string;
} }

View file

@ -1,7 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -40,7 +38,7 @@ interface UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.1 * @see https://tools.ietf.org/html/rfc3986#section-3.1
* @return string The URI scheme. * @return string The URI scheme.
*/ */
public function getScheme(); public function getScheme(): string;
/** /**
* Retrieve the authority component of the URI. * Retrieve the authority component of the URI.
@ -60,7 +58,7 @@ interface UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.2 * @see https://tools.ietf.org/html/rfc3986#section-3.2
* @return string The URI authority, in "[user-info@]host[:port]" format. * @return string The URI authority, in "[user-info@]host[:port]" format.
*/ */
public function getAuthority(); public function getAuthority(): string;
/** /**
* Retrieve the user information component of the URI. * Retrieve the user information component of the URI.
@ -77,7 +75,7 @@ interface UriInterface
* *
* @return string The URI user information, in "username[:password]" format. * @return string The URI user information, in "username[:password]" format.
*/ */
public function getUserInfo(); public function getUserInfo(): string;
/** /**
* Retrieve the host component of the URI. * Retrieve the host component of the URI.
@ -90,7 +88,7 @@ interface UriInterface
* @see http://tools.ietf.org/html/rfc3986#section-3.2.2 * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
* @return string The URI host. * @return string The URI host.
*/ */
public function getHost(); public function getHost(): string;
/** /**
* Retrieve the port component of the URI. * Retrieve the port component of the URI.
@ -107,7 +105,7 @@ interface UriInterface
* *
* @return null|int The URI port. * @return null|int The URI port.
*/ */
public function getPort(); public function getPort(): ?int;
/** /**
* Retrieve the path component of the URI. * Retrieve the path component of the URI.
@ -134,7 +132,7 @@ interface UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.3 * @see https://tools.ietf.org/html/rfc3986#section-3.3
* @return string The URI path. * @return string The URI path.
*/ */
public function getPath(); public function getPath(): string;
/** /**
* Retrieve the query string of the URI. * Retrieve the query string of the URI.
@ -156,7 +154,7 @@ interface UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.4 * @see https://tools.ietf.org/html/rfc3986#section-3.4
* @return string The URI query string. * @return string The URI query string.
*/ */
public function getQuery(); public function getQuery(): string;
/** /**
* Retrieve the fragment component of the URI. * Retrieve the fragment component of the URI.
@ -174,7 +172,7 @@ interface UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.5 * @see https://tools.ietf.org/html/rfc3986#section-3.5
* @return string The URI fragment. * @return string The URI fragment.
*/ */
public function getFragment(); public function getFragment(): string;
/** /**
* Return an instance with the specified scheme. * Return an instance with the specified scheme.
@ -191,7 +189,7 @@ interface UriInterface
* @return static A new instance with the specified scheme. * @return static A new instance with the specified scheme.
* @throws \InvalidArgumentException for invalid or unsupported schemes. * @throws \InvalidArgumentException for invalid or unsupported schemes.
*/ */
public function withScheme(string $scheme); public function withScheme(string $scheme): UriInterface;
/** /**
* Return an instance with the specified user information. * Return an instance with the specified user information.
@ -207,7 +205,7 @@ interface UriInterface
* @param null|string $password The password associated with $user. * @param null|string $password The password associated with $user.
* @return static A new instance with the specified user information. * @return static A new instance with the specified user information.
*/ */
public function withUserInfo(string $user, ?string $password = null); public function withUserInfo(string $user, ?string $password = null): UriInterface;
/** /**
* Return an instance with the specified host. * Return an instance with the specified host.
@ -221,7 +219,7 @@ interface UriInterface
* @return static A new instance with the specified host. * @return static A new instance with the specified host.
* @throws \InvalidArgumentException for invalid hostnames. * @throws \InvalidArgumentException for invalid hostnames.
*/ */
public function withHost(string $host); public function withHost(string $host): UriInterface;
/** /**
* Return an instance with the specified port. * Return an instance with the specified port.
@ -240,7 +238,7 @@ interface UriInterface
* @return static A new instance with the specified port. * @return static A new instance with the specified port.
* @throws \InvalidArgumentException for invalid ports. * @throws \InvalidArgumentException for invalid ports.
*/ */
public function withPort(?int $port); public function withPort(?int $port): UriInterface;
/** /**
* Return an instance with the specified path. * Return an instance with the specified path.
@ -264,7 +262,7 @@ interface UriInterface
* @return static A new instance with the specified path. * @return static A new instance with the specified path.
* @throws \InvalidArgumentException for invalid paths. * @throws \InvalidArgumentException for invalid paths.
*/ */
public function withPath(string $path); public function withPath(string $path): UriInterface;
/** /**
* Return an instance with the specified query string. * Return an instance with the specified query string.
@ -281,7 +279,7 @@ interface UriInterface
* @return static A new instance with the specified query string. * @return static A new instance with the specified query string.
* @throws \InvalidArgumentException for invalid query strings. * @throws \InvalidArgumentException for invalid query strings.
*/ */
public function withQuery(string $query); public function withQuery(string $query): UriInterface;
/** /**
* Return an instance with the specified URI fragment. * Return an instance with the specified URI fragment.
@ -297,7 +295,7 @@ interface UriInterface
* @param string $fragment The fragment to use with the new instance. * @param string $fragment The fragment to use with the new instance.
* @return static A new instance with the specified fragment. * @return static A new instance with the specified fragment.
*/ */
public function withFragment(string $fragment); public function withFragment(string $fragment): UriInterface;
/** /**
* Return the string representation as a URI reference. * Return the string representation as a URI reference.
@ -322,5 +320,5 @@ interface UriInterface
* @see http://tools.ietf.org/html/rfc3986#section-4.1 * @see http://tools.ietf.org/html/rfc3986#section-4.1
* @return string * @return string
*/ */
public function __toString(); public function __toString(): string;
} }

View file

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

View file

@ -1,8 +0,0 @@
PHP FIG Simple Cache PSR
========================
This repository holds all interfaces related to PSR-16.
Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details.
You can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package.

View file

@ -1,25 +0,0 @@
{
"name": "psr/simple-cache",
"description": "Common interfaces for simple caching",
"keywords": ["psr", "psr-16", "cache", "simple-cache", "caching"],
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}

View file

@ -1,10 +0,0 @@
<?php
namespace Psr\SimpleCache;
/**
* Interface used for all types of exceptions thrown by the implementing library.
*/
interface CacheException
{
}

View file

@ -1,114 +0,0 @@
<?php
namespace Psr\SimpleCache;
interface CacheInterface
{
/**
* Fetches a value from the cache.
*
* @param string $key The unique key of this item in the cache.
* @param mixed $default Default value to return if the key does not exist.
*
* @return mixed The value of the item from the cache, or $default in case of cache miss.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function get($key, $default = null);
/**
* Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.
*
* @param string $key The key of the item to store.
* @param mixed $value The value of the item to store, must be serializable.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function set($key, $value, $ttl = null);
/**
* Delete an item from the cache by its unique key.
*
* @param string $key The unique cache key of the item to delete.
*
* @return bool True if the item was successfully removed. False if there was an error.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function delete($key);
/**
* Wipes clean the entire cache's keys.
*
* @return bool True on success and false on failure.
*/
public function clear();
/**
* Obtains multiple cache items by their unique keys.
*
* @param iterable $keys A list of keys that can obtained in a single operation.
* @param mixed $default Default value to return for keys that do not exist.
*
* @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function getMultiple($keys, $default = null);
/**
* Persists a set of key => value pairs in the cache, with an optional TTL.
*
* @param iterable $values A list of key => value pairs for a multiple-set operation.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $values is neither an array nor a Traversable,
* or if any of the $values are not a legal value.
*/
public function setMultiple($values, $ttl = null);
/**
* Deletes multiple cache items in a single operation.
*
* @param iterable $keys A list of string-based keys to be deleted.
*
* @return bool True if the items were successfully removed. False if there was an error.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function deleteMultiple($keys);
/**
* Determines whether an item is present in the cache.
*
* NOTE: It is recommended that has() is only to be used for cache warming type purposes
* and not to be used within your live applications operations for get/set, as this method
* is subject to a race condition where your has() will return true and immediately after,
* another script can remove it making the state of your app out of date.
*
* @param string $key The cache item key.
*
* @return bool
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function has($key);
}

View file

@ -1,13 +0,0 @@
<?php
namespace Psr\SimpleCache;
/**
* Exception interface for invalid cache arguments.
*
* When an invalid argument is passed it must throw an exception which implements
* this interface
*/
interface InvalidArgumentException extends CacheException
{
}

View file

@ -0,0 +1,28 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare(strict_types=1);
namespace Slim\Exception;
class HttpTooManyRequestsException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 429;
/**
* @var string
*/
protected $message = 'Too many requests.';
protected string $title = '429 Too Many Requests';
protected string $description = 'The client application has surpassed its rate limit, ' .
'or number of requests they can send in a given period of time.';
}

View file

@ -48,7 +48,7 @@
"nikic/fast-route": "^1.3", "nikic/fast-route": "^1.3",
"psr/container": "^1.0 || ^2.0", "psr/container": "^1.0 || ^2.0",
"psr/http-factory": "^1.0", "psr/http-factory": "^1.0",
"psr/http-message": "^1.1", "psr/http-message": "^1.1 || ^2.0",
"psr/http-server-handler": "^1.0", "psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0", "psr/http-server-middleware": "^1.0",
"psr/log": "^1.1 || ^2.0 || ^3.0" "psr/log": "^1.1 || ^2.0 || ^3.0"
@ -56,19 +56,19 @@
"require-dev": { "require-dev": {
"ext-simplexml": "*", "ext-simplexml": "*",
"adriansuter/php-autoload-override": "^1.4", "adriansuter/php-autoload-override": "^1.4",
"guzzlehttp/psr7": "^2.5", "guzzlehttp/psr7": "^2.6",
"httpsoft/http-message": "^1.1", "httpsoft/http-message": "^1.1",
"httpsoft/http-server-request": "^1.1", "httpsoft/http-server-request": "^1.1",
"laminas/laminas-diactoros": "^2.17", "laminas/laminas-diactoros": "^2.17 || ^3",
"nyholm/psr7": "^1.8", "nyholm/psr7": "^1.8",
"nyholm/psr7-server": "^1.0", "nyholm/psr7-server": "^1.1",
"phpspec/prophecy": "^1.17", "phpspec/prophecy": "^1.19",
"phpspec/prophecy-phpunit": "^2.0", "phpspec/prophecy-phpunit": "^2.1",
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.6", "phpunit/phpunit": "^9.6",
"slim/http": "^1.3", "slim/http": "^1.3",
"slim/psr7": "^1.6", "slim/psr7": "^1.6",
"squizlabs/php_codesniffer": "^3.7" "squizlabs/php_codesniffer": "^3.9"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

View file

@ -1,3 +1,3 @@
vendor/
composer.lock composer.lock
phpunit.xml phpunit.xml
vendor/

View file

@ -0,0 +1,5 @@
CHANGELOG
=========
The changelog is maintained for all Symfony contracts at the following URL:
https://github.com/symfony/contracts/blob/main/CHANGELOG.md

View file

@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Cache;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\InvalidArgumentException;
/**
* Covers most simple to advanced caching needs.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface CacheInterface
{
/**
* Fetches a value from the pool or computes it if not found.
*
* On cache misses, a callback is called that should return the missing value.
* This callback is given a PSR-6 CacheItemInterface instance corresponding to the
* requested key, that could be used e.g. for expiration control. It could also
* be an ItemInterface instance when its additional features are needed.
*
* @param string $key The key of the item to retrieve from the cache
* @param callable|CallbackInterface $callback Should return the computed value for the given key/item
* @param float|null $beta A float that, as it grows, controls the likeliness of triggering
* early expiration. 0 disables it, INF forces immediate expiration.
* The default (or providing null) is implementation dependent but should
* typically be 1.0, which should provide optimal stampede protection.
* See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration
* @param array &$metadata The metadata of the cached item {@see ItemInterface::getMetadata()}
*
* @return mixed
*
* @throws InvalidArgumentException When $key is not valid or when $beta is negative
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null);
/**
* Removes an item from the pool.
*
* @param string $key The key to delete
*
* @throws InvalidArgumentException When $key is not valid
*
* @return bool True if the item was successfully removed, false if there was any error
*/
public function delete(string $key): bool;
}

View file

@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Cache;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Cache\InvalidArgumentException;
use Psr\Log\LoggerInterface;
// Help opcache.preload discover always-needed symbols
class_exists(InvalidArgumentException::class);
/**
* An implementation of CacheInterface for PSR-6 CacheItemPoolInterface classes.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
trait CacheTrait
{
/**
* {@inheritdoc}
*
* @return mixed
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
{
return $this->doGet($this, $key, $callback, $beta, $metadata);
}
/**
* {@inheritdoc}
*/
public function delete(string $key): bool
{
return $this->deleteItem($key);
}
private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null)
{
if (0 > $beta = $beta ?? 1.0) {
throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException { };
}
$item = $pool->getItem($key);
$recompute = !$item->isHit() || \INF === $beta;
$metadata = $item instanceof ItemInterface ? $item->getMetadata() : [];
if (!$recompute && $metadata) {
$expiry = $metadata[ItemInterface::METADATA_EXPIRY] ?? false;
$ctime = $metadata[ItemInterface::METADATA_CTIME] ?? false;
if ($recompute = $ctime && $expiry && $expiry <= ($now = microtime(true)) - $ctime / 1000 * $beta * log(random_int(1, \PHP_INT_MAX) / \PHP_INT_MAX)) {
// force applying defaultLifetime to expiry
$item->expiresAt(null);
$logger && $logger->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [
'key' => $key,
'delta' => sprintf('%.1f', $expiry - $now),
]);
}
}
if ($recompute) {
$save = true;
$item->set($callback($item, $save));
if ($save) {
$pool->save($item);
}
}
return $item->get();
}
}

View file

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Cache;
use Psr\Cache\CacheItemInterface;
/**
* Computes and returns the cached value of an item.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface CallbackInterface
{
/**
* @param CacheItemInterface|ItemInterface $item The item to compute the value for
* @param bool &$save Should be set to false when the value should not be saved in the pool
*
* @return mixed The computed value for the passed item
*/
public function __invoke(CacheItemInterface $item, bool &$save);
}

View file

@ -0,0 +1,65 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Cache;
use Psr\Cache\CacheException;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\InvalidArgumentException;
/**
* Augments PSR-6's CacheItemInterface with support for tags and metadata.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface ItemInterface extends CacheItemInterface
{
/**
* References the Unix timestamp stating when the item will expire.
*/
public const METADATA_EXPIRY = 'expiry';
/**
* References the time the item took to be created, in milliseconds.
*/
public const METADATA_CTIME = 'ctime';
/**
* References the list of tags that were assigned to the item, as string[].
*/
public const METADATA_TAGS = 'tags';
/**
* Reserved characters that cannot be used in a key or tag.
*/
public const RESERVED_CHARACTERS = '{}()/\@:';
/**
* Adds a tag to a cache item.
*
* Tags are strings that follow the same validation rules as keys.
*
* @param string|string[] $tags A tag or array of tags
*
* @return $this
*
* @throws InvalidArgumentException When $tag is not valid
* @throws CacheException When the item comes from a pool that is not tag-aware
*/
public function tag($tags): self;
/**
* Returns a list of metadata info that were saved alongside with the cached value.
*
* See ItemInterface::METADATA_* consts for keys potentially found in the returned array.
*/
public function getMetadata(): array;
}

View file

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

View file

@ -0,0 +1,9 @@
Symfony Cache Contracts
=======================
A set of abstractions extracted out of the Symfony components.
Can be used to build on semantics that the Symfony components proved useful - and
that already have battle tested implementations.
See https://github.com/symfony/contracts/blob/main/README.md for more information.

View file

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Cache;
use Psr\Cache\InvalidArgumentException;
/**
* Allows invalidating cached items using tags.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface TagAwareCacheInterface extends CacheInterface
{
/**
* Invalidates cached items using tags.
*
* When implemented on a PSR-6 pool, invalidation should not apply
* to deferred items. Instead, they should be committed as usual.
* This allows replacing old tagged values by new ones without
* race conditions.
*
* @param string[] $tags An array of tags to invalidate
*
* @return bool True on success
*
* @throws InvalidArgumentException When $tags is not valid
*/
public function invalidateTags(array $tags);
}

View file

@ -0,0 +1,38 @@
{
"name": "symfony/cache-contracts",
"type": "library",
"description": "Generic abstractions related to caching",
"keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.2.5",
"psr/cache": "^1.0|^2.0|^3.0"
},
"suggest": {
"symfony/cache-implementation": ""
},
"autoload": {
"psr-4": { "Symfony\\Contracts\\Cache\\": "" }
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
}
}

View file

@ -11,37 +11,32 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\AbstractTrait; use Symfony\Component\Cache\Traits\AbstractAdapterTrait;
use Symfony\Component\Cache\Traits\ContractsTrait;
use Symfony\Contracts\Cache\CacheInterface;
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
{ {
use AbstractAdapterTrait;
use ContractsTrait;
/** /**
* @internal * @internal
*/ */
const NS_SEPARATOR = ':'; protected const NS_SEPARATOR = ':';
use AbstractTrait;
private static $apcuSupported; private static $apcuSupported;
private static $phpFilesSupported; private static $phpFilesSupported;
private $createCacheItem; protected function __construct(string $namespace = '', int $defaultLifetime = 0)
private $mergeByLifetime;
/**
* @param string $namespace
* @param int $defaultLifetime
*/
protected function __construct($namespace = '', $defaultLifetime = 0)
{ {
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR; $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR;
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
@ -51,31 +46,45 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
static function ($key, $value, $isHit) { static function ($key, $value, $isHit) {
$item = new CacheItem(); $item = new CacheItem();
$item->key = $key; $item->key = $key;
$item->value = $value; $item->value = $v = $value;
$item->isHit = $isHit; $item->isHit = $isHit;
// Detect wrapped values that encode for their expiry and creation duration
// For compactness, these values are packed in the key of an array using
// magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) {
$item->value = $v[$k];
$v = unpack('Ve/Nc', substr($k, 1, -1));
$item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
$item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
}
return $item; return $item;
}, },
null, null,
CacheItem::class CacheItem::class
); );
$getId = function ($key) { return $this->getId((string) $key); }; $getId = \Closure::fromCallable([$this, 'getId']);
$this->mergeByLifetime = \Closure::bind( $this->mergeByLifetime = \Closure::bind(
static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifetime) { static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifetime) {
$byLifetime = []; $byLifetime = [];
$now = time(); $now = microtime(true);
$expiredIds = []; $expiredIds = [];
foreach ($deferred as $key => $item) { foreach ($deferred as $key => $item) {
$key = (string) $key;
if (null === $item->expiry) { if (null === $item->expiry) {
$byLifetime[0 < $defaultLifetime ? $defaultLifetime : 0][$getId($key)] = $item->value; $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
} elseif (0 === $item->expiry) { } elseif (!$item->expiry) {
$byLifetime[0][$getId($key)] = $item->value; $ttl = 0;
} elseif ($item->expiry > $now) { } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$byLifetime[$item->expiry - $now][$getId($key)] = $item->value;
} else {
$expiredIds[] = $getId($key); $expiredIds[] = $getId($key);
continue;
} }
if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) {
unset($metadata[CacheItem::METADATA_TAGS]);
}
// For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
$byLifetime[$ttl][$getId($key)] = $metadata ? ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item->value] : $item->value;
} }
return $byLifetime; return $byLifetime;
@ -86,6 +95,10 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
} }
/** /**
* Returns the best possible adapter that your runtime supports.
*
* Using ApcuAdapter makes system caches compatible with read-only filesystems.
*
* @param string $namespace * @param string $namespace
* @param int $defaultLifetime * @param int $defaultLifetime
* @param string $version * @param string $version
@ -95,37 +108,25 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
*/ */
public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null) public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
{ {
if (null === self::$apcuSupported) { $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true);
self::$apcuSupported = ApcuAdapter::isSupported(); if (null !== $logger) {
$opcache->setLogger($logger);
} }
if (!self::$apcuSupported && null === self::$phpFilesSupported) { if (!self::$apcuSupported = self::$apcuSupported ?? ApcuAdapter::isSupported()) {
self::$phpFilesSupported = PhpFilesAdapter::isSupported();
}
if (self::$phpFilesSupported) {
$opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory);
if (null !== $logger) {
$opcache->setLogger($logger);
}
return $opcache; return $opcache;
} }
$fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory); if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
if (null !== $logger) { return $opcache;
$fs->setLogger($logger);
}
if (!self::$apcuSupported || (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) {
return $fs;
} }
$apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version); $apcu = new ApcuAdapter($namespace, intdiv($defaultLifetime, 5), $version);
if (null !== $logger) { if (null !== $logger) {
$apcu->setLogger($logger); $apcu->setLogger($logger);
} }
return new ChainAdapter([$apcu, $fs]); return new ChainAdapter([$apcu, $opcache]);
} }
public static function createConnection($dsn, array $options = []) public static function createConnection($dsn, array $options = [])
@ -133,10 +134,10 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
if (!\is_string($dsn)) { if (!\is_string($dsn)) {
throw new InvalidArgumentException(sprintf('The "%s()" method expect argument #1 to be string, "%s" given.', __METHOD__, \gettype($dsn))); throw new InvalidArgumentException(sprintf('The "%s()" method expect argument #1 to be string, "%s" given.', __METHOD__, \gettype($dsn)));
} }
if (0 === strpos($dsn, 'redis://')) { if (str_starts_with($dsn, 'redis:') || str_starts_with($dsn, 'rediss:')) {
return RedisAdapter::createConnection($dsn, $options); return RedisAdapter::createConnection($dsn, $options);
} }
if (0 === strpos($dsn, 'memcached://')) { if (str_starts_with($dsn, 'memcached:')) {
return MemcachedAdapter::createConnection($dsn, $options); return MemcachedAdapter::createConnection($dsn, $options);
} }
@ -145,81 +146,8 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ *
public function getItem($key) * @return bool
{
if ($this->deferred) {
$this->commit();
}
$id = $this->getId($key);
$f = $this->createCacheItem;
$isHit = false;
$value = null;
try {
foreach ($this->doFetch([$id]) as $value) {
$isHit = true;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]);
}
return $f($key, $value, $isHit);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = [])
{
if ($this->deferred) {
$this->commit();
}
$ids = [];
foreach ($keys as $key) {
$ids[] = $this->getId($key);
}
try {
$items = $this->doFetch($ids);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => $keys, 'exception' => $e]);
$items = [];
}
$ids = array_combine($ids, $keys);
return $this->generateItems($items, $ids);
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$this->deferred[$item->getKey()] = $item;
return $this->commit();
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$this->deferred[$item->getKey()] = $item;
return true;
}
/**
* {@inheritdoc}
*/ */
public function commit() public function commit()
{ {
@ -229,7 +157,12 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
$retry = $this->deferred = []; $retry = $this->deferred = [];
if ($expiredIds) { if ($expiredIds) {
$this->doDelete($expiredIds); try {
$this->doDelete($expiredIds);
} catch (\Exception $e) {
$ok = false;
CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]);
}
} }
foreach ($byLifetime as $lifetime => $values) { foreach ($byLifetime as $lifetime => $values) {
try { try {
@ -244,7 +177,8 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
$ok = false; $ok = false;
$v = $values[$id]; $v = $values[$id];
$type = \is_object($v) ? \get_class($v) : \gettype($v); $type = \is_object($v) ? \get_class($v) : \gettype($v);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
} }
} else { } else {
foreach ($values as $id => $v) { foreach ($values as $id => $v) {
@ -266,49 +200,11 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
} }
$ok = false; $ok = false;
$type = \is_object($v) ? \get_class($v) : \gettype($v); $type = \is_object($v) ? \get_class($v) : \gettype($v);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
} }
} }
return $ok; return $ok;
} }
public function __sleep()
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
public function __wakeup()
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
public function __destruct()
{
if ($this->deferred) {
$this->commit();
}
}
private function generateItems($items, &$keys)
{
$f = $this->createCacheItem;
try {
foreach ($items as $id => $value) {
if (!isset($keys[$id])) {
$id = key($keys);
}
$key = $keys[$id];
unset($keys[$id]);
yield $key => $f($key, $value, true);
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]);
}
foreach ($keys as $key) {
yield $key => $f($key, null, false);
}
}
} }

View file

@ -0,0 +1,334 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Log\LoggerAwareInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\AbstractAdapterTrait;
use Symfony\Component\Cache\Traits\ContractsTrait;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
/**
* Abstract for native TagAware adapters.
*
* To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids
* to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate().
*
* @author Nicolas Grekas <p@tchwork.com>
* @author André Rømcke <andre.romcke+symfony@gmail.com>
*
* @internal
*/
abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface
{
use AbstractAdapterTrait;
use ContractsTrait;
private const TAGS_PREFIX = "\0tags\0";
protected function __construct(string $namespace = '', int $defaultLifetime = 0)
{
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
}
$this->createCacheItem = \Closure::bind(
static function ($key, $value, $isHit) {
$item = new CacheItem();
$item->key = $key;
$item->isTaggable = true;
// If structure does not match what we expect return item as is (no value and not a hit)
if (!\is_array($value) || !\array_key_exists('value', $value)) {
return $item;
}
$item->isHit = $isHit;
// Extract value, tags and meta data from the cache value
$item->value = $value['value'];
$item->metadata[CacheItem::METADATA_TAGS] = $value['tags'] ?? [];
if (isset($value['meta'])) {
// For compactness these values are packed, & expiry is offset to reduce size
$v = unpack('Ve/Nc', $value['meta']);
$item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
$item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
}
return $item;
},
null,
CacheItem::class
);
$getId = \Closure::fromCallable([$this, 'getId']);
$tagPrefix = self::TAGS_PREFIX;
$this->mergeByLifetime = \Closure::bind(
static function ($deferred, &$expiredIds) use ($getId, $tagPrefix, $defaultLifetime) {
$byLifetime = [];
$now = microtime(true);
$expiredIds = [];
foreach ($deferred as $key => $item) {
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
} elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);
continue;
}
// Store Value and Tags on the cache value
if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) {
$value = ['value' => $item->value, 'tags' => $metadata[CacheItem::METADATA_TAGS]];
unset($metadata[CacheItem::METADATA_TAGS]);
} else {
$value = ['value' => $item->value, 'tags' => []];
}
if ($metadata) {
// For compactness, expiry and creation duration are packed, using magic numbers as separators
$value['meta'] = pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME]);
}
// Extract tag changes, these should be removed from values in doSave()
$value['tag-operations'] = ['add' => [], 'remove' => []];
$oldTags = $item->metadata[CacheItem::METADATA_TAGS] ?? [];
foreach (array_diff($value['tags'], $oldTags) as $addedTag) {
$value['tag-operations']['add'][] = $getId($tagPrefix.$addedTag);
}
foreach (array_diff($oldTags, $value['tags']) as $removedTag) {
$value['tag-operations']['remove'][] = $getId($tagPrefix.$removedTag);
}
$byLifetime[$ttl][$getId($key)] = $value;
$item->metadata = $item->newMetadata;
}
return $byLifetime;
},
null,
CacheItem::class
);
}
/**
* Persists several cache items immediately.
*
* @param array $values The values to cache, indexed by their cache identifier
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
* @param array[] $addTagData Hash where key is tag id, and array value is list of cache id's to add to tag
* @param array[] $removeTagData Hash where key is tag id, and array value is list of cache id's to remove to tag
*
* @return array The identifiers that failed to be cached or a boolean stating if caching succeeded or not
*/
abstract protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array;
/**
* Removes multiple items from the pool and their corresponding tags.
*
* @param array $ids An array of identifiers that should be removed from the pool
*
* @return bool True if the items were successfully removed, false otherwise
*/
abstract protected function doDelete(array $ids);
/**
* Removes relations between tags and deleted items.
*
* @param array $tagData Array of tag => key identifiers that should be removed from the pool
*/
abstract protected function doDeleteTagRelations(array $tagData): bool;
/**
* Invalidates cached items using tags.
*
* @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id
*
* @return bool True on success
*/
abstract protected function doInvalidate(array $tagIds): bool;
/**
* Delete items and yields the tags they were bound to.
*/
protected function doDeleteYieldTags(array $ids): iterable
{
foreach ($this->doFetch($ids) as $id => $value) {
yield $id => \is_array($value) && \is_array($value['tags'] ?? null) ? $value['tags'] : [];
}
$this->doDelete($ids);
}
/**
* {@inheritdoc}
*/
public function commit(): bool
{
$ok = true;
$byLifetime = $this->mergeByLifetime;
$byLifetime = $byLifetime($this->deferred, $expiredIds);
$retry = $this->deferred = [];
if ($expiredIds) {
// Tags are not cleaned up in this case, however that is done on invalidateTags().
try {
$this->doDelete($expiredIds);
} catch (\Exception $e) {
$ok = false;
CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]);
}
}
foreach ($byLifetime as $lifetime => $values) {
try {
$values = $this->extractTagData($values, $addTagData, $removeTagData);
$e = $this->doSave($values, $lifetime, $addTagData, $removeTagData);
} catch (\Exception $e) {
}
if (true === $e || [] === $e) {
continue;
}
if (\is_array($e) || 1 === \count($values)) {
foreach (\is_array($e) ? $e : array_keys($values) as $id) {
$ok = false;
$v = $values[$id];
$type = \is_object($v) ? \get_class($v) : \gettype($v);
$message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
}
} else {
foreach ($values as $id => $v) {
$retry[$lifetime][] = $id;
}
}
}
// When bulk-save failed, retry each item individually
foreach ($retry as $lifetime => $ids) {
foreach ($ids as $id) {
try {
$v = $byLifetime[$lifetime][$id];
$values = $this->extractTagData([$id => $v], $addTagData, $removeTagData);
$e = $this->doSave($values, $lifetime, $addTagData, $removeTagData);
} catch (\Exception $e) {
}
if (true === $e || [] === $e) {
continue;
}
$ok = false;
$type = \is_object($v) ? \get_class($v) : \gettype($v);
$message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
}
}
return $ok;
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys): bool
{
if (!$keys) {
return true;
}
$ok = true;
$ids = [];
$tagData = [];
foreach ($keys as $key) {
$ids[$key] = $this->getId($key);
unset($this->deferred[$key]);
}
try {
foreach ($this->doDeleteYieldTags(array_values($ids)) as $id => $tags) {
foreach ($tags as $tag) {
$tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id;
}
}
} catch (\Exception $e) {
$ok = false;
}
try {
if ((!$tagData || $this->doDeleteTagRelations($tagData)) && $ok) {
return true;
}
} catch (\Exception $e) {
}
// When bulk-delete failed, retry each item individually
foreach ($ids as $key => $id) {
try {
$e = null;
if ($this->doDelete([$id])) {
continue;
}
} catch (\Exception $e) {
}
$message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
$ok = false;
}
return $ok;
}
/**
* {@inheritdoc}
*/
public function invalidateTags(array $tags)
{
if (empty($tags)) {
return false;
}
$tagIds = [];
foreach (array_unique($tags) as $tag) {
$tagIds[] = $this->getId(self::TAGS_PREFIX.$tag);
}
try {
if ($this->doInvalidate($tagIds)) {
return true;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to invalidate tags: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]);
}
return false;
}
/**
* Extracts tags operation data from $values set in mergeByLifetime, and returns values without it.
*/
private function extractTagData(array $values, ?array &$addTagData, ?array &$removeTagData): array
{
$addTagData = $removeTagData = [];
foreach ($values as $id => $value) {
foreach ($value['tag-operations']['add'] as $tag => $tagId) {
$addTagData[$tagId][] = $id;
}
foreach ($value['tag-operations']['remove'] as $tag => $tagId) {
$removeTagData[$tagId][] = $id;
}
unset($values[$id]['tag-operations']);
}
return $values;
}
}

View file

@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
// Help opcache.preload discover always-needed symbols
class_exists(CacheItem::class);
/** /**
* Interface for adapters managing instances of Symfony's CacheItem. * Interface for adapters managing instances of Symfony's CacheItem.
* *
@ -34,4 +37,13 @@ interface AdapterInterface extends CacheItemPoolInterface
* @return \Traversable|CacheItem[] * @return \Traversable|CacheItem[]
*/ */
public function getItems(array $keys = []); public function getItems(array $keys = []);
/**
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/* string $prefix = '' */);
} }

View file

@ -18,13 +18,9 @@ class ApcuAdapter extends AbstractAdapter
use ApcuTrait; use ApcuTrait;
/** /**
* @param string $namespace
* @param int $defaultLifetime
* @param string|null $version
*
* @throws CacheException if APCu is not enabled * @throws CacheException if APCu is not enabled
*/ */
public function __construct($namespace = '', $defaultLifetime = 0, $version = null) public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
{ {
$this->init($namespace, $defaultLifetime, $version); $this->init($namespace, $defaultLifetime, $version);
} }

View file

@ -16,11 +16,12 @@ use Psr\Log\LoggerAwareInterface;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ArrayTrait; use Symfony\Component\Cache\Traits\ArrayTrait;
use Symfony\Contracts\Cache\CacheInterface;
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
{ {
use ArrayTrait; use ArrayTrait;
@ -28,10 +29,9 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
private $defaultLifetime; private $defaultLifetime;
/** /**
* @param int $defaultLifetime
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
*/ */
public function __construct($defaultLifetime = 0, $storeSerialized = true) public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
{ {
$this->defaultLifetime = $defaultLifetime; $this->defaultLifetime = $defaultLifetime;
$this->storeSerialized = $storeSerialized; $this->storeSerialized = $storeSerialized;
@ -49,27 +49,35 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
); );
} }
/**
* {@inheritdoc}
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
{
$item = $this->getItem($key);
$metadata = $item->getMetadata();
// ArrayAdapter works in memory, we don't care about stampede protection
if (\INF === $beta || !$item->isHit()) {
$save = true;
$item->set($callback($item, $save));
if ($save) {
$this->save($item);
}
}
return $item->get();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getItem($key) public function getItem($key)
{ {
$isHit = $this->hasItem($key); if (!$isHit = $this->hasItem($key)) {
try {
if (!$isHit) {
$this->values[$key] = $value = null;
} elseif (!$this->storeSerialized) {
$value = $this->values[$key];
} elseif ('b:0;' === $value = $this->values[$key]) {
$value = false;
} elseif (false === $value = unserialize($value)) {
$this->values[$key] = $value = null;
$isHit = false;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]);
$this->values[$key] = $value = null; $this->values[$key] = $value = null;
$isHit = false; } else {
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
} }
$f = $this->createCacheItem; $f = $this->createCacheItem;
@ -82,14 +90,18 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
public function getItems(array $keys = []) public function getItems(array $keys = [])
{ {
foreach ($keys as $key) { foreach ($keys as $key) {
CacheItem::validateKey($key); if (!\is_string($key) || !isset($this->expiries[$key])) {
CacheItem::validateKey($key);
}
} }
return $this->generateItems($keys, time(), $this->createCacheItem); return $this->generateItems($keys, microtime(true), $this->createCacheItem);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItems(array $keys) public function deleteItems(array $keys)
{ {
@ -102,6 +114,8 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function save(CacheItemInterface $item) public function save(CacheItemInterface $item)
{ {
@ -113,37 +127,32 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
$value = $item["\0*\0value"]; $value = $item["\0*\0value"];
$expiry = $item["\0*\0expiry"]; $expiry = $item["\0*\0expiry"];
if (0 === $expiry) { if (null !== $expiry) {
$expiry = \PHP_INT_MAX; if (!$expiry) {
} $expiry = \PHP_INT_MAX;
} elseif ($expiry <= microtime(true)) {
$this->deleteItem($key);
if (null !== $expiry && $expiry <= time()) { return true;
$this->deleteItem($key);
return true;
}
if ($this->storeSerialized) {
try {
$value = serialize($value);
} catch (\Exception $e) {
$type = \is_object($value) ? \get_class($value) : \gettype($value);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => $key, 'type' => $type, 'exception' => $e]);
return false;
} }
} }
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;
}
if (null === $expiry && 0 < $this->defaultLifetime) { if (null === $expiry && 0 < $this->defaultLifetime) {
$expiry = time() + $this->defaultLifetime; $expiry = microtime(true) + $this->defaultLifetime;
} }
$this->values[$key] = $value; $this->values[$key] = $value;
$this->expiries[$key] = null !== $expiry ? $expiry : \PHP_INT_MAX; $this->expiries[$key] = $expiry ?? \PHP_INT_MAX;
return true; return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function saveDeferred(CacheItemInterface $item) public function saveDeferred(CacheItemInterface $item)
{ {
@ -152,9 +161,19 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function commit() public function commit()
{ {
return true; return true;
} }
/**
* {@inheritdoc}
*/
public function delete(string $key): bool
{
return $this->deleteItem($key);
}
} }

View file

@ -17,6 +17,9 @@ use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ContractsTrait;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Service\ResetInterface;
/** /**
* Chains several adapters together. * Chains several adapters together.
@ -26,8 +29,10 @@ use Symfony\Component\Cache\ResettableInterface;
* *
* @author Kévin Dunglas <dunglas@gmail.com> * @author Kévin Dunglas <dunglas@gmail.com>
*/ */
class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
{ {
use ContractsTrait;
private $adapters = []; private $adapters = [];
private $adapterCount; private $adapterCount;
private $syncItem; private $syncItem;
@ -36,7 +41,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
* @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items * @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items
* @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones * @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones
*/ */
public function __construct(array $adapters, $defaultLifetime = 0) public function __construct(array $adapters, int $defaultLifetime = 0)
{ {
if (!$adapters) { if (!$adapters) {
throw new InvalidArgumentException('At least one adapter must be specified.'); throw new InvalidArgumentException('At least one adapter must be specified.');
@ -46,7 +51,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
if (!$adapter instanceof CacheItemPoolInterface) { if (!$adapter instanceof CacheItemPoolInterface) {
throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($adapter), CacheItemPoolInterface::class)); throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($adapter), CacheItemPoolInterface::class));
} }
if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && $adapter instanceof ApcuAdapter && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) { if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && $adapter instanceof ApcuAdapter && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
continue; // skip putting APCu in the chain when the backend is disabled continue; // skip putting APCu in the chain when the backend is disabled
} }
@ -59,11 +64,18 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
$this->adapterCount = \count($this->adapters); $this->adapterCount = \count($this->adapters);
$this->syncItem = \Closure::bind( $this->syncItem = \Closure::bind(
static function ($sourceItem, $item) use ($defaultLifetime) { static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifetime) {
$sourceItem->isTaggable = false;
$sourceMetadata = $sourceMetadata ?? $sourceItem->metadata;
unset($sourceMetadata[CacheItem::METADATA_TAGS]);
$item->value = $sourceItem->value; $item->value = $sourceItem->value;
$item->isHit = $sourceItem->isHit; $item->isHit = $sourceItem->isHit;
$item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata;
if (0 < $defaultLifetime) { if (isset($item->metadata[CacheItem::METADATA_EXPIRY])) {
$item->expiresAt(\DateTime::createFromFormat('U.u', sprintf('%.6F', $item->metadata[CacheItem::METADATA_EXPIRY])));
} elseif (0 < $defaultLifetime) {
$item->expiresAfter($defaultLifetime); $item->expiresAfter($defaultLifetime);
} }
@ -74,6 +86,43 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
); );
} }
/**
* {@inheritdoc}
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
{
$doSave = true;
$callback = static function (CacheItem $item, bool &$save) use ($callback, &$doSave) {
$value = $callback($item, $save);
$doSave = $save;
return $value;
};
$lastItem = null;
$i = 0;
$wrap = function (CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$i, &$doSave, &$lastItem, &$metadata) {
$adapter = $this->adapters[$i];
if (isset($this->adapters[++$i])) {
$callback = $wrap;
$beta = \INF === $beta ? \INF : 0;
}
if ($adapter instanceof CacheInterface) {
$value = $adapter->get($key, $callback, $beta, $metadata);
} else {
$value = $this->doGet($adapter, $key, $callback, $beta, $metadata);
}
if (null !== $item) {
($this->syncItem)($lastItem = $lastItem ?? $item, $item, $metadata);
}
$save = $doSave;
return $value;
};
return $wrap();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -107,12 +156,12 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
return $this->generateItems($this->adapters[0]->getItems($keys), 0); return $this->generateItems($this->adapters[0]->getItems($keys), 0);
} }
private function generateItems($items, $adapterIndex) private function generateItems(iterable $items, int $adapterIndex)
{ {
$missing = []; $missing = [];
$misses = []; $misses = [];
$nextAdapterIndex = $adapterIndex + 1; $nextAdapterIndex = $adapterIndex + 1;
$nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null; $nextAdapter = $this->adapters[$nextAdapterIndex] ?? null;
foreach ($items as $k => $item) { foreach ($items as $k => $item) {
if (!$nextAdapter || $item->isHit()) { if (!$nextAdapter || $item->isHit()) {
@ -140,6 +189,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function hasItem($key) public function hasItem($key)
{ {
@ -154,14 +205,23 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/ */
public function clear() public function clear(/* string $prefix = '' */)
{ {
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
$cleared = true; $cleared = true;
$i = $this->adapterCount; $i = $this->adapterCount;
while ($i--) { while ($i--) {
$cleared = $this->adapters[$i]->clear() && $cleared; if ($this->adapters[$i] instanceof AdapterInterface) {
$cleared = $this->adapters[$i]->clear($prefix) && $cleared;
} else {
$cleared = $this->adapters[$i]->clear() && $cleared;
}
} }
return $cleared; return $cleared;
@ -169,6 +229,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItem($key) public function deleteItem($key)
{ {
@ -184,6 +246,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItems(array $keys) public function deleteItems(array $keys)
{ {
@ -199,6 +263,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function save(CacheItemInterface $item) public function save(CacheItemInterface $item)
{ {
@ -214,6 +280,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function saveDeferred(CacheItemInterface $item) public function saveDeferred(CacheItemInterface $item)
{ {
@ -229,6 +297,8 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function commit() public function commit()
{ {
@ -264,7 +334,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn
public function reset() public function reset()
{ {
foreach ($this->adapters as $adapter) { foreach ($this->adapters as $adapter) {
if ($adapter instanceof ResettableInterface) { if ($adapter instanceof ResetInterface) {
$adapter->reset(); $adapter->reset();
} }
} }

View file

@ -18,11 +18,7 @@ class DoctrineAdapter extends AbstractAdapter
{ {
use DoctrineTrait; use DoctrineTrait;
/** public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
* @param string $namespace
* @param int $defaultLifetime
*/
public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0)
{ {
parent::__construct('', $defaultLifetime); parent::__construct('', $defaultLifetime);
$this->provider = $provider; $this->provider = $provider;

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\FilesystemTrait; use Symfony\Component\Cache\Traits\FilesystemTrait;
@ -18,13 +20,9 @@ class FilesystemAdapter extends AbstractAdapter implements PruneableInterface
{ {
use FilesystemTrait; use FilesystemTrait;
/** public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
* @param string $namespace
* @param int $defaultLifetime
* @param string|null $directory
*/
public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
{ {
$this->marshaller = $marshaller ?? new DefaultMarshaller();
parent::__construct('', $defaultLifetime); parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory); $this->init($namespace, $directory);
} }

View file

@ -0,0 +1,239 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\FilesystemTrait;
/**
* Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls.
*
* @author Nicolas Grekas <p@tchwork.com>
* @author André Rømcke <andre.romcke+symfony@gmail.com>
*/
class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface
{
use FilesystemTrait {
doClear as private doClearCache;
doSave as private doSaveCache;
}
/**
* Folder used for tag symlinks.
*/
private const TAG_FOLDER = 'tags';
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
{
$this->marshaller = new TagAwareMarshaller($marshaller);
parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
$ok = $this->doClearCache($namespace);
if ('' !== $namespace) {
return $ok;
}
set_error_handler(static function () {});
$chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
try {
foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) {
if (rename($dir, $renamed = substr_replace($dir, bin2hex(random_bytes(4)), -8))) {
$dir = $renamed.\DIRECTORY_SEPARATOR;
} else {
$dir .= \DIRECTORY_SEPARATOR;
$renamed = null;
}
for ($i = 0; $i < 38; ++$i) {
if (!file_exists($dir.$chars[$i])) {
continue;
}
for ($j = 0; $j < 38; ++$j) {
if (!file_exists($d = $dir.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) {
continue;
}
foreach (scandir($d, \SCANDIR_SORT_NONE) ?: [] as $link) {
if ('.' !== $link && '..' !== $link && (null !== $renamed || !realpath($d.\DIRECTORY_SEPARATOR.$link))) {
unlink($d.\DIRECTORY_SEPARATOR.$link);
}
}
null === $renamed ?: rmdir($d);
}
null === $renamed ?: rmdir($dir.$chars[$i]);
}
null === $renamed ?: rmdir($renamed);
}
} finally {
restore_error_handler();
}
return $ok;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array
{
$failed = $this->doSaveCache($values, $lifetime);
// Add Tags as symlinks
foreach ($addTagData as $tagId => $ids) {
$tagFolder = $this->getTagFolder($tagId);
foreach ($ids as $id) {
if ($failed && \in_array($id, $failed, true)) {
continue;
}
$file = $this->getFile($id);
if (!@symlink($file, $tagLink = $this->getFile($id, true, $tagFolder)) && !is_link($tagLink)) {
@unlink($file);
$failed[] = $id;
}
}
}
// Unlink removed Tags
foreach ($removeTagData as $tagId => $ids) {
$tagFolder = $this->getTagFolder($tagId);
foreach ($ids as $id) {
if ($failed && \in_array($id, $failed, true)) {
continue;
}
@unlink($this->getFile($id, false, $tagFolder));
}
}
return $failed;
}
/**
* {@inheritdoc}
*/
protected function doDeleteYieldTags(array $ids): iterable
{
foreach ($ids as $id) {
$file = $this->getFile($id);
if (!file_exists($file) || !$h = @fopen($file, 'r')) {
continue;
}
if ((\PHP_VERSION_ID >= 70300 || '\\' !== \DIRECTORY_SEPARATOR) && !@unlink($file)) {
fclose($h);
continue;
}
$meta = explode("\n", fread($h, 4096), 3)[2] ?? '';
// detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
if (13 < \strlen($meta) && "\x9D" === $meta[0] && "\0" === $meta[5] && "\x5F" === $meta[9]) {
$meta[9] = "\0";
$tagLen = unpack('Nlen', $meta, 9)['len'];
$meta = substr($meta, 13, $tagLen);
if (0 < $tagLen -= \strlen($meta)) {
$meta .= fread($h, $tagLen);
}
try {
yield $id => '' === $meta ? [] : $this->marshaller->unmarshall($meta);
} catch (\Exception $e) {
yield $id => [];
}
}
fclose($h);
if (\PHP_VERSION_ID < 70300 && '\\' === \DIRECTORY_SEPARATOR) {
@unlink($file);
}
}
}
/**
* {@inheritdoc}
*/
protected function doDeleteTagRelations(array $tagData): bool
{
foreach ($tagData as $tagId => $idList) {
$tagFolder = $this->getTagFolder($tagId);
foreach ($idList as $id) {
@unlink($this->getFile($id, false, $tagFolder));
}
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doInvalidate(array $tagIds): bool
{
foreach ($tagIds as $tagId) {
if (!file_exists($tagFolder = $this->getTagFolder($tagId))) {
continue;
}
set_error_handler(static function () {});
try {
if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -9))) {
$tagFolder = $renamed.\DIRECTORY_SEPARATOR;
} else {
$renamed = null;
}
foreach ($this->scanHashDir($tagFolder) as $itemLink) {
unlink(realpath($itemLink) ?: $itemLink);
unlink($itemLink);
}
if (null === $renamed) {
continue;
}
$chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
for ($i = 0; $i < 38; ++$i) {
for ($j = 0; $j < 38; ++$j) {
rmdir($tagFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]);
}
rmdir($tagFolder.$chars[$i]);
}
rmdir($renamed);
} finally {
restore_error_handler();
}
}
return true;
}
private function getTagFolder(string $tagId): string
{
return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
}
}

View file

@ -11,6 +11,7 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\Traits\MemcachedTrait; use Symfony\Component\Cache\Traits\MemcachedTrait;
class MemcachedAdapter extends AbstractAdapter class MemcachedAdapter extends AbstractAdapter
@ -29,8 +30,8 @@ class MemcachedAdapter extends AbstractAdapter
* *
* Using a MemcachedAdapter as a pure items store is fine. * Using a MemcachedAdapter as a pure items store is fine.
*/ */
public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0) public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
{ {
$this->init($client, $namespace, $defaultLifetime); $this->init($client, $namespace, $defaultLifetime, $marshaller);
} }
} }

View file

@ -13,11 +13,12 @@ namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
use Symfony\Contracts\Cache\CacheInterface;
/** /**
* @author Titouan Galopin <galopintitouan@gmail.com> * @author Titouan Galopin <galopintitouan@gmail.com>
*/ */
class NullAdapter implements AdapterInterface class NullAdapter implements AdapterInterface, CacheInterface
{ {
private $createCacheItem; private $createCacheItem;
@ -36,6 +37,16 @@ class NullAdapter implements AdapterInterface
); );
} }
/**
* {@inheritdoc}
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
{
$save = true;
return $callback(($this->createCacheItem)($key), $save);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -56,6 +67,8 @@ class NullAdapter implements AdapterInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function hasItem($key) public function hasItem($key)
{ {
@ -64,14 +77,20 @@ class NullAdapter implements AdapterInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/ */
public function clear() public function clear(/* string $prefix = '' */)
{ {
return true; return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItem($key) public function deleteItem($key)
{ {
@ -80,6 +99,8 @@ class NullAdapter implements AdapterInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItems(array $keys) public function deleteItems(array $keys)
{ {
@ -88,26 +109,40 @@ class NullAdapter implements AdapterInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function save(CacheItemInterface $item) public function save(CacheItemInterface $item)
{ {
return false; return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function saveDeferred(CacheItemInterface $item) public function saveDeferred(CacheItemInterface $item)
{ {
return false; return true;
}
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{
return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function commit() public function delete(string $key): bool
{ {
return false; return $this->deleteItem($key);
} }
private function generateItems(array $keys) private function generateItems(array $keys)

View file

@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Adapter;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\PdoTrait; use Symfony\Component\Cache\Traits\PdoTrait;
@ -27,6 +28,9 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
* a Doctrine DBAL Connection or a DSN string that will be used to * a Doctrine DBAL Connection or a DSN string that will be used to
* lazy-connect to the database when the cache is actually used. * lazy-connect to the database when the cache is actually used.
* *
* When a Doctrine DBAL Connection is passed, the cache table is created
* automatically when possible. Otherwise, use the createTable() method.
*
* List of available options: * List of available options:
* * db_table: The name of the table [default: cache_items] * * db_table: The name of the table [default: cache_items]
* * db_id_col: The column where to store the cache id [default: item_id] * * db_id_col: The column where to store the cache id [default: item_id]
@ -37,17 +41,14 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
* * db_password: The password when lazy-connect [default: ''] * * db_password: The password when lazy-connect [default: '']
* * db_connection_options: An array of driver-specific connection options [default: []] * * db_connection_options: An array of driver-specific connection options [default: []]
* *
* @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null * @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null
* @param string $namespace
* @param int $defaultLifetime
* @param array $options An associative array of options
* *
* @throws InvalidArgumentException When first argument is not PDO nor Connection nor string * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
* @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
* @throws InvalidArgumentException When namespace contains invalid characters * @throws InvalidArgumentException When namespace contains invalid characters
*/ */
public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = []) public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null)
{ {
$this->init($connOrDsn, $namespace, $defaultLifetime, $options); $this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller);
} }
} }

View file

@ -17,7 +17,9 @@ use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ContractsTrait;
use Symfony\Component\Cache\Traits\PhpArrayTrait; use Symfony\Component\Cache\Traits\PhpArrayTrait;
use Symfony\Contracts\Cache\CacheInterface;
/** /**
* Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0. * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
@ -26,8 +28,9 @@ use Symfony\Component\Cache\Traits\PhpArrayTrait;
* @author Titouan Galopin <galopintitouan@gmail.com> * @author Titouan Galopin <galopintitouan@gmail.com>
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
{ {
use ContractsTrait;
use PhpArrayTrait; use PhpArrayTrait;
private $createCacheItem; private $createCacheItem;
@ -36,11 +39,10 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
* @param string $file The PHP file were values are cached * @param string $file The PHP file were values are cached
* @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
*/ */
public function __construct($file, AdapterInterface $fallbackPool) public function __construct(string $file, AdapterInterface $fallbackPool)
{ {
$this->file = $file; $this->file = $file;
$this->pool = $fallbackPool; $this->pool = $fallbackPool;
$this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
$this->createCacheItem = \Closure::bind( $this->createCacheItem = \Closure::bind(
static function ($key, $value, $isHit) { static function ($key, $value, $isHit) {
$item = new CacheItem(); $item = new CacheItem();
@ -56,9 +58,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
} }
/** /**
* This adapter should only be used on PHP 7.0+ to take advantage of how PHP * This adapter takes advantage of how PHP stores arrays in its latest versions.
* stores arrays in its latest versions. This factory method decorates the given
* fallback pool with this adapter only if the current PHP version is supported.
* *
* @param string $file The PHP file were values are cached * @param string $file The PHP file were values are cached
* @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit
@ -67,15 +67,44 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
*/ */
public static function create($file, CacheItemPoolInterface $fallbackPool) public static function create($file, CacheItemPoolInterface $fallbackPool)
{ {
if (\PHP_VERSION_ID >= 70000) { if (!$fallbackPool instanceof AdapterInterface) {
if (!$fallbackPool instanceof AdapterInterface) { $fallbackPool = new ProxyAdapter($fallbackPool);
$fallbackPool = new ProxyAdapter($fallbackPool);
}
return new static($file, $fallbackPool);
} }
return $fallbackPool; return new static($file, $fallbackPool);
}
/**
* {@inheritdoc}
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
{
if (null === $this->values) {
$this->initialize();
}
if (!isset($this->keys[$key])) {
get_from_pool:
if ($this->pool instanceof CacheInterface) {
return $this->pool->get($key, $callback, $beta, $metadata);
}
return $this->doGet($this->pool, $key, $callback, $beta, $metadata);
}
$value = $this->values[$this->keys[$key]];
if ('N;' === $value) {
return null;
}
try {
if ($value instanceof \Closure) {
return $value();
}
} catch (\Throwable $e) {
unset($this->keys[$key]);
goto get_from_pool;
}
return $value;
} }
/** /**
@ -89,23 +118,19 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
if (null === $this->values) { if (null === $this->values) {
$this->initialize(); $this->initialize();
} }
if (!isset($this->values[$key])) { if (!isset($this->keys[$key])) {
return $this->pool->getItem($key); return $this->pool->getItem($key);
} }
$value = $this->values[$key]; $value = $this->values[$this->keys[$key]];
$isHit = true; $isHit = true;
if ('N;' === $value) { if ('N;' === $value) {
$value = null; $value = null;
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { } elseif ($value instanceof \Closure) {
try { try {
$e = null; $value = $value();
$value = unserialize($value); } catch (\Throwable $e) {
} catch (\Error $e) {
} catch (\Exception $e) {
}
if (null !== $e) {
$value = null; $value = null;
$isHit = false; $isHit = false;
} }
@ -135,6 +160,8 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function hasItem($key) public function hasItem($key)
{ {
@ -145,11 +172,13 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
$this->initialize(); $this->initialize();
} }
return isset($this->values[$key]) || $this->pool->hasItem($key); return isset($this->keys[$key]) || $this->pool->hasItem($key);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItem($key) public function deleteItem($key)
{ {
@ -160,11 +189,13 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
$this->initialize(); $this->initialize();
} }
return !isset($this->values[$key]) && $this->pool->deleteItem($key); return !isset($this->keys[$key]) && $this->pool->deleteItem($key);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItems(array $keys) public function deleteItems(array $keys)
{ {
@ -176,7 +207,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
} }
if (isset($this->values[$key])) { if (isset($this->keys[$key])) {
$deleted = false; $deleted = false;
} else { } else {
$fallbackKeys[] = $key; $fallbackKeys[] = $key;
@ -195,6 +226,8 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function save(CacheItemInterface $item) public function save(CacheItemInterface $item)
{ {
@ -202,11 +235,13 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
$this->initialize(); $this->initialize();
} }
return !isset($this->values[$item->getKey()]) && $this->pool->save($item); return !isset($this->keys[$item->getKey()]) && $this->pool->save($item);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function saveDeferred(CacheItemInterface $item) public function saveDeferred(CacheItemInterface $item)
{ {
@ -214,37 +249,34 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
$this->initialize(); $this->initialize();
} }
return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item); return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function commit() public function commit()
{ {
return $this->pool->commit(); return $this->pool->commit();
} }
/** private function generateItems(array $keys): \Generator
* @return \Generator
*/
private function generateItems(array $keys)
{ {
$f = $this->createCacheItem; $f = $this->createCacheItem;
$fallbackKeys = []; $fallbackKeys = [];
foreach ($keys as $key) { foreach ($keys as $key) {
if (isset($this->values[$key])) { if (isset($this->keys[$key])) {
$value = $this->values[$key]; $value = $this->values[$this->keys[$key]];
if ('N;' === $value) { if ('N;' === $value) {
yield $key => $f($key, null, true); yield $key => $f($key, null, true);
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { } elseif ($value instanceof \Closure) {
try { try {
yield $key => $f($key, unserialize($value), true); yield $key => $f($key, $value(), true);
} catch (\Error $e) { } catch (\Throwable $e) {
yield $key => $f($key, null, false);
} catch (\Exception $e) {
yield $key => $f($key, null, false); yield $key => $f($key, null, false);
} }
} else { } else {
@ -256,9 +288,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl
} }
if ($fallbackKeys) { if ($fallbackKeys) {
foreach ($this->pool->getItems($fallbackKeys) as $key => $item) { yield from $this->pool->getItems($fallbackKeys);
yield $key => $item;
}
} }
} }

View file

@ -20,22 +20,19 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
use PhpFilesTrait; use PhpFilesTrait;
/** /**
* @param string $namespace * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire.
* @param int $defaultLifetime * Doing so is encouraged because it fits perfectly OPcache's memory model.
* @param string|null $directory
* *
* @throws CacheException if OPcache is not enabled * @throws CacheException if OPcache is not enabled
*/ */
public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false)
{ {
if (!static::isSupported()) { $this->appendOnly = $appendOnly;
throw new CacheException('OPcache is not enabled.'); self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
}
parent::__construct('', $defaultLifetime); parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory); $this->init($namespace, $directory);
$this->includeHandler = static function ($type, $msg, $file, $line) {
$e = new \Exception(); throw new \ErrorException($msg, 0, $type, $file, $line);
$this->includeHandler = function () use ($e) { throw $e; }; };
$this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
} }
} }

View file

@ -16,26 +16,26 @@ use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ContractsTrait;
use Symfony\Component\Cache\Traits\ProxyTrait; use Symfony\Component\Cache\Traits\ProxyTrait;
use Symfony\Contracts\Cache\CacheInterface;
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableInterface class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
{ {
use ContractsTrait;
use ProxyTrait; use ProxyTrait;
private $namespace; private $namespace;
private $namespaceLen; private $namespaceLen;
private $createCacheItem; private $createCacheItem;
private $setInnerItem;
private $poolHash; private $poolHash;
private $defaultLifetime; private $defaultLifetime;
/** public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0)
* @param string $namespace
* @param int $defaultLifetime
*/
public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defaultLifetime = 0)
{ {
$this->pool = $pool; $this->pool = $pool;
$this->poolHash = $poolHash = spl_object_hash($pool); $this->poolHash = $poolHash = spl_object_hash($pool);
@ -46,20 +46,71 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
static function ($key, $innerItem) use ($poolHash) { static function ($key, $innerItem) use ($poolHash) {
$item = new CacheItem(); $item = new CacheItem();
$item->key = $key; $item->key = $key;
if (null === $innerItem) {
return $item;
}
$item->value = $v = $innerItem->get();
$item->isHit = $innerItem->isHit();
$item->innerItem = $innerItem;
$item->poolHash = $poolHash; $item->poolHash = $poolHash;
if (null !== $innerItem) { // Detect wrapped values that encode for their expiry and creation duration
$item->value = $innerItem->get(); // For compactness, these values are packed in the key of an array using
$item->isHit = $innerItem->isHit(); // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
$item->innerItem = $innerItem; if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) {
$innerItem->set(null); $item->value = $v[$k];
$v = unpack('Ve/Nc', substr($k, 1, -1));
$item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
$item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
} elseif ($innerItem instanceof CacheItem) {
$item->metadata = $innerItem->metadata;
} }
$innerItem->set(null);
return $item; return $item;
}, },
null, null,
CacheItem::class CacheItem::class
); );
$this->setInnerItem = \Closure::bind(
/**
* @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix
*/
static function (CacheItemInterface $innerItem, array $item) {
// Tags are stored separately, no need to account for them when considering this item's newly set metadata
if (isset(($metadata = $item["\0*\0newMetadata"])[CacheItem::METADATA_TAGS])) {
unset($metadata[CacheItem::METADATA_TAGS]);
}
if ($metadata) {
// For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
$item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
}
$innerItem->set($item["\0*\0value"]);
$innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null);
},
null,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
{
if (!$this->pool instanceof CacheInterface) {
return $this->doGet($this, $key, $callback, $beta, $metadata);
}
return $this->pool->get($this->getId($key), function ($innerItem, bool &$save) use ($key, $callback) {
$item = ($this->createCacheItem)($key, $innerItem);
$item->set($value = $callback($item, $save));
($this->setInnerItem)($innerItem, (array) $item);
return $value;
}, $beta, $metadata);
} }
/** /**
@ -89,6 +140,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function hasItem($key) public function hasItem($key)
{ {
@ -97,14 +150,26 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/ */
public function clear() public function clear(/* string $prefix = '' */)
{ {
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
if ($this->pool instanceof AdapterInterface) {
return $this->pool->clear($this->namespace.$prefix);
}
return $this->pool->clear(); return $this->pool->clear();
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItem($key) public function deleteItem($key)
{ {
@ -113,6 +178,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItems(array $keys) public function deleteItems(array $keys)
{ {
@ -127,6 +194,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function save(CacheItemInterface $item) public function save(CacheItemInterface $item)
{ {
@ -135,6 +204,8 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function saveDeferred(CacheItemInterface $item) public function saveDeferred(CacheItemInterface $item)
{ {
@ -143,21 +214,22 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function commit() public function commit()
{ {
return $this->pool->commit(); return $this->pool->commit();
} }
private function doSave(CacheItemInterface $item, $method) private function doSave(CacheItemInterface $item, string $method)
{ {
if (!$item instanceof CacheItem) { if (!$item instanceof CacheItem) {
return false; return false;
} }
$item = (array) $item; $item = (array) $item;
$expiry = $item["\0*\0expiry"]; if (null === $item["\0*\0expiry"] && 0 < $this->defaultLifetime) {
if (null === $expiry && 0 < $this->defaultLifetime) { $item["\0*\0expiry"] = microtime(true) + $this->defaultLifetime;
$expiry = time() + $this->defaultLifetime;
} }
if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) { if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) {
@ -171,13 +243,12 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
$innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]); $innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]);
} }
$innerItem->set($item["\0*\0value"]); ($this->setInnerItem)($innerItem, $item);
$innerItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null);
return $this->pool->$method($innerItem); return $this->pool->$method($innerItem);
} }
private function generateItems($items) private function generateItems(iterable $items)
{ {
$f = $this->createCacheItem; $f = $this->createCacheItem;
@ -190,7 +261,7 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn
} }
} }
private function getId($key) private function getId($key): string
{ {
CacheItem::validateKey($key); CacheItem::validateKey($key);

View file

@ -0,0 +1,86 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ProxyTrait;
/**
* Turns a PSR-16 cache into a PSR-6 one.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface
{
use ProxyTrait;
/**
* @internal
*/
protected const NS_SEPARATOR = '_';
private $miss;
public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0)
{
parent::__construct($namespace, $defaultLifetime);
$this->pool = $pool;
$this->miss = new \stdClass();
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) {
if ($this->miss !== $value) {
yield $key => $value;
}
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return $this->pool->has($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
return $this->pool->deleteMultiple($ids);
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, int $lifetime)
{
return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);
}
}

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\Traits\RedisClusterProxy;
use Symfony\Component\Cache\Traits\RedisProxy;
use Symfony\Component\Cache\Traits\RedisTrait; use Symfony\Component\Cache\Traits\RedisTrait;
class RedisAdapter extends AbstractAdapter class RedisAdapter extends AbstractAdapter
@ -18,12 +21,12 @@ class RedisAdapter extends AbstractAdapter
use RedisTrait; use RedisTrait;
/** /**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient The redis client * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis The redis client
* @param string $namespace The default namespace * @param string $namespace The default namespace
* @param int $defaultLifetime The default lifetime * @param int $defaultLifetime The default lifetime
*/ */
public function __construct($redisClient, $namespace = '', $defaultLifetime = 0) public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
{ {
$this->init($redisClient, $namespace, $defaultLifetime); $this->init($redis, $namespace, $defaultLifetime, $marshaller);
} }
} }

View file

@ -0,0 +1,321 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\PredisCluster;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Response\ErrorInterface;
use Predis\Response\Status;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Exception\LogicException;
use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
use Symfony\Component\Cache\Traits\RedisClusterProxy;
use Symfony\Component\Cache\Traits\RedisProxy;
use Symfony\Component\Cache\Traits\RedisTrait;
/**
* Stores tag id <> cache id relationship as a Redis Set.
*
* Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even
* if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache
* relationship survives eviction (cache cleanup when Redis runs out of memory).
*
* Redis server 2.8+ with any `volatile-*` eviction policy, OR `noeviction` if you're sure memory will NEVER fill up
*
* Design limitations:
* - Max 4 billion cache keys per cache tag as limited by Redis Set datatype.
* E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 4 billion cache items also.
*
* @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies.
* @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype.
*
* @author Nicolas Grekas <p@tchwork.com>
* @author André Rømcke <andre.romcke+symfony@gmail.com>
*/
class RedisTagAwareAdapter extends AbstractTagAwareAdapter
{
use RedisTrait;
/**
* On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are
* preferred to be evicted over tag Sets, if eviction policy is configured according to requirements.
*/
private const DEFAULT_CACHE_TTL = 8640000;
/**
* @var string|null detected eviction policy used on Redis server
*/
private $redisEvictionPolicy;
private $namespace;
/**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis The redis client
* @param string $namespace The default namespace
* @param int $defaultLifetime The default lifetime
*/
public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
{
if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) {
throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, \get_class($redis->getConnection())));
}
if (\defined('Redis::OPT_COMPRESSION') && ($redis instanceof \Redis || $redis instanceof \RedisArray || $redis instanceof \RedisCluster)) {
$compression = $redis->getOption(\Redis::OPT_COMPRESSION);
foreach (\is_array($compression) ? $compression : [$compression] as $c) {
if (\Redis::COMPRESSION_NONE !== $c) {
throw new InvalidArgumentException(sprintf('phpredis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class));
}
}
}
$this->init($redis, $namespace, $defaultLifetime, new TagAwareMarshaller($marshaller));
$this->namespace = $namespace;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, int $lifetime, array $addTagData = [], array $delTagData = []): array
{
$eviction = $this->getRedisEvictionPolicy();
if ('noeviction' !== $eviction && !str_starts_with($eviction, 'volatile-')) {
throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction));
}
// serialize values
if (!$serialized = $this->marshaller->marshall($values, $failed)) {
return $failed;
}
// While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op
$results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData, $failed) {
// Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one
foreach ($serialized as $id => $value) {
yield 'setEx' => [
$id,
0 >= $lifetime ? self::DEFAULT_CACHE_TTL : $lifetime,
$value,
];
}
// Add and Remove Tags
foreach ($addTagData as $tagId => $ids) {
if (!$failed || $ids = array_diff($ids, $failed)) {
yield 'sAdd' => array_merge([$tagId], $ids);
}
}
foreach ($delTagData as $tagId => $ids) {
if (!$failed || $ids = array_diff($ids, $failed)) {
yield 'sRem' => array_merge([$tagId], $ids);
}
}
});
foreach ($results as $id => $result) {
// Skip results of SADD/SREM operations, they'll be 1 or 0 depending on if set value already existed or not
if (is_numeric($result)) {
continue;
}
// setEx results
if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) {
$failed[] = $id;
}
}
return $failed;
}
/**
* {@inheritdoc}
*/
protected function doDeleteYieldTags(array $ids): iterable
{
$lua = <<<'EOLUA'
local v = redis.call('GET', KEYS[1])
redis.call('DEL', KEYS[1])
if not v or v:len() <= 13 or v:byte(1) ~= 0x9D or v:byte(6) ~= 0 or v:byte(10) ~= 0x5F then
return ''
end
return v:sub(14, 13 + v:byte(13) + v:byte(12) * 256 + v:byte(11) * 65536)
EOLUA;
$results = $this->pipeline(function () use ($ids, $lua) {
foreach ($ids as $id) {
yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id] : [$lua, [$id], 1];
}
});
foreach ($results as $id => $result) {
if ($result instanceof \RedisException || $result instanceof ErrorInterface) {
CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]);
continue;
}
try {
yield $id => !\is_string($result) || '' === $result ? [] : $this->marshaller->unmarshall($result);
} catch (\Exception $e) {
yield $id => [];
}
}
}
/**
* {@inheritdoc}
*/
protected function doDeleteTagRelations(array $tagData): bool
{
$results = $this->pipeline(static function () use ($tagData) {
foreach ($tagData as $tagId => $idList) {
array_unshift($idList, $tagId);
yield 'sRem' => $idList;
}
});
foreach ($results as $result) {
// no-op
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doInvalidate(array $tagIds): bool
{
// This script scans the set of items linked to tag: it empties the set
// and removes the linked items. When the set is still not empty after
// the scan, it means we're in cluster mode and that the linked items
// are on other nodes: we move the links to a temporary set and we
// garbage collect that set from the client side.
$lua = <<<'EOLUA'
redis.replicate_commands()
local cursor = '0'
local id = KEYS[1]
repeat
local result = redis.call('SSCAN', id, cursor, 'COUNT', 5000);
cursor = result[1];
local rems = {}
for _, v in ipairs(result[2]) do
local ok, _ = pcall(redis.call, 'DEL', ARGV[1]..v)
if ok then
table.insert(rems, v)
end
end
if 0 < #rems then
redis.call('SREM', id, unpack(rems))
end
until '0' == cursor;
redis.call('SUNIONSTORE', '{'..id..'}'..id, id)
redis.call('DEL', id)
return redis.call('SSCAN', '{'..id..'}'..id, '0', 'COUNT', 5000)
EOLUA;
$results = $this->pipeline(function () use ($tagIds, $lua) {
if ($this->redis instanceof \Predis\ClientInterface) {
$prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : '';
} elseif (\is_array($prefix = $this->redis->getOption(\Redis::OPT_PREFIX) ?? '')) {
$prefix = current($prefix);
}
foreach ($tagIds as $id) {
yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id, $prefix] : [$lua, [$id, $prefix], 1];
}
});
$lua = <<<'EOLUA'
redis.replicate_commands()
local id = KEYS[1]
local cursor = table.remove(ARGV)
redis.call('SREM', '{'..id..'}'..id, unpack(ARGV))
return redis.call('SSCAN', '{'..id..'}'..id, cursor, 'COUNT', 5000)
EOLUA;
$success = true;
foreach ($results as $id => $values) {
if ($values instanceof \RedisException || $values instanceof ErrorInterface) {
CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]);
$success = false;
continue;
}
[$cursor, $ids] = $values;
while ($ids || '0' !== $cursor) {
$this->doDelete($ids);
$evalArgs = [$id, $cursor];
array_splice($evalArgs, 1, 0, $ids);
if ($this->redis instanceof \Predis\ClientInterface) {
array_unshift($evalArgs, $lua, 1);
} else {
$evalArgs = [$lua, $evalArgs, 1];
}
$results = $this->pipeline(function () use ($evalArgs) {
yield 'eval' => $evalArgs;
});
foreach ($results as [$cursor, $ids]) {
// no-op
}
}
}
return $success;
}
private function getRedisEvictionPolicy(): string
{
if (null !== $this->redisEvictionPolicy) {
return $this->redisEvictionPolicy;
}
$hosts = $this->getHosts();
$host = reset($hosts);
if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) {
// Predis supports info command only on the master in replication environments
$hosts = [$host->getClientFor('master')];
}
foreach ($hosts as $host) {
$info = $host->info('Memory');
if ($info instanceof ErrorInterface) {
continue;
}
$info = $info['Memory'] ?? $info;
return $this->redisEvictionPolicy = $info['maxmemory_policy'];
}
return $this->redisEvictionPolicy = '';
}
}

View file

@ -11,73 +11,11 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Psr\SimpleCache\CacheInterface; @trigger_error(sprintf('The "%s" class is @deprecated since Symfony 4.3, use "Psr16Adapter" instead.', SimpleCacheAdapter::class), \E_USER_DEPRECATED);
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\ProxyTrait;
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @deprecated since Symfony 4.3, use Psr16Adapter instead.
*/ */
class SimpleCacheAdapter extends AbstractAdapter implements PruneableInterface class SimpleCacheAdapter extends Psr16Adapter
{ {
/**
* @internal
*/
const NS_SEPARATOR = '_';
use ProxyTrait;
private $miss;
public function __construct(CacheInterface $pool, $namespace = '', $defaultLifetime = 0)
{
parent::__construct($namespace, $defaultLifetime);
$this->pool = $pool;
$this->miss = new \stdClass();
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) {
if ($this->miss !== $value) {
yield $key => $value;
}
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return $this->pool->has($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
return $this->pool->deleteMultiple($ids);
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);
}
} }

View file

@ -13,20 +13,26 @@ namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
use Psr\Cache\InvalidArgumentException; use Psr\Cache\InvalidArgumentException;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ContractsTrait;
use Symfony\Component\Cache\Traits\ProxyTrait; use Symfony\Component\Cache\Traits\ProxyTrait;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, ResettableInterface class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface, LoggerAwareInterface
{ {
const TAGS_PREFIX = "\0tags\0"; use ContractsTrait;
use LoggerAwareTrait;
use ProxyTrait; use ProxyTrait;
public const TAGS_PREFIX = "\0tags\0";
private $deferred = []; private $deferred = [];
private $createCacheItem; private $createCacheItem;
private $setCacheItemTags; private $setCacheItemTags;
@ -36,7 +42,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
private $knownTagVersions = []; private $knownTagVersions = [];
private $knownTagVersionsTtl; private $knownTagVersionsTtl;
public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, $knownTagVersionsTtl = 0.15) public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15)
{ {
$this->pool = $itemsPool; $this->pool = $itemsPool;
$this->tags = $tagsPool ?: $itemsPool; $this->tags = $tagsPool ?: $itemsPool;
@ -56,12 +62,13 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
); );
$this->setCacheItemTags = \Closure::bind( $this->setCacheItemTags = \Closure::bind(
static function (CacheItem $item, $key, array &$itemTags) { static function (CacheItem $item, $key, array &$itemTags) {
$item->isTaggable = true;
if (!$item->isHit) { if (!$item->isHit) {
return $item; return $item;
} }
if (isset($itemTags[$key])) { if (isset($itemTags[$key])) {
foreach ($itemTags[$key] as $tag => $version) { foreach ($itemTags[$key] as $tag => $version) {
$item->prevTags[$tag] = $tag; $item->metadata[CacheItem::METADATA_TAGS][$tag] = $tag;
} }
unset($itemTags[$key]); unset($itemTags[$key]);
} else { } else {
@ -78,7 +85,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
static function ($deferred) { static function ($deferred) {
$tagsByKey = []; $tagsByKey = [];
foreach ($deferred as $key => $item) { foreach ($deferred as $key => $item) {
$tagsByKey[$key] = $item->tags; $tagsByKey[$key] = $item->newMetadata[CacheItem::METADATA_TAGS] ?? [];
$item->metadata = $item->newMetadata;
} }
return $tagsByKey; return $tagsByKey;
@ -145,12 +153,15 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function hasItem($key) public function hasItem($key)
{ {
if ($this->deferred) { if (\is_string($key) && isset($this->deferred[$key])) {
$this->commit(); $this->commit();
} }
if (!$this->pool->hasItem($key)) { if (!$this->pool->hasItem($key)) {
return false; return false;
} }
@ -166,9 +177,11 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
} }
foreach ($this->getTagVersions([$itemTags]) as $tag => $version) { foreach ($this->getTagVersions([$itemTags]) as $tag => $version) {
if ($itemTags[$tag] !== $version && 1 !== $itemTags[$tag] - $version) { if ($itemTags[$tag] === $version || \is_int($itemTags[$tag]) && \is_int($version) && 1 === $itemTags[$tag] - $version) {
return false; continue;
} }
return false;
} }
return true; return true;
@ -191,18 +204,21 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
*/ */
public function getItems(array $keys = []) public function getItems(array $keys = [])
{ {
if ($this->deferred) {
$this->commit();
}
$tagKeys = []; $tagKeys = [];
$commit = false;
foreach ($keys as $key) { foreach ($keys as $key) {
if ('' !== $key && \is_string($key)) { if ('' !== $key && \is_string($key)) {
$commit = $commit || isset($this->deferred[$key]);
$key = static::TAGS_PREFIX.$key; $key = static::TAGS_PREFIX.$key;
$tagKeys[$key] = $key; $tagKeys[$key] = $key;
} }
} }
if ($commit) {
$this->commit();
}
try { try {
$items = $this->pool->getItems($tagKeys + $keys); $items = $this->pool->getItems($tagKeys + $keys);
} catch (InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
@ -216,16 +232,36 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/ */
public function clear() public function clear(/* string $prefix = '' */)
{ {
$this->deferred = []; $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
if ('' !== $prefix) {
foreach ($this->deferred as $key => $item) {
if (str_starts_with($key, $prefix)) {
unset($this->deferred[$key]);
}
}
} else {
$this->deferred = [];
}
if ($this->pool instanceof AdapterInterface) {
return $this->pool->clear($prefix);
}
return $this->pool->clear(); return $this->pool->clear();
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItem($key) public function deleteItem($key)
{ {
@ -234,6 +270,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItems(array $keys) public function deleteItems(array $keys)
{ {
@ -248,6 +286,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function save(CacheItemInterface $item) public function save(CacheItemInterface $item)
{ {
@ -261,6 +301,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function saveDeferred(CacheItemInterface $item) public function saveDeferred(CacheItemInterface $item)
{ {
@ -274,12 +316,17 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function commit() public function commit()
{ {
return $this->invalidateTags([]); return $this->invalidateTags([]);
} }
/**
* @return array
*/
public function __sleep() public function __sleep()
{ {
throw new \BadMethodCallException('Cannot serialize '.__CLASS__); throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
@ -295,7 +342,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
$this->commit(); $this->commit();
} }
private function generateItems($items, array $tagKeys) private function generateItems(iterable $items, array $tagKeys)
{ {
$bufferedItems = $itemTags = []; $bufferedItems = $itemTags = [];
$f = $this->setCacheItemTags; $f = $this->setCacheItemTags;
@ -321,10 +368,11 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
foreach ($itemTags as $key => $tags) { foreach ($itemTags as $key => $tags) {
foreach ($tags as $tag => $version) { foreach ($tags as $tag => $version) {
if ($tagVersions[$tag] !== $version && 1 !== $version - $tagVersions[$tag]) { if ($tagVersions[$tag] === $version || \is_int($version) && \is_int($tagVersions[$tag]) && 1 === $version - $tagVersions[$tag]) {
unset($itemTags[$key]); continue;
continue 2;
} }
unset($itemTags[$key]);
continue 2;
} }
} }
$tagVersions = $tagKeys = null; $tagVersions = $tagKeys = null;
@ -363,7 +411,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
$tags = []; $tags = [];
foreach ($tagVersions as $tag => $version) { foreach ($tagVersions as $tag => $version) {
$tags[$tag.static::TAGS_PREFIX] = $tag; $tags[$tag.static::TAGS_PREFIX] = $tag;
if ($fetchTagVersions || !isset($this->knownTagVersions[$tag])) { if ($fetchTagVersions || !isset($this->knownTagVersions[$tag]) || !\is_int($version)) {
$fetchTagVersions = true; $fetchTagVersions = true;
continue; continue;
} }
@ -385,6 +433,10 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
if (isset($invalidatedTags[$tag])) { if (isset($invalidatedTags[$tag])) {
$invalidatedTags[$tag] = $version->set(++$tagVersions[$tag]); $invalidatedTags[$tag] = $version->set(++$tagVersions[$tag]);
} }
if (!\is_int($tagVersions[$tag])) {
unset($this->knownTagVersions[$tag]);
continue;
}
$this->knownTagVersions[$tag] = [$now, $tagVersions[$tag]]; $this->knownTagVersions[$tag] = [$now, $tagVersions[$tag]];
} }

View file

@ -12,8 +12,11 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Service\ResetInterface;
/** /**
* An adapter that collects data about all cache calls. * An adapter that collects data about all cache calls.
@ -22,7 +25,7 @@ use Symfony\Component\Cache\ResettableInterface;
* @author Tobias Nyholm <tobias.nyholm@gmail.com> * @author Tobias Nyholm <tobias.nyholm@gmail.com>
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
class TraceableAdapter implements AdapterInterface, PruneableInterface, ResettableInterface class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
{ {
protected $pool; protected $pool;
private $calls = []; private $calls = [];
@ -32,6 +35,38 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
$this->pool = $pool; $this->pool = $pool;
} }
/**
* {@inheritdoc}
*/
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null)
{
if (!$this->pool instanceof CacheInterface) {
throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', \get_class($this->pool), CacheInterface::class));
}
$isHit = true;
$callback = function (CacheItem $item, bool &$save) use ($callback, &$isHit) {
$isHit = $item->isHit();
return $callback($item, $save);
};
$event = $this->start(__FUNCTION__);
try {
$value = $this->pool->get($key, $callback, $beta, $metadata);
$event->result[$key] = \is_object($value) ? \get_class($value) : \gettype($value);
} finally {
$event->end = microtime(true);
}
if ($isHit) {
++$event->hits;
} else {
++$event->misses;
}
return $value;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -54,6 +89,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function hasItem($key) public function hasItem($key)
{ {
@ -67,6 +104,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItem($key) public function deleteItem($key)
{ {
@ -80,6 +119,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function save(CacheItemInterface $item) public function save(CacheItemInterface $item)
{ {
@ -93,6 +134,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function saveDeferred(CacheItemInterface $item) public function saveDeferred(CacheItemInterface $item)
{ {
@ -132,11 +175,20 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/ */
public function clear() public function clear(/* string $prefix = '' */)
{ {
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
$event = $this->start(__FUNCTION__); $event = $this->start(__FUNCTION__);
try { try {
if ($this->pool instanceof AdapterInterface) {
return $event->result = $this->pool->clear($prefix);
}
return $event->result = $this->pool->clear(); return $event->result = $this->pool->clear();
} finally { } finally {
$event->end = microtime(true); $event->end = microtime(true);
@ -145,6 +197,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteItems(array $keys) public function deleteItems(array $keys)
{ {
@ -159,6 +213,8 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function commit() public function commit()
{ {
@ -191,13 +247,26 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab
*/ */
public function reset() public function reset()
{ {
if ($this->pool instanceof ResettableInterface) { if ($this->pool instanceof ResetInterface) {
$this->pool->reset(); $this->pool->reset();
} }
$this->clearCalls(); $this->clearCalls();
} }
/**
* {@inheritdoc}
*/
public function delete(string $key): bool
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$key] = $this->pool->deleteItem($key);
} finally {
$event->end = microtime(true);
}
}
public function getCalls() public function getCalls()
{ {
return $this->calls; return $this->calls;

View file

@ -11,10 +11,12 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
/** /**
* @author Robin Chalas <robin.chalas@gmail.com> * @author Robin Chalas <robin.chalas@gmail.com>
*/ */
class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface
{ {
public function __construct(TagAwareAdapterInterface $pool) public function __construct(TagAwareAdapterInterface $pool)
{ {

View file

@ -1,6 +1,43 @@
CHANGELOG CHANGELOG
========= =========
4.4.0
-----
* added support for connecting to Redis Sentinel clusters
* added argument `$prefix` to `AdapterInterface::clear()`
* improved `RedisTagAwareAdapter` to support Redis server >= 2.8 and up to 4B items per tag
* added `TagAwareMarshaller` for optimized data storage when using `AbstractTagAwareAdapter`
* added `DeflateMarshaller` to compress serialized values
* removed support for phpredis 4 `compression`
* [BC BREAK] `RedisTagAwareAdapter` is not compatible with `RedisCluster` from `Predis` anymore, use `phpredis` instead
* Marked the `CacheDataCollector` class as `@final`.
4.3.0
-----
* removed `psr/simple-cache` dependency, run `composer require psr/simple-cache` if you need it
* deprecated all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead
* deprecated `SimpleCacheAdapter`, use `Psr16Adapter` instead
4.2.0
-----
* added support for connecting to Redis clusters via DSN
* added support for configuring multiple Memcached servers via DSN
* added `MarshallerInterface` and `DefaultMarshaller` to allow changing the serializer and provide one that automatically uses igbinary when available
* implemented `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache
* added sub-second expiry accuracy for backends that support it
* added support for phpredis 4 `compression` and `tcp_keepalive` options
* added automatic table creation when using Doctrine DBAL with PDO-based backends
* throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool
* deprecated `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead
* deprecated the `AbstractAdapter::unserialize()` and `AbstractCache::unserialize()` methods
* added `CacheCollectorPass` (originally in `FrameworkBundle`)
* added `CachePoolClearerPass` (originally in `FrameworkBundle`)
* added `CachePoolPass` (originally in `FrameworkBundle`)
* added `CachePoolPrunerPass` (originally in `FrameworkBundle`)
3.4.0 3.4.0
----- -----
@ -13,7 +50,7 @@ CHANGELOG
3.3.0 3.3.0
----- -----
* [EXPERIMENTAL] added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any * added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any
* added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters * added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters
* added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16 * added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16
* added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16) * added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16)

View file

@ -11,34 +11,40 @@
namespace Symfony\Component\Cache; namespace Symfony\Component\Cache;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Exception\LogicException;
use Symfony\Contracts\Cache\ItemInterface;
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
final class CacheItem implements CacheItemInterface final class CacheItem implements ItemInterface
{ {
private const METADATA_EXPIRY_OFFSET = 1527506807;
protected $key; protected $key;
protected $value; protected $value;
protected $isHit = false; protected $isHit = false;
protected $expiry; protected $expiry;
protected $tags = []; protected $metadata = [];
protected $prevTags = []; protected $newMetadata = [];
protected $innerItem; protected $innerItem;
protected $poolHash; protected $poolHash;
protected $isTaggable = false;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getKey() public function getKey(): string
{ {
return $this->key; return $this->key;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return mixed
*/ */
public function get() public function get()
{ {
@ -48,7 +54,7 @@ final class CacheItem implements CacheItemInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isHit() public function isHit(): bool
{ {
return $this->isHit; return $this->isHit;
} }
@ -58,7 +64,7 @@ final class CacheItem implements CacheItemInterface
* *
* @return $this * @return $this
*/ */
public function set($value) public function set($value): self
{ {
$this->value = $value; $this->value = $value;
@ -70,12 +76,12 @@ final class CacheItem implements CacheItemInterface
* *
* @return $this * @return $this
*/ */
public function expiresAt($expiration) public function expiresAt($expiration): self
{ {
if (null === $expiration) { if (null === $expiration) {
$this->expiry = null; $this->expiry = null;
} elseif ($expiration instanceof \DateTimeInterface) { } elseif ($expiration instanceof \DateTimeInterface) {
$this->expiry = (int) $expiration->format('U'); $this->expiry = (float) $expiration->format('U.u');
} else { } else {
throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given.', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration))); throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given.', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration)));
} }
@ -88,14 +94,14 @@ final class CacheItem implements CacheItemInterface
* *
* @return $this * @return $this
*/ */
public function expiresAfter($time) public function expiresAfter($time): self
{ {
if (null === $time) { if (null === $time) {
$this->expiry = null; $this->expiry = null;
} elseif ($time instanceof \DateInterval) { } elseif ($time instanceof \DateInterval) {
$this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U'); $this->expiry = microtime(true) + \DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
} elseif (\is_int($time)) { } elseif (\is_int($time)) {
$this->expiry = $time + time(); $this->expiry = $time + microtime(true);
} else { } else {
throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($time) ? \get_class($time) : \gettype($time))); throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($time) ? \get_class($time) : \gettype($time)));
} }
@ -104,58 +110,64 @@ final class CacheItem implements CacheItemInterface
} }
/** /**
* Adds a tag to a cache item. * {@inheritdoc}
*
* @param string|string[] $tags A tag or array of tags
*
* @return $this
*
* @throws InvalidArgumentException When $tag is not valid
*/ */
public function tag($tags) public function tag($tags): ItemInterface
{ {
if (!\is_array($tags)) { if (!$this->isTaggable) {
throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key));
}
if (!is_iterable($tags)) {
$tags = [$tags]; $tags = [$tags];
} }
foreach ($tags as $tag) { foreach ($tags as $tag) {
if (!\is_string($tag)) { if (!\is_string($tag) && !(\is_object($tag) && method_exists($tag, '__toString'))) {
throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag))); throw new InvalidArgumentException(sprintf('Cache tag must be string or object that implements __toString(), "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag)));
} }
if (isset($this->tags[$tag])) { $tag = (string) $tag;
if (isset($this->newMetadata[self::METADATA_TAGS][$tag])) {
continue; continue;
} }
if ('' === $tag) { if ('' === $tag) {
throw new InvalidArgumentException('Cache tag length must be greater than zero.'); throw new InvalidArgumentException('Cache tag length must be greater than zero.');
} }
if (false !== strpbrk($tag, '{}()/\@:')) { if (false !== strpbrk($tag, self::RESERVED_CHARACTERS)) {
throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:.', $tag)); throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters "%s".', $tag, self::RESERVED_CHARACTERS));
} }
$this->tags[$tag] = $tag; $this->newMetadata[self::METADATA_TAGS][$tag] = $tag;
} }
return $this; return $this;
} }
/**
* {@inheritdoc}
*/
public function getMetadata(): array
{
return $this->metadata;
}
/** /**
* Returns the list of tags bound to the value coming from the pool storage if any. * Returns the list of tags bound to the value coming from the pool storage if any.
* *
* @return array * @deprecated since Symfony 4.2, use the "getMetadata()" method instead.
*/ */
public function getPreviousTags() public function getPreviousTags(): array
{ {
return $this->prevTags; @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "getMetadata()" method instead.', __METHOD__), \E_USER_DEPRECATED);
return $this->metadata[self::METADATA_TAGS] ?? [];
} }
/** /**
* Validates a cache key according to PSR-6. * Validates a cache key according to PSR-6.
* *
* @param string $key The key to validate * @param mixed $key The key to validate
*
* @return string
* *
* @throws InvalidArgumentException When $key is not valid * @throws InvalidArgumentException When $key is not valid
*/ */
public static function validateKey($key) public static function validateKey($key): string
{ {
if (!\is_string($key)) { if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
@ -163,8 +175,8 @@ final class CacheItem implements CacheItemInterface
if ('' === $key) { if ('' === $key) {
throw new InvalidArgumentException('Cache key length must be greater than zero.'); throw new InvalidArgumentException('Cache key length must be greater than zero.');
} }
if (false !== strpbrk($key, '{}()/\@:')) { if (false !== strpbrk($key, self::RESERVED_CHARACTERS)) {
throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:.', $key)); throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
} }
return $key; return $key;
@ -175,14 +187,14 @@ final class CacheItem implements CacheItemInterface
* *
* @internal * @internal
*/ */
public static function log(LoggerInterface $logger = null, $message, $context = []) public static function log(?LoggerInterface $logger, string $message, array $context = [])
{ {
if ($logger) { if ($logger) {
$logger->warning($message, $context); $logger->warning($message, $context);
} else { } else {
$replace = []; $replace = [];
foreach ($context as $k => $v) { foreach ($context as $k => $v) {
if (is_scalar($v)) { if (\is_scalar($v)) {
$replace['{'.$k.'}'] = $v; $replace['{'.$k.'}'] = $v;
} }
} }

View file

@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
/** /**
* @author Aaron Scherer <aequasi@gmail.com> * @author Aaron Scherer <aequasi@gmail.com>
* @author Tobias Nyholm <tobias.nyholm@gmail.com> * @author Tobias Nyholm <tobias.nyholm@gmail.com>
*
* @final since Symfony 4.4
*/ */
class CacheDataCollector extends DataCollector implements LateDataCollectorInterface class CacheDataCollector extends DataCollector implements LateDataCollectorInterface
{ {
@ -39,8 +41,10 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param \Throwable|null $exception
*/ */
public function collect(Request $request, Response $response, \Exception $exception = null) public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{ {
$empty = ['calls' => [], 'config' => [], 'options' => [], 'statistics' => []]; $empty = ['calls' => [], 'config' => [], 'options' => [], 'statistics' => []];
$this->data = ['instances' => $empty, 'total' => $empty]; $this->data = ['instances' => $empty, 'total' => $empty];
@ -62,7 +66,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
public function lateCollect() public function lateCollect()
{ {
$this->data = $this->cloneVar($this->data); $this->data['instances']['calls'] = $this->cloneVar($this->data['instances']['calls']);
} }
/** /**
@ -103,10 +107,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
return $this->data['instances']['calls']; return $this->data['instances']['calls'];
} }
/** private function calculateStatistics(): array
* @return array
*/
private function calculateStatistics()
{ {
$statistics = []; $statistics = [];
foreach ($this->data['instances']['calls'] as $name => $calls) { foreach ($this->data['instances']['calls'] as $name => $calls) {
@ -123,7 +124,15 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
foreach ($calls as $call) { foreach ($calls as $call) {
++$statistics[$name]['calls']; ++$statistics[$name]['calls'];
$statistics[$name]['time'] += $call->end - $call->start; $statistics[$name]['time'] += $call->end - $call->start;
if ('getItem' === $call->name) { if ('get' === $call->name) {
++$statistics[$name]['reads'];
if ($call->hits) {
++$statistics[$name]['hits'];
} else {
++$statistics[$name]['misses'];
++$statistics[$name]['writes'];
}
} elseif ('getItem' === $call->name) {
++$statistics[$name]['reads']; ++$statistics[$name]['reads'];
if ($call->hits) { if ($call->hits) {
++$statistics[$name]['hits']; ++$statistics[$name]['hits'];
@ -157,10 +166,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter
return $statistics; return $statistics;
} }
/** private function calculateTotalStatistics(): array
* @return array
*/
private function calculateTotalStatistics()
{ {
$statistics = $this->getStatistics(); $statistics = $this->getStatistics();
$totals = [ $totals = [

View file

@ -0,0 +1,81 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\DependencyInjection;
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\Cache\Adapter\TraceableAdapter;
use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Inject a data collector to all the cache services to be able to get detailed statistics.
*
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class CacheCollectorPass implements CompilerPassInterface
{
private $dataCollectorCacheId;
private $cachePoolTag;
private $cachePoolRecorderInnerSuffix;
public function __construct(string $dataCollectorCacheId = 'data_collector.cache', string $cachePoolTag = 'cache.pool', string $cachePoolRecorderInnerSuffix = '.recorder_inner')
{
$this->dataCollectorCacheId = $dataCollectorCacheId;
$this->cachePoolTag = $cachePoolTag;
$this->cachePoolRecorderInnerSuffix = $cachePoolRecorderInnerSuffix;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->dataCollectorCacheId)) {
return;
}
foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $attributes) {
$poolName = $attributes[0]['name'] ?? $id;
$this->addToCollector($id, $poolName, $container);
}
}
private function addToCollector(string $id, string $name, ContainerBuilder $container)
{
$definition = $container->getDefinition($id);
if ($definition->isAbstract()) {
return;
}
$collectorDefinition = $container->getDefinition($this->dataCollectorCacheId);
$recorder = new Definition(is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class) ? TraceableTagAwareAdapter::class : TraceableAdapter::class);
$recorder->setTags($definition->getTags());
if (!$definition->isPublic() || !$definition->isPrivate()) {
$recorder->setPublic($definition->isPublic());
}
$recorder->setArguments([new Reference($innerId = $id.$this->cachePoolRecorderInnerSuffix)]);
$definition->setTags([]);
$definition->setPublic(false);
$container->setDefinition($innerId, $definition);
$container->setDefinition($id, $recorder);
// Tell the collector to add the new instance
$collectorDefinition->addMethodCall('addInstance', [$name, new Reference($id)]);
$collectorDefinition->setPublic(false);
}
}

View file

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class CachePoolClearerPass implements CompilerPassInterface
{
private $cachePoolClearerTag;
public function __construct(string $cachePoolClearerTag = 'cache.pool.clearer')
{
$this->cachePoolClearerTag = $cachePoolClearerTag;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$container->getParameterBag()->remove('cache.prefix.seed');
foreach ($container->findTaggedServiceIds($this->cachePoolClearerTag) as $id => $attr) {
$clearer = $container->getDefinition($id);
$pools = [];
foreach ($clearer->getArgument(0) as $name => $ref) {
if ($container->hasDefinition($ref)) {
$pools[$name] = new Reference($ref);
}
}
$clearer->replaceArgument(0, $pools);
}
}
}

View file

@ -0,0 +1,228 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\DependencyInjection;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\NullAdapter;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class CachePoolPass implements CompilerPassInterface
{
private $cachePoolTag;
private $kernelResetTag;
private $cacheClearerId;
private $cachePoolClearerTag;
private $cacheSystemClearerId;
private $cacheSystemClearerTag;
public function __construct(string $cachePoolTag = 'cache.pool', string $kernelResetTag = 'kernel.reset', string $cacheClearerId = 'cache.global_clearer', string $cachePoolClearerTag = 'cache.pool.clearer', string $cacheSystemClearerId = 'cache.system_clearer', string $cacheSystemClearerTag = 'kernel.cache_clearer')
{
$this->cachePoolTag = $cachePoolTag;
$this->kernelResetTag = $kernelResetTag;
$this->cacheClearerId = $cacheClearerId;
$this->cachePoolClearerTag = $cachePoolClearerTag;
$this->cacheSystemClearerId = $cacheSystemClearerId;
$this->cacheSystemClearerTag = $cacheSystemClearerTag;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if ($container->hasParameter('cache.prefix.seed')) {
$seed = '.'.$container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed'));
} else {
$seed = '_'.$container->getParameter('kernel.project_dir');
}
$seed .= '.'.$container->getParameter('kernel.container_class');
$allPools = [];
$clearers = [];
$attributes = [
'provider',
'name',
'namespace',
'default_lifetime',
'reset',
];
foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) {
$adapter = $pool = $container->getDefinition($id);
if ($pool->isAbstract()) {
continue;
}
$class = $adapter->getClass();
while ($adapter instanceof ChildDefinition) {
$adapter = $container->findDefinition($adapter->getParent());
$class = $class ?: $adapter->getClass();
if ($t = $adapter->getTag($this->cachePoolTag)) {
$tags[0] += $t[0];
}
}
$name = $tags[0]['name'] ?? $id;
if (!isset($tags[0]['namespace'])) {
$namespaceSeed = $seed;
if (null !== $class) {
$namespaceSeed .= '.'.$class;
}
$tags[0]['namespace'] = $this->getNamespace($namespaceSeed, $name);
}
if (isset($tags[0]['clearer'])) {
$clearer = $tags[0]['clearer'];
while ($container->hasAlias($clearer)) {
$clearer = (string) $container->getAlias($clearer);
}
} else {
$clearer = null;
}
unset($tags[0]['clearer'], $tags[0]['name']);
if (isset($tags[0]['provider'])) {
$tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider']));
}
if (ChainAdapter::class === $class) {
$adapters = [];
foreach ($adapter->getArgument(0) as $provider => $adapter) {
if ($adapter instanceof ChildDefinition) {
$chainedPool = $adapter;
} else {
$chainedPool = $adapter = new ChildDefinition($adapter);
}
$chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]];
$chainedClass = '';
while ($adapter instanceof ChildDefinition) {
$adapter = $container->findDefinition($adapter->getParent());
$chainedClass = $chainedClass ?: $adapter->getClass();
if ($t = $adapter->getTag($this->cachePoolTag)) {
$chainedTags[0] += $t[0];
}
}
if (ChainAdapter::class === $chainedClass) {
throw new InvalidArgumentException(sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent()));
}
$i = 0;
if (isset($chainedTags[0]['provider'])) {
$chainedPool->replaceArgument($i++, new Reference(static::getServiceProvider($container, $chainedTags[0]['provider'])));
}
if (isset($tags[0]['namespace']) && !\in_array($adapter->getClass(), [ArrayAdapter::class, NullAdapter::class], true)) {
$chainedPool->replaceArgument($i++, $tags[0]['namespace']);
}
if (isset($tags[0]['default_lifetime'])) {
$chainedPool->replaceArgument($i++, $tags[0]['default_lifetime']);
}
$adapters[] = $chainedPool;
}
$pool->replaceArgument(0, $adapters);
unset($tags[0]['provider'], $tags[0]['namespace']);
$i = 1;
} else {
$i = 0;
}
foreach ($attributes as $attr) {
if (!isset($tags[0][$attr])) {
// no-op
} elseif ('reset' === $attr) {
if ($tags[0][$attr]) {
$pool->addTag($this->kernelResetTag, ['method' => $tags[0][$attr]]);
}
} elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) {
$pool->replaceArgument($i++, $tags[0][$attr]);
}
unset($tags[0][$attr]);
}
if (!empty($tags[0])) {
throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime" and "reset", found "%s".', $this->cachePoolTag, $id, implode('", "', array_keys($tags[0]))));
}
if (null !== $clearer) {
$clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
}
$allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
}
$notAliasedCacheClearerId = $this->cacheClearerId;
while ($container->hasAlias($this->cacheClearerId)) {
$this->cacheClearerId = (string) $container->getAlias($this->cacheClearerId);
}
if ($container->hasDefinition($this->cacheClearerId)) {
$clearers[$notAliasedCacheClearerId] = $allPools;
}
foreach ($clearers as $id => $pools) {
$clearer = $container->getDefinition($id);
if ($clearer instanceof ChildDefinition) {
$clearer->replaceArgument(0, $pools);
} else {
$clearer->setArgument(0, $pools);
}
$clearer->addTag($this->cachePoolClearerTag);
if ($this->cacheSystemClearerId === $id) {
$clearer->addTag($this->cacheSystemClearerTag);
}
}
if ($container->hasDefinition('console.command.cache_pool_list')) {
$container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($allPools));
}
}
private function getNamespace(string $seed, string $id)
{
return substr(str_replace('/', '-', base64_encode(hash('sha256', $id.$seed, true))), 0, 10);
}
/**
* @internal
*/
public static function getServiceProvider(ContainerBuilder $container, $name)
{
$container->resolveEnvPlaceholders($name, null, $usedEnvs);
if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) {
$dsn = $name;
if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) {
$definition = new Definition(AbstractAdapter::class);
$definition->setPublic(false);
$definition->setFactory([AbstractAdapter::class, 'createConnection']);
$definition->setArguments([$dsn, ['lazy' => true]]);
$container->setDefinition($name, $definition);
}
}
return $name;
}
}

View file

@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\DependencyInjection;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Rob Frawley 2nd <rmf@src.run>
*/
class CachePoolPrunerPass implements CompilerPassInterface
{
private $cacheCommandServiceId;
private $cachePoolTag;
public function __construct(string $cacheCommandServiceId = 'console.command.cache_pool_prune', string $cachePoolTag = 'cache.pool')
{
$this->cacheCommandServiceId = $cacheCommandServiceId;
$this->cachePoolTag = $cachePoolTag;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->cacheCommandServiceId)) {
return;
}
$services = [];
foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) {
$class = $container->getParameterBag()->resolveValue($container->getDefinition($id)->getClass());
if (!$reflection = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
if ($reflection->implementsInterface(PruneableInterface::class)) {
$services[$id] = new Reference($id);
}
}
$container->getDefinition($this->cacheCommandServiceId)->replaceArgument(0, new IteratorArgument($services));
}
}

View file

@ -13,6 +13,11 @@ namespace Symfony\Component\Cache;
use Doctrine\Common\Cache\CacheProvider; use Doctrine\Common\Cache\CacheProvider;
use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\CacheItemPoolInterface;
use Symfony\Contracts\Service\ResetInterface;
if (!class_exists(CacheProvider::class)) {
return;
}
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
@ -39,7 +44,7 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
*/ */
public function reset() public function reset()
{ {
if ($this->pool instanceof ResettableInterface) { if ($this->pool instanceof ResetInterface) {
$this->pool->reset(); $this->pool->reset();
} }
$this->setNamespace($this->getNamespace()); $this->setNamespace($this->getNamespace());
@ -47,6 +52,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return mixed
*/ */
protected function doFetch($id) protected function doFetch($id)
{ {
@ -57,6 +64,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
protected function doContains($id) protected function doContains($id)
{ {
@ -65,6 +74,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
protected function doSave($id, $data, $lifeTime = 0) protected function doSave($id, $data, $lifeTime = 0)
{ {
@ -79,6 +90,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
protected function doDelete($id) protected function doDelete($id)
{ {
@ -87,6 +100,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
protected function doFlush() protected function doFlush()
{ {
@ -95,6 +110,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return array|null
*/ */
protected function doGetStats() protected function doGetStats()
{ {

View file

@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception;
use Psr\Cache\CacheException as Psr6CacheInterface; use Psr\Cache\CacheException as Psr6CacheInterface;
use Psr\SimpleCache\CacheException as SimpleCacheInterface; use Psr\SimpleCache\CacheException as SimpleCacheInterface;
class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface if (interface_exists(SimpleCacheInterface::class)) {
{ class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface
{
}
} else {
class CacheException extends \Exception implements Psr6CacheInterface
{
}
} }

View file

@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception;
use Psr\Cache\InvalidArgumentException as Psr6CacheInterface; use Psr\Cache\InvalidArgumentException as Psr6CacheInterface;
use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface; use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface;
class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface if (interface_exists(SimpleCacheInterface::class)) {
{ class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface
{
}
} else {
class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface
{
}
} }

View file

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Exception;
use Psr\Cache\CacheException as Psr6CacheInterface;
use Psr\SimpleCache\CacheException as SimpleCacheInterface;
if (interface_exists(SimpleCacheInterface::class)) {
class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface
{
}
} else {
class LogicException extends \LogicException implements Psr6CacheInterface
{
}
}

View file

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

View file

@ -0,0 +1,161 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
/**
* LockRegistry is used internally by existing adapters to protect against cache stampede.
*
* It does so by wrapping the computation of items in a pool of locks.
* Foreach each apps, there can be at most 20 concurrent processes that
* compute items at the same time and only one per cache-key.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
final class LockRegistry
{
private static $openedFiles = [];
private static $lockedFiles;
private static $signalingException;
private static $signalingCallback;
/**
* The number of items in this list controls the max number of concurrent processes.
*/
private static $files = [
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractTagAwareAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AdapterInterface.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ApcuAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ArrayAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ChainAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpArrayAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpFilesAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ProxyAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'Psr16Adapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisTagAwareAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'SimpleCacheAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableAdapter.php',
__DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableTagAwareAdapter.php',
];
/**
* Defines a set of existing files that will be used as keys to acquire locks.
*
* @return array The previously defined set of files
*/
public static function setFiles(array $files): array
{
$previousFiles = self::$files;
self::$files = $files;
foreach (self::$openedFiles as $file) {
if ($file) {
flock($file, \LOCK_UN);
fclose($file);
}
}
self::$openedFiles = self::$lockedFiles = [];
return $previousFiles;
}
public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null)
{
if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) {
// disable locking on Windows by default
self::$files = self::$lockedFiles = [];
}
$key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1;
if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) {
return $callback($item, $save);
}
self::$signalingException ?? self::$signalingException = unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}");
self::$signalingCallback ?? self::$signalingCallback = function () { throw self::$signalingException; };
while (true) {
try {
// race to get the lock in non-blocking mode
$locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
if ($locked || !$wouldBlock) {
$logger && $logger->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]);
self::$lockedFiles[$key] = true;
$value = $callback($item, $save);
if ($save) {
if ($setMetadata) {
$setMetadata($item);
}
$pool->save($item->set($value));
$save = false;
}
return $value;
}
// if we failed the race, retry locking in blocking mode to wait for the winner
$logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]);
flock($lock, \LOCK_SH);
} finally {
flock($lock, \LOCK_UN);
unset(self::$lockedFiles[$key]);
}
try {
$value = $pool->get($item->getKey(), self::$signalingCallback, 0);
$logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]);
$save = false;
return $value;
} catch (\Exception $e) {
if (self::$signalingException !== $e) {
throw $e;
}
$logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]);
}
}
return null;
}
private static function open(int $key)
{
if (null !== $h = self::$openedFiles[$key] ?? null) {
return $h;
}
set_error_handler(function () {});
try {
$h = fopen(self::$files[$key], 'r+');
} finally {
restore_error_handler();
}
return self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r');
}
}

View file

@ -0,0 +1,99 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Marshaller;
use Symfony\Component\Cache\Exception\CacheException;
/**
* Serializes/unserializes values using igbinary_serialize() if available, serialize() otherwise.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class DefaultMarshaller implements MarshallerInterface
{
private $useIgbinarySerialize = true;
public function __construct(bool $useIgbinarySerialize = null)
{
if (null === $useIgbinarySerialize) {
$useIgbinarySerialize = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.6', phpversion('igbinary'), '<='));
} elseif ($useIgbinarySerialize && (!\extension_loaded('igbinary') || (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')))) {
throw new CacheException(\extension_loaded('igbinary') && \PHP_VERSION_ID >= 70400 ? 'Please upgrade the "igbinary" PHP extension to v3.1.6 or higher.' : 'The "igbinary" PHP extension is not loaded.');
}
$this->useIgbinarySerialize = $useIgbinarySerialize;
}
/**
* {@inheritdoc}
*/
public function marshall(array $values, ?array &$failed): array
{
$serialized = $failed = [];
foreach ($values as $id => $value) {
try {
if ($this->useIgbinarySerialize) {
$serialized[$id] = igbinary_serialize($value);
} else {
$serialized[$id] = serialize($value);
}
} catch (\Exception $e) {
$failed[] = $id;
}
}
return $serialized;
}
/**
* {@inheritdoc}
*/
public function unmarshall(string $value)
{
if ('b:0;' === $value) {
return false;
}
if ('N;' === $value) {
return null;
}
static $igbinaryNull;
if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') ? igbinary_serialize(null) : false)) {
return null;
}
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
if (':' === ($value[1] ?? ':')) {
if (false !== $value = unserialize($value)) {
return $value;
}
} elseif (false === $igbinaryNull) {
throw new \RuntimeException('Failed to unserialize values, did you forget to install the "igbinary" extension?');
} elseif (null !== $value = igbinary_unserialize($value)) {
return $value;
}
throw new \DomainException(error_get_last() ? error_get_last()['message'] : 'Failed to unserialize values.');
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}
/**
* @internal
*/
public static function handleUnserializeCallback($class)
{
throw new \DomainException('Class not found: '.$class);
}
}

View file

@ -0,0 +1,53 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Marshaller;
use Symfony\Component\Cache\Exception\CacheException;
/**
* Compresses values using gzdeflate().
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class DeflateMarshaller implements MarshallerInterface
{
private $marshaller;
public function __construct(MarshallerInterface $marshaller)
{
if (!\function_exists('gzdeflate')) {
throw new CacheException('The "zlib" PHP extension is not loaded.');
}
$this->marshaller = $marshaller;
}
/**
* {@inheritdoc}
*/
public function marshall(array $values, ?array &$failed): array
{
return array_map('gzdeflate', $this->marshaller->marshall($values, $failed));
}
/**
* {@inheritdoc}
*/
public function unmarshall(string $value)
{
if (false !== $inflatedValue = @gzinflate($value)) {
$value = $inflatedValue;
}
return $this->marshaller->unmarshall($value);
}
}

View file

@ -0,0 +1,40 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Marshaller;
/**
* Serializes/unserializes PHP values.
*
* Implementations of this interface MUST deal with errors carefully. They MUST
* also deal with forward and backward compatibility at the storage format level.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface MarshallerInterface
{
/**
* Serializes a list of values.
*
* When serialization fails for a specific value, no exception should be
* thrown. Instead, its key should be listed in $failed.
*/
public function marshall(array $values, ?array &$failed): array;
/**
* Unserializes a single value and throws an exception if anything goes wrong.
*
* @return mixed
*
* @throws \Exception Whenever unserialization fails
*/
public function unmarshall(string $value);
}

View file

@ -0,0 +1,89 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Marshaller;
/**
* A marshaller optimized for data structures generated by AbstractTagAwareAdapter.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class TagAwareMarshaller implements MarshallerInterface
{
private $marshaller;
public function __construct(MarshallerInterface $marshaller = null)
{
$this->marshaller = $marshaller ?? new DefaultMarshaller();
}
/**
* {@inheritdoc}
*/
public function marshall(array $values, ?array &$failed): array
{
$failed = $notSerialized = $serialized = [];
foreach ($values as $id => $value) {
if (\is_array($value) && \is_array($value['tags'] ?? null) && \array_key_exists('value', $value) && \count($value) === 2 + (\is_string($value['meta'] ?? null) && 8 === \strlen($value['meta']))) {
// if the value is an array with keys "tags", "value" and "meta", use a compact serialization format
// magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F allow detecting this format quickly in unmarshall()
$v = $this->marshaller->marshall($value, $f);
if ($f) {
$f = [];
$failed[] = $id;
} else {
if ([] === $value['tags']) {
$v['tags'] = '';
}
$serialized[$id] = "\x9D".($value['meta'] ?? "\0\0\0\0\0\0\0\0").pack('N', \strlen($v['tags'])).$v['tags'].$v['value'];
$serialized[$id][9] = "\x5F";
}
} else {
// other arbitratry values are serialized using the decorated marshaller below
$notSerialized[$id] = $value;
}
}
if ($notSerialized) {
$serialized += $this->marshaller->marshall($notSerialized, $f);
$failed = array_merge($failed, $f);
}
return $serialized;
}
/**
* {@inheritdoc}
*/
public function unmarshall(string $value)
{
// detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
if (13 >= \strlen($value) || "\x9D" !== $value[0] || "\0" !== $value[5] || "\x5F" !== $value[9]) {
return $this->marshaller->unmarshall($value);
}
// data consists of value, tags and metadata which we need to unpack
$meta = substr($value, 1, 12);
$meta[8] = "\0";
$tagLen = unpack('Nlen', $meta, 8)['len'];
$meta = substr($meta, 0, 8);
return [
'value' => $this->marshaller->unmarshall(substr($value, 13 + $tagLen)),
'tags' => $tagLen ? $this->marshaller->unmarshall(substr($value, 13, $tagLen)) : [],
'meta' => "\0\0\0\0\0\0\0\0" === $meta ? null : $meta,
];
}
}

View file

@ -0,0 +1,284 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache;
use Psr\Cache\CacheException as Psr6CacheException;
use Psr\Cache\CacheItemPoolInterface;
use Psr\SimpleCache\CacheException as SimpleCacheException;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Traits\ProxyTrait;
if (null !== (new \ReflectionMethod(CacheInterface::class, 'get'))->getReturnType()) {
throw new \LogicException('psr/simple-cache 3.0+ is not compatible with this version of symfony/cache. Please upgrade symfony/cache to 6.0+ or downgrade psr/simple-cache to 1.x or 2.x.');
}
/**
* Turns a PSR-6 cache into a PSR-16 one.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterface
{
use ProxyTrait;
private const METADATA_EXPIRY_OFFSET = 1527506807;
private $createCacheItem;
private $cacheItemPrototype;
public function __construct(CacheItemPoolInterface $pool)
{
$this->pool = $pool;
if (!$pool instanceof AdapterInterface) {
return;
}
$cacheItemPrototype = &$this->cacheItemPrototype;
$createCacheItem = \Closure::bind(
static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) {
$item = clone $cacheItemPrototype;
$item->poolHash = $item->innerItem = null;
$item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key);
$item->value = $value;
$item->isHit = false;
return $item;
},
null,
CacheItem::class
);
$this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) {
if (null === $this->cacheItemPrototype) {
$this->get($allowInt && \is_int($key) ? (string) $key : $key);
}
$this->createCacheItem = $createCacheItem;
return $createCacheItem($key, null, $allowInt)->set($value);
};
}
/**
* {@inheritdoc}
*
* @return mixed
*/
public function get($key, $default = null)
{
try {
$item = $this->pool->getItem($key);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
if (null === $this->cacheItemPrototype) {
$this->cacheItemPrototype = clone $item;
$this->cacheItemPrototype->set(null);
}
return $item->isHit() ? $item->get() : $default;
}
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
try {
if (null !== $f = $this->createCacheItem) {
$item = $f($key, $value);
} else {
$item = $this->pool->getItem($key)->set($value);
}
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
if (null !== $ttl) {
$item->expiresAfter($ttl);
}
return $this->pool->save($item);
}
/**
* {@inheritdoc}
*
* @return bool
*/
public function delete($key)
{
try {
return $this->pool->deleteItem($key);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*
* @return bool
*/
public function clear()
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
try {
$items = $this->pool->getItems($keys);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
$values = [];
if (!$this->pool instanceof AdapterInterface) {
foreach ($items as $key => $item) {
$values[$key] = $item->isHit() ? $item->get() : $default;
}
return $values;
}
foreach ($items as $key => $item) {
if (!$item->isHit()) {
$values[$key] = $default;
continue;
}
$values[$key] = $item->get();
if (!$metadata = $item->getMetadata()) {
continue;
}
unset($metadata[CacheItem::METADATA_TAGS]);
if ($metadata) {
$values[$key] = ["\x9D".pack('VN', (int) (0.1 + $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]];
}
}
return $values;
}
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{
$valuesIsArray = \is_array($values);
if (!$valuesIsArray && !$values instanceof \Traversable) {
throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', \is_object($values) ? \get_class($values) : \gettype($values)));
}
$items = [];
try {
if (null !== $f = $this->createCacheItem) {
$valuesIsArray = false;
foreach ($values as $key => $value) {
$items[$key] = $f($key, $value, true);
}
} elseif ($valuesIsArray) {
$items = [];
foreach ($values as $key => $value) {
$items[] = (string) $key;
}
$items = $this->pool->getItems($items);
} else {
foreach ($values as $key => $value) {
if (\is_int($key)) {
$key = (string) $key;
}
$items[$key] = $this->pool->getItem($key)->set($value);
}
}
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
$ok = true;
foreach ($items as $key => $item) {
if ($valuesIsArray) {
$item->set($values[$key]);
}
if (null !== $ttl) {
$item->expiresAfter($ttl);
}
$ok = $this->pool->saveDeferred($item) && $ok;
}
return $this->pool->commit() && $ok;
}
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
try {
return $this->pool->deleteItems($keys);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($key)
{
try {
return $this->pool->hasItem($key);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
}
}

View file

@ -1,18 +1,19 @@
Symfony PSR-6 implementation for caching Symfony PSR-6 implementation for caching
======================================== ========================================
This component provides an extended [PSR-6](http://www.php-fig.org/psr/psr-6/) The Cache component provides extended
implementation for adding cache to your applications. It is designed to have a [PSR-6](https://www.php-fig.org/psr/psr-6/) implementations for adding cache to
low overhead so that caching is fastest. It ships with a few caching adapters your applications. It is designed to have a low overhead so that caching is
for the most widespread and suited to caching backends. It also provides a fastest. It ships with adapters for the most widespread caching backends.
`doctrine/cache` proxy adapter to cover more advanced caching needs and a proxy It also provides a [PSR-16](https://www.php-fig.org/psr/psr-16/) adapter,
adapter for greater interoperability between PSR-6 implementations. and implementations for [symfony/cache-contracts](https://github.com/symfony/cache-contracts)'
`CacheInterface` and `TagAwareCacheInterface`.
Resources Resources
--------- ---------
* [Documentation](https://symfony.com/doc/current/components/cache.html) * [Documentation](https://symfony.com/doc/current/components/cache.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and * [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls) [send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony) in the [main Symfony repository](https://github.com/symfony/symfony)

View file

@ -11,10 +11,11 @@
namespace Symfony\Component\Cache; namespace Symfony\Component\Cache;
use Symfony\Contracts\Service\ResetInterface;
/** /**
* Resets a pool's local state. * Resets a pool's local state.
*/ */
interface ResettableInterface interface ResettableInterface extends ResetInterface
{ {
public function reset();
} }

View file

@ -12,37 +12,37 @@
namespace Symfony\Component\Cache\Simple; namespace Symfony\Component\Cache\Simple;
use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareInterface;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\AbstractTrait; use Symfony\Component\Cache\Traits\AbstractTrait;
use Symfony\Contracts\Cache\CacheInterface;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', AbstractCache::class, AbstractAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @deprecated since Symfony 4.3, use AbstractAdapter and type-hint for CacheInterface instead.
*/ */
abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, ResettableInterface abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface
{ {
/**
* @internal
*/
const NS_SEPARATOR = ':';
use AbstractTrait { use AbstractTrait {
deleteItems as private; deleteItems as private;
AbstractTrait::deleteItem as delete; AbstractTrait::deleteItem as delete;
AbstractTrait::hasItem as has; AbstractTrait::hasItem as has;
} }
/**
* @internal
*/
protected const NS_SEPARATOR = ':';
private $defaultLifetime; private $defaultLifetime;
/** protected function __construct(string $namespace = '', int $defaultLifetime = 0)
* @param string $namespace
* @param int $defaultLifetime
*/
protected function __construct($namespace = '', $defaultLifetime = 0)
{ {
$this->defaultLifetime = max(0, (int) $defaultLifetime); $this->defaultLifetime = max(0, $defaultLifetime);
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
@ -61,7 +61,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
return $value; return $value;
} }
} catch (\Exception $e) { } catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]); CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
} }
return $default; return $default;
@ -69,6 +69,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function set($key, $value, $ttl = null) public function set($key, $value, $ttl = null)
{ {
@ -79,6 +81,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return iterable
*/ */
public function getMultiple($keys, $default = null) public function getMultiple($keys, $default = null)
{ {
@ -95,7 +99,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
try { try {
$values = $this->doFetch($ids); $values = $this->doFetch($ids);
} catch (\Exception $e) { } catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => $keys, 'exception' => $e]); CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]);
$values = []; $values = [];
} }
$ids = array_combine($ids, $keys); $ids = array_combine($ids, $keys);
@ -105,6 +109,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function setMultiple($values, $ttl = null) public function setMultiple($values, $ttl = null)
{ {
@ -134,13 +140,16 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
foreach (\is_array($e) ? $e : array_keys($valuesById) as $id) { foreach (\is_array($e) ? $e : array_keys($valuesById) as $id) {
$keys[] = substr($id, \strlen($this->namespace)); $keys[] = substr($id, \strlen($this->namespace));
} }
CacheItem::log($this->logger, 'Failed to save values', ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]); $message = 'Failed to save values'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]);
return false; return false;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteMultiple($keys) public function deleteMultiple($keys)
{ {
@ -168,19 +177,19 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re
throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($ttl) ? \get_class($ttl) : \gettype($ttl))); throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($ttl) ? \get_class($ttl) : \gettype($ttl)));
} }
private function generateValues($values, &$keys, $default) private function generateValues(iterable $values, array &$keys, $default): iterable
{ {
try { try {
foreach ($values as $id => $value) { foreach ($values as $id => $value) {
if (!isset($keys[$id])) { if (!isset($keys[$id])) {
$id = key($keys); throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys)));
} }
$key = $keys[$id]; $key = $keys[$id];
unset($keys[$id]); unset($keys[$id]);
yield $key => $value; yield $key => $value;
} }
} catch (\Exception $e) { } catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => array_values($keys), 'exception' => $e]); CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]);
} }
foreach ($keys as $key) { foreach ($keys as $key) {

View file

@ -11,18 +11,20 @@
namespace Symfony\Component\Cache\Simple; namespace Symfony\Component\Cache\Simple;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Traits\ApcuTrait; use Symfony\Component\Cache\Traits\ApcuTrait;
use Symfony\Contracts\Cache\CacheInterface;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ApcuCache::class, ApcuAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
/**
* @deprecated since Symfony 4.3, use ApcuAdapter and type-hint for CacheInterface instead.
*/
class ApcuCache extends AbstractCache class ApcuCache extends AbstractCache
{ {
use ApcuTrait; use ApcuTrait;
/** public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
* @param string $namespace
* @param int $defaultLifetime
* @param string|null $version
*/
public function __construct($namespace = '', $defaultLifetime = 0, $version = null)
{ {
$this->init($namespace, $defaultLifetime, $version); $this->init($namespace, $defaultLifetime, $version);
} }

View file

@ -12,16 +12,20 @@
namespace Symfony\Component\Cache\Simple; namespace Symfony\Component\Cache\Simple;
use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareInterface;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface as Psr16CacheInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ArrayTrait; use Symfony\Component\Cache\Traits\ArrayTrait;
use Symfony\Contracts\Cache\CacheInterface;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ArrayCache::class, ArrayAdapter::class, CacheInterface::class), \E_USER_DEPRECATED);
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @deprecated since Symfony 4.3, use ArrayAdapter and type-hint for CacheInterface instead.
*/ */
class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInterface class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface
{ {
use ArrayTrait { use ArrayTrait {
ArrayTrait::deleteItem as delete; ArrayTrait::deleteItem as delete;
@ -31,12 +35,11 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
private $defaultLifetime; private $defaultLifetime;
/** /**
* @param int $defaultLifetime
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
*/ */
public function __construct($defaultLifetime = 0, $storeSerialized = true) public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
{ {
$this->defaultLifetime = (int) $defaultLifetime; $this->defaultLifetime = $defaultLifetime;
$this->storeSerialized = $storeSerialized; $this->storeSerialized = $storeSerialized;
} }
@ -45,13 +48,26 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
*/ */
public function get($key, $default = null) public function get($key, $default = null)
{ {
foreach ($this->getMultiple([$key], $default) as $v) { if (!\is_string($key) || !isset($this->expiries[$key])) {
return $v; CacheItem::validateKey($key);
} }
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > microtime(true) || !$this->delete($key))) {
$this->values[$key] = null;
return $default;
}
if (!$this->storeSerialized) {
return $this->values[$key];
}
$value = $this->unfreeze($key, $isHit);
return $isHit ? $value : $default;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return iterable
*/ */
public function getMultiple($keys, $default = null) public function getMultiple($keys, $default = null)
{ {
@ -61,14 +77,18 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys))); throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
} }
foreach ($keys as $key) { foreach ($keys as $key) {
CacheItem::validateKey($key); if (!\is_string($key) || !isset($this->expiries[$key])) {
CacheItem::validateKey($key);
}
} }
return $this->generateItems($keys, time(), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; }); return $this->generateItems($keys, microtime(true), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; });
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function deleteMultiple($keys) public function deleteMultiple($keys)
{ {
@ -84,16 +104,22 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function set($key, $value, $ttl = null) public function set($key, $value, $ttl = null)
{ {
CacheItem::validateKey($key); if (!\is_string($key)) {
CacheItem::validateKey($key);
}
return $this->setMultiple([$key => $value], $ttl); return $this->setMultiple([$key => $value], $ttl);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return bool
*/ */
public function setMultiple($values, $ttl = null) public function setMultiple($values, $ttl = null)
{ {
@ -103,27 +129,20 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
$valuesArray = []; $valuesArray = [];
foreach ($values as $key => $value) { foreach ($values as $key => $value) {
\is_int($key) || CacheItem::validateKey($key); if (!\is_int($key) && !(\is_string($key) && isset($this->expiries[$key]))) {
CacheItem::validateKey($key);
}
$valuesArray[$key] = $value; $valuesArray[$key] = $value;
} }
if (false === $ttl = $this->normalizeTtl($ttl)) { if (false === $ttl = $this->normalizeTtl($ttl)) {
return $this->deleteMultiple(array_keys($valuesArray)); return $this->deleteMultiple(array_keys($valuesArray));
} }
if ($this->storeSerialized) { $expiry = 0 < $ttl ? microtime(true) + $ttl : \PHP_INT_MAX;
foreach ($valuesArray as $key => $value) {
try {
$valuesArray[$key] = serialize($value);
} catch (\Exception $e) {
$type = \is_object($value) ? \get_class($value) : \gettype($value);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => $key, 'type' => $type, 'exception' => $e]);
return false;
}
}
}
$expiry = 0 < $ttl ? time() + $ttl : \PHP_INT_MAX;
foreach ($valuesArray as $key => $value) { foreach ($valuesArray as $key => $value) {
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;
}
$this->values[$key] = $value; $this->values[$key] = $value;
$this->expiries[$key] = $expiry; $this->expiries[$key] = $expiry;
} }

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